#include <reg51.h>#include <intrins.h>#define uchar unsigned char#define uint unsigned intuchar count_10ms; //定义10ms计数器sbit K1 = P3^7; //定义K1键sbit K2 = P3^4; //定义K2键sbit K3 = P3^5; //定义K3键sbit K4 = P3^6; //P1^3定义K4键sbit K5 = P3^3;sbit BEEP=P2^2; //定义蜂鸣器sbit reset = P1^6; //P2^5;sbit sclk = P1^7; //P2^6;sbit io = P2^6; //P2^7;sbit LCD_RS=P1^0;sbit LCD_RW=P1^1 ;sbit LCD_EN=P1^2;bit K1_FLAG=0; //定义按键标志位,当按下K1键时,该位置1,K1键未按下时,该位为0。
uchar disp_buf[16] ={0x00}; //定义显示缓冲区uchar time_buf[7] ={0,0,0x12,0,0,0,0}; //DS1302时间缓冲区,存放秒、分、时、日、月、星期、年uchar temp [2]={0}; //用来存放设置时的小时、分钟的中间值uint m=0,n=0,r=0;/********以下是函数声明********/void Delay_ms(uint xms) ;bit lcd_busy();void lcd_wcmd(uchar cmd);void lcd_wdat(uchar dat) ;void lcd_clr() ;void lcd_init() ;void write_byte(uchar inbyte); //写一字节数据函数声明uchar read_byte(); //读一字节数据函数声明void write_ds1302(uchar cmd,uchar indata); //写DS1302函数声明uchar read_ds1302(uchar addr); //读DS1302函数声明void set_ds1302(uchar addr,uchar *p,uchar n); //设置DS1302初始时间函数声明void get_ds1302(uchar addr,uchar *p,uchar n); //读当前时间函数声明void init_ds1302(); //DS1302初始化函数声明/********以下是延时函数********/void Delay_ms(uint xms){uint i,j;for(i=xms;i>0;i--) //i=xms即延时约xms毫秒for(j=70;j>0;j--);}/********以下是LCD忙碌检查函数********/bit lcd_busy(){bit result;LCD_RS = 0;LCD_RW = 1;LCD_EN = 1;_nop_();_nop_();_nop_();_nop_();result = (bit)(P0&0x80);LCD_EN = 0;return result;}/********以下是写指令寄存器IR函数********/void lcd_wcmd(uchar cmd){while(lcd_busy());LCD_RS = 0;LCD_RW = 0;LCD_EN = 0;_nop_();_nop_();P0 = cmd;_nop_();_nop_();_nop_();_nop_();LCD_EN = 1;_nop_();_nop_();_nop_();_nop_();LCD_EN = 0;}/********以下是写寄存器DR函数********/void lcd_wdat(uchar dat){while(lcd_busy());LCD_RS = 1;LCD_RW = 0;LCD_EN = 0;P0 = dat;_nop_();_nop_();_nop_();_nop_();LCD_EN = 1;_nop_();_nop_();_nop_();_nop_();LCD_EN = 0;}/********以下是LCD清屏函数********/void lcd_clr(){lcd_wcmd(0x01); //清除LCD的显示内容Delay_ms(5);}/********以下是LCD初始化函数********/void lcd_init(){Delay_ms(15); //等待LCD电源稳定lcd_wcmd(0x38); //16*2显示,5*7点阵,8位数据Delay_ms(5);lcd_wcmd(0x38);Delay_ms(5);lcd_wcmd(0x38);Delay_ms(5);lcd_wcmd(0x0c); //显示开,关光标Delay_ms(5);lcd_wcmd(0x06); //移动光标Delay_ms(5);lcd_wcmd(0x01); //清除LCD的显示内容Delay_ms(5);}/********以下是写一字节数据函数********/void write_byte(uchar inbyte){uchar i;for(i=0;i<8;i++){sclk=0; //写时低电平改变数据if(inbyte&0x01)io=1;elseio=0;sclk=1; //高电平把数据写入DS1302_nop_();inbyte=inbyte>>1;}}/********以下是读一字节数据函数********/uchar read_byte(){uchar i,temp=0;io=1;for(i=0;i<7;i++){sclk=0;if(io==1)temp=temp|0x80;elsetemp=temp&0x7f;sclk=1; //产生下跳沿temp=temp>>1;}return (temp);}/********写DS1302函数, 往DS1302的某个地址写入数据********/ void write_ds1302(uchar cmd,uchar indata){sclk=0;reset=1;write_byte(cmd);write_byte(indata);sclk=0;reset=0;}/********读DS1302函数,读DS1302某地址的的数据********/ uchar read_ds1302(uchar addr){uchar backdata;sclk=0;reset=1;write_byte(addr); //先写地址backdata=read_byte(); //然后读数据sclk=0;reset=0;return (backdata);}/********初始化DS1302函数********/void init_ds1302(){reset=0;sclk=0;write_ds1302(0x80,0x00); //写秒寄存器write_ds1302(0x90,0xab); //写充电器write_ds1302(0x8c,0x13); //以下写入初始化时间日期write_ds1302(0x88,0x09); //write_ds1302(0x86,0x16); //write_ds1302(0x8a,0x05); //写入星期write_ds1302(0x84,0x10); //write_ds1302(0x82,0x13); //write_ds1302(0x80,0x00); //write_ds1302(0x8e,0x80); //写保护控制字,禁止写}/*********以下是蜂鸣器响一声函数********/void beep(){BEEP=0; //蜂鸣器响Delay_ms(100);BEEP=1; //关闭蜂鸣器Delay_ms(100);}/********以下是转换函数,负责将走时数据转换为适合LCD显示的数据********/void LCD_conv (uchar in7,in5,in4,in1,in2,in3 )//形参in1、in2、in3接收实参time_buf[2]、time_buf[1]、time_buf[0]传来的小时、分钟、秒数据{disp_buf[0]=in1/10+0x30; //小时十位数据disp_buf[1]=in1%10+0x30; //小时个位数据disp_buf[2]=in2/10+0x30; //分钟十位数据disp_buf[3]=in2%10+0x30; //分钟个位数据disp_buf[4]=in3/10+0x30; //秒十位数据disp_buf[5]=in3%10+0x30; //秒个位数据disp_buf[6]=2+0x30; //年千位数据disp_buf[7]=0+0x30; //年百位数据disp_buf[8]=in7/10+0x30; //年十位数据disp_buf[9]=in7%10+0x30; //年时个位数据disp_buf[10]=in5/10+0x30; //月十位数据disp_buf[11]=in5%10+0x30; //月个位数据disp_buf[12]=in4/10+0x30; //日十位数据disp_buf[13]=in4%10+0x30; //日个位数据}/********以下是LCD显示函数,负责将函数LCD_conv转换后的数据显示在LCD上********/void LCD_disp (){lcd_wcmd(0x80+3); //显示第一行lcd_wdat(disp_buf[6]); //显示年千位lcd_wdat(disp_buf[7]); //显示年百位lcd_wdat(disp_buf[8]); //显示年十位lcd_wdat(disp_buf[9]); //显示年个位lcd_wdat(0x3a);lcd_wdat(disp_buf[10]); //显示月十位lcd_wdat(disp_buf[11]); //显示月个位lcd_wdat(0x3a);lcd_wdat(disp_buf[12]); //显示日十位lcd_wdat(disp_buf[13]); //显示日个位lcd_wcmd(0x44 + 0x80); //从第2行第4列开始显示lcd_wdat(disp_buf[0]); //显示小时十位lcd_wdat(disp_buf[1]); //显示小时个位lcd_wdat(0x3a); //显示':'lcd_wdat(disp_buf[2]); //显示分钟十位lcd_wdat(disp_buf[3]); //显示分钟个位lcd_wdat(0x3a); //显示':'lcd_wdat(disp_buf[4]); //显示秒十位lcd_wdat(disp_buf[5]); //显示秒个位}/********以下是按键处理函数********/void KeyProcess(){uchar min16,hour16,ri16,yue16,nian16; //定义16进制的分钟和小时变量write_ds1302(0x8e,0x00); //DS1302写保护控制字,允许写write_ds1302(0x80,0x80); //时钟停止运行lcd_wcmd(0x0f);lcd_wcmd(0x80+0x40+12);if(K2==0){Delay_ms(10); //延时去抖if(K2==0){while(!K2);m++;if(m==6){m=1;}}}if(K3==0){Delay_ms(10); //延时去抖if(K3==0){while(!K3);m--;if(m==0){m=5;}}}if(m!=0){if(m==1&&K4==0){Delay_ms(10); //延时去抖if(m==1&&K4==0){lcd_wcmd(0x0f);lcd_wcmd(0x80+0x40+8);while(!K4);beep();time_buf[1]=time_buf[1]+1; //分钟加1if(time_buf[1]==60) time_buf[1]=0; //当分钟加到60时初始化为0min16=time_buf[1]/10*16+time_buf[1]%10; //将所得的分钟数据转变成16进制数据write_ds1302(0x82,min16);}}if(m==2&&K4==0){Delay_ms(10); //延时去抖if(m==2&&K4==0){lcd_wcmd(0x0f);lcd_wcmd(0x80+0x40+5);while(!K4);beep();time_buf[2]=time_buf[2]+1; //小时减1if(time_buf[2]==24) time_buf[2]=0; //当变成0时初始化为24hour16=time_buf[2]/10*16+time_buf[2]%10; //将所得的小时数据转变成16进制数据write_ds1302(0x84,hour16);}}if(m==3&&K4==0){Delay_ms(10); //延时去抖if(m==3&&K4==0){lcd_wcmd(0x0f);lcd_wcmd(0x80+12);while(!K4);beep();time_buf[3]=time_buf[3]+1; //分钟减1if(time_buf[3]==32) time_buf[3]=0; //当分钟加到60时初始化为0ri16=time_buf[3]/10*16+time_buf[3]%10; //将所得的分钟数据转变成16进制数据write_ds1302(0x86,ri16);}}if(m==4&&K4==0){Delay_ms(10); //延时去抖if(m==4&&K4==0){lcd_wcmd(0x0f);lcd_wcmd(0x80+8);while(!K4);beep();time_buf[4]=time_buf[4]+1; //分钟减1if(time_buf[4]==13) time_buf[4]=0; //当分钟加到60时初始化为0yue16=time_buf[4]/10*16+time_buf[4]%10; //将所得的分钟数据转变成16进制数据write_ds1302(0x88,yue16);}}if(m==5&&K4==0){Delay_ms(10); //延时去抖if(m==5&&K4==0){lcd_wcmd(0x0f);lcd_wcmd(0x80+6);while(!K4);beep();time_buf[6]=time_buf[6]+1; //分钟减1if(time_buf[6]==100) time_buf[6]=0; //当分钟加到60时初始化为0nian16=time_buf[6]/10*16+time_buf[6]%10; //将所得的分钟数据转变成16进制数据write_ds1302(0x8C,nian16);}}if(m==1&&K5==0){Delay_ms(10); //延时去抖if(m==1&&K5==0){lcd_wcmd(0x0f);lcd_wcmd(0x80+0x40+8);while(!K5);beep();time_buf[1]=time_buf[1]-1; //分钟加1if(time_buf[1]==-1) time_buf[1]=59; //当分钟加到60时初始化为0min16=time_buf[1]/10*16+time_buf[1]%10; //将所得的分钟数据转变成16进制数据write_ds1302(0x82,min16);}}if(m==2&&K5==0){Delay_ms(10); //延时去抖if(m==2&&K5==0){lcd_wcmd(0x0f);lcd_wcmd(0x80+0x40+5);while(!K5);beep();time_buf[2]=time_buf[2]-1; //小时减1if(time_buf[2]==-1) time_buf[2]=23; //当变成0时初始化为24hour16=time_buf[2]/10*16+time_buf[2]%10; //将所得的小时数据转变成16进制数据write_ds1302(0x84,hour16);}}if(m==3&&K5==0){Delay_ms(10); //延时去抖if(m==3&&K5==0){lcd_wcmd(0x0f);lcd_wcmd(0x80+12);while(!K5);beep();time_buf[3]=time_buf[3]-1; //分钟减1if(time_buf[3]==0) time_buf[3]=31; //当分钟加到60时初始化为0ri16=time_buf[3]/10*16+time_buf[3]%10; //将所得的分钟数据转变成16进制数据write_ds1302(0x86,ri16);}}if(m==4&&K5==0){Delay_ms(10); //延时去抖if(m==4&&K5==0){lcd_wcmd(0x0f);lcd_wcmd(0x80+8);while(!K5);beep();time_buf[4]=time_buf[4]-1; //分钟减1if(time_buf[4]==0) time_buf[4]=12; //当分钟加到60时初始化为0yue16=time_buf[4]/10*16+time_buf[4]%10; //将所得的分钟数据转变成16进制数据write_ds1302(0x88,yue16);}}if(m==5&&K5==0){Delay_ms(10); //延时去抖if(m==5&&K5==0){lcd_wcmd(0x0f);lcd_wcmd(0x80+6);while(!K5);beep();time_buf[6]=time_buf[6]-1; //分钟减1if(time_buf[6]==0) time_buf[6]=99; //当分钟加到60时初始化为0nian16=time_buf[6]/10*16+time_buf[6]%10; //将所得的分钟数据转变成16进制数据write_ds1302(0x8C,nian16);}}}}/********以下是读取时间函数,负责读取当前的时间,并将读取到的时间转换为10进制数********/void get_time(){uchar sec,min,hour,ri,yue,nian; //定义秒、分和小时变量write_ds1302(0x8e,0x00); //控制命令,WP=0,允许写操作write_ds1302(0x90,0xab); //涓流充电控制sec=read_ds1302(0x81); //读取秒min=read_ds1302(0x83); //读取分hour=read_ds1302(0x85); //读取时ri=read_ds1302(0x87); //读取日yue=read_ds1302(0x89); //读取月nian=read_ds1302(0x8D); //读取年time_buf[0]=sec/16*10+sec%16; //将读取到的16进制数转化为10进制time_buf[1]=min/16*10+min%16; //将读取到的16进制数转化为10进制time_buf[2]=hour/16*10+hour%16; //将读取到的16进制数转化为10进制time_buf[3]=ri/16*10+ri%16; //将读取到的16进制数转化为10进制time_buf[4]=yue/16*10+yue%16; //将读取到的16进制数转化为10进制time_buf[6]=nian/16*10+nian%16; //将读取到的16进制数转化为10进制if(m!=0){if(m==1)lcd_wcmd(0x80+0x40+8);if(m==2)lcd_wcmd(0x80+0x40+5);if(m==3)lcd_wcmd(0x80+12);if(m==4)lcd_wcmd(0x80+9);if(m==5)lcd_wcmd(0x80+6);}}/********以下是主函数********/void main(void){uint a;P0 = 0xff;P2 = 0xff;lcd_init(); //LCD初始化函数(在LCD驱动程序软件包中)lcd_clr(); //清屏函数(在LCD驱动程序软件包中)init_ds1302(); //DS1302初始化while(1){get_time(); //读取当前时间if(K1==0) //若K1键按下{Delay_ms(10); //延时10ms去抖if(K1==0){while(!K1);a++;}}if(a!=0){if(a==1){beep(); //蜂鸣器响一声K1_FLAG=1; //K1键标志位置1,以便进行时钟调整//时钟停止运行}if(a==2){beep();lcd_wcmd(0x0c);write_ds1302(0x80,time_buf[0]); //调整完毕后,启动时钟运行write_ds1302(0x8e,0x80); //写保护控制字,禁止写K1_FLAG=0; //将K1键按下标志位清0a=0;m=0;}}if(K1_FLAG==1)KeyProcess(); //若K1_FLAG为1,则进行走时调整LCD_conv(time_buf[6],time_buf[4],time_buf[3],time_buf[2],time_buf[1],time_buf[0]);//将DS1302的年/月/日/小时/分/秒传送到转换函数LCD_disp(); //调LCD显示函数,显示年、月、日小时、分和秒}}。