📄 clock.c
字号:
#include <reg51.h>
#include <intrins.h>
unsigned char code dis_week[]={"SUN,MON,TUE,WED,THU,FRI,SAT"};
unsigned char code para_month[13]={0,0,3,3,6,1,4,6,2,5,0,3,5}; //星期月参变数
unsigned char data dis_buf1[17];//lcd上排显示缓冲区
unsigned char data dis_buf2[17];//lcd下排显示缓冲区
unsigned char data year,month,date,week;//年、月、日、星期
unsigned char hour,min,sec,sec100;//时、分、秒、10ms
unsigned char data flag,vkey,skey;//设置状态计数标志、按键先前值、按键当前值
sbit rs = P3^0;//LCD数据/命令选择端(H/L)
sbit rw = P3^1;//LCD读/写选择端(H/L)
sbit ep = P3^2;//LCD使能控制
sbit PRE = P1^1; //调整键(AN3)
sbit SET = P1^2; //调整键(AN4)
sbit in=P3^3; //外部中断1 触发
//sbit JJ=P2^0;
unsigned char scan_key();//检测独立键盘
void delay(unsigned char ms);//延时子程序
void lcd_init();//LCD初始化
bit chek_busy();//测试LCD忙碌状态程序
void write_cmd(char cmd);//写入指令到LCD程序
void write_dat(char dat);//写入数据到LCD程序
void lcd_pos(char pos);//LCD数据指针位置程序
void update_disbuf(unsigned char t1,unsigned char t2[]);//更新显示缓冲区函数
bit leap_year();//判断是否为闰年
unsigned char week_proc();//星期自动计算与显示函数
void pro_timedate();//时间日期处理程序
void pro_display() reentrant;//显示处理程序
unsigned char scan_key(); //按键扫描程序
void pro_key(); //按键处理程序
//LCD初始化设定
void lcd_init()
{
write_cmd(0x08);
delay(5);
write_cmd(0x01); //清除LCD的显示内容
delay(5);
write_cmd(0x06); //LCD显示光标移动设置(光标地址指针加1,整屏显示不移动)
delay(5);
write_cmd(0x0c); //LCD开显示及光标设置(光标不闪烁,不显示"-")
}
//测试LCD忙碌状态
bit chek_busy()
{
bit result;
rs = 0;
rw = 1;
ep = 1;
_nop_();
_nop_();
_nop_();
_nop_();
result =(bit)(P0&0x80); //LCD的D0--D7中,D7=1为忙碌,D7=0为空闲
ep = 0;
return result;
}
//写入指令到LCD
void write_cmd(char cmd)
{
//while(chek_busy()); //当chek_busy为1时,再次检测LCD忙碌状态,chek-busy为0时,开始写指令
rs = 0;
rw = 0;
ep = 0;
P0 = cmd;
delay(3);
ep = 1;
delay(3);
ep = 0;
}
//写入数据到LCD
void write_dat(char dat)
{
//while(chek_busy()); //当chek_busy为1时,再次检测LCD忙碌状态,chek_busy为0时,开始写数据
rs = 1;
rw = 0;
ep = 0;
P0 = dat;
delay(3);
ep = 1;
delay(3);
ep = 0;
}
//LCD数据指针位置程序
void lcd_pos(char pos)
{
write_cmd(pos|0x80); //数据指针=80+地址码(00H~27H,40H~67H)
}
unsigned char scan_key()
{
skey=0x00; //给变量vkey置初值
skey|=PRE; //读取PRE键的状态
skey=skey<<1; //将PRE键的状态存于skey的B1位
skey|=SET; //读取SET键的状态,并存于skey的B0位
return skey; //返回skey的键值(即PRE,SET的状态)
}
//Timer0中断处理程序,秒的产生
void timer0() interrupt 1
{
//TH0=(63336-45872)/256;
//TL0=(63336-45872)%256;
TH0=0x4c;
TL0=0x00;
sec100++;
if(sec100>=20)///1秒时间 (100*10ms=1000ms=1s)
{sec100 = 0;
pro_timedate();//调用时间和日期处理程序
}
if (sec&0x01) //"NJUPT"闪一秒,停一秒
update_disbuf(0x20," "); //0x00表示显示00位置的自定义字符
else
update_disbuf(0x20,"NJUPT ");
pro_display(); //调用显示处理函数
}
void int0() interrupt 2
{
TR0=0; //禁止Timer0
EA=0; //禁止中断
write_cmd(0x0e); //显示光标"_",整个光标不闪烁
flag=0;
vkey=0x03;
while(flag^0x07)
{skey = scan_key(); //扫描按键状态
if (skey^vkey) //若skey与vkey相同,跳出循环,相异执行循环体
{ delay(5); //去按键抖动
skey = scan_key(); //转回扫描按键状态
if (skey^vkey) //若skey与vkey相同,跳出循环,相异执行循环体
{ vkey=skey; //将skey的值付给vkey
if (skey==0x01) //PRE键按下
{ flag++; //调整标志位加1
switch (flag) //将光标置于相应调整位置
{
case 1: update_disbuf(0x50,"time: ");
pro_display();
lcd_pos(0x05);break; //光标置年调整位置
case 2: lcd_pos(0x08);break; //光标置月调整位置
case 3: lcd_pos(0x0b);break; //光标置日调整位置
case 4: lcd_pos(0x49);break; //光标置时调整位置
case 5: lcd_pos(0x4c);break; //光标置分调整位置
case 6: lcd_pos(0x4f);break; //光标置秒调整位置
default:break;
}
}
if (skey==0x02) //SET键按下
{
pro_key(); //转设置按键处理程序
}
}
}
}
write_cmd(0x0c); //设置LCD开显示及光标不闪烁,不显示"-"
write_cmd(0x01); //清除LCD的显示内容
in=1;
EA=1; //CPU开中断,INT0,INT1,开中断
TR0=1; //Timer0启动
}
void pro_key()
{
switch (flag)
{
case 1:year++;
if (year> 99) year= 0;
week_proc(); //星期自动运算
update_disbuf(0x50,"time: ");
pro_display();
lcd_pos(0x05);break;
case 2:month++;
if (month>12) month=1;
week_proc(); //星期自动运算
update_disbuf(0x50,"time: ");
pro_display();
lcd_pos(0x08);break;
case 3: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: ");
pro_display();
lcd_pos(0x0b);break;
case 4:hour++;
if (hour>23) hour=0;
update_disbuf(0x50,"time: ");
pro_display();
lcd_pos(0x49);break;
case 5:min++;
if (min>59) min=0;
update_disbuf(0x50,"time: ");
pro_display();
lcd_pos(0x4c);break;
case 6:sec++;
if (sec>59) sec=0;
update_disbuf(0x50,"time: ");
pro_display();
lcd_pos(0x4f);break;
default: break ;
}
}
// 延时子程序
void delay(unsigned char ms)
{
unsigned char x,y;
for(x=ms;x>0;x--)
for(y=110;y>0;y--);
}
//计算闰年子程序
bit leap_year()
{
bit leap;
if((year%4==0&&year%100!=0)||year%400==0)//闰年的条件
leap=1;
else
leap=0;
return leap;
}
//星期的自动运算和处理
unsigned char week_proc()
{ unsigned char num_leap;
unsigned char c;
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;//计算对应的星期
return week;
}
//时间和日期处理程序
void pro_timedate()
{
sec++;
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();
}
//显示处理程序
void pro_display() reentrant
{ unsigned char i;
lcd_pos(0x00);
for (i=0;i<=15;i++)
{write_dat(dis_buf1[i]);}
lcd_pos(0x40);
for (i=0;i<=15;i++)
{write_dat(dis_buf2[i]);}
}
//更新显示缓冲区
void update_disbuf(unsigned char t1,unsigned char t2[])
{ 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]='/'; ///'/
dis_buf1[7]=month/10+48;//月
dis_buf1[8]=month%10+48;
dis_buf1[9]='/'; //'/'
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]; //空格
dis_buf2[7]=t2[7];
dis_buf2[8]=hour/10+48;
dis_buf2[9]=hour%10+48;
dis_buf2[10]=0x3a; //':'
dis_buf2[11]=min/10+48;
dis_buf2[12]=min%10+48;
dis_buf2[13]=0x3a; //':'
dis_buf2[14]=sec/10+48;
dis_buf2[15]=sec%10+48;
}
//主程序,初始化及初值设定
void main()
{
lcd_init(); //初始化LCD
hour=0;min=0;sec=0; //开机时的时,分,秒显示
year= 5; month=1;date=1; //开机时的年,月,日,星期显示
week_proc();
update_disbuf(0x20,"NJUPT ");
pro_display();
TMOD = 0x01; //定时器0工作于模式1, 16位定时方式
//TH0=(63336-45872)/256; //Timer0置10ms定时初值
//TL0=(63336-45872)%256;
TH0=0x4c;
TL0=0x00;
EA=1; //CPU开中断
EX1=1;//开外部中断1
ET0=1;//Timer0开中断
PX1=1;;//设置INT1为中断最高优先级
//IT1=1; //外部INT0设置为电平触发方式
TR0 = 1; //Timer0启动
while(1)
{
if(PRE==0) //软控制触发外部中断1
in=0;
else
in=1;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -