关键词:定时器T0;秒表;数码管;按键扫描;中断;Delay;按键暂停/启动、清零;定时器的精准定时和多时段计时;小蜜蜂
一、实验
实验目的:
所需部件:
1.定时器T0的初始化函数——>计数初值设置(由最小单位0.5s即50ms决定)
2.定时器T0的中断服务函数——>计数初值重置、......
3.数码管:要显示多位,用到动态数码管显示原理——>先数码管显示单位Bit(显示的数值,显示的位置)——>HC573锁存器选择不同信道+段码表
4.数码管要显示分-秒-0.5秒,所以需要3个变量,且这三个变量会随着值的变化而变化——>中断服务函数中t_05s++......
5.独立按键S4,S5,位声明以及扫描按键
模块化:
1.独立按键S4,S5,位声明+数码管要显示分-秒-0.5秒这3个变量的设置+段码表
2.HC573锁存器选择不同信道函数
3.数码管显示单位Bit(value,pos)函数
4..数码管显示完整时间
5.扫描数码管的延时函数
6.定时器T0的初始化函数
7.定时器T0的中断服务函数
8.扫描按键S4,S5,并做清零、启动/暂停操作
9.main函数
完整代码:
#include <REGX52.H>
sbit S4=P3^3;
sbit S5=P3^2;
unsigned char t_min=0;
unsigned char t_s=0;
unsigned char t_05s=0;
unsigned char code SMG_duanma[18]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E,0xBF,0xFF};
//数码管0-9,A-F,-,空白(b,d用小写表示)
void SelectHC573(unsigned char channel)
{
switch(channel)
{
case 4:P2=(P2&0x1f)|0x80;break;
case 5:P2=(P2&0x1f)|0xA0;break;
case 6:P2=(P2&0x1f)|0xC0;break;
case 7:P2=(P2&0x1f)|0xE0;break;
}
}
void DisplaySMG_Bit(unsigned char value,pos)
{
SelectHC573(6);
P0=0x01<<pos;
SelectHC573(7);
P0=value;
}
void DelaySMG(unsigned int t)
{
while(t--);
}
void DisplaySMG_Time()
{
DisplaySMG_Bit(SMG_duanma[t_05s%10],7);
DelaySMG(500);
DisplaySMG_Bit(SMG_duanma[t_05s/10],6);
DelaySMG(500);
DisplaySMG_Bit(SMG_duanma[16],5);
DelaySMG(500);
DisplaySMG_Bit(SMG_duanma[t_s%10],4);
DelaySMG(500);
DisplaySMG_Bit(SMG_duanma[t_s/10],3);
DelaySMG(500);
DisplaySMG_Bit(SMG_duanma[16],2);
DelaySMG(500);
DisplaySMG_Bit(SMG_duanma[t_min%10],1);
DelaySMG(500);
DisplaySMG_Bit(SMG_duanma[t_min/10],0);
DelaySMG(500);
}
//**************定时器相关函数*****************
void InitTimer0()
{
TMOD=0x01;
TL0=(65535-50000)%256;
TH0=(65535-50000)/256;
ET0=1;
EA=1;
TR0=1;
}
void ServiceTimer0() interrupt 1
{
TL0=(65535-50000)%256;
TH0=(65535-50000)/256;//重置计数初值
t_05s++;
if(t_05s==20)
{
t_s++;
t_05s=0; //低位满值后,高位+1,低位清零,依次循环嵌套
if(t_s==60)
{
t_min++;
t_s=0;
if(t_min==99)
t_min=0;
}
}
}
//*********************************************
void DelayK(unsigned char t)
{
while(t--);
}
void ScanKeys()
{
if(S4==0) //暂停/启动
{
DelayK(100);
if(S4==0)
{
TR0=~TR0;//暂停/启动的快捷写法,即定时器的启动和暂停
}
}
if(S5==0) //清零
{
DelayK(100);
if(S5==0)
{
t_min=0;
t_s=0;
t_05s=0; //所有数据/变量清零
}
}
}
void main()
{
InitTimer0();
while(1)
{
DisplaySMG_Time();
ScanKeys(); //数码管显示完整时间和按键需要不断扫描
}
}
二、亮点收获
1.中断服务函数中关于分-秒-0.5秒的循环嵌套
void ServiceTimer0() interrupt 1
{
TL0=(65535-50000)%256;
TH0=(65535-50000)/256;//重置计数初值
t_05s++;
if(t_05s==20)
{
t_s++;
t_05s=0; //低位满值后,高位+1,低位清零,依次循环嵌套
if(t_s==60)
{
t_min++;
t_s=0;
if(t_min==99)
t_min=0;
}
}
}
2. Delay函数在不同场合下的不同
①按键扫描中消抖——短延时
void DelayK(unsigned char t)
{
while(t--);
}
一般Delay(100)
②数码管动态扫描
void DelaySMG(unsigned int t)
{
while(t--);
}
一般Delay(500)
③LED闪烁较明显或要求长延时
void Delay(unsigned int t)
{
while(t--);
while(t--);
while(t--);//较长的延时
}
一般Delay(60000)
3.定时器中断中暂停方法
void ScanKeys()
{
if(S4==0) //暂停/启动
{
DelayK(100);
if(S4==0)
{
TR0=~TR0;//暂停/启动的快捷写法,即定时器的启动和暂停
}
}
}
4. 在main函数while内和while执行的函数模块
void main()
{
InitTimer0();
while(1)
{
DisplaySMG_Time();
ScanKeys(); //数码管显示完整时间和按键需要不断扫描
}
}
三、联想拓展—— AT24C02数据存储加Buff
感谢B站小蜜蜂老师的教程,本笔记资料及代码均来自教程,仅作为个人复习、整理和学习交流用。