综合实例:51单片机(AT89C52)万年历(温度闹钟年月日时分秒星期)

2019-04-15 13:40发布

功能说明: LCD1602液晶显示年、月、日、时、分、秒、星期、温度,三个按键控制时间日期调整以及闹钟设定。   三个按键: 1、“校时”键,每次按下分别对应调整秒、调整分钟、调整小时、调整星期、调整日、调整月份、调整年份、调整闹钟分钟、调整闹钟小时、退出校时模式; 2、“增加/开闹钟功能”键,校时模式下按下此键则数值加一,非校时模式下按下此键则显示出闹钟时间并打开闹钟功能(屏幕显示字母A); 3、“减小/关闹钟功能”键,校时模式下按下此键则数值减一,非校时模式下按下此键则关闭闹钟显示并关闭闹钟功能(屏幕字母A消失);     #include typedef unsigned char uchar; typedef unsigned int uint; #define rs_h P3|=0x01//单片机向LCD1602液晶RS引脚输出高电平 #define rs_l P3&=0xfe #define rw_h P3|=0x02 #define rw_l P3&=0xfd #define en_h P3|=0x04 #define en_l P3&=0xfb #define temp_h P3|=0x40//单片机向DS18B20输出高电平 #define temp_l P3&=0xbf//单片机向DS18B20输出低电平 #define rst_h P3|=0x08//单片机向DS1302时钟芯片RST引脚输出高电平 #define rst_l P3&=0xf7 #define sck_h P3|=0x10 #define sck_l P3&=0xef #define io_h P3|=0x20 #define io_l P3&=0xdf #define SECADD 0X80//秒寄存器地址 #define MINADD 0x82 #define HRADD 0x84 #define DATEADD 0x86 #define MONTHADD 0x88 #define DAYADD 0x8a #define YEARADD 0x8c #define CONTROLADD 0x8e #define PORT (P2)//P2连接LCD1602的8个数据引脚 sbit time=P3^5;//DS1302输入输出引脚 sbit tmp=P3^6;//DS18B20输入输出引脚 void delayms(uint x);//延时函数 void lcd_com(uchar com);//LCD1602液晶写命令函数 void lcd_dat(uchar dat);//LCD1602液晶写数据函数 void lcd_write(uchar c,uchar r,uchar dat);//向LCD1602液晶指定行、指定列写数据函数 void lcd_init();//LCD1602液晶初始化 void Ds1302Init();//DS1302初始化 void WriteByte(uchar dat);//往DS1302写一字节 uchar ReadByte();//从DS1302读一字节 uchar BCDtoDex(uchar dat);//BCD码转十进制 uchar DextoBCD(uchar dat);//十进制转BCD码 void Ds1302Write(uchar add,uchar dat);//往DS1302指定地址写数据 uchar Ds1302Read(uchar add);//读DS1302制定地址的数据 void Ds18b20_reset();//DS18B20温度传感器复位 void Ds18b20_write(uchar dat);//往DS18B20写一字节 void showtem();//显示温度 uchar Ds18b20_read();//从DS18B20读一字节 char keyscan();//按键检测,有键按下返回1,否则返回0 uchar Timflag;//表示50ms时间到 uchar Temflag;//让"命令DS18B20转换温度"和"读温度值"两个模块错开执行 uchar dat1,dat2;//读回的温度值,dat1保存低字节,dat2保存高字节 uchar keystate=2;//按键状态标志,初始化为2,是为了程序第一次运行时能够进入keystat1分支 #define keystate0 1//keystate0在keyscan()函数中,代表按下确认功能 #define keystate1 2//keystate1在keyscan()函数中,代表无按键按下 uchar keynum;//调用keyscan()函数,如果该函数返回1,说明有键按下,keynum保存按键值 uchar keynum1=0;//指示键1按下了多少次 uchar TimeShowEn=1;//设置此变量是为了在校时状态期间,不让主函数再刷新时间显示 uchar TimeChanged;//用来指示用户是否修改了时间 sbit led1=P0^0;//键1指示灯,按下键1此灯变换状态 sbit led2=P0^1;//键2指示灯,按下键2此灯变换状态 sbit led3=P0^2;//键3指示灯,按下键3此灯变换状态 sbit buzz=P1^0;//蜂鸣器接口 uchar AlarmEn,AlarmCome;//AlarmEn指示是否开启了闹钟功能,AlarmCome指示定时时间是否到了 char AlarmMin,AlarmHr;//保存闹钟分钟、闹钟小时 uchar CountForAlarm;//用于累加时间,时间到,翻转蜂鸣器接口电平,决定蜂鸣器响声频率 uchar ToShowAlarm;//ToShowAlarm为1,则允许主函数中显示闹钟时间模块执行 uchar CountForShowAlarm;//CountForShowAlarm用于累加闹钟显示时间 ... ... ... ... ... ... void Timer0() interrupt 1 { TH0=(65536-50000)/256; TL0=(65536-50000)%256; Timflag=1;//Timflag 为1说明50ms定时时间到了 } void Ds1302Init() { rst_l; sck_l; Ds1302Write(CONTROLADD,0);//关闭写保护 Ds1302Write(MINADD,DextoBCD(06)); Ds1302Write(HRADD,DextoBCD(19)); Ds1302Write(DATEADD,DextoBCD(20)); Ds1302Write(MONTHADD,DextoBCD(5)); Ds1302Write(DAYADD,DextoBCD(7)); Ds1302Write(YEARADD,DextoBCD(12)); Ds1302Write(SECADD,DextoBCD(30));//写秒,同时启动时钟 //Ds1302Write(CONTROLADD,0x80);//写保护 } void WriteByte(uchar dat)//上升沿输出 { uchar i; for(i=8;i>0;i--) { sck_l;//低电平时数据线可变 if(dat&0x01) io_h; else io_l; sck_h; dat>>=1; } } uchar BCDtoDex(uchar dat)//BCD码转十进制 { uchar i; i=dat/16; dat%=16; i=i*10+dat; return i; } uchar DextoBCD(uchar dat)//十进制转BCD码 { uchar i; i=dat/10; dat%=10; i=i*16+dat; return i; } uchar ReadByte()//下降沿输出 { uchar i; uchar dat; for(i=8;i>0;i--)//要考虑之前写完后的状态,第一次进入此循环体即有下降沿 { dat>>=1; sck_l; if(time==1) dat|=0x80; sck_h; } return dat; } void Ds1302Write(uchar add,uchar dat) { rst_l; sck_l; rst_h; WriteByte(add);//最低位为0表示写 WriteByte(dat); rst_l; } uchar Ds1302Read(uchar add) { uchar dat; rst_l; sck_l; rst_h; WriteByte(add+1);//地址最低位置1表示读 dat=ReadByte(); rst_l; return dat; } void delayms(uint x)//延时1ms { uint y,z; for(y=x;y>0;y--) for(z=111;z>0;z--); } void lcd_init()//LCD1602初始化 { lcd_com(0x38); lcd_com(0x0c); lcd_com(0x06); lcd_write(0,5,0xb0);//显示- lcd_write(0,8,0xb0);//显示- lcd_write(1,3,0x3a);//显示: lcd_write(1,6,0x3a);//显示: } void lcd_com(uchar com)//向LCD1602写命令 { rs_l; rw_l; PORT=com; delayms(1); en_h; delayms(1); en_l; } void lcd_dat(uchar dat)//向LCD1602写数据 { rs_h; rw_l; PORT=dat; delayms(1); en_h; delayms(1); en_l; } void lcd_write(uchar c,uchar r,uchar dat)//向LCD1602指定行、指定列、写数据 { lcd_com(0x80+0x40*c+r); lcd_dat(dat); } ... ... ... ... ... ...