新闻详细
新闻当前位置:新闻详细

51单片机数字时钟代码与仿真,急求一个用51单片机编的可按键调时的数字时钟程序,数码管显示,C语言...

专业编程培训机构——完成蜕变以后轻松拿高薪

电话+V: 152079-09430 ,欢迎咨询51单片机数字时钟代码与仿真,[python实用课程],[C++单片机原理],[C#网站搭建],[Nodejs小程序开发],[ios游戏开发],[安卓游戏开发],[教会用大脑用想法赚钱实现阶层跨越]

一、急求一个用51单片机编的可按键调时的数字时钟程序,数码管显示,C语言...

#include<reg51.h>

#include<intrins.h>

unsignedcharcodedis_week[]={"SUN,MON,TUE,WED,THU,FRI,SAT"};

unsignedcharcodepara_month[13]={0,0,3,3,6,1,4,6,2,5,0,3,5};//星期月参变数

unsignedchardatadis_buf1[16];//lcd上排显示缓冲区

unsignedchardatadis_buf2[16];//lcd下排显示缓冲区

unsignedchardatayear,month,date,week;//年、月、日、星期

unsignedchardataarmhour,armmin,armsec;//闹钟时、分、秒

unsignedchardatahour,min,sec,sec100;//时、分、秒、百分之一秒

unsignedchardataflag,vkey,skey;//设置状态计数标志、按键先前值、按键当前值

bitalarm;//标识是否启用闹钟,1--启用,0--关闭

sbitrs=P2^0;//LCD数据/命令选择端(H/L)

sbitrw=P2^1;//LCD读/写选择端(H/L)

sbitep=P2^2;//LCD使能控制

sbitPRE=P3^3;//调整键(AN3)

sbitSET=P3^4;//调整键(AN4)

sbitSPK=P3^6;

voiddelayms(unsignedcharms);//延时程序

bitlcd_busy();//测试LCD忙碌状态程序

voidlcd_wcmd(charcmd);//写入指令到LCD程序

voidlcd_wdat(chardat);//写入数据到LCD程序

voidlcd_pos(charpos);//LCD数据指针位置程序

voidlcd_init();//LCD初始化设定程序

voidpro_timedate();//时间日期处理程序

voidpro_display();//显示处理程序

voidpro_key();//按键处理程序

voidtime_alarm();//定时报警功能(闹钟)

unsignedcharscan_key();//按键扫描程序

unsignedcharweek_proc();//星期自动计算与显示函数

bitleap_year();//判断是否为闰年

voidlcd_sef_chr();//LCD自定义字符程序

voidupdate_disbuf(unsignedchart1,unsignedchart2[],unsignedchardis_h,unsignedchardis_m,unsignedchardis_s);

//更新显示缓冲区函数

//延时程序

voiddelay(unsignedcharms)

{while(ms--)

{unsignedchari;

for(i=0;i<250;i++)

{

_nop_();//执行一条_nop_()指令为一个机器周期

_nop_();

_nop_();

_nop_();

}

}

}

//测试LCD忙碌状态

bitlcd_busy()

{

bitresult;

rs=0;

rw=1;

ep=1;

_nop_();

_nop_();

_nop_();

_nop_();

result=(bit)(P00x80);//LCD的D0--D7中,D7=1为忙碌,D7=0为空闲

ep=0;

returnresult;

}

//写入指令到LCD

voidlcd_wcmd(charcmd)

{

while(lcd_busy());//当lcd_busy为1时,再次检测LCD忙碌状态,lcd-busy为0时,开始写指令

rs=0;

rw=0;

ep=0;

_nop_();

_nop_();

P0=cmd;

_nop_();

_nop_();

_nop_();

_nop_();

ep=1;

_nop_();

_nop_();

_nop_();

_nop_();

ep=0;

}

//写入数据到LCD

voidlcd_wdat(chardat)

{

while(lcd_busy());//当lcd_busy为1时,再次检测LCD忙碌状态,lcd-busy为0时,开始写数据

rs=1;

rw=0;

ep=0;

P0=dat;

_nop_();

_nop_();

_nop_();

_nop_();

ep=1;

_nop_();

_nop_();

_nop_();

_nop_();

ep=0;

}

//LCD数据指针位置程序

voidlcd_pos(charpos)

{

lcd_wcmd(pos|0x80);//数据指针=80+地址码(00H~27H,40H~67H)

}

//设定二个自定义字符,(注意:LCD1602中自定义字符的地址为0x00--0x07,即可定义8个字符)

//这里我们设定把一个自定义字符放在0x00位置(000),另一个放在0x01位子(001)

voidlcd_sef_chr()

{//第一个自定义字符

lcd_wcmd(0x40);//"01000000"第1行地址(D7D6为地址设定命令形式D5D4D3为字符存放位置(0--7),D2D1D0为字符行地址(0--7))

lcd_wdat(0x1f);//"XXX11111"第1行数据(D7D6D5为XXX,表示为任意数(一般用000),D4D3D2D1D0为字符行数据(1-点亮,0-熄灭)

lcd_wcmd(0x41);//"01000001"第2行地址

lcd_wdat(0x11);//"XXX10001"第2行数据

lcd_wcmd(0x42);//"01000010"第3行地址

lcd_wdat(0x15);//"XXX10101"第3行数据

lcd_wcmd(0x43);//"01000011"第4行地址

lcd_wdat(0x11);//"XXX10001"第4行数据

lcd_wcmd(0x44);//"01000100"第5行地址

lcd_wdat(0x1f);//"XXX11111"第5行数据

lcd_wcmd(0x45);//"01000101"第6行地址

lcd_wdat(0x0a);//"XXX01010"第6行数据

lcd_wcmd(0x46);//"01000110"第7行地址

lcd_wdat(0x1f);//"XXX11111"第7行数据

lcd_wcmd(0x47);//"01000111"第8行地址

lcd_wdat(0x00);//"XXX00000"第8行数据

//第二个自定义字符

lcd_wcmd(0x48);//"01001000"第1行地址

lcd_wdat(0x01);//"XXX00001"第1行数据

lcd_wcmd(0x49);//"01001001"第2行地址

lcd_wdat(0x1b);//"XXX11011"第2行数据

lcd_wcmd(0x4a);//"01001010"第3行地址

lcd_wdat(0x1d);//"XXX11101"第3行数据

lcd_wcmd(0x4b);//"01001011"第4行地址

lcd_wdat(0x19);//"XXX11001"第4行数据

lcd_wcmd(0x4c);//"01001100"第5行地址

lcd_wdat(0x1d);//"XXX11101"第5行数据

lcd_wcmd(0x4d);//"01001101"第6行地址

lcd_wdat(0x1b);//"XXX11011"第6行数据

lcd_wcmd(0x4e);//"01001110"第7行地址

lcd_wdat(0x01);//"XXX00001"第7行数据

lcd_wcmd(0x4f);//"01001111"第8行地址

lcd_wdat(0x00);//"XXX00000"第8行数据

}

//LCD初始化设定

voidlcd_init()

{

lcd_wcmd(0x38);//设置LCD为16X2显示,5X7点阵,八位数据借口

delay(1);

lcd_wcmd(0x0c);//LCD开显示及光标设置(光标不闪烁,不显示"-")

delay(1);

lcd_wcmd(0x06);//LCD显示光标移动设置(光标地址指针加1,整屏显示不移动)

delay(1);

lcd_wcmd(0x01);//清除LCD的显示内容

delay(1);

}

//闰年的计算

bitleap_year()

{

bitleap;

if((year%4==0year%100!=0)||year%400==0)//闰年的条件

leap=1;

else

leap=0;

returnleap;

}

//星期的自动运算和处理

unsignedcharweek_proc()

{unsignedcharnum_leap;

unsignedcharc;

num_leap=year/4-year/100+year/400;//自00年起到year所经历的闰年数

if(leap_year()month<=2)//既是闰年且是1月和2月

c=5;

else

c=6;

week=(year+para_month[month]+date+num_leap+c)%7;//计算对应的星期

returnweek;

}

//更新显示缓冲区

voidupdate_disbuf(unsignedchart1,unsignedchart2[],unsignedchardis_h,unsignedchardis_m,unsignedchardis_s)

{dis_buf1[0]=t1;//

dis_buf1[1]=0x20;//空格

dis_buf1[2]=50;//'2'

dis_buf1[3]=48;//'0'

dis_buf1[4]=year/10+48;

dis_buf1[5]=year%10+48;

dis_buf1[6]=0x2d;

dis_buf1[7]=month/10+48;

dis_buf1[8]=month%10+48;

dis_buf1[9]=0x2d;//'-'

dis_buf1[10]=date/10+48;

dis_buf1[11]=date%10+48;

dis_buf1[12]=0x20;

dis_buf1[13]=dis_week[4*week];

dis_buf1[14]=dis_week[4*week+1];

dis_buf1[15]=dis_week[4*week+2];

dis_buf2[0]=t2[0];

dis_buf2[1]=t2[1];

dis_buf2[2]=t2[2];

dis_buf2[3]=t2[3];

dis_buf2[4]=t2[4];

dis_buf2[5]=t2[5];

dis_buf2[6]=t2[6];//空格

if(alarm)

dis_buf2[7]=0x01;//alarm=1,显示闹钟启用标致(第二个自定义字符)

else

dis_buf2[7]=0x20;//alarm=0,不显示闹钟启用标致

dis_buf2[8]=dis_h/10+48;

dis_buf2[9]=dis_h%10+48;

dis_buf2[10]=0x3a;//':'

dis_buf2[11]=dis_m/10+48;

dis_buf2[12]=dis_m%10+48;

dis_buf2[13]=0x3a;

dis_buf2[14]=dis_s/10+48;

dis_buf2[15]=dis_s%10+48;

}

//时间和日期处理程序

voidpro_timedate()

{

sec++;

51单片机数字时钟代码与仿真

if(sec>59)

{sec=0;

min++;

if(min>59)

{min=0;

hour++;

if(hour>23)

{hour=0;

date++;

if(month==1||month==3||month==5||month==7||month==8||month==10||month==12)

if(date>31){date=1;month++;}//大月31天

if(month==4||month==6||month==9||month==11)

if(date>30){date=1;month++;}//小月30天

if(month==2)

{if(leap_year())//闰年的条件

{if(date>29){date=1;month++;}}//闰年2月为29天

else

{if(date>28){date=1;month++;}}//平年2月为28天

}

if(month>12){month=1;year++;}

if(year>99)year=0;

}

}

}

week_proc();

if(sec==armsecmin==armminhour==armhour)

{if(alarm)

TR1=1;//闹钟启用时,报警时间到,启动Timer1

}

}

//显示处理程序

voidpro_display()

{unsignedchari;

lcd_pos(0x00);

for(i=0;i<=15;i++)

{lcd_wdat(dis_buf1[i]);}

lcd_pos(0x40);

for(i=0;i<=15;i++)

{lcd_wdat(dis_buf2[i]);}

}

//Timer0中断处理程序,秒的产生

voidtimer0()interrupt1

{

TH0=0xD8;

TL0=0xF0;

sec100++;

if(sec100>=100)//1秒时间(100*10ms=1000ms=1s)

{sec100=0;

pro_timedate();//调用时间和日期处理程序

}

if(sec0x01)//"RICHMCU"闪一秒,停一秒

update_disbuf(0x00,"",hour,min,sec);//0x00表示显示00位置的自定义字符

else

update_disbuf(0x00,"RICHMCU",hour,min,sec);

pro_display();//调用显示处理函数

}

//按键扫描程序

unsignedcharscan_key()

{

skey=0x00;//给变量vkey置初值

skey|=PRE;//读取PRE键的状态

skey=skey<<1;//将PRE键的状态存于skey的B1位

skey|=SET;//读取SET键的状态,并存于skey的B0位

returnskey;//返回skey的键值(即PRE,SET的状态)

}

//外部中断INT0中断处理程序

voidint0()interrupt0

{

TR0=0;//禁止Timer0

IE=0;//禁止中断

lcd_wcmd(0x0e);//显示光标"_",整个光标不闪烁

alarm=1;

update_disbuf(0x50,"alarm:",armhour,armmin,armsec);//更新显示数据,0x50表示要显示"P"

pro_display();//调用显示处理程序

lcd_pos(0x47);//使光标位于第一个调整项下

flag=0;

vkey=0x03;

while(flag^0x0a)

{skey=scan_key();//扫描按键状态

if(skey^vkey)//若skey与vkey相同,跳出循环,相异执行循环体

{delay(10);//去按键抖动

skey=scan_key();//转回扫描按键状态

if(skey^vkey)//若skey与vkey相同,跳出循环,相异执行循环体

{vkey=skey;//将skey的值付给vkey

if(skey==0x01)//PRE键按下

{flag++;//调整标志位加1

switch(flag)//将光标置于相应调整位置

{

case1:lcd_pos(0x49);break;//光标置小时报警设置位置

case2:lcd_pos(0x4c);break;//光标置分钟报警设置位置

case3:lcd_pos(0x4f);break;//光标置秒时报警设置位置

case4:update_disbuf(0x50,"time:",hour,min,sec);

pro_display();

lcd_pos(0x05);break;//光标置年调整位置

case5:lcd_pos(0x08);break;//光标置月调整位置

case6:lcd_pos(0x0b);break;//光标置日调整位置

case7:lcd_pos(0x49);break;//光标置时调整位置

case8:lcd_pos(0x4c);break;//光标置分调整位置

case9:lcd_pos(0x4f);break;//光标置秒调整位置

default:break;

}

}

if(skey==0x02)//SET键按下

{pro_key();//转设置按键处理程序

}

}

}

}

lcd_wcmd(0x0c);//设置LCD开显示及光标不闪烁,不显示"-"

lcd_wcmd(0x01);//清除LCD的显示内容

IE=0x8f;//CPU开中断,INT0,INT1,开中断

TR0=1;//Timer0启动

}

//主程序,初始化及初值设定

voidmain()

{

lcd_init();//初始化LCD

lcd_sef_chr();//写入自定义字符号

hour=0;min=0;sec=0;//开机时的时,分,秒显示

armhour=0;armmin=0;armsec=0;//开机时的时,分,秒报警初值

year=5;month=1;date=1;//开机时的年,月,日,星期显示

week_proc();

alarm=1;//初始开机,启用闹钟

IE=0x8f;//CPU开中断,INT0,INT1,Timer0,Timer1开中断

IP=0x04;//设置INT0为中断最高优先级

IT0=0;IT1=0;//外部INT0,INT1设置为电平触发方式(注意,触发不要选边沿方式,易误动)

TMOD=0x11;//Timer0,Timer1工作于模式1,16位定时方式

TH0=0xdc;TL0=0x00;//Timer0置10ms定时初值

TH1=0xff;TL1=0x00;//Timer1置初值

TR0=1;//Timer0启动

TR1=0;

while(1);

}

//设置按键处理程序

voidpro_key()

{

switch(flag)

{

case0:alarm=!alarm;//启用或关闭闹钟(alarm=1:启用,alarm=0:关闭)

update_disbuf(0x50,"alarm:",armhour,armmin,armsec);//更新显示数据

pro_display();//调用显示处理

lcd_pos(0x47);break;//光标回到原调整位置

case1:armhour++;

if(armhour>23)armhour=0;

update_disbuf(0x50,"alarm:",armhour,armmin,armsec);//更新显示数据

pro_display();//调用显示处理

lcd_pos(0x49);break;//光标回到原调整位置

case2:armmin++;

if(armmin>59)armmin=0;

update_disbuf(0x50,"alarm:",armhour,armmin,armsec);

pro_display();

lcd_pos(0x4c);break;

case3:armsec++;

if(armsec>59)armsec=0;

update_disbuf(0x50,"alarm:",armhour,armmin,armsec);

pro_display();

lcd_pos(0x4f);break;

case4:year++;

if(year>99)year=0;

week_proc();//星期自动运算

update_disbuf(0x50,"time:",hour,min,sec);

pro_display();

lcd_pos(0x05);break;

case5:month++;

if(month>12)month=1;

week_proc();//星期自动运算

update_disbuf(0x50,"time:",hour,min,sec);

pro_display();

lcd_pos(0x08);break;

case6:date++;

if(month==1||month==3||month==5||month==7||month==8||month==10||month==12)

if(date>31)date=1;//大月31天

if(month==4||month==6||month==9||month==11)

if(date>30)date=1;//小月30天

if(month==2)

{if(leap_year())//闰年的条件

{if(date>29)date=1;}//闰年2月为29天

else

{if(date>28)date=1;}}//平年2月为28天

week_proc();//星期自动运算

update_disbuf(0x50,"time:",hour,min,sec);

pro_display();

lcd_pos(0x0b);break;

case7:hour++;

if(hour>23)hour=0;

update_disbuf(0x50,"time:",hour,min,sec);

pro_display();

lcd_pos(0x49);break;

case8:min++;

if(min>59)min=0;

update_disbuf(0x50,"time:",hour,min,sec);

pro_display();

lcd_pos(0x4c);break;

case9:sec++;

if(sec>59)sec=0;

update_disbuf(0x50,"time:",hour,min,sec);

pro_display();

lcd_pos(0x4f);break;

default:break;

}

}

//Timer1中断处理程序,产生报警的声音

voidtimer1()interrupt3

{

TH1=0xff;

TL1=0x00;

SPK=~SPK;

}

//外部中断INT1中断处理程序,停止报警声音

voidint1()interrupt2

{

if(TR1)

TR1=0;

}

实验说明:

按K1按键进入设定状态

按K2,依次进入闹钟功能是否启用,闹钟时,分秒,年,月,日及时间时,分,秒的设置,直到退出设置状态

按K3,调整是否起用闹钟和调节闹钟时,分,秒,年,月,日,时间的时,分,秒的数字

LCD第二排中间显示小喇叭,表示启用闹钟功能,无则禁止闹钟功能(可在调整状态进行设置)

正常状态,LCD上排最前面显示自定义字符,LCD下排最前面闪动"RICHMCU"

设置状态,LCD上排最前面显示"P",下排最前面在设置闹钟时间时显示"alarm:",其它状态显示"time"

年代变化2000--2099,星期自动转换

【FUTURE PROGRAMMING COURSE】尊享对接老板

电话+V: 152079-09430

机构由一批拥有10年以上开发管理经验,且来自互联网或研究机构的IT精英组成,负责研究、开发教学模式和课程内容。公司具有完善的课程研发体系,一直走在整个行业发展的前端,在行业内竖立起了良好的品质口碑。

51单片机数字时钟代码与仿真
Copyright2023未知推广科技