📄 av.c
字号:
#include <reg51.h>
#include <intrins.h>
#define Key_Port P1
#define LCD1602_DataPort P2
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 code DefineChar[14]={ 0x00,0x0e,0x0a,0x0e,0x00,0x15,0x00,//第一个自定义字符
0x1e,0x04,0x02,0x06,0x02,0x04,0x1e,
}; //第二个自定义字符
unsigned char data dis_buf1[16]; //lcd上排显示缓冲区
unsigned char data dis_buf2[16]; //lcd下排显示缓冲区
unsigned char data year,month,date,week;//年、月、日、星期
unsigned char data armhour,armmin,armsec;//闹钟时、分、秒
unsigned char data hour,min,sec,sec100; //时、分、秒、百分之一秒
unsigned char data flag,vkey,skey;//设置状态计数标志、按键先前值、按键当前值
unsigned char const Dis_Char0=0xf2,Dis_Char1=0x5c;
bit alarm; //标识是否启用闹钟,1--启用,0--关闭
//av
sbit rs = P3^7; //LCD数据/命令选择端(H/L)
sbit rw = P3^6; //LCD读/写选择端(H/L)
sbit ep = P3^5; //LCD使能控制
sbit PRE = P1^4; //调整键(k3)
sbit SET = P1^5; //调整键(k4)
sbit SPK = P3^1;
/*
sbit rs = P2^0; //LCD数据/命令选择端(H/L)
sbit rw = P2^1; //LCD读/写选择端(H/L)
sbit ep = P2^2; //LCD使能控制
sbit SPK = P1^6;
*/
void delayms(unsigned char ms); //延时程序
bit lcd_busy(); //测试LCD忙碌状态程序
void lcd_wcmd(char cmd); //写入指令到LCD程序
void lcd_wdat(char dat); //写入数据到LCD程序
void lcd_pos(char pos); //LCD数据指针位置程序
void lcd_init(); //LCD初始化设定程序
void pro_timedate(); //时间日期处理程序
void pro_display(); //显示处理程序
void pro_key(); //按键处理程序
void time_alarm(); //定时报警功能(闹钟)
unsigned char scan_key(); //按键扫描程序
unsigned char week_proc(); //星期自动计算与显示函数
bit leap_year(); //判断是否为闰年
void lcd_sef_chr(); //LCD自定义字符程序
void update_disbuf(unsigned char t1,unsigned char t2[],unsigned char dis_h,unsigned char dis_m,unsigned char dis_s);
//更新显示缓冲区函数
// 延时程序
void delayms(unsigned char ms)
{ while(ms--)
{ unsigned char i;
for(i = 0; i< 250; i++)
{
_nop_(); //执行一条_nop_()指令为一个机器周期
_nop_();
_nop_();
_nop_();
}
}
}
//测试LCD忙碌状态
bit lcd_busy()
{
bit result;
rs = 0;
rw = 1;
ep = 1;
_nop_();
_nop_();
_nop_();
_nop_();
result =(bit)(LCD1602_DataPort&0x80); //LCD的D0--D7中,D7=1为忙碌,D7=0为空闲
ep = 0;
return result;
}
//写入指令到LCD
void lcd_wcmd(char cmd)
{
while(lcd_busy()); //当lcd_busy为1时,再次检测LCD忙碌状态,lcd-busy为0时,开始写指令
rs = 0;
rw = 0;
ep = 0;
_nop_();
_nop_();
LCD1602_DataPort = cmd;
_nop_();
_nop_();
_nop_();
_nop_();
ep = 1;
_nop_();
_nop_();
_nop_();
_nop_();
ep = 0;
}
//写入数据到LCD
void lcd_wdat(char dat)
{
while(lcd_busy()); //当lcd_busy为1时,再次检测LCD忙碌状态,lcd-busy为0时,开始写数据
rs = 1;
rw = 0;
ep = 0;
LCD1602_DataPort = dat;
_nop_();
_nop_();
_nop_();
_nop_();
ep = 1;
_nop_();
_nop_();
_nop_();
_nop_();
ep = 0;
}
//LCD数据指针位置程序
void lcd_pos(char pos)
{
lcd_wcmd(pos|0x80); //数据指针=80+地址码(00H~27H,40H~67H)
}
//设定二个自定义字符,(注意:LCD1602中自定义字符的地址为0x00--0x07,即可定义8个字符)
//这里我们设定把一个自定义字符放在0x00位置(000),另一个放在0x01位子(001)
void lcd_sef_chr()
{ lcd_wcmd(0x40);
lcd_wdat(0x1f);
lcd_wcmd(0x41);
lcd_wdat(0x11);
lcd_wcmd(0x42);
lcd_wdat(0x15);
lcd_wcmd(0x43);
lcd_wdat(0x11);
lcd_wcmd(0x44);
lcd_wdat(0x1f);
lcd_wcmd(0x45);
lcd_wdat(0x0a);
lcd_wcmd(0x46);
lcd_wdat(0x1f);
lcd_wcmd(0x48);
lcd_wdat(0x01);
lcd_wcmd(0x49);
lcd_wdat(0x1b);
lcd_wcmd(0x4a);
lcd_wdat(0x1d);
lcd_wcmd(0x4b);
lcd_wdat(0x19);
lcd_wcmd(0x4c);
lcd_wdat(0x1d);
lcd_wcmd(0x4d);
lcd_wdat(0x1b);
lcd_wcmd(0x4e);
lcd_wdat(0x01);
}
//LCD初始化设定
void lcd_init()
{
lcd_wcmd(0x38); //设置LCD为16X2显示,5X7点阵,八位数据借口
delayms(1);
lcd_wcmd(0x0c); //LCD开显示及光标设置(光标不闪烁,不显示"-")
delayms(1);
lcd_wcmd(0x06); //LCD显示光标移动设置(光标地址指针加1,整屏显示不移动)
delayms(1);
lcd_wcmd(0x01); //清除LCD的显示内容
delayms(1);
}
//闰年的计算
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 update_disbuf(unsigned char t1,unsigned char t2[],unsigned char dis_h,unsigned char dis_m,unsigned char dis_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]=0x20; //空格
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;
}
void Define_CharSelf(unsigned char code *p,unsigned char index,unsigned char vec)
{
unsigned char temp,i,tp;
tp = 7*index;
temp =vec<<3;
temp|=0x40;
for(i=0;i<7;i++)
{
lcd_wcmd(temp+i);
lcd_wdat(*(p+tp+i));
}
lcd_wcmd(temp+i);
lcd_wdat(0x1f);
}
//时间和日期处理程序
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++;}
if (month==4||month==6||month==9||month==11)
if (date>30) {date=1;month++;}
if (month==2)
{if( leap_year())
{if (date>29) {date=1;month++;}}
else
{if (date>28) {date=1;month++;}}
}
if (month>12) {month=1;year++;}
if (year>99) year=0;
}
}
}
week_proc();
if (sec==armsec && min==armmin && hour==armhour)
{if (alarm)
TR1=1; //闹钟启用时,报警时间到,启动Timer1
}
}
//显示处理程序
void pro_display()
{ unsigned char i;
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中断处理程序,秒的产生
void timer0() interrupt 1
{
TH0=0x3c; //Timer0置10ms定时初值dc00H(2^16=65536D,dc00H=56320D)
TL0=0xd0; //定时时间=(65536-56320)*(1/11.0592)*12=10ms (f0=11.0592Mhz)
sec100++;
if(sec100 >= 9) //1秒时间 (100*10ms=1000ms=1s)
{sec100 = 0;
pro_timedate();//调用时间和日期处理程序
}
if (sec&0x01)
update_disbuf(0x00,"willed",hour,min,sec);
else
update_disbuf(0x00,"willed ",hour,min,sec);
pro_display(); //调用显示处理函数
}
//按键扫描程序
unsigned char scan_key()
{
unsigned char Key,Temp;
Key = Key_Port;
Key = ~Key;
Key = Key&0x3f;
if(Key!=0)
{
delayms(1);
Temp = Key_Port;
Temp = ~Temp;
Temp = Temp&0x3f;
if(Temp==Key)
return Key;
else
return 0;
}
else
return 0;
}
//外部中断INT0中断处理程序
void Key_Process()
{
TR0=0; //禁止Timer0
IE=0; //禁止中断
lcd_wcmd(0x0e); //显示光标"_",整个光标不闪烁
alarm=1;
Define_CharSelf(DefineChar,0,0);
Define_CharSelf(DefineChar,1,1);
update_disbuf(0x00,"alarm:",armhour,armmin,armsec); //更新显示数据,0x50表示要显示"P"
pro_display(); //调用显示处理程序
lcd_pos(0x47); //使光标位于第一个调整项下
switch(skey)
{
case 0x01: //PRE键按下
{
flag++; //调整标志位加1
switch (flag) //将光标置于相应调整位置
{
case 1: {
lcd_pos(0x49);
}break; //光标置小时报警设置位置
case 2:{
lcd_pos(0x4c);
}break; //光标置分钟报警设置位置
case 3: lcd_pos(0x4f);break; //光标置秒时报警设置位置
case 4:
update_disbuf(0x00,"time: ",hour,min,sec);
pro_display();
lcd_pos(0x05);break; //光标置年调整位置
case 5: lcd_pos(0x08);break; //光标置月调整位置
case 6: lcd_pos(0x0b);break; //光标置日调整位置
case 7: lcd_pos(0x49);break; //光标置时调整位置
case 8: lcd_pos(0x4c);break; //光标置分调整位置
case 9: lcd_pos(0x4f);break; //光标置秒调整位置
default:flag = 0;break;
}
} break;
case 0x02: //SET键按下
{
pro_key(); //转设置按键处理程序
}break;
case 0x04:
{
lcd_sef_chr();//写入自定义字符号
lcd_wcmd(0x0c); //设置LCD开显示及光标不闪烁,不显示"-"
lcd_wcmd(0x01); //清除LCD的显示内容
IE=0x8f; //CPU开中断,INT0,INT1,开中断
TR0=1; //Timer0启动
}
case 0x08:
{
if(TR1)
TR1=0;
}break;
default:break;
}
}
//主程序,初始化及初值设定
void main()
{
lcd_init(); //初始化LCD
lcd_sef_chr();//写入自定义字符号
hour=3;min=4;sec=0;
SPK = 0;
// OutDisplay =0;
//开机时的时,分,秒显示
armhour=0;armmin=0;armsec=0; //开机时的时,分,秒报警初值
year= 1; month=9;date=4; //开机时的年,月,日,星期显示
week_proc();
alarm=1;
//初始开机,启用闹钟
//CPU开中断,INT0,INT1,Timer0,Timer1开中断
// IP = 0x04; //设置INT0为中断最高优先级
// IT0=0;IT1=0; //外部INT0,INT1设置为电平触发方式(注意,触发不要选边沿方式,易误动)
TMOD = 0x11; //Timer0,Timer1工作于模式1, 16位定时方式
TH0 = 0x3c;TL0 = 0xd0; //Timer0置10ms定时初值
TH1 = 0xff;TL1 = 0xff; //Timer1置初值
TR0 = 1; //Timer0启动
TR1 = 0;
ET0 = 1;
ET1 = 1;
EA =1;
while(1)
{
skey = scan_key();
if(skey!=0)
{
Key_Process();
while(skey == scan_key());
}
}
}
//设置按键处理程序
void pro_key()
{
switch (flag)
{
case 0:alarm=!alarm; //启用或关闭闹钟(alarm=1:启用,alarm=0:关闭)
update_disbuf(Dis_Char0,"alarm:",armhour,armmin,armsec); //更新显示数据
pro_display(); //调用显示处理
lcd_pos(0x47);break; //光标回到原调整位置
case 1:armhour++;
if (armhour>23) armhour=0;
update_disbuf(Dis_Char0,"alarm:",armhour,armmin,armsec); //更新显示数据
pro_display(); //调用显示处理
;break; //光标回到原调整位置
case 2:armmin++;
if (armmin>59) armmin=0;
update_disbuf(Dis_Char0,"alarm:",armhour,armmin,armsec);
pro_display();
break;
case 3:armsec++;
if (armsec>59) armsec=0;
update_disbuf(Dis_Char0,"alarm:",armhour,armmin,armsec);
pro_display();
lcd_pos(0x4f);break;
case 4:year++;
if (year> 99) year= 0;
week_proc(); //星期自动运算
update_disbuf(Dis_Char0,"time: ",hour,min,sec);
pro_display();
lcd_pos(0x05);break;
case 5:month++;
if (month>12) month=1;
week_proc(); //星期自动运算
update_disbuf(Dis_Char0,"time: ",hour,min,sec);
pro_display();
lcd_pos(0x08);break;
case 6: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(Dis_Char0,"time: ",hour,min,sec);
pro_display();
lcd_pos(0x0b);break;
case 7:hour++;
if (hour>23) hour=0;
update_disbuf(Dis_Char0,"time: ",hour,min,sec);
pro_display();
lcd_pos(0x49);break;
case 8:min++;
if (min>59) min=0;
update_disbuf(Dis_Char0,"time: ",hour,min,sec);
pro_display();
lcd_pos(0x4c);break;
case 9:sec++;
if (sec>59) sec=0;
update_disbuf(Dis_Char0,"time: ",hour,min,sec);
pro_display();
lcd_pos(0x4f);break;
default: break ;
}
}
//Timer1中断处理程序,产生报警的声音
void timer1() interrupt 3
{
TH1=0xff;
TL1=0xff;
SPK=~SPK;
}
//外部中断INT1中断处理程序,停止报警声音
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -