定时器 + 动态数码管实现秒表功能
// 定时器 + 动态数码管显示秒表功能 #include <reg52.h> #define u16 unsigned int #define u8 unsigned char // 74LS138译码器的管脚(用于控制动态数码管的显示,本例只使用右边的四个数码管) sbit LSA=P2^2; sbit LSB=P2^3; sbit LSC=P2^4; // 数码管显示0-9 u8 code smgduan[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; // 将4位数码管的数字保存到一个数组中 u8 disp[4]; u16 num=0; // 数码管要显示的数字 // 延迟函数 void delay(u16 j) { while(j--); } // 数据处理,提取各位数字 void datapros() { disp[0]=smgduan[num/1000]; // 千位 disp[1]=smgduan[num%1000/100]; // 百位 disp[2]=smgduan[num%1000%100/10]; // 十位 disp[3]=smgduan[num%1000%100%10]; // 个位 } // 数码管显示函数 void DigDisplay() { u8 t; for(t=0;t<4;t++) { switch(t) // 位选,选择点亮的数码管, { case(0): LSA=0;LSB=0;LSC=0; break; // 显示第0位 case(1): LSA=1;LSB=0;LSC=0; break; // 显示第1位 case(2): LSA=0;LSB=1;LSC=0; break; // 显示第2位 case(3): LSA=1;LSB=1;LSC=0; break; // 显示第3位 } P0=disp[3-t]; // 发送数据 delay(100); // 间隔一段时间扫描 P0=0x00; // 消隐 } } // 定时器T0初始化函数 void Timer0Init() { /* (1)工作方式:TMOD是8位的,高四位用于T1(GATE、C/T非、M1、M0), 低四位用于T0(GATE、C/T非、M1、M0),它们的使用请参考单片机资料。 这里设置GATE=0,C/T非=0,M1M0=01(工作方式1,16位定时器),所以低四位是:0001, 高四位是:0000,所以是0x01 */ TMOD=0x01; /* (2)计算初值:假设定时器定时1ms,即1000us,则需要1001个计数才会溢出,发生中断请求, 因为定时器0是由TH0和TL0两个寄存器组成,每个寄存器是8位,总共是16位,总数是2^16=65536, 从0开始计数,所以是0-65535,所以,初值=65535-1000+1=64536,转成十六进制数是:FC18, 故高四位TH0=0xFC,低四位TL0=0x18 */ TH0=0xFC; TL0=0x18; /* (3)中断允许位:如果定时器在数据溢出后需要向单片机CPU发出中断请求, 还需要开启CPU中断总允许位,即EA=1,同时,需要开启定时器T0的中断允许位ET0,即ET0=1 */ EA=1; ET0=1; /* (4)启动定时器工作:由电路图可知,需要将TR0置1,才能让定时器工作 */ TR0=1; } // 主函数 void main() { // 定时器初始化 Timer0Init(); while(1) { DigDisplay(); // 数码管显示函数 } } // 定时器T0的中断函数 void Timer0() interrupt 1 { // 计数变量:用static关键字修饰,表示全局变量 static u16 i; /* 因为定时器选择工作方式1(M1M0=01,表示工作方式1,16位的定时器,没有自动重装功能), 工作方式2(M1M0=10)由自动重装功能,是8位的定时器,总共有4中工作方式,查资料可知, 需要把初始值重新写入TH0和TL0中 */ TH0=0xFC; TL0=0x18; /* 每次中断i都加1表示计数,每次中断时长是1ms,如果想让LED灯每隔1s切换一次状态, 就需要让i=1000 */ i++; if(i==1000) // 计时达到1s { i=0; // 让i复位 num ++; // 每隔1秒就自增 datapros(); // 数据处理函数 } }