《电子万年历的设计.docx》由会员分享,可在线阅读,更多相关《电子万年历的设计.docx(11页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、电子万年历的设计 ?单片机电子万年历的设计论文一?项目背景随着社会的发展?时间的推移?从以前的观察太阳、摆钟?到现在的单片机电子钟?人类在不断地研究?不断地突破?不断地创造新纪录?单片机电子钟也已成为当今社会人类准确、快速获取信息的重要工具之一。现代社会生活节奏逐渐加快?很多人没有时间观念?也相应导致了一些社会问题的发生。而市场上一些其他的钟表?不是价格昂贵?就是质量问题?对许多普通家庭并不适用。我们设计的电子万年历以单片机 AT89S52 为控制核心?加以时钟构成时钟电路?能够实现时间和日期的显示。以下详细介绍分析设计原理和制作过程。关键词 ? 单片机?实时时钟?显示电路?按键扫描?温度传感
2、器?二?设计任务与要求基本要求?1.能够显示年、月、日、时、分、秒和星期、温度?2.可以人为校正年、月、日、时、分、秒和星期、温度?3.掉电情况下原有的信息不会丢失?三?方案设计与论证方案一?按照系统的设计的功能要求?初步确定系统由主控模块?时钟模块、显示模块、各键盘接口模块共四个模块组成?电路系统框图如图1 所示。主控芯片采用 AT89S52 单片机?时钟芯片使用 DS1302。采用DS1302 作为计时芯片?可以做到计时准确。更重要的是?DS1302 可以在很小电流的后备电源?2.5V-5.5V 电源?在 2.5V 时耗电0; i-)DS1302_IO = ACC0; /相当于汇编中的 R
3、RCDS1302_CLK = 1;DS1302_CLK = 0;ACC = ACC 1;unsigned char DS1302OutputByte(void) /实时时钟读取一字节(内部函数)unsigned char i;for(i=8; i0; i-)ACC = ACC 1; /相当于汇编中的 RRCACC7 = DS1302_IO;DS1302_CLK = 1;DS1302_CLK = 0;return(ACC);void Write1302(unsigned char ucAddr, unsigned char ucDa) /ucAddr:DS1302 地址, ucData: 要写的
4、数据DS1302_RST = 0;DS1302_CLK = 0;DS1302_RST = 1;DS1302InputByte(ucAddr); / 地址?命令DS1302InputByte(ucDa); / 写 1Byte 数据DS1302_CLK = 1;DS1302_RST = 0;unsigned char Read1302(unsigned char ucAddr) /读取 DS1302 某地址的数据unsigned char ucData;DS1302_RST = 0;DS1302_CLK = 0;DS1302_RST = 1;DS1302InputByte(ucAddr|0x01)
5、; / 地址?命令ucData = DS1302OutputByte(); / 读 1Byte 数据DS1302_CLK = 1;DS1302_RST = 0;return(ucData); void DS1302_GetTime(SYSTEMTIME *Time) /获取时钟芯片的时钟数据到自定义的结构型数组unsigned char ReadValue;ReadValue = Read1302(DS1302_SECOND);Time-Second = (ReadValue&0x70)4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_M
6、INUTE);Time-Minute = (ReadValue&0x70)4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_HOUR);Time-Hour = (ReadValue&0x70)4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_DAY);Time-Day = (ReadValue&0x70)4)*10 + (ReadValue&0x0F); ReadValue = Read1302(DS1302_WEEK);Time-Week = (ReadValue&0x70)4)*
7、10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_MONTH);Time-Month = (ReadValue&0x70)4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_YEAR);Time-Year = (ReadValue&0x70)4)*10 + (ReadValue&0x0F);void DateToStr(SYSTEMTIME *Time) /将时间年,月,日,星期数据转换成液晶显示字符串,放到数组里 DateString if(hide_yearDateString0 = 2
8、;Time-DateString1 = 0; Time-DateString2 = Time-Year/10 + 0;Time-DateString3 = Time-Year%10 + 0;elseTime-DateString0 = ;Time-DateString1 = ; Time-DateString2 = ;Time-DateString3 = ;Time-DateString4 = /;if(hide_monthDateString5 = Time-Month/10 + 0;Time-DateString6 = Time-Month%10 + 0;elseTime-DateStri
9、ng5 = ;Time-DateString6 = ;Time-DateString7 = /;if(hide_dayDateString8 = Time-Day/10 + 0;Time-DateString9 = Time-Day%10 + 0;elseTime-DateString8 = ;Time-DateString9 = ;if(hide_weekWeek%10 + 0; /星期的数据另外放到week_value数组里,跟年,月,日的分开存放,因为等一下要在最后显示elseweek_value0 = ;week_value1 = 0;Time-DateString10 = 0; /字
10、符串末尾加 0 ,判断结束字符void TimeToStr(SYSTEMTIME *Time) /将时,分,秒数据转换成液晶显示字符放到数组 TimeString; if(hide_hourTimeString0 = Time-Hour/10 + 0;Time-TimeString1 = Time-Hour%10 + 0;elseTime-TimeString0 = ;Time -TimeString1 = ;Time-TimeString2 = :;if(hide_minTimeString3 = Time-Minute/10 + 0;Time-TimeString4 = Time-Minu
11、te%10 + 0;elseTime-TimeString3 = ;Time-TimeString4 = ;Time-TimeString5 = :;if(hide_secTimeString6 = Time-Second/10 + 0;Time-TimeString7 = Time-Second%10 + 0;elseTime-TimeString6 = ;Time-TimeString7 = ;Time-DateString8 = 0; void Initial_DS1302(void) /时钟芯片初始化unsigned char Second=Read1302(DS1302_SECOND
12、);if(Second&0x80) /判断时钟芯片是否关闭 Write1302(0x8e,0x00); /写入允许Write1302(0x8c,0x07); /以下写入初始化时间 日期:07/07/25.星期: 3.时间: 23:59:55Write1302(0x88,0x07);Write1302(0x86,0x25);Write1302(0x8a,0x07);Write1302(0x84,0x23);Write1302(0x82,0x59);Write1302(0x80,0x55);Write1302(0x8e,0x80); /禁止写入/*ds18b20 子程序*/*ds18b20 延迟子
13、函数?晶振 12MHz ?*/void delay_18B20(unsigned int i)while(i-);/*ds18b20 初始化函数*/void Init_DS18B20(void)unsigned char x=0;DQ = 1; /DQ 复位delay_18B20(8); /稍做延时DQ = 0; /单片机将 DQ 拉低delay_18B20(80); /精确延时 大于 480usDQ = 1; /拉高总线delay_18B20(14);x=DQ; /稍做延时后 如果 x=0 则初始化成功 x=1 则初始化失败delay_18B20(20);/*ds18b20 读一个字节*/u
14、nsigned char ReadOneChar(void)uchar i=0;uchar dat = 0;for (i=8;i0;i-)DQ = 0; / 给脉冲信号dat=1;DQ = 1; / 给脉冲信号if(DQ)dat|=0x80;delay_18B20(4);return(dat);/*ds18b20 写一个字节*/void WriteOneChar(uchar dat)unsigned char i=0;for (i=8; i0; i-)DQ = 0;DQ = dat&0x01;delay_18B20(5);DQ = 1;dat=1;/*读取 ds18b20 当前温度*/void
15、 ReadTemp(void)unsigned char a=0;unsigned char b=0;unsigned char t=0;Init_DS18B20();WriteOneChar(0xCC); / 跳过读序号列号的操作WriteOneChar(0x44); / 启动温度转换delay_18B20(100); / this message is wery importantInit_DS18B20();WriteOneChar(0xCC); /跳过读序号列号的操作WriteOneChar(0xBE); /读取温度寄存器等?共可读 9 个寄存器? 前两个就是温度delay_18B20
16、(100);a=ReadOneChar(); /读取温度值低位b=ReadOneChar(); /读取温度值高位temp_value=b4;void temp_to_str() /温度数据转换成液晶字符显示TempBuffer0=temp_value/10+0; /十位TempBuffer1=temp_value%10+0; /个位TempBuffer2=0xdf; /温度符号TempBuffer3=C;TempBuffer4=0;void Delay1ms(unsigned int count)unsigned int i,j;for(i=0;i0;delay-)for(i=0;i0x59)
17、 /超过 59 秒,清零temp=0;break;case 2:temp=Read1302(DS1302_MINUTE); /读取分数temp=temp+1; /分数加 1up_flag=1;if(temp0x59) /超过 59 分,清零temp=0;break;case 3:temp=Read1302(DS1302_HOUR); /读取小时数temp=temp+1; /小时数加 1up_flag=1;if(temp0x23) /超过 23 小时,清零temp=0;break;case 4:temp=Read1302(DS1302_WEEK); /读取星期数temp=temp+1; /星期数
18、加 1up_flag=1;if(temp0x7)temp=1;break;case 5:temp=Read1302(DS1302_DAY); /读取日数temp=temp+1; /日数加 1up_flag=1;if(temp0x31)temp=1;break;case 6:temp=Read1302(DS1302_MONTH); /读取月数temp=temp+1; /月数加 1up_flag=1;if(temp0x12)temp=1;break;case 7:temp=Read1302(DS1302_YEAR); /读取年数temp=temp+1; /年数加 1up_flag=1;if(tem
19、p0x85)temp=0;break;default:break;while(Up=0);while(wireless_2=1);/void Downkey()/降序按键Down=1;if(Down=0|wireless_3=1)mdelay(8);switch(count)case 1:temp=Read1302(DS1302_SECOND); /读取秒数temp=temp-1; /秒数减 1down_flag=1; /数据调整后更新标志if(temp=0x7f) /小于 0 秒,返回 59 秒temp=0x59;break;case 2:temp=Read1302(DS1302_MINUT
20、E); /读取分数temp=temp-1; /分数减 1down_flag=1;if(temp=-1)temp=0x59; /小于 0 秒,返回 59 秒break;case 3:temp=Read1302(DS1302_HOUR); /读取小时数temp=temp-1; /小时数减 1down_flag=1;if(temp=-1)temp=0x23;break;case 4:temp=Read1302(DS1302_WEEK); /读取星期数temp=temp-1; /星期数减 1down_flag=1;if(temp=0)temp=0x7;break;case 5:temp=Read130
21、2(DS1302_DAY); /读取日数temp=temp-1; /日数减 1down_flag=1;if(temp=0)temp=31;break;case 6:temp=Read1302(DS1302_MONTH); /读取月数temp=temp-1; /月数减 1down_flag=1;if(temp=0)temp=12;break;case 7:temp=Read1302(DS1302_YEAR); /读取年数temp=temp-1; /年数减 1down_flag=1;if(temp=-1)temp=0x85;bre ak;default:break;while(Down=0);wh
22、ile(wireless_3=1);void Setkey()/模式选择按键Set=1;if(Set=0|wireless_4=1)mdelay(8);count=count+1; /Setkey 按一次,count 就加 1done=1; /进入调整模式while(Set=0);while(wireless_4=1);void keydone()/按键功能执行 uchar Second;if(flag=0) /关闭时钟,停止计时 Write1302(0x8e,0x00); /写入允许temp=Read1302(0x80);Write1302(0x80,temp|0x80);Write1302
23、(0x8e,0x80); /禁止写入flag=1;Setkey(); /扫描模式切换按键switch(count)case 1:do /count=1,调整秒outkey(); /扫描跳出按钮Upkey(); /扫描加按钮Downkey(); /扫描减按钮if(up_flag=1|down_flag=1) /数据更新?重新写入新的数据Write1302(0x8e,0x00); /写入允许Write1302(0x80,temp|0x80); /写入新的秒数Write1302(0x8e,0x80); /禁止写入up_flag=0;down_flag=0;hide_sec+; /位闪计数if(hid
24、e_sec3)hide_sec=0;show_time(); /液晶显示数据while(count=2);break;case 2:do /count=2,调整分hide_sec=0;outkey();Upkey();Downkey();if(temp0x60)temp=0;if(up_flag=1|down_flag=1)Write1302(0x8e,0x00); /写入允许Write1302(0x82,temp); /写入新的分数Write1302(0x8e,0x80); /禁止写入up_flag=0;down_flag=0;hide_min+;if(hide_min3)hide_min=
25、0;show_time();while(count=3);break;case 3:do /count=3,调整小时hide_min=0;outkey();Upkey();Downkey();if(up_flag=1|down_flag=1)Write1302(0x8e,0x00); /写入允许Write1302(0x84,temp); /写入新的小时数Write1302(0x8e,0x80); /禁止写入up_flag=0;down_flag=0;hide_hour+;if(hide_hour3)hide_hour=0;show_time();while(count=4);break;cas
26、e 4:do /count=4,调整星期hide_hour=0;outkey();Upkey();Downkey();if(up_flag=1|down_flag=1)Write1302(0x8e,0x00); /写入允许Write1302(0x8a,temp); /写入新的星期数Write1302(0x8e,0x80); /禁止写入up_flag=0;down_flag=0;hide_week+;if(hide_week3)hide_week=0;show_time();while(count=5);break;case 5:do /count=5,调整日hide_week=0;outkey
27、();Upkey();Downkey();if(up_flag=1|down_flag=1)Write1302(0x8e,0x00); /写入允许Write1302(0x86,temp); /写入新的日数Write1302(0x8e,0x80); /禁止写入up_flag=0;down_flag=0;hide_day+;if(hide_day3)hide_day=0;show_time();while(count=6);break;case 6:do /count=6,调整月hide_day=0;outkey();Upkey();Downkey();if(up_flag=1|down_flag
28、=1)Write1302(0x8e,0x00); /写入允许Write1302(0x88,temp); /写入新的月数Write1302(0x8e,0x80); /禁止写入up_flag=0;down_flag=0;hide_month+;if(hide_month3)hide_month=0;show_time();while(count=7);break;case 7:do /count=7,调整年hide_month=0;outkey();Upkey();Downkey();if(up_flag=1|down_flag=1)Write1302(0x8e,0x00); /写入允许Write1302(0x8c,temp); /