#include <REG52.H> #include <intrins.H> #include <math.h> /* 液晶引脚定义 */ //1602 #define LCD_DB P0 //P0.0-P0.7 DB0-DB7 sbit LCD_RS=P2^0; //data/command (HL) sbit LCD_RW=P2^1; //read/write(HL) sbit LCD_E=P2^2; //disenable/enable /* 温度传感器引脚定义 */ //DS18B20 sbit B20_IO=P1^3; /* 时钟芯片引脚定义 */ //DS1302 sbit DS1302_IO=P1^0; sbit DS1302_SCLK=P1^1; sbit DS1302_RST_CE=P1^2; //CE /* 独立按键引脚定义 */ sbit KeyOne = P3^2; //功能键 sbit KeyThree = P3^3; //+ sbit KeyTwo = P3^4; //- sbit KeyFour = P3^5; /* 第0位 第八位 位操作 */ sbit ACC0=ACC^0; sbit ACC7=ACC^7; /* 报警指示引脚定义 */ sbit Red = P3^6; sbit Green = P3^7; sbit Beep = P1^4; #if 0 /* 时钟芯片寄存器定义 */ #define write_second 0x80 #define write_minute 0x82 #define write_hour 0x84 #define write_day 0x86 #define write_month 0x88 #define write_week 0x8a #define write_year 0x8c #else /* 时钟芯片寄存器定义 */ #define write_second 0x80 #define read_second 0x81 #define write_minute 0x82 #define read_minute 0x83 #define write_hour 0x84 #define read_hour 0x85 #define write_day 0x86 #define read_day 0x87 #define write_month 0x88 #define read_month 0x89 #define write_year 0x8c #define read_year 0x8d #define write_week 0x8a #define read_week 0x8b #endif /* 按键状态 */ enum KEYSTART { KEYDOWN, //0 按下 KEYUP }; /* 按键键值 */ enum KEYCONFIG { KEYINIT, KEYYEAR, KEYMONTH, KEYDAY, KEYWEEK, KEYHOUR, KEYMINTH, KEYALARH, KEYALARM }; /* 逻辑变量定义 */ unsigned char miao=0,shi=0,fen=0,ri=0,yue=0,nian=0,week=0; extern unsigned char miao,shi,fen,ri,yue,nian,week; unsigned int TempVal=0,AlarmFlag=0; unsigned char YearData=0,MonthData=0,DayData=0,WeekData=0,HourData=0, MinuteData=0,AlarmH=0,AlarmM=0; /* n*10微妙延时 */ void delay_n10us(unsigned int n) { unsigned int i=0; for(i=n;i>0;i--) { _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); } } /* 写命令函数 */ void LCD_write_command(unsigned char dat) { delay_n10us(10); LCD_RS=0; LCD_RW=0; LCD_E=1; LCD_DB=dat; delay_n10us(10); LCD_E=0; delay_n10us(10); } /* 写数据函数 */ void LCD_write_data(unsigned char dat) { delay_n10us(10); LCD_RS=1; LCD_RW=0; LCD_E=1; LCD_DB=dat; delay_n10us(10); LCD_E=0; delay_n10us(10); } /* 写字符函数 X:0~15 Y:1,2 */ void LCD_disp_char(const unsigned char x,const unsigned char y,unsigned char dat) { unsigned char address=0; if(y==1) address=0x80+x; else address=0xc0+x; //address = 0x80 + 0x40 + x; LCD_write_command(address); LCD_write_data(dat); } /* 写一串字符 X:0~15 Y:1,2 */ void LCD_disp_str(const unsigned char x,const unsigned char y,const unsigned char *str) { unsigned char address=0; if(y==1) address=0x80+x; else address=0xc0+x; LCD_write_command(address); while(*str!='\0') { LCD_write_data(*str); str++; } } /* 液晶初始化 */ void LCD_init(void) { delay_n10us(10); LCD_write_command(0x38);//16x2显示 5X7点阵 8bit数据接口 delay_n10us(10); LCD_write_command(0x0c);//开显示,不显示光标 00001100 delay_n10us(10); LCD_write_command(0x06);//写最后一个字符后,地址指针自动加1 delay_n10us(10); LCD_write_command(0x01);//显示清0,数据指针清0 delay_n10us(100); } /* 温度传感器最小单位延时 */ /* 延时n x ms */ //1000(1s) void delay_n_ms(unsigned int ms) { unsigned int i=0,j=0; for(i=ms;i>0;i--) for(j=110;j>0;j--); } /* 温度传感器复位操作 DS18B20 复位, INIT 初始化DS18B20 让DS18B20一段相对长时间低电平, 然后一段相对非常短时间高电平, 即可启动 一定要使用unsigned int型, 一个i++指令的时间, 作为与DS18B20通信的小时间间隔 */ void dsB20_reset(void) { unsigned int i=0; B20_IO=0; i=105; while(i>0) i--; B20_IO=1; i=5; while(i>0) i--; } /* 读温度传感器一位数据信息 */ /* 读DS18B20 1bit 向DS18B20读取一位数据 读一位, 让DS18B20一小周期低电平, 然后两小周期高电平, 之后DS18B20则会输出持续一段时间的一位数据 */ bit temp_read_bit(void) //temperature { unsigned int i=0; bit dat=0; B20_IO=0; i++; B20_IO=1; i++; i++; dat=B20_IO; i=8; while(i>0) i--; return (dat); } /* 读温度传感器八位数据信息 */ unsigned char temp_read_byte(void) { unsigned char i=0,j=0,dat=0; for(i=1;i<=8;i++) { j=temp_read_bit(); //最先读出的是最低位数据 dat=(j<<7)|(dat>>1); } return(dat); } /* 写DS18B20 八位数据 */ void temp_write_byte(unsigned char dat) { unsigned int i=0; unsigned char j=0; bit testb=0; for(j=1;j<=8;j++) { testb=dat&0x01; dat=dat>>1; if(testb) //write 1 让低电平持续2个小延时, 高电平持续8个小延时 { B20_IO=0; i++; i++; B20_IO=1; i=8; while(i>0) i--; } else { B20_IO=0; //write 0 让低电平持续8个小延时, 高电平持续2个小延时 i=8; while(i>0) i--; B20_IO=1; i++; i++; } } } /* DS18B20开始获取温度并转换 */ void temp_change(void) { dsB20_reset(); delay_n_ms(1); temp_write_byte(0xcc); //cc 跳过rom temp_write_byte(0x44); //44 转换 } /* 读取温度寄存器转换数据 */ unsigned int get_temp_value(void) { float tt=0; unsigned char a=0,b=0; unsigned int tempA=0; dsB20_reset(); delay_n_ms(1); temp_write_byte(0xcc); temp_write_byte(0xbe);//读取数据命令 a=temp_read_byte();//读低8位 b=temp_read_byte();//读高8位 //高低两字节合并为一个整形变量 tempA=b; tempA<<=8; tempA=tempA|a; tt=tempA*0.0625;//精确度为0.0625度 tempA=tt*10+0.5;//乘以10,表示小数点后只取一位, 0.5是进行4舍5入 return tempA; } /* 控制字总是从最低位开始输出。在控制字指令输入 后的下一个SCLK时钟的上升沿时,数据被写入DS1302 数据输入从最低位(0位)开始。 同样,在紧跟8位的控制字指令后的下一个SCLK脉 冲的下降沿,读出DS1302的数据,读出的数据也是 从最低位到最高位。 */ /* 写时钟芯片八位数据信息 */ void write_1302_byte(unsigned char dat) { unsigned char a=0; ACC=dat; DS1302_RST_CE=1; // CE:输入信号,在读、写数据期间,必须为高。 for(a=8;a>0;a--) { DS1302_IO=ACC0; DS1302_SCLK=0; //delay_n_ms(1); DS1302_SCLK=1;//上升沿写入,下降沿读出 //delay_n_ms(1); ACC=ACC>>1; } } /* 读时钟芯片八位数据信息 */ unsigned char read_1302_byte() { unsigned char a=0; DS1302_RST_CE=1; for(a=8;a>0;a--) { ACC7=DS1302_IO; DS1302_SCLK=1; //delay_n_ms(1); DS1302_SCLK=0; //delay_n_ms(1); ACC=ACC>>1; } return (ACC); } /* 在时钟芯片指定位置写指定数据 */ void write_1302_addr_data(unsigned char add,unsigned char dat) { DS1302_RST_CE=0;//初始CE线置为0 DS1302_SCLK=0; //初始时钟线置为0 DS1302_RST_CE=1;//初始CE置为1,传输开始 write_1302_byte(add); write_1302_byte(dat); DS1302_SCLK=1; //时钟线拉高 DS1302_RST_CE=0;//读取结束,CE置为0,结束数据的传输 } /* 读取时钟芯片指定地址的数据信息 */ unsigned char read_1302_addr_data(unsigned char add) { unsigned char temp; DS1302_RST_CE=0; DS1302_SCLK=0; DS1302_RST_CE=1; write_1302_byte(add); temp=read_1302_byte(); DS1302_SCLK=1; DS1302_RST_CE=0; return(temp); } /* 时钟芯片数据转换 */ unsigned char BCD_Decimal(unsigned char bcd) { unsigned char Decimal; Decimal=bcd>>4; return(Decimal=Decimal*10+(bcd&=0x0F)); } /* 时钟芯片初始化操作 */ /* 控制寄存器(8Fh、8Eh)的位7是写保护位(WP) 其它7位均置为0。在任何的对时钟和RAM的写操作之前 WP位必须为0。当WP位为1时,写保护位 防止对任一寄存器的写操作. */ void ds1302_init() { DS1302_RST_CE=0; DS1302_SCLK=0; write_1302_addr_data(0x8e,0x00); //写保护关 将控制寄存器值设为0,wp=0允许写 write_1302_addr_data(0x8e,0x80); //写保护开,防止影响时间值 } /* 设置时钟芯片参数信息 */ void Set_RTC(unsigned char address,unsigned char temp) { unsigned char tmp=0; tmp=temp/10; temp=temp%10; temp=temp+tmp*16; write_1302_addr_data(0x8E,0X00); write_1302_addr_data(address,temp&0x7f); write_1302_addr_data(0x8E,0x80); } /* 提取时钟芯片时间信息 */ void GetTime(void) { #if 0 miao = BCD_Decimal(read_1302_addr_data(0x81)); fen = BCD_Decimal(read_1302_addr_data(0x83)); shi = BCD_Decimal(read_1302_addr_data(0x85)); ri = BCD_Decimal(read_1302_addr_data(0x87)); yue = BCD_Decimal(read_1302_addr_data(0x89)); nian=BCD_Decimal(read_1302_addr_data(0x8d)); week=BCD_Decimal(read_1302_addr_data(0x8b)); #else nian = BCD_Decimal(read_1302_addr_data(read_year)); yue = BCD_Decimal(read_1302_addr_data(read_month)); ri = BCD_Decimal(read_1302_addr_data(read_day)); shi = BCD_Decimal(read_1302_addr_data(read_hour)); fen = BCD_Decimal(read_1302_addr_data(read_minute)); miao = BCD_Decimal(read_1302_addr_data(read_second)); week = BCD_Decimal(read_1302_addr_data(read_week))-1; #endif } /* 按键消抖动 */ void KeyDelay(void) { unsigned char i=0,j=0; for(i=15;i>0;i--) for(j=80;j>0;j--); } /* 读取按键键值 */ unsigned char KeyProcess(void) { static unsigned char KeyVal=KEYINIT; if(KeyOne==KEYDOWN) { KeyDelay(); if(KeyOne==KEYDOWN) { while(KeyOne==KEYDOWN); LCD_disp_str(0,1," "); LCD_disp_str(0,2," "); KeyVal++; if(KeyVal>KEYALARM) KeyVal=KEYINIT; } } return KeyVal; } /* 定时器配置 */ void Time_init() //定时器、计数器设置函数 //void init() //定时器、计数器设置函数 { TMOD=0x01; //指定定时/计数器的工作方式为3 // TMOD=0x01; 定时器0 中断号1 方式1 16位定时器 TH0=0x3c; //定时器T0的高四位=0 TL0=0xb0; //定时器T0的低四位=0 EA=1; //系统允许有开放的中断 ET0=1; //允许T0中断 TR0=1; //开启中断,启动定时器T0 } /* 外围硬件初始化 */ void HandInit(void) { LCD_init(); ds1302_init(); Time_init(); Red = 1; Green = 0; } /* 年月日信息显示 */ void show_Data(void) { unsigned char dis_Data[16]={0}; dis_Data[0]='2'; dis_Data[1]='0'; dis_Data[2]=(nian/10)+'0'; //ascii0(48) 0x30(48) //dis_Data[2]=(nian/10)+'0'; dis_Data[3]=(nian%10)+'0'; dis_Data[4]='-'; dis_Data[5]=(yue/10)+'0'; dis_Data[6]=(yue%10)+'0'; dis_Data[7]='-'; dis_Data[8]=(ri/10)+'0'; dis_Data[9]=(ri%10)+'0'; dis_Data[10]=' '; dis_Data[11]='W'; dis_Data[12]=126;//~ dis_Data[13]='<'; dis_Data[14]=(week%10)+'0'; dis_Data[15]='>'; LCD_disp_str(0,1,dis_Data); } /* 时分秒温度信息显示 */ void Show_Time_Temperature(void) { unsigned char dis_Time[16]={0}; dis_Time[0]=' '; dis_Time[1]=(shi/10)+'0'; dis_Time[2]=(shi%10)+'0'; dis_Time[3]=':'; dis_Time[4]=(fen/10)+'0'; dis_Time[5]=(fen%10)+'0'; dis_Time[6]=':'; dis_Time[7]=(miao/10)+'0'; dis_Time[8]=(miao%10)+'0'; dis_Time[9]=' '; dis_Time[10]=TempVal/100+'0'; dis_Time[11]=TempVal%100/10+'0'; dis_Time[12]='.'; dis_Time[13]=TempVal%10+'0'; dis_Time[14]=223; dis_Time[15]='C'; LCD_disp_str(0,2,dis_Time); } /* 设置年参数 */ void Set_Year(void) { YearData=read_1302_addr_data(0x8D); YearData=(YearData>>4)*10+(YearData&0x0f); if(KeyTwo==KEYDOWN) { KeyDelay(); if(KeyTwo==KEYDOWN) { while(KeyTwo==KEYDOWN); if(YearData<=0) YearData=1; YearData-=1; Set_RTC(write_year,YearData); } } if(KeyThree==KEYDOWN) { KeyDelay(); if(KeyThree==KEYDOWN) { while(KeyThree==KEYDOWN); if(YearData>=99) YearData=98; YearData+=1; Set_RTC(write_year,YearData); } } LCD_disp_str(0,1," SET YEAR "); LCD_disp_char(4,2,'2'); LCD_disp_char(5,2,'0'); LCD_disp_char(6,2,YearData/10+'0'); LCD_disp_char(7,2,YearData%10+'0'); } /* 设置月参数 */ void SetMonth(void) { MonthData=read_1302_addr_data(0x89); MonthData=(MonthData>>4)*10+(MonthData&0x0f); if(KeyTwo==KEYDOWN) { KeyDelay(); if(KeyTwo==KEYDOWN) { while(KeyTwo==KEYDOWN); if(MonthData<=1) MonthData=2; MonthData-=1; Set_RTC(write_month,MonthData); } } if(KeyThree==KEYDOWN) { KeyDelay(); if(KeyThree==KEYDOWN) { while(KeyThree==KEYDOWN); if(MonthData>=12) MonthData=11; MonthData+=1; Set_RTC(write_month,MonthData); } } LCD_disp_str(0,1," SET MONTH "); LCD_disp_char(6,2,MonthData/10+'0'); LCD_disp_char(7,2,MonthData%10+'0'); } /* 设置日参数 */ void SetDay(void) { DayData=read_1302_addr_data(0x87); DayData=(DayData>>4)*10+(DayData&0x0f); if(KeyTwo==KEYDOWN) { KeyDelay(); if(KeyTwo==KEYDOWN) { while(KeyTwo==KEYDOWN); if(DayData<=1) DayData=2; DayData-=1; Set_RTC(write_day,DayData); } } if(KeyThree==KEYDOWN) { KeyDelay(); if(KeyThree==KEYDOWN) { while(KeyThree==KEYDOWN); if(DayData>=30) DayData=29; DayData+=1; Set_RTC(write_day,DayData); } } LCD_disp_str(0,1," SET DAY "); LCD_disp_char(6,2,DayData/10+'0'); LCD_disp_char(7,2,DayData%10+'0'); } /* 设置周期参数 */ void SetWeek(void) { WeekData=read_1302_addr_data(0x8b); WeekData=(WeekData>>4)*10+(WeekData&0x0f); if(KeyTwo==KEYDOWN) { KeyDelay(); if(KeyTwo==KEYDOWN) { while(KeyTwo==KEYDOWN); if(WeekData<=1) WeekData=2; WeekData-=1; Set_RTC(write_week,WeekData); } } if(KeyThree==KEYDOWN) { KeyDelay(); if(KeyThree==KEYDOWN) { while(KeyThree==KEYDOWN); if(WeekData>=7) WeekData=6; WeekData+=1; Set_RTC(write_week,WeekData); } } LCD_disp_str(0,1," SET WEEK "); LCD_disp_char(6,2,WeekData/10+'0'); LCD_disp_char(7,2,WeekData%10+'0'); } /* 设置小时参数 */ void SetHour(void) { HourData=read_1302_addr_data(0x85); HourData=(HourData>>4)*10+(HourData&0x0f); if(KeyTwo==KEYDOWN) { KeyDelay(); if(KeyTwo==KEYDOWN) { while(KeyTwo==KEYDOWN); if(HourData<=0) HourData=1; HourData-=1; Set_RTC(write_hour,HourData); } } if(KeyThree==KEYDOWN) { KeyDelay(); if(KeyThree==KEYDOWN) { while(KeyThree==KEYDOWN); if(HourData>=23) HourData=22; HourData+=1; Set_RTC(write_hour,HourData); } } LCD_disp_str(0,1," SET HOUR "); LCD_disp_char(6,2,HourData/10+'0'); LCD_disp_char(7,2,HourData%10+'0'); } /* 设置分钟参数 */ void SetMinute(void) { MinuteData=read_1302_addr_data(0x83); MinuteData=(MinuteData>>4)*10+(MinuteData&0x0f); if(KeyTwo==KEYDOWN) { KeyDelay(); if(KeyTwo==KEYDOWN) { while(KeyTwo==KEYDOWN); if(MinuteData<=0) MinuteData=1; MinuteData-=1; Set_RTC(write_minute,MinuteData); } } if(KeyThree==KEYDOWN) { KeyDelay(); if(KeyThree==KEYDOWN) { while(KeyThree==KEYDOWN); if(MinuteData>=59) MinuteData=58; MinuteData+=1; Set_RTC(write_minute,MinuteData); } } LCD_disp_str(0,1," SET MINUTE "); LCD_disp_char(6,2,MinuteData/10+'0'); LCD_disp_char(7,2,MinuteData%10+'0'); } /* 设置闹钟小时参数 */ void SetAlarH(void) { if(KeyTwo==KEYDOWN) { KeyDelay(); if(KeyTwo==KEYDOWN) { while(KeyTwo==KEYDOWN); if(AlarmH<=0) AlarmH=1; AlarmH-=1; } } if(KeyThree==KEYDOWN) { KeyDelay(); if(KeyThree==KEYDOWN) { while(KeyThree==KEYDOWN); if(AlarmH>=23) AlarmH=22; AlarmH+=1; } } LCD_disp_str(0,1," SET ALARMH "); LCD_disp_char(6,2,AlarmH/10+'0'); LCD_disp_char(7,2,AlarmH%10+'0'); } /* 设置闹钟分钟参数 */ void SetAlarM(void) { if(KeyTwo==KEYDOWN) { KeyDelay(); if(KeyTwo==KEYDOWN) { while(KeyTwo==KEYDOWN); if(AlarmM<=0) AlarmM=1; AlarmM-=1; } } if(KeyThree==KEYDOWN) { KeyDelay(); if(KeyThree==KEYDOWN) { while(KeyThree==KEYDOWN); if(AlarmM>=59) AlarmM=58; AlarmM+=1; } } LCD_disp_str(0,1," SET ALARMM "); LCD_disp_char(6,2,AlarmM/10+'0'); LCD_disp_char(7,2,AlarmM%10+'0'); } /* 逻辑信息处理 */ void Process(void) { unsigned char StartChange=KEYINIT; StartChange=KeyProcess(); if(KeyFour==KEYDOWN) { KeyDelay(); if(KeyFour==KEYDOWN) { while(KeyFour==KEYDOWN); AlarmFlag=!AlarmFlag; if(AlarmFlag) { Red = 0; Green = 1; } else { Red = 1; Green = 0; } } } switch(StartChange) { case KEYINIT: show_Data(); Show_Time_Temperature(); break; case KEYYEAR: Set_Year(); break; case KEYMONTH: SetMonth(); break; case KEYDAY: SetDay(); break; case KEYWEEK: SetWeek(); break; case KEYHOUR: SetHour(); break; case KEYMINTH: SetMinute(); break; case KEYALARH: SetAlarH(); break; case KEYALARM: SetAlarM(); break; default:break; } } /* 取得并显示日历和时间 */ void timer0() interrupt 1 { TH0=0x3c; //定时器T0的高四位=0 TL0=0xb0; //定时器T0的低四位=0 temp_change(); TempVal=get_temp_value(); GetTime(); if(AlarmFlag) { HourData=read_1302_addr_data(0x85); HourData=(HourData>>4)*10+(HourData&0x0f); MinuteData=read_1302_addr_data(0x83); MinuteData=(MinuteData>>4)*10+(MinuteData&0x0f); if((HourData==AlarmH)&&(MinuteData==AlarmM)) { Beep=!Beep; } } else { Beep=0; } } /* 主函数 */ void main(void) { HandInit(); while(1) { Process(); } }