当前位置:文档之家› 89C51单片机最小系统设计(电子时钟,秒表,按键计数的单片机设计)

89C51单片机最小系统设计(电子时钟,秒表,按键计数的单片机设计)

一、电子时钟、秒表和计数器的设计1、实现的功能:1)有key0,key1两个功能按键,复位后,数码管会默认显示时钟模式HH.MM 。

(HH表示小时,MM表示分钟),key0短按一次就进入到了秒表模式,数码管显示格式S.SS.S,(分别表示百秒,秒,毫秒)key0再短按一次就进入到了计数器模式,数码管显示格式CCCC(分别为千位百位十位个位)。

key0再短按一次,又进入到了时钟显示模式,就这样由key0控制模式的转换。

2)有RST复位键,本身电路设计有上电自动复位功能,按下RST后,电路复位。

3)有ckey0,ckey1 两个计数按键,按下ckey0,计数加一,按下ckey1,计数减一。

4) 电子时钟和秒表时间计时方法是采用89S52内部计时器0的一种工作方式(详见后面的代码分析),通过计时器0中断来控制时间的运行。

5)计数器是采用外部中断0和外部中断1这两个外部中断实现加1和减1的操作。

(1)电子时钟模式:(以下“长按”表示按下按键的时间大于1秒,“短按”表示按下的时间小于0.7 秒)1)长按key1一次,会进入到调整分钟的模式,短按key1一次,分钟会加一。

第二次长按key1,会进入到调整小时的模式,短按key1一次,小时加一。

第三次长按key1,重新回到时钟显示模式,这时再短按key1,时间不会变化2)长按key0一次,会进入到显示秒的模式(2)秒表模式:1)由key0控制进入秒表模式后,短按key1一次,秒表计时开始,再短按key1一次计时结束2)长按key1一次,秒表清零(3)计数器模式1)按ckey0一下,计数加一,数码管相应的显示的数值加一,按ckey1一下,计数减一,数码管相应的显示的数值减一,由于数码管的位数限制,最大只能显示到9999,此时按下ckey0无反应;考虑到实际计数功能,没有设置负数,所以最小显示0000,这时按下ckey1 ,无反应。

2)长按key1一次计数器清零。

2、电路原理图(1)使用片内振荡器(2)具有上电复位和手动复位两个功能(3)key0,key1分别接P1.0和P1.1引脚(4)由P0.0~P0.7输出到七段数码显示管(5)由P2.0~P2.3接三极管,驱动共阳七段数码显示管(6) ckey0,ckey1接P3.2和P3.3两个引脚,为两个外部中断4.电路焊接实物图(1)正面(2)反面:由于显影、腐蚀过程做得不好,导致电路板过度腐蚀,但是经过修改之后,电路可以正常运行,并无大碍,只是不美观。

(4)电路板工作时。

此时为显示时钟的秒显示时钟显示秒表显示计数器5、程序设计分析(1)程序代码#include<Reg51.h>sbit key0=P1^0;sbit key1=P1^1; //定义key0,key1接口unsigned char flag,con,mcount; //flag为计数到一秒时给时钟发的信号unsigned char count = 0;unsigned char seccount =0; //作为时钟的秒的计量单位unsigned char hour = 0; //时钟的时unsigned char min = 0; //时钟的分unsigned char sec = 0; //时钟的秒unsigned char keypress0,keypress1,mode,ms,s,ss,start;unsigned charDisplaynum[]={0x14,0xd7,0x4c,0x45,0x87,0x25,0x24,0x57,0x04,0x05, 0x10,0xd3,0x48,0x41,0x83,0x21,0x20,0x53,0x00,0x01,0xff,0xfb};//数码管十六进制译码表unsigned char controlnum[]={0x08,0x04,0x02,0x01}; //控制四个数码管显示unsigned char DisplayBuff[]={0x00, 0x00, 0x00, 0x00}; //每个数码管的值void display_state(); //数码管显示子程序void keyscan(); //键盘扫描子程序void timer(); //秒表子程序unsigned char count1,flag1,t_adjust=0,tm_adjust=0;unsigned charbKey0Pressed = 0, bKey1Pressed = 0;unsigned char ucStatus = 0;void main(){TMOD = 0x01; //定时器0工作在模式1,GATE=0,C/t=0,16位模TH0= (2^16-5000)/256;//定时器0 预存值,TL0= (2^16-5000)%256;TR0= 1; //定时器0 启动ET0= 1; //定时器中断0 允许EA= 1; //开中断IT0=1; //外部中断0下降沿触发IT1=1; //外部中断1 下降沿触发EX0=1; //外部中断0允许EX1=1; //外部中断1允许PX1=1; //外部中断1 为高优先级中断while(1) //死循环,{if(flag == 1) //时钟显示{flag = 0;sec++;if(sec ==60){sec = 0;min++;if(min ==60){min = 0;hour ++;if(hour == 24){hour = 0;}}}}display_state();keyscan();timer();}}//////////////////////////////////ISR中断服务程序,每5ms产生一个定时器0 中断void Display() interrupt 1{TH0 = (2^16-5000)/256;TL0 = (2^16-5000)%256;seccount ++;mcount ++;keypress0++;keypress1++;P2=0x00; //P2口先清零P0 = Displaynum[DisplayBuff[count]]; //P0口输出P2 = controlnum[count]; //P2口输出count++;if(count==4)count=0;if(seccount == 200) //200*5ms=1s{ seccount =0;flag =1; //每过1秒给时钟信号加一秒}}///////////////////////////////////////////void display_state(){if(mode == 0) //时钟模式,显示时间{DisplayBuff[0] = hour/10;DisplayBuff[1] = (hour%10)+10; //“+10”是为了显示加点的数字DisplayBuff[2] = min/10;DisplayBuff[3] = min%10;}if(mode == 1) //秒表模式,显示秒表{DisplayBuff[0] = ss +10; //“+10”是为了显示加点的数字DisplayBuff[1] = s/10;DisplayBuff[2] = (s%10)+10;DisplayBuff[3] = ms;}if(mode == 2) // 计数器模式,显示计数{DisplayBuff[0] = count1/1000; //千位DisplayBuff[1] = (count1-(count1/1000)*1000)/100; //百位DisplayBuff[2] = (count1-(count1/100)*100)/10; //十位DisplayBuff[3] = count1%10; //个位}if(mode==3) //显示时钟的秒,{DisplayBuff[0] = 20; //第一位不显示DisplayBuff[1] = 21; //第二位显示一个点DisplayBuff[2] = sec/10;//显示秒的十位DisplayBuff[3] = sec%10;//显示秒的个位}}//**************////键盘扫描子程序////**************//void keyscan(){if(!key0 && bKey0Pressed == 0) //检测到key0按下{keypress0 = 0;bKey0Pressed = 1; //防止重入此判断while(!key0); //如果没放开,就等下去}if(key0 && bKey0Pressed == 1) //检测到key0放开{bKey0Pressed = 0; //防止重入此判断if (keypress0<120) //如果是短按{if(ucStatus == 0x02){ucStatus = 0x00;mode = 0; //时钟模式t_adjust=0;}else if(ucStatus == 0x00){ucStatus = 0x01;mode = 1; //秒表模式}else if(ucStatus == 0x01){ucStatus = 0x02;mode = 2; //计数模式}}else if(keypress0>200) //如果是长按mode=3; //显示时钟的秒的模式}////////////////////////////////if(mode == 0) //进入时钟模式后{if(!key1 && (bKey1Pressed == 0)){ keypress1 = 0;bKey1Pressed = 1;while(!key1);}if(key1 && (bKey1Pressed == 1)){bKey1Pressed = 0;if(keypress1 >= 200) //如果是长按{t_adjust++;if(t_adjust==3)t_adjust=0;}else if(keypress1 < 120) 如果是短按switch (t_adjust){case 1:{ //调整分min++;sec = 0;if(min == 60)min = 0;}break;case 2: { //调整时hour ++ ;sec = 0;if(hour == 24)hour = 0;}break;default:break;}}}else if(mode == 1) //进入秒表模式{if(!key1 && bKey1Pressed == 0){keypress1 = 0;bKey1Pressed = 1;while(!key1);}if(key1 && bKey1Pressed == 1){bKey1Pressed = 0;if(keypress1 < 120) //短按{if(flag1==0) { start=2;flag1=1;} //start=2代表秒表开始计时else {start=0;flag1=0;} //start=0,秒表停止计时}else if(keypress1>200) //长按start=1; //秒表清零}}}void timer() //秒表子程序{if(mode==1) //进入秒表模式才执行{if(start==1) //清零{ms = 0;s = 0;ss = 0;mcount=0;}if(start==2) //秒表开始计时{if(mcount==20) //20*5ms=0.1s{mcount=0;ms++;if(ms == 10) // 10*0.1s=1s,s++{ms = 0;s ++;if(s == 100) //100s{s = 0;ss ++;if(ss == 10){ss = 0;s = 0;ms = 0;}}}}}if(start==0);//秒表停止}}//////////////////////void it0(void) interrupt 0 using 1 //外部中断0 服务程序{if(mode==2) //只有在计数模式才执行{count1++; //每响应一次,计数加一if(count1==10000) //超出四位时,不能再加count1 =9999;}}void it2(void) interrupt 2 using 2 //外部中断0 服务程序{if(mode==2) //只有在计数模式才执行{if(count1!=0){count1--;} //计数减一,不显示负数,当减到零时便不能再减 }}。

相关主题