学了一个多月51了,终于整了个电子钟出来,个人感觉还是比较有趣的。
需要注意的是我用的是普中的板子,板子类型不同,io口的功能可能会有所差异。然后我这个k1开关和k2开关是接反了的,原本k1应该是接P3^0,k2接P3^1的,结果我一测试才知道k1接到了P3^1,k2接到P3^0了,不过这不要紧,用sbit定义位变量时注意换一下就可以了。然后大概讲讲功能,用8个数码管显示目前时间和闹铃时间,然后用4个独立按键对目前时间和闹铃时间进行调整(k2是加,k3是减 ,k4是用来停止闹铃的),第一次按k1是对目前时间秒数调整,第2次按k1是对目前时间分钟数调整,第三次按k1是对目前时间小时数调整,第4次按k1是对闹铃秒数调整,第5次按k1是对闹铃时间分钟数调整,第6次按k1是对闹铃秒数调整,第7次按k1是调整完毕,进去非调整状态即实时显示目前时间(不过有点差异,时间走的快了一点)。主要用到了数码管动态显示,独立按键,定时器中断这些。
代码如下:
#include typedef unsigned int u16; typedef unsigned char u8; sbit led=P2^0; sbit lsa=P2^2; sbit lsb=P2^3; sbit lsc=P2^4; sbit beep=P1^5; sbit k1=P3^1; sbit k2=P3^0; sbit k3=P3^2; sbit k4=P3^3; sbit dian=P0^7; u8 keyvalue,alarmexist=0; u8 smgduan[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x67,0x00};//段选码,分别对应0到无 u16 cnt=0,i=0,j=0,flag=0,time[]={0,0,0,0,0,0,0,0};//只用数码管0,1 3,4 6,7 u16 alarm[]={0,0,0,0,0,0,1,0}; u16*p; void delay(u16 mmp); void t0andt1init(); void addproct(int x); void addproca(int x); void reduceproct(int x); void reduceproca(int x); void keyscan(); void jia(); void jian(); void main() { led=0; t0andt1init(); P0=0x00; while(1) { if(time[0]==alarm[0]&&time[1]==alarm[1]&&time[3]==alarm[3]&&time[4]==alarm[4]&&time[6]==alarm[6]&&time[7]==alarm[7])//满足条件 蜂鸣器以一定的时间间隔响,只到K4按键并松开,此时数码管任然正常显示当前时间 { alarmexist=0; while(k4) { beep=~beep; delay(25); beep=~beep; delay(25); } } keyscan(); } } void delay(u16 mmp) { while(mmp--); } void t0andt1init() { TMOD=0x11; TH0=0xfc; TL0=0x67;//赋定时器初始值,定时1ms TH1=0xfc; TL1=0x67; TR0=1;//T0定时器开始定时 EA=1; ET0=1; ET1=1; } void addproct(int x) //对非调整状态和调整状态的加1处理(仅用于对当前时间) { if(x==0||x==3||x==6) if(time[x]==10) { time[x]=0; time[x+1]=time[x+1]+1; addproct(x+1); } if(x==1||x==4) if(time[x]==6) { time[x]=0; time[x+2]=time[x+2]+1; addproct(x+2); } if(time[6]==4&&time[7]==2) time[6]=time[7]=0; } void addproca(int x) //对调整状态的加1处理(仅用于对闹钟时间) { if(x==0||x==3||x==6) if(alarm[x]==10) { alarm[x]=0; alarm[x+1]=alarm[x+1]+1; addproca(x+1); } if(x==1||x==4) if(alarm[x]==6) { alarm[x]=0; alarm[x+2]=alarm[x+2]+1; addproca(x+2); } if(alarm[6]==4&&alarm[7]==2) alarm[6]=alarm[7]=0; } void reduceproct(int x) // 对调整状态的减1处理(仅用于对当前时间) { if(time[0]==0&&time[1]==0&&time[3]==0&&time[4]==0&&time[6]==0&&time[7]==0) { time[0]=time[3]=9; time[1]=time[4]=5; time[6]=3; time[7]=2; return ; } if(x==0||x==3||x==6) { if(time[x]>=1) time[x]=time[x]-1; else { if(time[7]==0&&x==6) { time[6]=3; time[7]=2; } else { time[x]=9; reduceproct(x+1); } } } else { if(time[x]>=1) time[x]=time[x]-1; else { time[x]=5; if(x!=7) reduceproct(x+2); else time[x]=1; } } } void reduceproca(int x) // 对调整状态的减1处理(仅用于对闹钟时间) { if(alarm[0]==0&&alarm[1]==0&&alarm[3]==0&&alarm[4]==0&&alarm[6]==0&&alarm[7]==0) { alarm[0]=alarm[3]=9; alarm[1]=alarm[4]=5; alarm[6]=3; alarm[7]=2; return ; } if(x==0||x==3||x==6) { if(alarm[x]>=1) alarm[x]=alarm[x]-1; else { if(alarm[7]==0&&x==6) { alarm[6]=3; alarm[7]=2; } else { alarm[x]=9; reduceproca(x+1); } } } else { if(alarm[x]>=1) alarm[x]=alarm[x]-1; else { alarm[x]=5; if(x!=7) reduceproca(x+2); else alarm[x]=1; } } } void keyscan() { flag=0; keyvalue=0; if(k1==0) { TR0=0;//不在显示当前时间 TR1=1; delay(1000); if(k1==0) { while(!k1) ; delay(1000); led=~led; keyvalue++; } else return ; while(keyvalue!=7) { if(k1==0) { delay(1000); if(k1==0) { while(!k1) ; led=~led; keyvalue++; if(keyvalue==4) flag=1; } } if(k2==0) { delay(1000); if(k2==0) { while(!k2) ; led=~led; jia(); } } if(k3==0) { delay(1000); if(k3==0) { while(!k3) ; led=~led; jian(); } } } TR0=1; TR1=0; if(((alarm[6]+alarm[7]*10)*60+alarm[3]+alarm[4]*10)>((time[6]+time[7]*10)*60+time[3]+time[4]*10))//判断闹钟时间是否大于当前时间, alarmexist=1; else alarmexist=0; } } void jia() { switch(keyvalue) { case 1:time[0]=time[0]+1;addproct(0);break; case 2:time[3]=time[3]+1;addproct(3);break; case 3:time[6]=time[6]+1;addproct(6);break; case 4:alarm[0]=alarm[0]+1;addproca(0);break; case 5:alarm[3]=alarm[3]+1;addproca(3);break; case 6:alarm[6]=alarm[6]+1;addproca(6);break; } } void jian() { switch(keyvalue) { case 1:reduceproct(0);break; case 2:reduceproct(3);break; case 3:reduceproct(6);break; case 4:reduceproca(0);break; case 5:reduceproca(3);break; case 6:reduceproca(6);break; } } void Timer0() interrupt 1//非调整时,执行的中断服务程序 { TH0=0xfc; TL0=0x67;//赋定时器初始值,定时1ms cnt++; if(1000==cnt) { cnt=0; time[0]=time[0]+1; addproct(0); } P0=0X00; switch(i) { case 0:lsa=0;lsb=0;lsc=0;P0=smgduan[time[0]];dian=(alarmexist==1)?1:0;i++;break; case 1:lsa=1;lsb=0;lsc=0;P0=smgduan[time[1]];i++;i++;break; case 3:lsa=1;lsb=1;lsc=0;P0=smgduan[time[3]];i++;break; case 4:lsa=0;lsb=0;lsc=1;P0=smgduan[time[4]];i++;i++;break; case 6:lsa=0;lsb=1;lsc=1;P0=smgduan[time[6]];i++;break; case 7:lsa=1;lsb=1;lsc=1;P0=smgduan[time[7]];i=0;break; } } void Timer1() interrupt 3 //调整时,执行的中断服务程序 ,flag=0显示正在调整的time,为1显示正在调整的alarm { TH1=0xfc; TL1=0x67;//赋定时器初始值,定时1ms if(flag==0) p=time; else p=alarm; P0=0X00; switch(j) { case 0:lsa=0;lsb=0;lsc=0;P0=smgduan[p[0]];j++;break; case 1:lsa=1;lsb=0;lsc=0;P0=smgduan[p[1]];j++;j++;break; case 3:lsa=1;lsb=1;lsc=0;P0=smgduan[p[3]];j++;break; case 4:lsa=0;lsb=0;lsc=1;P0=smgduan[p[4]];j++;j++;break; case 6:lsa=0;lsb=1;lsc=1;P0=smgduan[p[6]];j++;break; case 7:lsa=1;lsb=1;lsc=1;P0=smgduan[p[7]];j=0;break; } }
上一篇:单片机之时钟工作原理
下一篇:51单片机外围模块——A/D模数转换
推荐阅读最新更新时间:2024-11-11 12:24
设计资源 培训 开发板 精华推荐
- STA516B13TR 400W 典型单 BTL 配置电路,60V,6A 四路功率半桥
- (已验证)超好用的ESP32烧录器
- ZXLD1371EV4,基于 ZXLD1371 LED 驱动器的评估板
- KITPT2000FRDM6C: PT2000 Evaluation Kit with KL25Z for 4/6 Cylinder
- SLASH1000A、BGX13S 蓝牙屏蔽板可加快上市时间并提高蓝牙集成产品的开发难度
- C500628-TSSOP-16&24_IO口扩展器方案验证板
- NCN4555GEVB:Sim 卡接口评估板
- LTC6360 演示板驱动 LTC2367-16 16 位、0.5Msps SAR ADC
- 基于 LT1055 运算放大器的复位稳定振荡器
- LT1086IM 调节固定稳压器输出电压的典型应用