一、 电子时钟、秒表和计数器的设计
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) 使用片内振荡器
单片机源程序:
- #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 char
- Displaynum[]={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 char bKey0Pressed = 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)
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
全部资料打包下载:
miaob.rar
(63.09 KB, 下载次数: 266)
|