前言
学习资料参考
基本应用:
https://www.bilibili.com/video/BV1Bt41187hw?p=9&vd_source=e2191f89c557f5ac44bb6c7aa3967c7c
进阶应用:
LED基本控制可以参考以下笔记:
https://blog.csdn.net/zicheng_G/article/details/142025188?fromshare=blogdetail&sharetype=blogdetail&sharerId=142025188&sharerefer=PC&sharesource=zicheng_G&sharefrom=from_link
数码管的基本控制可以参考以下笔记:
https://blog.csdn.net/zicheng_G/article/details/142304378?fromshare=blogdetail&sharetype=blogdetail&sharerId=142304378&sharerefer=PC&sharesource=zicheng_G&sharefrom=from_link
本节训练重点
- 定时器实现秒闪功能:利用51单片机的定时/计数器T0的模式1实现间隔定时,每隔1秒L1指示灯闪烁一下,也就是点亮0.5秒,熄灭0.5秒;每隔10秒L8指示灯闪烁一下,即点亮5秒,熄灭5秒。
- 定时器实现秒表功能:利用定时器T0、数码管模块和2个独立按键,设计一个秒表,具有清零、暂停、启动功能。
定时器/计数器
原理
51单片机有两个定时器/计数器T0和T1,为16位加法计数器,由低8位TLx和高8位THx两个寄存器组成,最大计数值为65535个技术脉冲。
计数器的技术脉冲有两个来源:
- 系统时钟振荡器输出的12分频
- T0或T1引脚输入的外部脉冲信号
计数器每接收到一个脉冲是计数脉冲,计数器加1,当计数器记满时溢出,计数归零,计数器向内核发出中断请求,进入中断函数。
关于定时器的相关知识,可以参考我的51单片机的笔记中9的内容,链接如下:
https://blog.csdn.net/zicheng_G/article/details/140287386?fromshare=blogdetail&sharetype=blogdetail&sharerId=140287386&sharerefer=PC&sharesource=zicheng_G&sharefrom=from_link
编程思路
定时器实现秒闪功能
/*函数声明区域*/
#include <REGX52.H>
/*变量声明区域*/
sbit HC89C53_C = P2^7;
sbit HC89C53_B = P2^6;
sbit HC89C53_A = P2^5;
sbit L1 = P0^0;
sbit L8 = P0^7;
unsigned char CountShort; //定时器短定时专用
unsigned char CountLong; //定时器长定时专用
/*三八译码器选中Y4*/
void HC89C53()
{
HC89C53_C = 1;
HC89C53_B = 0;
HC89C53_A = 0;
}
/*定时器初始化函数*/
void Timer0Init(void) //50毫秒@12.000MHz
{
/*TMOD=0x01,选中定时器1,置为计时器模式*/
TMOD &= 0xF0; //把TMOD的低四位清零,高四位保持不变
TMOD |= 0x01; //把TMOD最低位置1,高四位保持不变
/*设置定时初值,50毫秒*/
TL0 = (65535 - 50000) / 256;
TH0 = (65535 - 50000) % 256;
ET0=1; //中断允许控制寄存器闭合
EA=1; //CPU开放中断
TR0 = 1; //定时器0开始计时
}
/*主函数*/
void main()
{
Timer0Init();
while(1)
{
}
}
/*定时器中断函数*/
void ServiceTimer0() interrupt 1
{
/*重新配置定时值,50毫秒*/
TL0 = (65535 - 50000) / 256;
TH0 = (65535 - 50000) % 256;
CountShort++;
CountLong++;
/*每隔500毫秒L1指示灯闪烁一下*/
if(CountShort == 10)
{
HC89C53();
L1 = ~L1;
CountShort = 0;
}
/*每隔10秒L8指示灯闪烁一下*/
if(CountLong == 100)
{
HC89C53();
L8 = ~L8;
CountLong = 0;
}
}
定时器实现秒表功能
- 显示格式为:分 - 秒 - 50ms记一次
- 独立按键S4控制暂停和启动,S5控制清零,按键按下有效。
/*函数声明区域*/
#include <REGX52.H>
/*变量声明区域*/
sbit HC138_C = P2^7;
sbit HC138_B = P2^6;
sbit HC138_A = P2^5;
sbit S4=P3^3;//定义独立按键
sbit S5=P3^2;
unsigned char min,s,x5ms;//定义变量记录分、秒、0.05毫秒
unsigned char code lib_Bit_Number[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf};//数码管显示的数字和分隔符
/*三八译码器选中函数*/
void HC138(unsigned char Y)
{
switch(Y)
{
case 6:
{
HC138_C = 1;
HC138_B = 1;
HC138_A = 0;
break;
}
case 7:
{
HC138_C = 1;
HC138_B = 1;
HC138_A = 1;
break;
}
}
}
/*单个数码管的静态显示函数*/
void NiTu_Sig(unsigned char Seg,value)
{
/*数码管位选*/
HC138(6);
P0=(0x01<<Seg);
/*数码管段选*/
HC138(7);
P0=lib_Bit_Number[value];
}
/*数码管用的延时延时函数*/
void DelayNi(unsigned char t)
{
while(t--);
}
/*数码管的动态显示*/
void NiTu_Show()
{
/*第三部分的显示*/
NiTu_Sig(7,x5ms%10);
DelayNi(500);
NiTu_Sig(6,x5ms/10);
DelayNi(500);
/*第二部分的显示*/
NiTu_Sig(4,s%10);
DelayNi(500);
NiTu_Sig(3,s/10);
DelayNi(500);
/*第一部分的显示*/
NiTu_Sig(1,min%10);
DelayNi(500);
NiTu_Sig(0,min/10);
DelayNi(500);
/*分隔符的显示*/
NiTu_Sig(5,10);
DelayNi(500);
NiTu_Sig(2,10);
DelayNi(500);
}
/*按键去抖函数*/
void DelayKey(unsigned char t)
{
while(t--);
}
/*独立按键扫描函数*/
void Key_Scan()
{
/*S4按下,计时暂停或启动*/
if(S4==0)
{
DelayKey(100);
if(S4==0)
{
TR0= ~TR0;
while(S4==0);
}
}
/*S5按下,数码管清零*/
if(S5==0)
{
DelayKey(100);
if(S5==0)
{
x5ms=0;
s=0;
min=0;
while(S5==0);
}
}
}
/*定时器初始化函数*/
void Timer0Init(void) //50毫秒@12.000MHz
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0xB0; //设置定时初值
TH0 = 0x3C; //设置定时初值
ET0 = 1;
EA=1;
TR0 = 1; //定时器0开始计时
}
/*主函数*/
void main()
{
Timer0Init();
while(1)
{
NiTu_Show();
Key_Scan();
}
}
/*定时器中断函数*/
void ServiceTimer0() interrupt 1
{
/*重新配置定时值,50毫秒*/
TL0 = 0xB0;
TH0 = 0x3C;
x5ms++;//数码管第三部分加一
if(x5ms==20)//当计时时间到达100毫秒时
{
s++; //每隔100ms,秒数加一
x5ms=0;//第三部分重新开始计时
if(s==60)
{
min++;//每隔60s,分钟加一
s=0;//秒数部分重新开始计时
/*当分钟计到100时,计时重新开始*/
if(min==100)
{
x5ms=0;
s=0;
min=0;
}
}
}
}