51单片机万年历

合集下载

基于51单片机的液晶显示万年历设计

基于51单片机的液晶显示万年历设计

基于51单片机的液晶显示万年历设计摘要随着社会的进步和发展,电子万年历作为日常计时工具被广泛地应用。

此电子万年历在硬件方面主要采用STC89C51单片机作为主控核心,由DS1302时钟芯片提供时钟及1602LCD液晶显示屏显示。

STC89C51单片机是由宏晶公司公司生产的,功耗小,电压可选用3.4v~5.5v电压供电;DS1302时钟芯片是美国DALLAS公司推出的低功耗实时时钟芯片,它可以对年、月、日、星期、时、分、秒进行计时,而且DS1302的使用寿命长,误差小;对于数字电子万年历采用直观的数字显示,数字显示是采用的1602LCD液晶显示屏来显示,可以同时显示年、月、日、星期、时、分、秒、温度等信息。

此外,该电子万年历在软件方面主要包括日历程序、时间调整程序,显示程序等。

所有程序编写完成后,在Keil软件中进行调试,确定没有问题后,烧写到单片机上进行测试。

本次课程设计主要由时钟芯片DS1302和温度传感器DS18B20采集数据到单片机进行处理再通过LCD1602显示出来,本设计主要研究了液晶显示器LCD及时钟芯片DS1302,温度传感器DS18B20与单片机之间的硬件互联及通信,对数种硬件连接方案进行了详尽的比较。

关键词:单片机;DS1302;DS18B20;LCD1602ABSTRACTWith the social progress and development, Electronic calendar is widely used as a daily timing tool. The electronic calendar in hardware using STC89C51 microcontroller as the main control center, provided by the DS1302 clock chip and 1602LCD LCD display. STC89C51 microcontroller is produced by the macro crystal company, small power consumption, the voltage can be choosen among 3.4V ~ 5.5V for power supply; DS1302 clock chip is a low power real-time clock chip produced by DALLAS, it can be a time of years,months,days,weeks,hours,minutes,seconds, and DS1302 has a long service life. The error is small; for the digital electronic calendar using visual digital display, 1602LCD digital display is used to display LCD screen that can display years, months, days, weeks, hours, minutes and seconds, temperature and other information. In addition, the electronic calendar mainly includes calendar program,time to adjust procedures,display program etc in sofeware. After the completion of all the procedures, in the Keil software debugging, determine no problem after, and burning to the microcontroller test.The curriculum design mainly by the clock chip DS1302 and temperature sensor DS18B20 collecting data to the microcontroller for processing and then through the LCD1602 display, this design mainly studies the liquid crystal display LCD and the clock chip DS1302, the hardware connection and communication between the temperature sensor DS18B20 and the MCU, a number of hardware connection scheme for a detailed comparison.Key words:SCM,DS1302,DS18B20,LCD1602目录第一章绪论 ------------------------------------------------------------------------------------------------------------ - 1 -1.1 单片机的概述------------------------------------------------------------------------------------------------- - 1 -1.1.1 单片机的概念 --------------------------------------------------------------------------------------- - 1 -1.1.2 单片机的特点 --------------------------------------------------------------------------------------- - 1 -1.2 课题背景 ------------------------------------------------------------------------------------------------------- - 1 -1.3 课题内容 ------------------------------------------------------------------------------------------------------- - 2 - 第二章设计要求和方案 --------------------------------------------------------------------------------------------- - 3 -2.1 设计要求 ------------------------------------------------------------------------------------------------------- - 3 -2.2 设计方案 ------------------------------------------------------------------------------------------------------- - 3 -2.2.1 单片机芯片的选择--------------------------------------------------------------------------------- - 3 -2.2.2 各模块方案选择 ------------------------------------------------------------------------------------ - 3 -2.3 工作原理 ------------------------------------------------------------------------------------------------------- - 4 - 第三章系统的硬件设计及实现------------------------------------------------------------------------------------ - 7 -3.1 电路设计原理框图 ------------------------------------------------------------------------------------------ - 7 -3.2 STC89C51单片机的介绍 ----------------------------------------------------------------------------------- - 7 -3.2.1 主要功能及性能参数 ----------------------------------------------------------------------------- - 7 -3.2.2单片机的引脚功能说明 --------------------------------------------------------------------------- - 8 -3.3 各模块电路的设计及原理图 ----------------------------------------------------------------------------- - 9 -3.3.1 时钟电路模块的设计 ----------------------------------------------------------------------------- - 9 -3.3.2 温度采集模块的设计及原理图 --------------------------------------------------------------- - 11 -3.3.3 显示模块的设计及原理 ------------------------------------------------------------------------- - 11 - 第四章系统的软件设计 -------------------------------------------------------------------------------------------- - 13 -4.1 程序流程框图------------------------------------------------------------------------------------------------ - 13 -4.2 时间调整程序流程图 -------------------------------------------------------------------------------------- - 14 - 第五章系统测试 ------------------------------------------------------------------------------------------------------ - 15 -5.1 硬件测试 ------------------------------------------------------------------------------------------------------ - 15 -5.2 软件测试 ------------------------------------------------------------------------------------------------------ - 15 - 第六章总结与致谢 --------------------------------------------------------------------------------------------------- - 17 -6.1 总结------------------------------------------------------------------------------------------------------------- - 17 -6.2 致谢------------------------------------------------------------------------------------------------------------- - 18 - 参考文献 ------------------------------------------------------------------------------------------------------------------- - 19 - 附录 ------------------------------------------------------------------------------------------------------------------------ - 21 - 附录一:实物图 --------------------------------------------------------------------------------------------------- - 21 - 附录二:源程序 --------------------------------------------------------------------------------------------------- - 23 -第一章绪论1.1 单片机的概述1.1.1 单片机的概念单片机即单片微型计算机,是把中央处理器、存储器、定时/计数器、输入输出接口都集成在一块集成电路芯片上的微型计算机。

51单片机12864万年历(图片+主要程序C语言)

51单片机12864万年历(图片+主要程序C语言)

51单片机做的12864万年历这是我花了一个星期时间做的万年历;一开始是一些图片,后面是这个制作的C语言源程序;希望大家稀饭:Main.c#include "reg52.h"#include "macroconst.h"#include "keyscan.h"#include "screen.h"#include "18b20.h"#include "ds1302.h"#include "atao_12864.h"#include "24c02.h"idata unsigned char state1[1];unsigned char screennum=1;//屏幕号#define time_task_sec 200 //节拍200Hz#define clock 24000000 //晶振#define max_task 4 //最大任务数idata unsigned char task_delay[4];#define task_delay0 time_task_sec/1 //2赫兹18b20 #define task_delay1 time_task_sec/5 //10赫兹屏幕#define task_delay2 time_task_sec/3 //4赫兹1302 #define task_delay3 time_task_sec/20 //20赫兹键盘void init(){unsigned char i;init18b20();ds1302_init();initina1(); //---------------------------LCD字库初始化程序RdFromROM(state1,8,1);state[0]=state1[0]; //-------界面RdFromROM(state1,15,1);state[1]=state1[0];//------- 闹钟RdFromROM(state1,11,1);key_sound=state1[0];//-------按键音// state[2]=state1[2];// state[3]=state1[3];screennum=1;//------默认一号屏for(i=0;i<max_task;i++)//清除任务延时{task_delay[i]=0;}TMOD=0x11;EA=1;TH0=255-clock/time_task_sec/12/526;TL0=255-clock/time_task_sec/12%526;ET0=1;TR0=1;}void main(){init();while(1){ if(task_delay[0]==0){readtemp(); task_delay[0]=task_delay0;} if(task_delay[3]==0){MenuCheckKey();task_delay[3]=task_delay1;}if(task_delay[1]==0){screen_select(screennum);task_delay[1]=task_delay1;} if(task_delay[2]==0){ds1302_read_time(); task_delay[2]=task_delay0;} }}void timer0() interrupt 1{uchar i=0;TH0=255-clock/time_task_sec/12/526;TH1=255-clock/time_task_sec/12%526;for(i=0;i<max_task;i++)if(task_delay[i]) task_delay[i]--; // miao=21,fen=33,xiaomiao=94;if(ma_start==1){tt++;if(tt==8){tt=0;xiaomiao++;if(xiaomiao==99){xiaomiao=0;miao++;if(miao==60){miao=0;fen++;if(fen==99){fen=0;}}}}}}Screen.c:#include "reg52.h"#include "macroconst.h"#include "delay.h"#include "18b20.h"#include "atao_12864.h"#include "ds1302.h"#include "24c02.h"#include "festival.h"#include "keyscan.h"idata unsigned char miao=0,fen=78,xiaomiao=0,tt=0;idata unsigned char bai,shi,ge,shinian,genian,shiyue,geyue,shiri,geri,shishi,geshi,shifen,gefen,shimi ao,gemiao;idata unsigned char Number[4];unsigned char code mainmenu[]={" 主菜单""3.查询 4.温度""1.调时 2.秒表""5.设置 6.返回"};unsigned char code setmenu[]={" 设置""3.查温 4.按键""1.界面 2.闹铃""5.报时 6.返回"};void gettime(){shinian=(time_buf1[1]%100)/10;genian=(time_buf1[1]%100)%10;shiyue=(time_buf1[2])/10;geyue=(time_buf1[2])%10;shiri=(time_buf1[3])/10;geri=(time_buf1[3])%10;shishi=(time_buf1[4])/10;geshi=(time_buf1[4])%10;shifen=(time_buf1[5])/10;gefen=(time_buf1[5])%10;shimiao=(time_buf1[6])/10;gemiao=(time_buf1[6])%10;}void screen_select(uchar num){// initina1();gettime() ;if(num==1) //----------主界面{Lcd_Set_Post(1,0);TransferData(shinian+48,1);//----------------------年TransferData(genian+48,1);TransferData('/',1);TransferData(shiyue+48,1);//----------------------月TransferData(geyue+48,1);TransferData('/',1);TransferData(shiri+48,1);//----------------------日TransferData(geri+48,1);Lcd_Set_Post(1,4);if(state[1]==1)//----------------闹铃的状态图标{TransferData(' ',1);TransferData(14,1);}Lcd_Set_Post(1,5);if(key_sound==1){TransferData(13,1);}if(state[0]==0){Lcd_Set_Post(1,7); //----------------农历年nian(0);Lcd_Set_Post(2,0);//----------------------- 农历日月LCD_WRITE_CHAR("农历");Conversion(0,time_buf[1],time_buf[2],time_buf[3]);TransferData(month_moon/16+'0',1);TransferData(month_moon%16+'0',1);TransferData('/',1);TransferData(day_moon/16+'0',1);TransferData(day_moon%16+'0',1);}if(state[0]==1){Lcd_Set_Post(3,5);}else {Lcd_Set_Post(2,5);}LCD_WRITE_CHAR("星期");//----------------------星期if(time_buf1[7]==7) {LCD_WRITE_CHAR("日");}if(time_buf1[7]==6) {LCD_WRITE_CHAR("六");}if(time_buf1[7]==5) {LCD_WRITE_CHAR("五");}if(time_buf1[7]==4) {LCD_WRITE_CHAR("四");}if(time_buf1[7]==3) {LCD_WRITE_CHAR("三");}if(time_buf1[7]==2) {LCD_WRITE_CHAR("二");}if(time_buf1[7]==1) {LCD_WRITE_CHAR("一");}Lcd_Set_Post(3,0);TransferData(shishi+48,1);//----------------------时TransferData(geshi+48,1);TransferData(58,1);TransferData(shifen+48,1);//----------------------分TransferData(gefen+48,1);TransferData(58,1);TransferData(shimiao+48,1);//----------------------秒TransferData(gemiao+48,1);if(state[0]==0){bai=(temph/100); //---------------------------------温度shi=(temph%100)/10;ge=(temph%100)%10;Lcd_Set_Post(3,4);if(zerotemp==0){TransferData(' ',1);TransferData(' ',1);} Lcd_Set_Post(3,5);TransferData(shi+48,1);TransferData(ge+48,1);TransferData('.',1);TransferData(templ+48,1);TransferData(0xa1,1);TransferData(0xe6,1);Lcd_Set_Post(4,0);festival(time_buf[2],time_buf[3],time_buf[4]);//农历}}if(num==3)//----------主菜单{Lcd_Set_Post(1,0);//--------设置显示位置LCD_WRITE_CHAR(mainmenu);}if(num==4)//----------设置菜单{Lcd_Set_Post(1,0);//--------设置显示位置LCD_WRITE_CHAR(setmenu);}if(num==5)//----------时间设置{Lcd_Set_Post(1,2);//--------设置显示位置LCD_WRITE_CHAR("时间设置");Lcd_Set_Post(2,1);TransferData(shinian+48,1);//----------------------年TransferData(genian+48,1);LCD_WRITE_CHAR("年");TransferData(shiyue+48,1);//----------------------月TransferData(geyue+48,1);LCD_WRITE_CHAR("月");TransferData(shiri+48,1);//----------------------日TransferData(geri+48,1);LCD_WRITE_CHAR("日");TransferData(time_buf1[7]+48,1);//---------------星期Lcd_Set_Post(3,2);TransferData(shishi+48,1);//--------------------时TransferData(geshi+48,1);LCD_WRITE_CHAR("时");TransferData(shifen+48,1);//---------------------分TransferData(gefen+48,1);LCD_WRITE_CHAR("分");TransferData(shimiao+48,1);//--------------------秒TransferData(gemiao+48,1);}if(num==6)//----------秒表{uchar shi1,shi2,shi3,ge1,ge2,ge3;Lcd_Set_Post(1,3);//--------设置显示位置LCD_WRITE_CHAR("秒表");Lcd_Set_Post(3,2);shi1=fen/10;ge1=fen%10;TransferData(shi1+48,1);TransferData(ge1+48,1);TransferData(':',1);shi2=miao/10;ge2=miao%10;TransferData(shi2+48,1);TransferData(ge2+48,1);TransferData(':',1);shi3=xiaomiao/10;ge3=xiaomiao%10;TransferData(shi3+48,1);TransferData(ge3+48,1);}if(num==8){Lcd_Set_Post(1,2);//--------农历查询LCD_WRITE_CHAR("温度查询");Lcd_Set_Post(3,0);//--------农历查询LCD_WRITE_CHAR("最高温度"); TransferData(':',1);RdFromROM(Number,0,4);if(Number[3]==0){TransferData('-',1);}Lcd_Set_Post(3,5);TransferData(Number[0]+48,1); TransferData(Number[1]+48,1); TransferData('.',1);TransferData(Number[2]+48,1); TransferData(0xa1,1);TransferData(0xe6,1); Lcd_Set_Post(4,0);//--------农历查询LCD_WRITE_CHAR("最低温度"); TransferData(':',1);RdFromROM(Number,4,4);if(Number[3]==0){TransferData('-',1);}Lcd_Set_Post(4,5);TransferData(Number[0]+48,1); TransferData(Number[1]+48,1); TransferData('.',1);TransferData(Number[2]+48,1); TransferData(0xa1,1);TransferData(0xe6,1); }if(num==9)//----------界面菜单{Lcd_Set_Post(1,2);//--------设置显示位置LCD_WRITE_CHAR("界面选择");Lcd_Set_Post(2,0);TransferData(1+48,1);TransferData('.',1);LCD_WRITE_CHAR("多功能界面");Lcd_Set_Post(3,0);TransferData(2+48,1);TransferData('.',1);LCD_WRITE_CHAR("简洁界面");}。

51单片机万年历汇编程序 2

51单片机万年历汇编程序 2

;真正的万年历: 84 bytes 的51 ASM;==SUB_WNL=== 万年历==* Deng Miao * 2004-06-01 ***** GuangZhou ****** SJ DA TA30H ; 世纪BCD 00 TO 99NH DA TA31H ; 年号BCD 00 TO 99 0000 TO 9999 年YF DA TA32H ; 月份BCD 01 TO 12org 000hMOV SP, #40HMOV SJ, #21H ;2004-05MOV NH, #01HMOV YF, #4HACALL SUB_WNLSJMP $;===============SUB_WNL===================; 入口:; SJ DA TA30H ; 世纪BCD 00 TO 99; NH DA TA31H ; 年号BCD 00 TO 99 0000 TO 9999 年; YF DA TA32H ; 月份BCD 01 TO 12; 出口; ACC -- 本月天数BCD 28 to 31; B -- 本月1日的星期数1 to 6 == 星期1 to 星期6; 0 -- 星期日; 使用: ACC, B, R5, R6; STACK: 3 bytes (不包括调用)ORG 50HSUB_WNL:PUSH PSWMOV A, SJACALL BCD2BIN_MOD4; x 400年: (大周期); =146097天= 7 * 20871 + 0 天; x 100年:; 000年= 7 * 0 + 0 + 1 - 1 1 = 0 * 2 + 1 ****; 100年= 7 * 5217 + 7 + 1 - 2 2 = 1 * 2; 200年= 7 * 10435 + 7 + 1 - 4 4 = 2 * 2; 300年= 7 * 15653 + 7 + 1 - 6 6 = 3 * 2; {1,2,4,6}MOV A, R6 ; A=R6= SJ_BIN MOD 4RLC A; A=A*2+C A = {1,2,4,6} ****XRL A, #10000111B ; A = 87H - A; 边界调整MOV R5, A; A = {86H, 85H, 83H, 81H} ; R5: 星期MOV A, NHJZ WNL_1ACALL BCD2BIN_MOD4XCH A, R5SUBB A, R5 ; 0 年; 0 = 0 + 0 + 1 + (-1) ***MOV R5, A单片机日记:WNL_1:MOV A, YFADD A, #(WNL_TAB-$-4)MOVC A, @A+PCMOV R6, ASW AP AACALL WNL_F0; 大年对>=3月调整准备ADDC A, R5 ; 月调整MOV B, #7DIV AB ; B = A MOD 7MOV A, R6ACALL WNL_F0; 大年调整准备ADDC A, #28POP PSWRETWNL_TAB:DB 3*2 + 5 * 32+0 ;1 BIT 0 : "2月" 标志DB 0*2+1+1 * 32+0 ;2 ** BIT 1..2: 月大小DB 3*2 + 1 * 32+16 ;3 00:28 天DB 2*2 + 4 * 32+16 ;4 01:----DB 3*2 + 6 * 32+16 ;5 10: 30 天DB 2*2 + 2 * 32+16 ;6 11: 31 天DB 3*2 + 4 * 32+16 ;7 BIT 3: 0 -----DB 3*2 + 7 * 32+16 ;8 BIT 4: 0: 1/2月DB 2*2 + 3 * 32+16 ;9 1: >=3月WNL_F0: ; 6 BYTES ; 大年调整准备RRC A;0AHANL A, #07H ;0BH;0CHANL C, F0 ;0DH;0EHRET ;0FHDB 3*2 + 5 * 32+16 ;10H BIT 5..7: 星期调整数DB 2*2 + 1 * 32+16 ;11H 0:---DB 3*2 + 3 * 32+16 ;12H 1-7: 调整数BCD2BIN_MOD4:; 功能:A. 1 BYTES BCD TO BIN; B. MOD 4; C. MUL 2; 入口:; A: SJ OR NH; F0 : 大世纪; 出口; ACC -- (BIN(A) \ 4) * 2 - (BIN(A) MOD 4) - F0; R6 -- BIN(A) MOD 4; C -- IIF( (BIN(A) MOD 4)=0, 1, 0 ); 使用: ACC, B, R6, PSW; STACK: 0 bytes (不包括调用)MOV R6, A; BCD ==> BINANL A, #0F0H ; 16X+Y ==> 10X+YSW AP AMOV B, #(256-6) ; (256-6)*X + (16X+Y)MUL AB ;ADD A, R6 ; = 256X + (10X+Y)MOV R6, A; MOD4ANL A, #3XCH A, R6 ; R6 = BIN MOD 4 = {0,1,2,3}; X 4年:3 * 365 + 366 = 7*209 + (-2) ** XRL A, R6 ; A = (BIN \ 4)RR A; A = (BIN \4 ) * 2 **MOV C, F0 ; 大世纪调整SUBB A, R6;X 1 年:;0 年0 = 0 + 0 + 1 + (-1) ***;1 年366 = 7*52 + 1 + 1;2 年366 + 365 = 7*104 + 2 + 1;3 年366 + 365 + 365 = 7*156+3 + 1; {-1,1,2,3}CJNE R6, #1, $ + 3 ; C = IIF(R6>=1, 0, 1)MOV F0, C ; C=1 为大年/大世纪RET;-----------------------------END ;======== END OF FILE。

基于51单片机的万年历设计

基于51单片机的万年历设计

基于51单片机的万年历设计一、系统设计方案本万年历系统主要由 51 单片机、时钟芯片、液晶显示屏、按键等部分组成。

51 单片机作为核心控制器,负责整个系统的运行和数据处理。

时钟芯片用于提供精确的时间信息,液晶显示屏用于显示万年历的相关内容,按键则用于设置时间和功能切换。

二、硬件设计1、单片机选型选用常见的 51 单片机,如 STC89C52 单片机,它具有性能稳定、价格低廉、易于编程等优点。

2、时钟芯片选择 DS1302 时钟芯片,该芯片能够提供高精度的实时时钟,具有闰年补偿功能,并且可以通过串行接口与单片机进行通信。

3、液晶显示屏采用 1602 液晶显示屏,能够清晰地显示字符和数字,满足万年历的显示需求。

4、按键电路设计四个按键,分别用于时间设置、功能切换、加和减操作。

三、软件设计1、主程序流程系统上电后,首先进行初始化操作,包括单片机端口初始化、时钟芯片初始化、液晶显示屏初始化等。

然后读取时钟芯片中的时间数据,并在液晶显示屏上显示出来。

接着进入循环,不断检测按键状态,根据按键操作执行相应的功能,如时间设置、功能切换等。

2、时钟芯片驱动程序通过单片机的串行接口向 DS1302 发送命令和数据,实现对时钟芯片的读写操作,获取准确的时间信息。

3、液晶显示屏驱动程序编写相应的函数,实现对1602 液晶显示屏的字符和数字显示控制。

4、按键处理程序采用扫描方式检测按键状态,当检测到按键按下时,执行相应的按键处理函数,实现时间设置和功能切换等操作。

四、时间设置功能通过按键操作进入时间设置模式,可以分别设置年、月、日、时、分、秒等信息。

在设置过程中,液晶显示屏会显示当前设置的项目和数值,并通过加、减按键进行调整。

设置完成后,将新的时间数据保存到时钟芯片中。

五、显示功能万年历的显示内容包括年、月、日、星期、时、分、秒等信息。

通过合理的排版和显示控制,使这些信息在液晶显示屏上清晰、直观地呈现给用户。

六、系统调试在完成硬件和软件设计后,需要对系统进行调试。

51单片机c语言电子万年历完整程序

51单片机c语言电子万年历完整程序

该程序为51单片机c语言电子万年历#include"reg52.h"//#include<stdio.h>#define uchar unsigned char#define uint unsigned intsbit lcden=P3^4;sbit lcdrs=P3^5;sbit DATA=P0^7;sbit RST=P0^5;sbit SCLK=P0^6;sbit menu=P3^0; //菜单sbit add=P3^1; //加一sbit dec=P3^7; //减一sbit led0=P1^0;sbit led1=P1^1;sbit led2=P1^2;sbit led3=P1^3;sbit ds=P3^2;//sbit beep=P3^3;uint temp;float f_temp;uint warn_l1=270;uint warn_l2=250;uint warn_h1=300;uint warn_h2=320;uint get_temp();void delayms(uint x);void write_com(uchar com);void write_data(uchar date);void init();void dis_temp(uint t);void Write1302(uchar dat);void WriteSet1302(uchar Cmd,uchar dat);uchar Read1302(void);uchar ReadSet1302(uchar Cmd);void Init_DS1302(void);void DisplaySecond(uchar x);void DisplayMinute(uchar x);void DisplayHour(uchar x);void DisplayDay(uchar x);void DisplayMonth(uchar x);void DisplayYear(uchar x);void DisplayWeek(uchar x);void dis_temp(uint t);void read_date(void);void turn_val(char newval,uchar flag,uchar newaddr,uchar s1num);void key_scan(void);char code table[]="0123456789" ;uchar code table2[]= "TUEWESTHUFRISATSUNMON"; uchar second,minute,hour,day,month,year,week,count=0; uchar ReadValue,num,time;void delayms(uint x){uint i,j;for(i=x;i>0;i--)for(j=110;j>0;j--);}////////////////////////////////////////////////////////////void write_com(uchar com){lcdrs=0;P2=com;delayms(5);lcden=1;delayms(5);lcden=0;}void write_data(uchar date){lcdrs=1;P2=date;delayms(5);lcden=1;delayms(5);lcden=0;}void init(){lcden=0;write_com(0x38);write_com(0x0c);write_com(0x06);write_com(0x01);}/////////////////////////////////////////////////////////////////void Write1302(uchar dat){uchar i;SCLK=0; //拉低SCLK,为脉冲上升沿写入数据做好准备 delayms(2); //稍微等待,使硬件做好准备for(i=0;i<8;i++) //连续写8个二进制位数据DATA=dat&0x01; //取出dat的第0位数据写入1302delayms(2); //稍微等待,使硬件做好准备SCLK=1; //上升沿写入数据delayms(2); //稍微等待,使硬件做好准备SCLK=0; //重新拉低SCLK,形成脉冲dat>>=1; //将dat的各数据位右移1位,准备写入下一个数据位 }}void WriteSet1302(uchar Cmd,uchar dat){RST=0; //禁止数据传递SCLK=0; //确保写数居前SCLK被拉低RST=1; //启动数据传输delayms(2); //稍微等待,使硬件做好准备Write1302(Cmd); //写入命令字Write1302(dat); //写数据SCLK=1; //将时钟电平置于已知状态RST=0; //禁止数据传递}uchar Read1302(void){uchar i,dat;delayms(2); //稍微等待,使硬件做好准备for(i=0;i<8;i++) //连续读8个二进制位数据dat>>=1; //将dat的各数据位右移1位,因为先读出的是字节的最低位if(DATA==1) //如果读出的数据是1dat|=0x80; //将1取出,写在dat的最高位SCLK=1; //将SCLK置于高电平,为下降沿读出delayms(2); //稍微等待SCLK=0; //拉低SCLK,形成脉冲下降沿delayms(2); //稍微等待}return dat; //将读出的数据返回}uchar ReadSet1302(uchar Cmd){uchar dat;RST=0; //拉低RSTSCLK=0; //确保写数居前SCLK被拉低RST=1; //启动数据传输Write1302(Cmd); //写入命令字dat=Read1302(); //读出数据SCLK=1; //将时钟电平置于已知状态RST=0; //禁止数据传递return dat; //将读出的数据返回}void Init_DS1302(void){WriteSet1302(0x8E,0x00); //根据写状态寄存器命令字,写入不保护指令WriteSet1302(0x80,((0/10)<<4|(0%10))); //根据写秒寄存器命令字,写入秒的初始值WriteSet1302(0x82,((59/10)<<4|(59%10))); //根据写分寄存器命令字,写入分的初始值WriteSet1302(0x84,((23/10)<<4|(23%10))); //根据写小时寄存器命令字,写入小时的初始值WriteSet1302(0x86,((28/10)<<4|(28%10))); //根据写日寄存器命令字,写入日的初始值 WriteSet1302(0x88,((2/10)<<4|(2%10))); //根据写月寄存器命令字,写入月的初始值WriteSet1302(0x8c,((14/10)<<4|(14%10))); //nian//WriteSet1302(0x8a,((4/10)<<4|(4%10)));}/////////////////////////////////////////////////////////////////void DisplaySecond(uchar x){uchar i,j;i=x/10;j=x%10;write_com(0x80+0x46);write_data(i+0x30);write_com(0x80+0x47);write_data(j+0x30);write_com(0x80+0x48);write_data(' ');dis_temp(get_temp());}void DisSecond(uchar x){uchar i,j;ReadValue = ReadSet1302(0x81);second=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);i=x/10;j=x%10;write_com(0x80+0x46);write_data(i+0x30);write_com(0x80+0x47);write_data(j+0x30);}void DisplayMinute(uchar x) {uchar i,j;i=x/10;j=x%10;write_com(0x80+0x43);write_data(i+0x30);write_com(0x80+0x44);write_data(j+0x30);write_com(0x80+0x45);write_data(':');}void DisplayHour(uchar x){uchar i,j;i=x/10;j=x%10;write_com(0x80+0x40);write_data(i+0x30);write_com(0x80+0x41);write_data(j+0x30);write_com(0x80+0x42);write_data(':');}void DisplayDay(uchar x) {uchar i,j;i=x/10;j=x%10;write_com(0x89);write_data(i+0x30);write_com(0x8a);write_data(j+0x30); }void DisplayMonth(uchar x) {uchar i,j;i=x/10;j=x%10;write_com(0x86);write_data(i+0x30); write_com(0x87);write_data(j+0x30);write_com(0x88);write_data('/');}void DisplayYear(uchar x) {uchar i,j;i=x/10;j=x%10;write_com(0x81);write_data(2+0x30);write_com(0x82);write_data(0+0x30);write_com(0x83);write_data(i+0x30);write_com(0x84);write_data(j+0x30);write_com(0x85);write_data('/');}void DisplayWeek(uchar x){ uchar i;x=x*3;// write_com(0x8c);write_data(table2[x]);// write_com(0x8d);write_data(table2[x+1]);// write_com(0x8e);write_data(table2[x+2]);write_com(0x8c);for(i=0;i<3;i++){write_data(table2[x]);x++;}}void read_date(void){ReadValue = ReadSet1302(0x81);second=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); ReadValue = ReadSet1302(0x83);minute=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = ReadSet1302(0x85);hour=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = ReadSet1302(0x87);day=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = ReadSet1302(0x89);month=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = ReadSet1302(0x8d);year=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue=ReadSet1302(0x8b); //读星期week=ReadValue&0x07;DisplayYear(year);DisplayMonth(month);DisplayDay(day);DisplayWeek(week);DisplayHour(hour);DisplayMinute(minute);DisplaySecond(second);dis_temp(get_temp()); ///温度显示key_scan(); ///按键检测}void turn_val(char newval,uchar flag,uchar newaddr,uchar s1num){newval=ReadSet1302(newaddr); //读取当前时间newval=((newval&0x70)>>4)*10+(newval&0x0f); //将bcd码转换成十进制 if(flag) //判断是加一还是减一{newval++;switch(s1num){ case 1: if(newval>99) newval=0;DisplayYear(newval);break;case 2: if(newval>12) newval=1;DisplayMonth(newval);break;case 3: if(newval>31) newval=1;DisplayDay(newval);break;case 4: if(newval>6) newval=0;DisplayWeek(newval);break;case 5: if(newval>23) newval=0;DisplayHour(newval);break;case 6: if(newval>59) newval=0;DisplayMinute(newval);break;case 7: if(newval>59) newval=0;DisplaySecond(newval);break;default:break;}}else{newval--;switch(s1num){ case 1: if(newval==0) newval=99;DisplayYear(newval);break;case 2: if(newval==0) newval=12;DisplayMonth(newval);break;case 3: if(newval==0) newval=31;DisplayDay(newval);break;case 4: if(newval<0) newval=6;DisplayWeek(newval);break;case 5: if(newval<0) newval=23;DisplayHour(newval);break;case 6: if(newval<0) newval=59;DisplayMinute(newval);break;case 7: if(newval<0) newval=59;DisplaySecond(newval);break;default:break;}}WriteSet1302((newaddr-1),((newval/10)<<4)|(newval%10)); //将新数据写入寄存器}//////////////////////////////////////void dsreset(void){uint i;ds=0;i=103;while(i>0)i=4;while(i>0)i--;}bit tempreadbit(void){uint i;bit dat;ds=0;i++;ds=1;i++;i++;dat=ds;i=8;while(i>0)i--;return(dat);}uchar tempread(void){uchar i,j,dat;dat=0;for(i=1;i<=8;i++){j=tempreadbit();dat=(j<<7)|(dat>>1); }return(dat);}void tempwritebyte(uchar dat) {bit testb;for(j=1;j<=8;j++){testb=dat&0x01;dat=dat>>1;if(testb){ds=0;i++;i++;ds=1;i=8;while(i>0)i--;}else{ds=0;i=8;while(i>0)i--;ds=1;i++;i++;}}}void tempchange(void) {dsreset();delayms(1);tempwritebyte(0xcc);tempwritebyte(0x44);key_scan(); //////按键函数}uint get_temp(){uchar a,b;tempchange(); //////温度函数dsreset();delayms(1);tempwritebyte(0xcc);tempwritebyte(0xbe);a=tempread();b=tempread();temp=b;temp<<=8;temp=temp|a;f_temp=temp*0.0625;temp=f_temp*10+0.5;f_temp=f_temp+0.05;return temp;}//////void dis_temp(uint t){uchar n1,n2,n3;n1=t/100;n2=t%100/10;n3=t%100%10;DisSecond(second); ///秒显示 write_com(0x80+0x49);write_data(table[n1]);//delayms(5);write_com(0x80+0x4a);write_data(table[n2]);//delayms(5);write_com(0x80+0x4b);write_data('.');// delayms(5);write_com(0x80+0x4c);write_data(table[n3]);//delayms(5);write_com(0x80+0x4d);write_data('^');//delayms(5);write_com(0x80+0x4e);write_data('C');//delayms(5);DisSecond(second); ////秒显示}/*********************液晶显示*****************/ void warn(uint s,uchar led){uchar i;i=s;// beep=0;P1=~(led);while(i--){dis_temp(get_temp());}// beep=1;P1=0xff;i=s;while(i--){dis_temp(get_temp());}}void deal(uint t){uchar i;if((t>warn_l2)&&(t<=warn_l1)){warn(40,0x01);}else if(t<=warn_l2){warn(10,0x03);}else if((t<warn_h2)&&(t>=warn_h1)) {warn(40,0x04);}else if(t>=warn_h2){warn(10,0x0c);}else{i=40;while(i--){dis_temp(get_temp());DisSecond(second);}}}///////////////////////////////////////void main(){init();Init_DS1302();while(1){tempchange();read_date();deal(temp);key_scan();}}////******************************************* void key_scan(void){// uchar miao,s1num=0;uchar s1num=0;if(menu==0){delayms(5);if(menu==0){while(!menu);s1num++;while(1){if(menu==0){delayms(5);if(menu==0){while(!menu);s1num++;}}// miao=ReadSet1302(0x81);// second=miao;// WriteSet1302(0x80,miao|0x80);write_com(0x0f);//光标闪射if(s1num==1){ //year=ReadSet1302(0x8d);write_com(0x80+4); //年光标if(add==0){delayms(3);if(add==0){ while(!add);turn_val(year,1,0x8d,1);}}if(dec==0){delayms(3);if(dec==0){ while(!dec);turn_val(year,0,0x8d,1);}}}if(s1num==2){//month=ReadSet1302(0x89);write_com(0x80+7); //月光标if(add==0){delayms(3);if(add==0){ while(!add);turn_val(month,1,0x89,2);}}if(dec==0){delayms(3);if(dec==0){ while(!dec);turn_val(month,0,0x89,2);}}}if(s1num==3){ //day=ReadSet1302(0x87);write_com(0x80+10);//日光标{delayms(3);if(add==0){ while(!add);turn_val(day,1,0x87,3);}}if(dec==0){delayms(3);if(dec==0){ while(!dec);turn_val(day,0,0x87,3); //写入日寄存器 }}}if(s1num==4){ //week=ReadSet1302(0x8b);write_com(0x80+14); //星期光标if(add==0){delayms(3);if(add==0){ while(!add);turn_val(week,1,0x8b,4);}}if(dec==0){delayms(3);{ while(!dec);turn_val(week,0,0x8b,4);}}}if(s1num==5){// hour=ReadSet1302(0x85)write_com(0x80+0x40+1); //时光标if(add==0){delayms(3);if(add==0){ while(!add);turn_val(hour,1,0x85,5);}}if(dec==0){delayms(3);if(dec==0){ while(!dec);turn_val(hour,0,0x85,5);}}}if(s1num==6)//调时间分{ // minute=ReadSet1302(0x83);write_com(0x80+0x40+4);if(add==0){delayms(5);if(add==0){ while(!add);turn_val(minute,1,0x83,6); //写入分寄存器}}if(dec==0){delayms(3);if(dec==0){ while(!dec);turn_val(minute,0,0x83,6); //写入分寄存器}}}if(s1num==7)//调时间秒{// second=ReadSet1302(0x81);write_com(0x80+0x40+7);//秒光标if(add==0){delayms(3);if(add==0){ while(!add);if(second==0x60)second=0x00;turn_val(second,1,0x81,7);}}if(dec==0){delayms(3);if(dec==0){ while(!dec);turn_val(second,0,0x81,7);}}}if(s1num==8){// miao=ReadSet1302(0x81);// second=miao;// WriteSet1302(0x80,second&0x7f);s1num=0;//s1num清零//write_com(0x0c);//光标不闪烁//break;}}}}}。

51单片机万年历实验原理

51单片机万年历实验原理

51单片机万年历实验原理1. 概述51单片机万年历实验是一项基于51单片机的实验项目,用于模拟和显示日期和时间信息,使其具备一定的时钟和日历功能。

本文将详细介绍该实验的原理和实现方法。

2. 实验所需材料完成51单片机万年历实验需要以下材料: - 51单片机开发板 - LCD显示屏 - 时钟芯片(如DS1302) - 电容 - 电阻 - 键盘模块 - 连接线等3. 实验原理本实验的原理主要包括三个方面:51单片机的控制逻辑、时钟芯片的数据存储和显示屏的信息展示。

3.1 51单片机的控制逻辑在51单片机中,首先需要定义和初始化各个引脚和功能模块。

通过引脚的输入输出控制、时钟和定时器的设置,实现对时钟芯片和LCD显示屏的控制和数据传输。

3.2 时钟芯片的数据存储时钟芯片一般具有独立的电源供应和存储空间,用于储存日期和时间等信息。

通过与51单片机的通讯接口,读取和写入时钟芯片中的数据,实现对日期和时间信息的读取和更新。

3.3 显示屏的信息展示LCD显示屏作为用户界面,用于展示日期和时间等信息。

通过51单片机的输出控制,将读取到的日期和时间信息通过LCD显示屏进行展示。

具体的显示方式可以根据需求设计,如以年、月、日的格式显示,或者以星期和时间的格式显示等。

4. 实验步骤基于以上原理,可以按照以下步骤进行51单片机万年历实验:4.1 硬件连接按照实验所需材料,将51单片机开发板、LCD显示屏和时钟芯片等进行正确的连接。

根据引脚功能和电平要求,通过连接线将它们连接在一起。

4.2 编写程序使用合适的集成开发环境(如Keil)编写51单片机的程序。

程序主要包括引脚和功能模块的初始化设置、时钟芯片数据的读写和LCD显示屏信息的输出等。

4.3 载入程序将编写好的程序通过USB下载线或其他方式,将程序载入到开发板中。

确保程序可以正确地运行在51单片机上。

4.4 测试实验接通电源,观察LCD显示屏是否正常显示日期和时间信息。

51单片机实现万年历程序

51单片机实现万年历程序

51单片机实现万年历利用AT89S52单片机的P0口来和另外几个口来控制1602液晶的显示和P1口还有其它口来控制ds12887时钟芯片。

设置四个按键,1个定义为时间设置功能键,一个定义为闹钟设置功能键,另外两个用来调节时间的增减。

原理图:pcb图:源程序:#include<reg52.h>#define uint unsigned int#define uchar unsigned charsbit beep=P2^0;//蜂鸣器控制口sbit timeadd=P2^1;//调节时间加sbit timesub=P2^2;//调节时间减sbit timeclk=P2^3;//闹钟设定键sbit timefun=P2^4;//时间设定键sbit lcdrs=P2^5;//液晶的命令和数据控制口sbit ledrw=P2^6;//液晶的写数据口sbit lcden=P2^7;//液晶显示模块的使能端sbit timeds=P3^3;//时钟芯片地址闸sbit timerw=P3^4;//时钟芯片读写sbit timeas=P3^5;//时钟芯片地址闸sbit timeen=P3^6;//时钟芯片片选uchar code table[]="20 - - week ";uchar code table1[]=" : : ";//要显示的字符串char num,shi,fen,miao,nian=2000,yue,ri,week,numfun,anumfun,flag,flag1; uchar leap;void delay(uint x){uchar i,j;for(i=x;i>0;i--)for(j=110;j>0;j--);}void didi(){beep=0;delay(1000);beep=1;delay(1000);}void write_com(uchar com){lcdrs=0;P0=com;delay(5);lcden=1;delay(20);lcden=0;}void write_date(uchar date){lcdrs=1;P0=date;delay(5);lcden=1;delay(20);lcden=0;}void write_sfm(uchar add,uchar date){ uchar shi,ge;shi=date/10;ge=date%10;write_com(0x80+0x40+add);write_date(0x30+shi);write_date(0x30+ge);}void write_nyr(uchar add,uchar date){ uchar shi,ge;shi=date/10;ge=date%10;write_com(0x80+add);write_date(0x30+shi);write_date(0x30+ge);}void write_zhou(uchar add,uchar date) {write_com(0x80+add);write_date(0x30+date);}void write_ds(uchar add,uchar date){ timeen=0;timeas=1;timeds=1;timerw=1;P1=add;timeas=0;timerw=0;P1=date;timerw=1;timeas=1;timeen=1;}uchar read_ds(uchar add){uchar ds_date;timeas=1;timeds=1;timerw=1;timeen=0;P1=add;timeas=0;timeds=0;P1=0xff;ds_date=P1;timeds=1;timeas=1;timeen=1;return ds_date;}void keyscan(){if(flag1==1)//用来关闭闹钟铃声{if(timeadd==0){delay(5);if(timeadd==0){while(!timeadd==0);flag1=0;}}if(timesub==0){delay(5);if(timesub==0){while(!timesub==0);flag1=0;}}}if(timefun==0){delay(5);if(timefun==0){while(!timefun);flag=1;numfun++;if(numfun==1){write_com(0x80+0x40+0x0a);write_com(0x0f);}if(numfun==2){write_com(0x80+0x40+0x07);write_com(0x0f);}if(numfun==3){write_com(0x80+0x40+0x04);write_com(0x0f);}if(numfun==4){write_com(0x80+0x0f);write_com(0x0f);}if(numfun==5){write_com(0x80+0x09);write_com(0x0f);}if(numfun==6){write_com(0x80+0x06);write_com(0x0f);}if(numfun==7){write_com(0x80+0x03);write_com(0x0f);}if(numfun==8){numfun=0;flag=0;}}}if(numfun!=0){if(timeadd==0){delay(5);while(!timeadd);if(numfun==1){miao++;if(miao==60)miao=0;write_sfm(9,miao);write_com(0x80+0x40+9);write_ds(0,miao);}if(numfun==2){fen++;if(fen==60)fen=0;write_sfm(6,fen);write_com(0x80+0x40+6);write_ds(2,fen);}if(numfun==3){shi++;if(shi==24)shi=0;write_sfm(3,shi);write_com(0x80+0x40+3);write_ds(4,shi);}if(numfun==4){week++;if(week==8)week=1;write_zhou(0x0f,week);write_com(0x80+0x0f);write_ds(6,week);}if(numfun==5){if(nian==0){switch(yue){case 1:ri++;if(ri==32) ri=1;break;case 2:ri++;if(ri==30) ri=1;break;case 3:ri++;if(ri==32) ri=1;break;case 4:ri++;if(ri==31) ri=1;break;case 5:ri++;if(ri==32) ri=1;break;case 6:ri++;if(ri==31) ri=1;break;case 7:ri++;if(ri==32) ri=1;break;case 8:ri++;if(ri==32) ri=1;break;case 9:ri++;if(ri==31)ri=1;break;case 10:ri++;if(ri==32)ri=1;break;case 11:ri++;if(ri==31)ri=1;break;case 12:ri++;if(ri==32)ri=1;break;}}else if(leap&&yue==2){ri++;if(ri==30)ri=1;}else if(yue==2&&leap==0){ri++;if(ri==29)ri=1;}elseswitch(yue){case 1:ri++;if(ri==32) ri=1;break;case 3:ri++;if(ri==32) ri=1;break;case 4:ri++;if(ri==31) ri=1;break;case 5:ri++;if(ri==32) ri=1;break;case 6:ri++;if(ri==31) ri=1;break;case 7:ri++;if(ri==32) ri=1;break;case 8:ri++;if(ri==32) ri=1;break;case 9:ri++;if(ri==31) ri=1;break;case 10:ri++;if(ri==32) ri=1;break;case 11:ri++;if(ri==31) ri=1;break;case 12:ri++;if(ri==32) ri=1;break;}write_nyr(8,ri);write_com(0x80+0x08);write_ds(7,ri);}if(numfun==6){yue++;if(yue==13)yue=0;write_nyr(5,yue);write_com(0x80+0x05);write_ds(8,yue);}if(numfun==7){nian++;if(nian==100)nian=0;leap=nian%4==0&&nian%100!=0;write_nyr(2,nian);write_com(0x80+2);write_ds(9,nian);}}if(timesub==0){delay(5);while(!timesub);if(numfun==1){miao--;if(miao==-1)miao=59;write_sfm(9,miao);write_com(0x80+0x40+9);write_ds(0,miao);}if(numfun==2){fen--;if(fen==-1)fen=59;write_sfm(6,fen);write_com(0x80+0x40+6);write_ds(2,fen);}if(numfun==3){shi--;if(shi==-1)shi=23;write_sfm(3,shi);write_com(0x80+0x40+3);write_ds(4,shi);}if(numfun==4){week--;if(week==0)week=7;write_zhou(0x0f,week);write_com(0x80+0x0f);write_ds(6,week);}if(numfun==5){if(nian==0){switch(yue){case 1:ri--;if(ri==0) ri=31;break;case 2:ri--;if(ri==0) ri=29;break;case 3:ri--;if(ri==0) ri=31;break;case 4:ri--;if(ri==0) ri=30;break;case 5:ri--;if(ri==0) ri=31;break;case 6:ri--;if(ri==0) ri=30;break;case 7:ri--;if(ri==0) ri=31;break;case 8:ri--;if(ri==0) ri=31;break;case 9:ri--;if(ri==0) ri=30;break;case 10:ri--;if(ri==0) ri=31;break;case 11:ri--;if(ri==0) ri=30;break;case 12:ri--;if(ri==0) ri=31;break;}}else if(leap&&yue==2){ri--;if(ri==0)ri=29;}else if(yue==2&&leap==0){ri--;if(ri==0)ri=28;}elseswitch(yue){case 1:ri--;if(ri==0) ri=31;break;case 3:ri--;if(ri==0) ri=31;break;case 4:ri--;if(ri==0) ri=30;break;case 5:ri--;if(ri==0) ri=31;break;case 6:ri--;if(ri==0) ri=30;break;case 7:ri--;if(ri==0) ri=31;break;case 8:ri--;if(ri==0) ri=31;break;case 9:ri--;if(ri==0) ri=30;break;case 10:ri--;if(ri==0) ri=31;break;case 11:ri--;if(ri==0) ri=30;break;case 12:ri--;if(ri==0) ri=31;break;}write_nyr(8,ri);write_com(0x80+0x08);write_ds(7,ri);}if(numfun==6){yue--;if(yue==-1)yue=12;write_nyr(5,yue);write_com(0x80+0x05);write_ds(8,yue);}if(numfun==7){nian--;if(nian==-1)nian=99;leap=nian%4==0&&nian%100!=0;write_nyr(2,nian);write_com(0x80+2);write_ds(9,nian);}}}}void set_alarm(){uchar ashi,afen,amiao;if(timeclk==0)//判断是否按下闹钟设定键{delay(5);//延时消抖if(timeclk==0){while(!timeclk);anumfun++;//按键次数加1if(anumfun==1){flag=1;write_com(0x80+0x40+0x0a);write_com(0x0f);}if(anumfun==2){flag=1;write_com(0x80+0x40+0x07);write_com(0x0f);}if(anumfun==3){flag=1;write_com(0x80+0x40+0x04);write_com(0x0f);}if(anumfun==4){flag=0;anumfun=0;}}}if(anumfun!=0){if(timeadd==0)//如果加功能键按下{delay(5);while(!timeadd);if(anumfun==1) //设定秒{amiao++;if(amiao==60)amiao=0;write_sfm(9,amiao);write_com(0x80+0x40+9);write_ds(1,amiao);}if(anumfun==2){afen++;if(afen==60)afen=0;write_sfm(6,afen);write_com(0x80+0x40+6);write_ds(3,afen);}if(anumfun==3){ashi++;if(ashi==24)ashi=0;write_sfm(3,ashi);write_com(0x80+0x40+3);write_ds(5,ashi);}}}if(anumfun!=0){if(timesub==0){delay(5);while(!timesub);if(anumfun==1){amiao--;if(amiao==-1)amiao=59;write_sfm(9,amiao);write_com(0x80+0x40+9);write_ds(1,amiao);}if(anumfun==2){afen--;if(afen==-1)afen=59;write_sfm(6,afen);write_com(0x80+0x40+6);write_ds(3,afen);}if(anumfun==3){ashi--;if(ashi==-1)ashi=23;write_sfm(3,ashi);write_com(0x80+0x40+3);write_ds(5,ashi);}}}}void init(){EA=1;//开总中断EX0=1;//开外部中断0IT0=1;//设定触发方式为负跳变沿有效lcden=0;//选通液晶显示屏ledrw=0;//设定液晶显示屏的读写方式为读write_com(0x38);//设置液晶显示模式为16*2显示,5*7点阵,8位数据接口 write_com(0x0c);//打开显示,并使光标不显示也不闪烁write_com(0x06);//光标指针每次自动加1write_com(1);//清屏write_com(0x80);//送地址指针for(num=0;num<16;num++){write_date(table[num]);delay(5);}write_com(0x80+0x40);//写到第二行for(num=0;num<11;num++){write_date(table1[num]);delay(5);}write_ds(0x0a,0x20);//开启时钟芯片振荡器write_ds(0x0b,0x26);//开启闹钟read_ds(0x0c);//读取时钟芯片c寄存器}void main(){init();while(1){keyscan();set_alarm();if(flag1==1)didi();if(flag==0){//读取时间miao=read_ds(0x00);fen=read_ds(0x02);shi=read_ds(0x04);yue=read_ds(0x08);ri=read_ds(0x07);nian=read_ds(0x09);week=read_ds(0x06);//写入液晶显示屏write_sfm(9,miao);write_sfm(6,fen);write_sfm(3,shi);write_nyr(2,nian);write_nyr(5,yue);write_nyr(8,ri);write_zhou(0x0f,week);}}}void exter() interrupt 0{flag1=1;read_ds(0x0c);//读时钟芯片c寄存器。

基于51单片机的万年历设计流程

基于51单片机的万年历设计流程

基于51单片机的万年历设计流程
基于51单片机的万年历设计流程可以分为以下几个步骤:
1. 确定需求:首先,你需要明确你的万年历需要有哪些功能。

例如,是否需要显示日期、时间、星期,是否需要闹钟功能,是否需要手动或自动校准等。

2. 选择硬件:选择合适的单片机作为主控制器。

常用的单片机有8051系列,如AT89C51、AT89S52等。

此外,还需要选择适当的显示模块、按键模块、实时时钟模块等。

3. 设计硬件电路:根据选择的硬件设备,设计电路原理图和PCB图。

需要
考虑单片机的引脚连接、电源供给、时钟源、外部扩展等问题。

4. 编写软件程序:根据硬件电路和需求,编写相应的软件程序。

这包括初始化程序、主程序、中断服务程序等。

5. 调试和测试:将编写好的程序下载到单片机中,进行实际测试。

根据测试结果,对程序进行调试和修改,直到满足设计要求。

6. 生产:完成调试后,就可以进行批量生产了。

在生产过程中,还需要对产品进行质量检测,确保每个产品都能正常工作。

7. 后期维护:在产品上市后,可能需要对产品进行维护或升级。

例如,如果用户在使用过程中发现了问题,或者有新的需求,就需要对产品进行改进或升级。

以上是基于51单片机的万年历设计的基本流程,但具体的步骤可能会根据具体的需求和硬件设备有所不同。

单片机课程设计--基于51单片机的万年历

单片机课程设计--基于51单片机的万年历

单片机课程设计--基于51单片机的万年历单片机课程设计基于 51 单片机的万年历一、引言在现代生活中,时间的准确记录和显示对于我们的日常生活和工作具有重要意义。

万年历作为一种能够同时显示年、月、日、星期、时、分、秒等信息的设备,给人们带来了极大的便利。

本次课程设计旨在利用 51 单片机实现一个简单实用的万年历系统。

二、系统设计方案(一)硬件设计1、单片机选型选择经典的 51 单片机,如 STC89C52 单片机,其具有性能稳定、价格低廉、资源丰富等优点,能够满足本设计的需求。

2、显示模块采用液晶显示屏(LCD1602)作为显示设备,能够清晰地显示数字和字符信息。

3、时钟芯片选用DS1302 时钟芯片,它可以提供精确的实时时钟数据,包括年、月、日、星期、时、分、秒等。

4、按键模块设置三个按键,分别用于调整时间、选择调整项(年、月、日、时、分、秒等)以及切换显示模式(正常显示和设置模式)。

(二)软件设计1、主程序流程系统初始化后,首先读取 DS1302 中的时间数据,并将其显示在LCD1602 上。

然后进入循环,不断检测按键状态,根据按键操作进行相应的时间调整和显示模式切换。

2、时间读取与显示程序通过与 DS1302 进行通信,读取实时时间数据,并将其转换为适合LCD1602 显示的格式进行显示。

3、按键处理程序检测按键的按下状态,根据不同的按键执行相应的操作,如调整时间、切换显示模式等。

三、硬件电路设计(一)单片机最小系统单片机最小系统包括单片机芯片、晶振电路和复位电路。

晶振电路为单片机提供时钟信号,复位电路用于系统初始化时将单片机的状态恢复到初始值。

(二)显示电路LCD1602 显示屏通过数据总线和控制总线与单片机相连。

数据总线用于传输要显示的数据,控制总线用于控制显示屏的读写操作和显示模式。

(三)时钟电路DS1302 时钟芯片通过串行通信接口与单片机进行通信。

单片机通过发送特定的指令和数据,对 DS1302 进行读写操作,获取或设置时间信息。

基于51单片机的电子万年历系统的设计

基于51单片机的电子万年历系统的设计

参考内容
一、引言
单片机是现代电子设备中的重要组成部分,广泛应用于各种嵌入式系统设计。 51单片机作为一种经典的微控制器,因其结构简单、易于编程、可靠性高等优点, 被广泛用于各种领域,如智能家居、工业控制、物联网等。万年历作为一种日常 生活中常见的计时工具,具有显示日期、时间、星期、月份等功能,对于人们的 日常生活和工作有着重要的作用。本次演示将介绍一种基于51单片机的万年历设 计。
二、系统设计
1、硬件设计
基于51单片机的万年历设计需要硬件和软件的配合实现。硬件部分主要包括 51单片机、显示模块、按键输入模块和时钟芯片等。其中,51单片机作为主控制 器,负责处理各种数据和控制信号;显示模块用于显示日期、时间等信息;按键 输入模块用于用户输入操作;时钟芯片则为系统提供实时时间。
基于51单片机的电子万年历系 统的设计
目录
01 一、概述
03 三、软件设计
02 二、硬件设计 04 四、系统调试与优化
目录
05 五、应用场景及前景
07 参考内容
06 六、结论
随着科技的不断发展,单片机已经成为现代于51单片机的电子万年历系统设计具有广泛的实际应用价值。 本次演示将详细介绍这种系统的设计过程和实现方法。
感谢观看
首先需要进行硬件搭建,包括选择合适的单片机、显示模块、按键输入模块 和时钟芯片等,并将其连接起来。需要注意的是,在搭建硬件时需要考虑各个模 块之间的接口和连接方式,以确保系统能够正常工作。
2、软件编程
在硬件搭建完成后,需要进行软件编程。首先需要进行系统初始化,包括对 单片机进行初始化和对显示进行清屏处理。然后需要进行按键处理和时钟数据处 理,以实现用户输入和实时时间的读取。最后需要进行显示处理,将处理后的数 据显示到显示模块上。

基于51单片机的万年历设计

基于51单片机的万年历设计

一、引言万年历是一种日历工具,能够显示任何一个公历日期的星期、年、月和日,并且能够自动判断闰年。

在本设计中,我们将使用51单片机设计一个基于LCD显示屏的万年历。

它将能够显示当前的日期和星期,并且具备一些附加功能,如闹钟、计时器等。

二、设计目标本设计的主要目标是通过51单片机实现以下功能:1.显示当前日期和星期:使用LCD显示屏显示当前的年、月、日和星期。

2.闰年判断:根据公历算法判断是否为闰年,并在显示屏上进行标识。

3.闹钟功能:设置一个闹钟时间,并在指定时间到达时发出提醒。

4.计时器功能:实现一个简单的计时器,能够显示经过的时间。

三、系统框图```+------------------+51单片+---+----------+---++--v--++--v--+LCD ,, Keypa+-----++-------+```四、系统设计1.时钟模块:使用定时器模块实现系统的主时钟,根据预设的频率进行中断,更新时间和日期。

2.LCD模块:使用51单片机的IO口控制LCD显示屏,实现对日期、星期和其他功能的显示。

3.按键模块:通过按键模块实现对系统功能的操作,包括设置闹钟、切换功能等。

4.闹钟模块:根据预设的时间进行判断,判断是否到达闹钟时间并触发相应的操作。

5.计时器模块:通过计时器模块实现计时功能,显示经过的时间。

五、代码实现以下是基于51单片机的万年历的主要代码实现的伪代码:1.时钟模块:```初始化定时器;定时器中断中获取当前的日期和时间;```2.LCD模块:```定义LCD引脚;初始化LCD显示;定时刷新LCD内容;```3.按键模块:```定义按键引脚;初始化按键;判断按键事件并执行相应的操作;```4.闹钟模块:```设置闹钟时间;判断当前时间是否与闹钟时间相等;触发相应操作;```5.计时器模块:```设置起始时间;计算当前时间与起始时间的差值;显示计时时间;```六、实验结果通过上述的代码实现和电路连接,我们可以成功地实现了基于51单片机的万年历。

单片机课程设计--基于51单片机的万年历

单片机课程设计--基于51单片机的万年历

单片机课程设计报告万年历的设计基于51单片机的万年历摘要:电子万年历是一种非常广泛日常计时工具,对现代社会越来越流行。

它可以对年、月、日、周日、时、分、秒进行计时,使用寿命长,误差小。

对于数字电子万年历采用直观的数字显示,可以同时显示年、月、日、周日、时、分、秒和温度等信息,还具有时间校准等功能。

该电路采用AT89S52单片机作为核心,功耗小,能在3V的低压工作,电压可选用3~5V电压供电。

本设计是基于51系列的单片机进行的电子万年历设计,可以显示年月日时分秒及周信息,具有可调整日期和时间功能。

在设计的同时对单片机的理论基础和外围扩展知识进行了比较全面准备。

万年历的设计过程在硬件与软件方面进行同步设计。

硬件部分主要由AT89C52单片机,LCD显示电路,以及调时按键电路等组成。

在单片机的选择上本人使用了AT89C52单片机,该单片机适合于许多较为复杂控制应用场合。

显示器使用了1602液晶显示,并且使用蜂鸣器实现了整点报警的功能,温度测试的功能实现使用了DS18B20,并实现了温度过高或过低时的温度报警。

软件方面主要包括日历程序、时间调整程序,显示程序等。

程序采用C语言编写。

所有程序编写完成后,在KeilC51软件中进行调试,确定没有问题后,在Proteus软件中嵌入单片机内进行仿真,并最终实现基本要求。

综上所述此万年历具有读取方便、显示直观、功能多样、电路简洁、成本低廉等诸多优点,符合电子仪器仪表的发展趋势,具有广阔的市场前景。

一、设计要求基本要求:1,8 个数码管上显示,显示时间的格式为(假如当前时间是19:32:20)“19-32-20”;2,具有日历功能;③时间可以通过按键调整。

发挥部分:④具有闹钟功能(可以设定多个)。

二:总体设计电路设计框图系统硬件概述本电路是由AT89S52单片机为控制核心,具有在线编程功能,低功耗,能在3V超低压工作;时钟电路由单片机定时功能提供;温度的采集由DS18B20构成,它具有独特的单线接口方式,DS18B20在与微处理器连接时仅需要一条口线即可实现微处理器与DS18B20的双向通讯,使用时不需要额外的外围电路。

51单片机汇编语言万年历完美版.

51单片机汇编语言万年历完美版.

;**************万年历制作 BY----信工七班 ;**************************** ;***************************** ;----------------------------------------------------------------------------------------- RCK BIT P0.5 SCK BIT P0.4 DAT BIT P0.7 RST BIT P0.6 BUZZER BIT P1.3 ;蜂鸣器 BYTE EQU 40H ;用于给锁存器送入数据 GEWEI EQU 41H ;用于存放数码管显示的第一位 SHIWEI EQU 42H ;用于存放数码管显示的第二位 BAIWEI EQU 43H ;用于存放数码管显示的第三位 QIANWEI EQU 44H ;用于存放数码管显示的第四位 TEMP1 EQU 45H TEMP2 EQU 46H COUNT EQU 47H ;用于扩展定时器计数时间 KTIME EQU 49H TEMP EQU 50H DMS EQU 51H ;用于存放运动秒表的最低位 DSECOND EQU 52H ;用于存放运动秒表的秒 DMIN EQU 53H ;用于存放运动秒表的分钟 CLKMIN EQU 54H ;用于存放闹钟分钟 CLKHOUR EQU 55H ;用于存放闹钟时 CLKF EQU 56H ;用于闹钟开启的标志位 ;----------------------------------------------------------------------------------------- ORG 0000H AJMP MAIN ORG 000BH ;定时器0中断入口地址 AJMP T0_INT ORG 001BH ;定时器1中断入口地址 AJMPT1_INT ;********************************主程序************************************************* ;----------------------------------------------------------------------------------------- MAIN: MOV R4,#00 ;计数秒 MOVR5,#50 ;计数分 MOV R6,#15 ;计数时 MOV R0,#14H ;2013年 MOV R1,#0DH MOV R2,#6 ;6月 MOV R3,#18 ;18日 MOV COUNT,#0H MOV A,#5 ;开始使A不等于0,用于后面的判断 MOV CLKMIN,#0H MOV CLKHOUR,#0H MOV CLKF,#0H MOV SP,#60H MOV TMOD,#11H ;设置定时器0为工作模式1 MOV TH0, #03CH MOV TL0, #0B0H ;定时50000 us MOV TH1, #0D8H MOV TL1, #0F0H ;定时1000us=1MS SETB ET0 ;允许定时器中断 SETB ET1 SETB EA ;允许全局中断 SETB PT0 ;定时器中断设为高优先级 SETB EX0 ;允许外部中断 SETB EX1 SETB IT0 ;外部中断设为下降沿触发 SETB IT1 SETB TR0 ;启动定时器 ;--------------------------------------- START: MOV DPTR,#TABLE LJMP KEYSCAN ;首先进入时间显示,由于地址相差太远所以代码顺序有所改变 ;-------------------------------------- MARK2: LJMP KEYSCAN ;地址差跳远无法跳转,此处进行中间跳转到时间显示界面 KEYCLK: MOV A,CLKF ;此处为闹钟设置刚进入时的程序,由按键s12进入 JNZ KEYCLKF ;进入后通过CLKF来判断闹钟功能是否启动,未启动时正常 ;显示为SHOWCLKF,启动时显示SHOWCLKF1,此两种显示差一个数码管最低位标志的点 KEYCLK1: LCALL SHOWCLK ;此处判定未启动闹钟功能时的显示 LCALL S4 ;在闹钟界面查看有无切换显示模式(此处也可认为是确定 ;按键)的按键s4按下, JZ MARK2 ;按下后跳转到时间显示 LCALL S8 ;在闹钟显示界面下查看启动闹钟功能的键s8是否按下MOV A,CLKF JNZ KEYCLKF ;按下后显示SHOWCLKF1的显示 LCALL S16 ;未按下则显示没有闹钟标志的数码管显示,再查看有无进 ;入调节s16的键按下,CJNE A,#7EH,KEYCLK1 ;未按下继续闹钟界面显示 KEYCLK2: LCALL SCLKMIN ;按下进入调节 MOV A,CLKMIN ;显示设置分钟的调节 MOV TEMP,A LCALL KEYSUB1 ;通过加减键s8,s12来设置闹钟 LCALL KEYADD1 MOV A,TEMP SUBB A,#60 ;调节分钟不超过59 JC REMAIN0 MOV TEMP,#0 REMAIN0: MOV A,TEMP MOV CLKMIN,A LCALL S16 ;查看有无进入调节s16的键按下, CJNE A,#7EH,KEYCLK2 ;未按下继续显示分钟调节 KEYCLK3: LCALL SCLKHOUR ;按下进入显示时调节 MOV A,CLKHOUR MOV TEMP,A ;送入参数,通过加减键进行调节设置 LCALL KEYSUB2 LCALL KEYADD2 MOV A,TEMP SUBB A,#24 ;时的设置不超过24 JC REMAIN1 MOV TEMP,#0 ;超过24置0 REMAIN1: MOVA,TEMP MOV CLKHOUR,A LCALL S16 CJNE A,#7EH,KEYCLK3 ;再次判断有无调节的切换键(按3次为确定)按下 KEYCLK4: LCALL SHOWCLK ;按下后跳转为闹钟的界面正常显示 LCALL S4 ;再判断有无切换显示模式的键按下,按下跳转显示 JZ KEYSCAN LCALL S8 ;再判断有无启动(关闭)闹钟功能的键按下 MOV A,CLKF ;根据CLKF(闹钟功能启动)的标志位显示不同的闹钟界面 JNZ KEYCLKF ;闹钟功能启动,跳转到KEYCLKF显示闹钟启动标记 GOON: LCALL S16 ;未启动则又判断有无进入调节的键按下 CJNE A,#7EH,KEYCLK4 ;没有按下继续正常显示 AJMP KEYCLK2 ;按下后重复KEYCLK2开始的内容 KEYCLKF: LCALL SHOWCLK1 ;显示出闹钟功能启动后的标记(数码管最低位标记) LCALLS4 ;查看有无切换显示模式(闹钟设置确定后)键按下 JZ KEYSCAN ;按下后跳转到显示时间的界面 LCALL S8 ;未按则扫描开启(关闭)闹钟功能的键按下 MOV A,CLKF JZ KEYCLK4 ;根据闹钟功能的标记位跳转显示,若判断闹钟功能关闭则 ;跳转到KEYCLK4 显示无标志的闹钟 LCALL S16 ;若判断闹钟功能开启则扫描有无进入调节的按键s16按下CJNE A,#7EH,KEYCLKF ;未按下则继续显示有标记的闹钟界面 AJMP KEYCLK2 ;按下后则又进入调节界面KEYCLK2 ;-------------------------------------------------- MARK3: LJMP MARK1 ;地址差跳远无法跳转,此处进行中间跳转到闹钟界面 ;---------------------------------------------------- KEYSCAN: LCALL HOURMINUTE ;显示时间 PUSH ACC ;为s12的判断先把A入堆栈,否则s12出会出现判断错误LCALL S4 ;查看有无切换键s4按下,按下跳转显示秒 JZ KEYSCAN1 MOVA,CLKF ;在显示时间时判断闹钟功能是否开启,未开则跳转显示 JZ GO MOVA,R6 ;判断是否与闹钟设置的时间相等,R6---时 CJNE A,CLKHOUR,GO MOV A,R5 ;R5--分 CJNE A,CLKMIN,GO LCALL SOUND ;闹钟功能开启,时分相等,则闹铃响 ;-------------------------------------------------- GO: POP ACC ; 如果不pop,A=0一直成立,此时出现错误跳转 LCALL S12 ;查看有无进入闹钟设置的键按下 JZ MARK3 ; 按下则跳入显示闹钟设置界面 LCALL S16 ;查看有无进入调节键s16按下,按下进入调节 CJNE A,#7EH,KEYSCAN ;未按下则继续显示时间 SMINUTE: LCALL MINUTE ;s16按下后进入分调节显示 MOV TEMP,R5 ;将要调节的分钟送入函数参数 LCALL KEYADD1 ;进入调节后查看是否按下加法键s8,按下加一LCALL KEYSUB1 ;进入调节后查看是否按下减法键s8,按下减一 MOV A,TEMP SUBB A,#60 ;调节不超过60 JC REMAIN2 MOV TEMP,#0 REMAIN2: MOVR5,TEMP ;把运算完后的分钟送出显示 LCALL S16 CJNE A,#7EH,SMINUTE ;没有s16按下,继续显示分调节 SHOUR: LCALL HOUR ;按下后进入显示时调节 MOV TEMP,R6 ;R6为装时的寄存器,送入参数进行调节 LCALL KEYADD2 LCALL KEYSUB2 MOV A,TEMP SUBB A,#24 ;调节不超过24 JC REMAIN3 MOV TEMP,#0 REMAIN3: MOV R6,TEMP LCALL S16 ; 再次按下s16键可确定时间调节完成 CJNE A,#7EH,SHOUR AJMP KEYSCAN ;调节完后重新正常显示时间 ;--------------------------------------- ;--------------------------------------- KEYSCAN1: LCALL SHOWSECOND ;按切换键s4后进入的秒显示 LCALL S4 ;与时间显示的时候一样查看有无切换模式的键按下 JZ KEYSCAN2 ;按下则跳转显示日期 LCALL S12 ;此处为查看有无进入闹钟功能的键按下,有则跳转 JZ MARK1 LCALL S16 ;若无闹钟键按下,查看有无进入调节的键s16按下 CJNE A,#7EH,KEYSCAN1 SMS: LCALL MS ;调节键按下显示需要调节内容 MOV A,COUNT ;与之前的一样把调节参数送入进行调节,此处调姐秒显示的低位 MOV TEMP,A LCALL KEYADD1 LCALL KEYSUB1 MOV A,TEMP SUBB A,#60 ;调节不超过60 JC REMAIN4 MOV TEMP,#0 MOV A,TEMP REMAIN4: MOVA,TEMP MOV COUNT,A LCALL S16 ;查看有无切换调节内容的键s16按下CJNE A,#7EH,SMS ;没有s16键按下则显示原先调节内容 SSECOND: LCALL SECOND ;有键s16按下则显示进入秒的调节 MOV TEMP,R4 ;参数送入进行调节LCALL KEYADD2 LCALL KEYSUB2 MOV A,TEMP SUBB A,#60 ;调节不超过60 JC REMAIN9 MOV TEMP,#0 REMAIN9: MOV R4,TEMP LCALL S16 ; 再次按下s16键可确定时间调节完成 CJNE A,#7EH,SSECOND ;未按下则继续显示选中的调节内容 AJMP KEYSCAN1 ;---------------------------------------- MARK1: LJMP KEYCLK ;地址差跳远无法跳转,此处进行中间跳转到闹钟界面 ;---------------------------------------- KEYSCAN2: LCALL SHOWDAY ;此处为日期显示,当切换模式键按下两下后进入显示 LCALL S4 ;与时间显示的时候一样查看有无切换模式的键按下JZ KEYSCAN3 ;按下则跳转显示年份 LCALL S12 ;此处为查看有无进入闹钟功能的键按下,有则跳转 JZ MARK1 LCALL S16 ;若无闹钟键按下,查看有无进入调节的键s16按下 CJNE A,#7EH,KEYSCAN2 SDAY: LCALL DAY ;调节键按下显示需要调节内容,此处为日 MOV TEMP,R3 ; 把日期寄存器R2的值送入临时变量用于调节 LCALL KEYADD1 ;调用加减按键扫描,按下后进行操作 LCALL KEYSUB1 MOV A,TEMP SUBB A,#32 ;调节不超过31 JC REMAIN5 MOV TEMP,#0 REMAIN5: MOV R3,TEMP LCALL S16 ;查看有无切换调节内容的键s16按下 CJNE A,#7EH,SDAY ;没有s16键按下则显示原先调节内容 SSMOUNTH: LCALL MOUNTH ;有键s16按下则显示进入月的调节 MOV TEMP,R2 LCALL KEYADD2LCALL KEYSUB2 MOV A,TEMP SUBB A,#13 ;调节不超过12 JC REMAIN6 MOV TEMP,#0 REMAIN6: MOV R2,TEMP LCALL S16 ; 再次按下s16键可确定时间调节完成 CJNE A,#7EH,SSMOUNTH ;未按下则继续显示选中的调节内容 AJMP KEYSCAN2 ;--------------------------------------------- ;---------------------------------------------- KEYSCAN3: LCALL SHOWYEAR ;此处为日期显示,当切换模式键按下三下后进入显示 LCALL S4 JZ SHOW0 ;代码的内容除了显示的内容不同其他和以上的一样 LCALL S12 JZ MARK1 LCALL S16 CJNE A,#7EH,KEYSCAN3 SYEAR1: LCALL YEAR1 MOV TEMP,R1 LCALL KEYADD1 LCALL KEYSUB1 MOVA,TEMP SUBB A,#100 ;调节不超过99 JC REMAIN7 MOV TEMP,#0 REMAIN7: MOV R1,TEMP LCALL S16 ; CJNE A,#7EH,SYEAR1 SYEAR2: LCALL YEAR2 MOV TEMP,R0 LCALL KEYADD2 LCALL KEYSUB2 MOV A,TEMP SUBBA,#100 ;调节不超过99 JC REMAIN8 MOV TEMP,#0 REMAIN8: MOV R0,TEMP LCALL S16 CJNE A,#7EH,SYEAR2 AJMP KEYSCAN3 ;------------------------------------------ MARK: LJMP KEYSCAN ;地址差跳远无法跳转,此处进行中间跳转到时间显示界面 ;------------------------------------------ SHOW0: MOV DMS,#0 ;切换键按下四次后此时切换到运动秒表计时从0开始计时 MOV DMIN,#0 MOV DSECOND,#0 LCALL SHOWDD ; 刚进入运动秒表模式,显示全为0 LCALL S4 JZ MARK LCALL S16 CJNE A,#7EH,SHOW0 ;运动秒表开始键按下,则计时开始,否则继续显示0 SETB TR1 ;开启定时器1 SHOWD: LCALL SHOWDD ;开始键s16按下后显示变化的数字 LCALL S4 ;查看有无模式显示键的按下 JZ MARK ;按下则跳转显示LCALL S16 ;查看s16有无按下 CJNE A,#7EH,SHOWD ;再次按下该键s16,停止计时 CLR TR1 ;关闭定时器1 SHOWTING: LCALL SHOWDD ;显示为定时的内容LCALL S4 ;查看有无模式显示键的按下 JZ MARK LCALL S16 CJNEA,#7EH,SHOWTING ;再次按下s16,显示继续上次状态开始计时 SETB TR1 ;再次开启定时器 SHOWTING1: LCALL SHOWDD ;显示定时变化的定时内容 LCALL S4 JZ MARK LCALL S16 CJNE A,#7EH,SHOWTING1 ;再按一下s16再次进入暂停状态 CLR TR1 SHOWTING2: LCALL SHOWDD LCALL S4 JZ MARK LCALL S16CJNE A,#7EH,SHOWTING2 AJMP SHOW0 ;再按一下s16 内容清零,重新进入初始化运动秒表模式 ;---------------------------------------------此段主要为调节、显示的过程内容 ;************主程序结束****************************************************************** ;--------------出程序结束,一下为各个子函数 ;向74hc595发送一个字,并显示数据 ;----------------------------------------------------------------------------------------- SENDBYTE: MOV BYTE,A ;送入需要写入锁存器的参数 MOV A, #1 ;用1来移位选取各个位的数据ANL A,BYTE ;用与来选取数据 JNZ SEND CLR DAT ;与后结果为0则送入0 CLR SCK ;将写入的数据进行右移 SETB SCK AJMP LOOP ;跳转继续重复7次 SEND: SETB DAT ;与后结果不为0,则送入数据1 CLR SCK SETB SCK ;--------送入第一位数据 LOOP: MOV R7,#7 MOV A, #1 LOOP1: RL A MOV B,A ANL A,BYTE JNZ SEND1 SEND0: CLR DAT ;送0 AJMP SUOCUN SEND1: SETB DAT ;送1 AJMP SUOCUN SUOCUN: CLR SCK SETB SCK MOV A,B DJNZ R7,LOOP1 CLR RCK SETB RCK RET ;------------------------以上为数据进行输入锁存 DISPLAY: ACALL JISUAN DISPLAY1: MOV P0,#00H MOV A,GEWEI ACALL SENDBYTE ORLP0,#08H ;给出最左边数码管的位选 MOV R7,#10H LCALL DLY ;-----------显示最左边的数码管 MOV P0,#00H MOV R7,#03H LCALL DLY MOV A,SHIWEI ACALL SENDBYTE ORL P0,#04H ;给出第二位数码管的位选 MOV R7,#10H LCALL DLY ;--------------显示第二位数码管MOV P0,#00H MOV R7,#03H LCALL DLY MOV A,BAIWEI ACALL SENDBYTE ORL P0,#02H ;给出第三位数码管的位选 MOV R7,#10H LCALL DLY ;----------------显示第三位数码管 MOV P0,#00H MOV R7,#03H LCALL DLY MOV A,QIANWEI ACALL SENDBYTE ORL P0,#01H ;给出第三位数码管的位选 MOV R7,#10H LCALL DLY ;-------------------显示第四位数码管 RET ; ------------------------以上为数据显示 ;计算各位数的值把要显示的数进行分解 ;----------------------------------------- JISUAN: MOV A,TEMP1 MOV B,#10 DIV AB MOV TEMP1,B MOVC A,@A+DPTR MOV SHIWEI,A MOV A,TEMP1 MOVC A,@A+DPTR MOV GEWEI,A MOVA,TEMP2 MOV B,#10 DIV AB MOV TEMP2,B MOVC A,@A+DPTR MOVQIANWEI,A MOV A,TEMP2 MOVC A,@A+DPTR MOV BAIWEI,A RET ;-----------------以上为计算各个位数 ;----------------------------------------------------------------------------------------- ;显示高两位数(用于调节的时候显示) ;---------------------------------------------------------------------------------------- DISPLAY4: ACALL JISUAN MOV P0,#00H MOV A,BAIWEI ACALL SENDBYTE ORL P0,#02H MOV R7,#03H LCALL DLY ;----------------显示第三位数码管 MOV P0,#00H MOV R7,#03H LCALL DLY MOVA,QIANWEI ACALL SENDBYTE ORL P0,#01H MOV R7,#03H LCALL DLY ;-------------------显示第四位数码管 RET ;------------------------------------------------------------------------------------------ ;只显示低两位数(用于调节的时候显示) ;------------------------------------------------------------------------------------------ DISPLAY2: LCALL JISUAN MOV P0,#00H MOV A,GEWEI LCALL SENDBYTE ORL P0,#08H MOV R7,#03H LCALL DLY ;-----------显示最左边的数码管 MOV P0,#00H MOV R7,#03H LCALL DLY MOV A,SHIWEI LCALL SENDBYTE ORL P0,#04H MOV R7,#03H LCALL DLY ;--------------显示第二位数码管 MOV P0,#00H MOV R7,#03H LCALL DLY RET ;----------------------------------------------------------------------------------------- ;显示时间子程序 ;----------------------------------------------------------------------------------------- HOURMINUTE: MOV TEMP2,R6 MOV TEMP1,R5 LCALL JISUAN ORL BAIWEI,#01H ;--------第三个数码管显示小数点 LCALL DISPLAY1 RET ;由于只有四个数码管,此处显示时、分 SHOWSECOND: MOV TEMP2,R4 MOV A,COUNT MOV TEMP1,A LCALL JISUAN ORL BAIWEI,#01H LCALL DISPLAY1 RET ;此处单独显示秒 SHOWYEAR: MOV TEMP2,R0 MOV TEMP1,R1 LCALL DISPLAY RET SHOWDAY: MOV TEMP2,R2 MOV TEMP1,R3 LCALL DISPLAY RET SHOWCLK: MOV TEMP2,CLKHOUR MOV TEMP1,CLKMIN LCALL JISUAN ORL BAIWEI,#01H LCALL DISPLAY1 RET SHOWCLK1: MOV TEMP2,CLKHOUR MOV TEMP1,CLKMIN LCALL JISUAN ORL BAIWEI,#01H ORL GEWEI,#01H LCALL DISPLAY1 RET ;----------------------------------------------------------------------------------------- ;调节时间日期时独立显示每两位(用于调节的时候显示) ;---------------------------------------------------------------------------------------- MS: MOV TEMP1,COUNTLCALL DISPLAY2 RET SECOND: MOV TEMP2,R4 LCALL DISPLAY4 RET MINUTE: MOV TEMP1,R5 LCALL DISPLAY2 RET HOUR: MOV TEMP2,R6 LCALL DISPLAY4 RET DAY: MOV TEMP1,R3 LCALL DISPLAY2 RET MOUNTH: MOV TEMP2,R2 LCALL DISPLAY4 RET YEAR1: MOV TEMP1,R1 LCALL DISPLAY2 RET YEAR2: MOV TEMP2,R0 LCALL DISPLAY4 RET SCLKMIN: MOV TEMP1,CLKMIN LCALL DISPLAY2 RET SCLKHOUR: MOVTEMP2,CLKHOUR LCALL DISPLAY4 RET ;----------------------------------------------------------------------------------------- ;键盘扫描函数 ;---------------------------------------------------------------------------------------- ;切换调节显示内容键 S16: MOV P2,#0FFH CLRP2.7 JB P2.0,S16END MOV R7,#18H LCALL DLY JNB P2.0,$ ;当键盘松开时往下执行否则停留在这一步 MOV A,#7EH S16END: RET ;切换模式显示内容键 S4: MOV P2,#0FFH CLR P2.7 JB P2.3,S4END MOV R7,#18H LCALL DLY JNB P2.3,$ ;当键盘松开时往下执行否则停留在这一步 MOV A,#0H ;设置扫描标志位A=0 S4END: RET ;设置闹钟键扫描与减法键位同一键s12 S12: MOV P2,#0FFH CLR P2.7 JBP2.1,S12END MOV R7,#18H LCALL DLY JNB P2.1,$ ;当键盘松开时往下执行否则停留在这一步 MOV A,#0 ;设置扫描标志位A=0 S12END: RET ;用于确定启动闹钟功能的键盘扫描,与加法键位同一个 S8: MOV P2,#0FFH CLR P2.7 JB P2.2,S8END MOV R7,#18H LCALL DLY JNB P2.2,$ ;当键盘松开时往下执行否则停留在这一步MOV A,CLKF CPL A ;设置扫描标志位A=1 MOV CLKF,A S8END: RET ;单步、连续调节加法键 ;----------------------------------------------------------------------------------------- ;----------------------------------------------------------------------------------------- KEYADD2: MOV P2,#0FFH CLR P2.7 JB P2.2,ADDEND2 MOV R7,#18H LCALL DLY JT1: JNB P2.2,KT1 INC TEMP AJMP ADDEND2 KT1: INC KTIME MOV R7,#10H LCALL DLY ;用于调节高两位 MOV A,KTIME CJNEA,#30,JT1 ADD2: INC TEMP MOV A,TEMP CJNE A,#99,ON2 MOV TEMP,#0 ON2: MOV R7,TEMP MOV TEMP2,R7 LCALL DISPLAY4 MOV R7,#30H LCALL DLY JNB P2.2,ADD2 ADDEND2: RET KEYADD1: MOV P2,#0FFH CLR P2.7 JBP2.2,ADDEND1 MOV R7,#18H LCALL DLY JT2: JNB P2.2,KT2 INC TEMP AJMPADDEND1 ;用于调节低两位 KT2: INC KTIME MOV R7,#10H LCALL DLY MOV A,KTIME CJNE A,#30,JT2 ADD1: INC TEMP MOV A,TEMP CJNE A,#99,ON3 MOV TEMP,#0 ON3: MOV R7,TEMP MOV TEMP1,R7 LCALL DISPLAY2 MOV R7,#30H LCALL DLY JNB P2.2,ADD1 ADDEND1: RET ;----------------------------------------------------------------------------------------- ;单步、连续调节减法键 KEYSUB2: MOVP2,#0FFH CLR P2.7 JB P2.1,SUBEND2 MOV R7,#18H LCALL DLY JT3: JNBP2.1,KT3 DEC TEMP AJMP SUBEND2 KT3: INC KTIME MOV R7,#10H ;用于调节高两位 LCALL DLY MOV A,KTIME CJNE A,#30,JT3 SUB2: DEC TEMP MOVA,TEMP CJNE A,#0,ON MOV TEMP,#99 ON: MOV R7,TEMP MOV TEMP2,R7 LCALL DISPLAY4 MOV R7,#30H LCALL DLY JNB P2.1,SUB2 SUBEND2: RET ;----------------------------------------------------------------------------------------- KEYSUB1: MOV P2,#0FFH CLR P2.7 JB P2.1,SUBEND1 MOV R7,#18H LCALL DLY JT4: JNB P2.1,KT4 DEC TEMP AJMP SUBEND2 KT4: INC KTIME MOV R7,#10H ; LCALL DLY MOV A,KTIME CJNE A,#30,JT4 SUB1: DEC TEMP ;用于调节低两位 MOV A,TEMP CJNE A,#0,ON1 MOV TEMP,#99 ON1: MOV R7,TEMP MOV TEMP1,R7 LCALL DISPLAY2 MOV R7,#30H LCALL DLY JNB P2.1,SUB1 SUBEND1: RET ;蜂鸣器响的子程序 ;----------------------------------------------------------------------------------------- SOUND: CLR BUZZER MOV R7,#5H LCALL DLY SETB BUZZER MOVR7,#04H LCALL DLY RET ;----------------------------------------------------------------------------------------- ;延时子程序 ;----------------------------------------------------------------------------------------- DLY: PUSH 07H DY1: PUSH 07H DY2: PUSH 07H DY3: DJNZR7,DY3 POP 07H DJNZ R7,DY2 POP 07H DJNZ R7,DY1 POP 07H DJNZ R7,DLY RET ;----------------------------------------------------------------------------------------- ;定时器中断程序: ;----------------------------------------------------------------------------------------- T0_INT: MOV TH0,#3CH ;定时中断子程序。

51单片机实现万年历程序文件

51单片机实现万年历程序文件

51单片机实现万年历利用AT89S52单片机的P0口来和另外几个口来控制1602液晶的显示和P1口还有其它口来控制ds12887时钟芯片。

设置四个按键,1个定义为时间设置功能键,一个定义为闹钟设置功能键,另外两个用来调节时间的增减。

原理图:pcb图:源程序:#include<reg52.h>#define uint unsigned int#define uchar unsigned charsbit beep=P2^0;//蜂鸣器控制口sbit timeadd=P2^1;//调节时间加sbit timesub=P2^2;//调节时间减sbit timeclk=P2^3;//闹钟设定键sbit timefun=P2^4;//时间设定键sbit lcdrs=P2^5;//液晶的命令和数据控制口sbit ledrw=P2^6;//液晶的写数据口sbit lcden=P2^7;//液晶显示模块的使能端sbit timeds=P3^3;//时钟芯片地址闸sbit timerw=P3^4;//时钟芯片读写sbit timeas=P3^5;//时钟芯片地址闸sbit timeen=P3^6;//时钟芯片片选uchar code table[]="20 - - week ";uchar code table1[]=" : : ";//要显示的字符串char num,shi,fen,miao,nian=2000,yue,ri,week,numfun,anumfun,flag,flag1; uchar leap;void delay(uint x){uchar i,j;for(i=x;i>0;i--)for(j=110;j>0;j--);}void didi(){beep=0;delay(1000);beep=1;delay(1000);}void write_com(uchar com){lcdrs=0;P0=com;delay(5);lcden=1;delay(20);lcden=0;}void write_date(uchar date){lcdrs=1;P0=date;delay(5);lcden=1;delay(20);lcden=0;}void write_sfm(uchar add,uchar date){ uchar shi,ge;shi=date/10;ge=date%10;write_com(0x80+0x40+add);write_date(0x30+shi);write_date(0x30+ge);}void write_nyr(uchar add,uchar date){ uchar shi,ge;shi=date/10;ge=date%10;write_com(0x80+add);write_date(0x30+shi);write_date(0x30+ge);}void write_zhou(uchar add,uchar date) {write_com(0x80+add);write_date(0x30+date);}void write_ds(uchar add,uchar date){timeas=1;timeds=1;timerw=1;P1=add;timeas=0;timerw=0;P1=date;timerw=1;timeas=1;timeen=1;}uchar read_ds(uchar add){ uchar ds_date;timeas=1;timeds=1;timerw=1;timeen=0;P1=add;timeas=0;timeds=0;ds_date=P1;timeds=1;timeas=1;timeen=1;return ds_date;}void keyscan(){if(flag1==1)//用来关闭闹钟铃声{if(timeadd==0){delay(5);if(timeadd==0){while(!timeadd==0); flag1=0;}}if(timesub==0){delay(5);if(timesub==0){while(!timesub==0);flag1=0;}}}if(timefun==0){delay(5);if(timefun==0){while(!timefun);flag=1;numfun++;if(numfun==1){write_com(0x80+0x40+0x0a); write_com(0x0f);}if(numfun==2){write_com(0x80+0x40+0x07); write_com(0x0f);}if(numfun==3){write_com(0x80+0x40+0x04); write_com(0x0f);}if(numfun==4){write_com(0x80+0x0f);write_com(0x0f);}if(numfun==5){write_com(0x80+0x09);write_com(0x0f);}if(numfun==6){write_com(0x80+0x06);write_com(0x0f);}if(numfun==7){write_com(0x80+0x03); write_com(0x0f);}if(numfun==8){numfun=0;flag=0;}}}if(numfun!=0){if(timeadd==0){delay(5);while(!timeadd);if(numfun==1){miao++;if(miao==60)miao=0;write_sfm(9,miao);write_com(0x80+0x40+9); write_ds(0,miao);}if(numfun==2){fen++;if(fen==60)fen=0;write_sfm(6,fen);write_com(0x80+0x40+6); write_ds(2,fen);}if(numfun==3){shi++;if(shi==24)shi=0;write_sfm(3,shi);write_com(0x80+0x40+3);write_ds(4,shi);}if(numfun==4){week++;if(week==8)week=1;write_zhou(0x0f,week);write_com(0x80+0x0f);write_ds(6,week);}if(numfun==5){if(nian==0){switch(yue){case 1:ri++;if(ri==32) ri=1;break; case 2:ri++;if(ri==30) ri=1;break; case 3:ri++;if(ri==32) ri=1;break; case 4:ri++;if(ri==31) ri=1;break; case 5:ri++;if(ri==32) ri=1;break;case 6:ri++;if(ri==31) ri=1;break; case 7:ri++;if(ri==32) ri=1;break; case 8:ri++;if(ri==32) ri=1;break; case 9:ri++;if(ri==31) ri=1;break; case 10:ri++;if(ri==32) ri=1;break; case 11:ri++;if(ri==31) ri=1;break; case 12:ri++;if(ri==32) ri=1;break; }}else if(leap&&yue==2){ri++;if(ri==30)ri=1;}else if(yue==2&&leap==0){ri++;if(ri==29)ri=1;}elseswitch(yue){case 1:ri++;if(ri==32) ri=1;break; case 3:ri++;if(ri==32) ri=1;break; case 4:ri++;if(ri==31) ri=1;break; case 5:ri++;if(ri==32) ri=1;break; case 6:ri++;if(ri==31) ri=1;break; case 7:ri++;if(ri==32) ri=1;break; case 8:ri++;if(ri==32) ri=1;break; case 9:ri++;if(ri==31) ri=1;break; case 10:ri++;if(ri==32) ri=1;break; case 11:ri++;if(ri==31) ri=1;break; case 12:ri++;if(ri==32) ri=1;break; }write_nyr(8,ri);write_com(0x80+0x08);write_ds(7,ri);}if(numfun==6){yue++;if(yue==13)yue=0;write_nyr(5,yue);write_com(0x80+0x05);write_ds(8,yue);}if(numfun==7){nian++;if(nian==100)nian=0;leap=nian%4==0&&nian%100!=0; write_nyr(2,nian);write_com(0x80+2);write_ds(9,nian);}}if(timesub==0){delay(5);while(!timesub);if(numfun==1){miao--;if(miao==-1)miao=59;write_sfm(9,miao);write_com(0x80+0x40+9); write_ds(0,miao);}if(numfun==2){fen--;if(fen==-1)fen=59;write_sfm(6,fen);write_com(0x80+0x40+6); write_ds(2,fen);}if(numfun==3){shi--;if(shi==-1)shi=23;write_sfm(3,shi);write_com(0x80+0x40+3);write_ds(4,shi);}if(numfun==4){week--;if(week==0)week=7;write_zhou(0x0f,week);write_com(0x80+0x0f);write_ds(6,week);}if(numfun==5){if(nian==0){switch(yue){case 1:ri--;if(ri==0) ri=31;break; case 2:ri--;if(ri==0) ri=29;break; case 3:ri--;if(ri==0) ri=31;break; case 4:ri--;if(ri==0) ri=30;break; case 5:ri--;if(ri==0) ri=31;break; case 6:ri--;if(ri==0) ri=30;break;case 7:ri--;if(ri==0) ri=31;break; case 8:ri--;if(ri==0) ri=31;break; case 9:ri--;if(ri==0) ri=30;break; case 10:ri--;if(ri==0) ri=31;break; case 11:ri--;if(ri==0) ri=30;break; case 12:ri--;if(ri==0) ri=31;break; }}else if(leap&&yue==2){ri--;if(ri==0)ri=29;}else if(yue==2&&leap==0){ri--;if(ri==0)ri=28;}elseswitch(yue){case 1:ri--;if(ri==0) ri=31;break; case 3:ri--;if(ri==0) ri=31;break; case 4:ri--;if(ri==0) ri=30;break; case 5:ri--;if(ri==0) ri=31;break; case 6:ri--;if(ri==0) ri=30;break; case 7:ri--;if(ri==0) ri=31;break; case 8:ri--;if(ri==0) ri=31;break; case 9:ri--;if(ri==0) ri=30;break; case 10:ri--;if(ri==0) ri=31;break; case 11:ri--;if(ri==0) ri=30;break; case 12:ri--;if(ri==0) ri=31;break; }write_nyr(8,ri);write_com(0x80+0x08);write_ds(7,ri);}if(numfun==6){yue--;if(yue==-1)yue=12;write_nyr(5,yue);write_com(0x80+0x05);write_ds(8,yue);}if(numfun==7){nian--;if(nian==-1)nian=99;leap=nian%4==0&&nian%100!=0; write_nyr(2,nian);write_com(0x80+2);write_ds(9,nian);}}}}void set_alarm(){uchar ashi,afen,amiao;if(timeclk==0)//判断是否按下闹钟设定键{delay(5);//延时消抖if(timeclk==0){while(!timeclk);anumfun++;//按键次数加1if(anumfun==1){flag=1;write_com(0x80+0x40+0x0a); write_com(0x0f);}if(anumfun==2){flag=1;write_com(0x80+0x40+0x07); write_com(0x0f);}if(anumfun==3){flag=1;write_com(0x80+0x40+0x04); write_com(0x0f);}{flag=0;anumfun=0;}}}if(anumfun!=0){if(timeadd==0)//如果加功能键按下{delay(5);while(!timeadd);if(anumfun==1) //设定秒{amiao++;if(amiao==60)amiao=0;write_sfm(9,amiao);write_com(0x80+0x40+9); write_ds(1,amiao);}{afen++;if(afen==60)afen=0;write_sfm(6,afen);write_com(0x80+0x40+6); write_ds(3,afen);}if(anumfun==3){ashi++;if(ashi==24)ashi=0;write_sfm(3,ashi);write_com(0x80+0x40+3); write_ds(5,ashi);}}}if(anumfun!=0){if(timesub==0){delay(5);while(!timesub);if(anumfun==1){amiao--;if(amiao==-1)amiao=59;write_sfm(9,amiao);write_com(0x80+0x40+9); write_ds(1,amiao);}if(anumfun==2){afen--;if(afen==-1)afen=59;write_sfm(6,afen);write_com(0x80+0x40+6); write_ds(3,afen);}if(anumfun==3){ashi--;if(ashi==-1)ashi=23;write_sfm(3,ashi);write_com(0x80+0x40+3);write_ds(5,ashi);}}}}void init(){EA=1;//开总中断EX0=1;//开外部中断0IT0=1;//设定触发方式为负跳变沿有效lcden=0;//选通液晶显示屏ledrw=0;//设定液晶显示屏的读写方式为读write_com(0x38);//设置液晶显示模式为16*2显示,5*7点阵,8位数据接口 write_com(0x0c);//打开显示,并使光标不显示也不闪烁write_com(0x06);//光标指针每次自动加1write_com(1);//清屏write_com(0x80);//送地址指针for(num=0;num<16;num++){write_date(table[num]);delay(5);}write_com(0x80+0x40);//写到第二行for(num=0;num<11;num++){write_date(table1[num]);delay(5);}write_ds(0x0a,0x20);//开启时钟芯片振荡器 write_ds(0x0b,0x26);//开启闹钟read_ds(0x0c);//读取时钟芯片c寄存器}void main(){init();while(1){keyscan();set_alarm();if(flag1==1)didi();if(flag==0){//读取时间miao=read_ds(0x00);fen=read_ds(0x02);shi=read_ds(0x04);yue=read_ds(0x08);ri=read_ds(0x07);nian=read_ds(0x09);week=read_ds(0x06);//写入液晶显示屏write_sfm(9,miao);write_sfm(6,fen);write_sfm(3,shi);write_nyr(2,nian);write_nyr(5,yue);write_nyr(8,ri);write_zhou(0x0f,week);}}}void exter() interrupt 0{flag1=1;read_ds(0x0c);//读时钟芯片c寄存器。

基于51单片机电子万年历设计

基于51单片机电子万年历设计

一、引言电子万年历是一种以数字形式实时显示日期、星期和时间等信息的电子设备。

在现代人日常生活中,万年历是一种常见的小型电子产品。

本文将基于51单片机设计一款简单实用的电子万年历。

二、设计原理1.时钟模块:采用DS1302实时时钟模块。

DS1302通过三线式串行接口与51单片机进行通信,可以实时获取日期、星期和时间等信息。

2.显示模块:使用数码管显示日期、星期和时间等信息。

共使用四块共阳数码管,采用数码管模块进行驱动,通过IO口进行数据传输。

3.按键模块:设计四个按键,分别为设置、上、下和确定。

通过按键来调整日期、星期和时间等信息。

4.闹钟功能:加入闹钟功能,可以设定闹钟时间,到达设定时间时,会有提示音。

5.温湿度传感器:加入温湿度传感器,可以实时监测环境温湿度,并在数码管上进行显示。

6.外部电源:由于51单片机工作电压较高,需要使用外部电源进行供电。

三、硬件设计1.电源电路:使用稳压电源芯片LM7805进行5V稳压,将稳压后的电压供给单片机和各个模块。

2.时钟模块:DS1302模块与单片机通过串行通信进行连接。

时钟模块上的时钟信号、数据信号和复位信号分别与单片机的IO口相连。

3.数码管显示模块:共有四块共阳数码管,通过595芯片进行驱动。

单片机的IO口与595芯片的串行、时钟和锁存引脚相连,595芯片的输出引脚与数码管的各段相连。

4.按键模块:通过电阻分压来实现按键功能,按下按键时,相应的IO口会被拉低。

5.闹钟功能:使用蜂鸣器来产生提示音,通过IO口与单片机相连。

6.温湿度传感器:使用DHT11温湿度传感器。

传感器的数据引脚通过IO口与单片机相连。

四、软件设计1.时钟显示:通过DS1302获取日期、星期和时间等信息,将其转化为数码管需要的编码格式,并通过595芯片进行显示。

2.按键操作:对按键进行扫描,根据按键的不同操作进行相应的处理。

例如按下设置键进行日期和时间的设置,按下上下键进行数值的变化,按下确定键进行数值的确认。

用51单片机做的万年历,显示用12864液晶

用51单片机做的万年历,显示用12864液晶

LCD12864.c#include "reg52.h"#include "intrins.h"#define uchar unsigned char#define uint unsigned int#define LCD_DB_PORT P0 //液晶DB0~DB7 #define LCD_START_ROW 0xc0 //起始行#define LCD_PAGE 0xb8 //页指令#define LCD_COL 0x40 //列指令//液晶引脚定义sbit LCD_DI=P2^0;sbit LCD_RW=P2^1;sbit LCD_E=P2^2;sbit LCD_CS1=P2^3;sbit LCD_CS2=P2^4;sbit LCD_RST=P2^5;bit Reverse_Display=0;//检查LCD是否忙bit LCD_Check_Busy(void){ LCD_DB_PORT=0xff;LCD_RW=1; _nop_(); LCD_DI=0;LCD_E=1; _nop_(); LCD_E=0;return(bit)(P0&0x80);}//向LCD发送命令void LCD_Write_Command(uchar c){ while(LCD_Check_Busy());LCD_DB_PORT=0xff; LCD_RW=0; _nop_(); LCD_DI=0;LCD_DB_PORT=c; LCD_E=1; _nop_(); LCD_E=0;}//向LCD发送数据void LCD_Write_Data(uchar d){ while(LCD_Check_Busy());LCD_DB_PORT=0xff;LCD_RW=0;_nop_();LCD_DI=1;//根据Reverse_Display决定是否反相显示if(!Reverse_Display)LCD_DB_PORT=d;else LCD_DB_PORT=~d;LCD_E=1;_nop_();LCD_E=0;}//初始化LCDvoid LCD_Initialize(void){ LCD_CS1=1;LCD_CS2=1;LCD_Write_Command(0x38);LCD_Write_Command(0x0f);LCD_Write_Command(0x01);LCD_Write_Command(0x06);LCD_Write_Command(LCD_START_ROW);}//通用显示函数//从第P页第L列开始显示W个字节数据,数据在r所指向的缓冲//每字节8位是垂直显示的,高位在下,低位在上//每个8*128的矩形区域为一页//整个LCD右由64*64的左半屏和64*64的右半屏构成void Common_Show(uchar P,uchar L,uchar W,uchar *r){ uchar i;if(L<64) //显示在左半屏或左右半屏{ LCD_CS1=1;LCD_CS2=0;LCD_Write_Command(LCD_PAGE+P);LCD_Write_Command(LCD_COL+L);if(L+W<64) //全部显示在左右半屏{ for(i=0;i<W;i++)LCD_Write_Data(r[i]);}else //如果越界则跨左右半屏显示{ for(i=0;i<64-L;i++)LCD_Write_Data(r[i]); //左半屏显示LCD_CS1=0;LCD_CS2=1; //右半屏显示LCD_Write_Command(LCD_PAGE+P);LCD_Write_Command(LCD_COL);for(i=64;i<W;i++)LCD_Write_Data(r[i]);}}else //全部显示在右半屏{ LCD_CS1=0;LCD_CS2=1;LCD_Write_Command(LCD_PAGE+P);LCD_Write_Command(LCD_COL+L-61);for(i=0;i<W;i++)LCD_Write_Data(r[i]);}}//显示8*16点阵字符void Display_A_Char_8X16(uchar P,uchar L,uchar *M) { Common_Show(P,L,8,M);Common_Show(P+1,L,8,M+8);}//显示一个16*16点阵汉字void Display_A_WORD(uchar P,uchar L,uchar *M) { Common_Show(P,L,16,M); //显示汉字上半部分Common_Show(P+1,L,16,M+16);}Main.c#include "reg52.h"#include "intrins.h"#include "string.h"#include "LCD_12864.c"#define uchar unsigned char#define uint unsigned int/*extern void LCD_Initialize(void);extern void Display_A_Char_8X16(uchar P,uchar L,uchar *M); extern void Display_A_WORD(uchar P,uchar L,uchar *M);//在调整日期时间时,用该位决定是否反白显示extern bit Reverse_Display=0;*/sbit SDA=P1^0; //DS1302数据线sbit CLK=P1^1; //DS1302时钟线sbit RST=P1^2; //DS1302复位线sbit k1=P3^4; //选择sbit k2=P3^5; //加sbit k3=P3^6; //减sbit k4=P3^7; //确定uchar tCount=0;//一年中每个月的天数,2月的天数由年份决定uchar MonthsDays[]={0,31,0,31,30,31,30,31,31,30,31,30,31};//所读取的日期时间uchar DateTime[7];//当前调整的时间对象:秒,分,时,日,月,年(0,1,2,3,4,6)//5对应星期,星期调节由年月日调整自动完成char Adjust_Index=-1;//水平与垂直偏移uchar H_Offset=10,V_Page_Offset=0;//年月日,星期,时分秒汉字点阵(16*16)------------------------------- uchar code DATE_TIME_WORDS[]={/*-- 文字: 年--*//*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/0x00,0x20,0x18,0xC7,0x44,0x44,0x44,0x44,0xFC,0x44,0x44,0x44,0x44,0x 04,0x00,0x00,0x04,0x04,0x04,0x07,0x04,0x04,0x04,0x04,0xFF,0x04,0x04,0x04,0x04,0x 04,0x04,0x00,/*-- 文字: 月--*//*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/0x00,0x00,0x00,0xFE,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0xFE,0x 00,0x00,0x00,0x80,0x40,0x30,0x0F,0x02,0x02,0x02,0x02,0x02,0x02,0x42,0x82,0x7F,0x/*-- 文字: 日--*//*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/0x00,0x00,0x00,0xFE,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0xFE,0x00,0x 00,0x00,0x00,0x00,0x00,0x00,0xFF,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0xFF,0x00,0x 00,0x00,0x00,/*-- 文字: 星--*//*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/0x00,0x00,0x00,0xBE,0x2A,0x2A,0x2A,0xEA,0x2A,0x2A,0x2A,0x3E,0x00, 0x00,0x00,0x00,0x00,0x44,0x42,0x49,0x49,0x49,0x49,0x7F,0x49,0x49,0x49,0x49,0x41,0x 40,0x00,0x00,/*-- 文字: 期--*//*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/0x00,0x04,0xFF,0x24,0x24,0x24,0xFF,0x04,0x00,0xFE,0x22,0x22,0x22,0xF E,0x00,0x00,0x88,0x48,0x2F,0x09,0x09,0x19,0xAF,0x48,0x30,0x0F,0x02,0x42,0x82,0x 7F,0x00,0x00,/*-- 文字: 时--*//*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/0x00,0xFC,0x84,0x84,0x84,0xFC,0x00,0x10,0x10,0x10,0x10,0x10,0xFF,0x0x00,0x3F,0x10,0x10,0x10,0x3F,0x00,0x00,0x01,0x06,0x40,0x80,0x7F,0x0 0,0x00,0x00,/*-- 文字: 分--*//*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/0x80,0x40,0x20,0x90,0x88,0x86,0x80,0x80,0x80,0x83,0x8C,0x10,0x20,0x 40,0x80,0x00,0x00,0x80,0x40,0x20,0x18,0x07,0x00,0x40,0x80,0x40,0x3F,0x00,0x00,0x 00,0x00,0x00,/*-- 文字: 秒--*//*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/0x24,0x24,0xA4,0xFE,0x23,0x22,0x00,0xC0,0x38,0x00,0xFF,0x00,0x08,0x 10,0x60,0x00,0x08,0x06,0x01,0xFF,0x01,0x06,0x81,0x80,0x40,0x40,0x27,0x10,0x0C,0x 03,0x00,0x00,};//星期几的汉字点阵(16*16)----------------------------------uchar code WEEDDAY_WORDS[]={/*-- 文字: 日--*//*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/0x00,0x00,0x00,0xFE,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0xFE,0x00,0x 00,0x00,0x00,0x00,0x00,0x00,0xFF,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0xFF,0x00,0x 00,0x00,0x00,/*-- 文字: 一--*//*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x 80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x 00,0x00,0x00,/*-- 文字: 二--*//*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/0x00,0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x 00,0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x 10,0x10,0x00,/*-- 文字: 三--*//*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/0x00,0x04,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x 04,0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x 20,0x20,0x00,/*-- 文字: 四--*//*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/0x00,0xFC,0x04,0x04,0x04,0xFC,0x04,0x04,0x04,0xFC,0x04,0x04,0x04,0x FC,0x00,0x00,0x00,0x7F,0x28,0x24,0x23,0x20,0x20,0x20,0x20,0x21,0x22,0x22,0x22,0x 7F,0x00,0x00,/*-- 文字: 五--*//*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/0x00,0x02,0x42,0x42,0x42,0xC2,0x7E,0x42,0x42,0x42,0x42,0xC2,0x02,0x 02,0x00,0x00,0x40,0x40,0x40,0x40,0x78,0x47,0x40,0x40,0x40,0x40,0x40,0x7F,0x40,0x 40,0x40,0x00,/*-- 文字: 六--*//*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/0x20,0x20,0x20,0x20,0x20,0x20,0x21,0x22,0x2C,0x20,0x20,0x20,0x20,0x 20,0x20,0x00,0x00,0x40,0x20,0x10,0x0C,0x03,0x00,0x00,0x00,0x01,0x02,0x04,0x18,0x 60,0x00,0x00,};//半角数字点阵(8*16)---------------------------------------------------- uchar code DIGITS[]={/*-- 文字: 0 --*//*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,/*-- 文字: 1 --*//*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x 20,0x00,0x00,/*-- 文字: 2 --*//*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x 21,0x30,0x00,/*-- 文字: 3 --*//*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x 11,0x0E,0x00,/*-- 文字: 4 --*//*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x 3F,0x24,0x00,/*-- 文字: 5 --*//*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x 11,0x0E,0x00,/*-- 文字: 6 --*//*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x 11,0x0E,0x00,/*-- 文字: 7 --*//*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x 00,0x00,0x00,/*-- 文字: 8 --*//*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x 22,0x1C,0x00,/*-- 文字: 9 --*//*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x 11,0x0F,0x00,};//向DS1302写入一字节void Write_A_Byte_TO_DS1302(uchar x){ uchar i;for(i=0;i<8;i++){ SDA=x&1; CLK=1; CLK=0; x>>=1;}}//从DS1302读取一字节uchar Get_A_Byte_FROM_DS1302(void) { uchar i,b,t;for(i=0;i<8;i++){ b>>=1; t=SDA; b|=t<<7; CLK=1; CLK=0;}//BCD码转换return(b/16*10+b%16);}//从DS1302指定位置读数据uchar Read_Data(uchar addr){ uchar dat;RST=0; CLK=0; RST=1;Write_A_Byte_TO_DS1302(addr);dat=Get_A_Byte_FROM_DS1302();CLK=1; RST=0;return(dat);}//向DS1302某地址写入数据void Write_DS1302(uchar addr,uchar dat){ CLK=0; RST=1;Write_A_Byte_TO_DS1302(addr);Write_A_Byte_TO_DS1302(dat);CLK=0; RST=0;}//设置时间void SET_DS1302(void){ uchar i;Write_DS1302(0x8e,0x00);//秒分时日月年依次写入for(i=0;i<7;i++){ //秒的起始地址1000 0000(0x80)//后续依次是分,时,月,周,年,写入地址每次递增2Write_DS1302(0x80+2*i,(DateTime[i]/10<<4)|(DateTime[i]%10));}Write_DS1302(0x8e,0x80);}//读取当前日期时间void GetTime(void){ uchar i;for(i=0;i<7;i++){ DateTime[i]=Read_Data(0x81+2*i);}}//半断是否为闰年uchar isLeapYear(uint y){ return((y%4==0&&y%100!=0)||(y%400==0)); }//--------------------------------------------//求自2000.1.1开始的任何一天是星期几//函数没有通过,求出总天数后在求出星期几//因为求总天数可能会月出uint的范围//--------------------------------------------void RefreshWeekDay(void){ uint i,d,w=5; //已知1999.12.31是周五for(i=2000;i<2000+DateTime[6];i++){ d=isLeapYear(i)?366:365;w=(w+d)%7;}d=0;for(i=1;i<DateTime[4];i++)d+=MonthsDays[i];d+=DateTime[3];//保存星期,0~6表示星期日,星期一,二,、、、六,为了与DS1302的星期格式匹配,返回值需要加1DateTime[5]=(w+d)%7+1;}//年月日时分秒++/--void DateTime_Adjust(char x){ switch(Adjust_Index){ case 6: //年00-99if(x==1&&DateTime[6]<99)DateTime[6]++;if(x==-1&&DateTime[6]>0)DateTime[6]--;//获取2月天数MonthsDays[2]=isLeapYear(2000+DateTime[6])?29:28;//如果年份变化后当前月份的天数大于上限则设为上限if(DateTime[3]>MonthsDays[DateTime[4]])DateTime[3]=MonthsDays [DateTime[4]];RefreshWeekDay(); //刷新星期break;case 4: //月01-12if(x==1&&DateTime[4]<12)DateTime[4]++;if(x==-1&&DateTime[4]>1)DateTime[4]--;//获取2月份天数MonthsDays[2]=isLeapYear(2000+DateTime[6])?29:28;//如果月份变化后当前月份的天数大于上限则设为上限if(DateTime[3]>MonthsDays[DateTime[4]])DateTime[3]=MonthsDays [DateTime[4]];RefreshWeekDay(); //刷新星期break;case 3: //日00-28/29/30/31;调节之前首先根据年份得出该年中2月的天数MonthsDays[2]=isLeapYear(2000+DateTime[6])?29:28;//根据当前月份决定调节日期的上限if(x==1&&DateTime[3]<MonthsDays[DateTime[4]])DateTime[3]++;if(x==-1&&DateTime[3]>1)DateTime[3]--;RefreshWeekDay(); //刷新星期break;case 2: //时if(x==1&&DateTime[2]<23)DateTime[2]++;if(x==-1&&DateTime[3]>1)DateTime[2]--;break;case 1: //分if(x==1&&DateTime[1]<59)DateTime[1]++;if(x==-1&&DateTime[1]>1)DateTime[1]--;break;case 0: //秒if(x==1&&DateTime[0]<59)DateTime[0]++;if(x==-1&&DateTime[0]>1)DateTime[0]--;}}//定时器0每秒刷新LCD显示void T0_INT(void) interrupt 1{ TH0=-50000/256;TL0=-50000%256;if(++tCount!=2)return;tCount=0;if(Adjust_Index==-1)GetTime(); //如果未执行调整操作则正常读取当前时间//年后两位Reverse_Display=Adjust_Index==6; /*等同于{ if(Adjust_Index==6)Reverse_Display=1;else Reverse_Display=0; } */Display_A_Char_8X16(V_Page_Offset,16+H_Offset,DIGITS+DateTime [6]/10*16);Display_A_Char_8X16(V_Page_Offset,24+H_Offset,DIGITS+DateTime [6]%10*16);//月Reverse_Display=Adjust_Index==4;Display_A_Char_8X16(V_Page_Offset,48+H_Offset,DIGITS+DateTime [4]/10*16);Display_A_Char_8X16(V_Page_Offset,56+H_Offset,DIGITS+DateTime [4]%10*16);//日Reverse_Display=Adjust_Index==3;Display_A_Char_8X16(V_Page_Offset,80+H_Offset,DIGITS+DateTime [3]/10*16);Display_A_Char_8X16(V_Page_Offset,88+H_Offset,DIGITS+DateTime [3]%10*16);//星期Reverse_Display=Adjust_Index==5;Display_A_WORD(V_Page_Offset+2,96+H_Offset,WEEDDAY_WORDS +(DateTime[5]-1)*32);//时Reverse_Display=Adjust_Index==2;Display_A_Char_8X16(V_Page_Offset+5,16+H_Offset,DIGITS+DateTi me[2]/10*16);Display_A_Char_8X16(V_Page_Offset+5,24+H_Offset,DIGITS+DateTi me[2]%10*16);//分Reverse_Display=Adjust_Index==1;Display_A_Char_8X16(V_Page_Offset+5,48+H_Offset,DIGITS+DateTi me[1]/10*16);Display_A_Char_8X16(V_Page_Offset+5,56+H_Offset,DIGITS+DateTi me[1]%10*16);//秒Reverse_Display=Adjust_Index==0;Display_A_Char_8X16(V_Page_Offset+5,80+H_Offset,DIGITS+DateTi me[0]/10*16);Display_A_Char_8X16(V_Page_Offset+5,88+H_Offset,DIGITS+DateTi me[0]%10*16);}//键盘中断(INT0)void EX_INT0(void) interrupt 0{ if(k1==0) //选择调整对象{ if(Adjust_Index==-1||Adjust_Index==0)Adjust_Index=7;Adjust_Index--;if(Adjust_Index==5)Adjust_Index=4; //跳过对星期的调整}else if(k2==0)DateTime_Adjust(1); //加else if(k3==0)DateTime_Adjust(-1); //减else if(k4==0) //确定{ SET_DS1302(); //将调整后的时间写入DS1302Adjust_Index=-1; //操作索引重设为-1,时间继续正常显示}}//主程序void main(){ //液晶初始化LCD_Initialize();//显示年的固定前两位Display_A_Char_8X16(V_Page_Offset,0+H_Offset,DIGITS+2*16);Display_A_Char_8X16(V_Page_Offset,8+H_Offset,DIGITS);//显示固定汉字:年月日,星期,时分秒Display_A_WORD(V_Page_Offset,32+H_Offset,DATE_TIME_WORDS+ 0*32);Display_A_WORD(V_Page_Offset,64+H_Offset,DATE_TIME_WORDS+ 1*32);Display_A_WORD(V_Page_Offset,96+H_Offset,DATE_TIME_WORDS+ 2*32);Display_A_WORD(V_Page_Offset+2,64+H_Offset,DATE_TIME_WORD S+3*32);Display_A_WORD(V_Page_Offset+2,80+H_Offset,DATE_TIME_WORD S+4*32);Display_A_WORD(V_Page_Offset+5,32+H_Offset,DATE_TIME_WORD S+5*32);Display_A_WORD(V_Page_Offset+5,64+H_Offset,DATE_TIME_WORD S+6*32);Display_A_WORD(V_Page_Offset+5,96+H_Offset,DATE_TIME_WORD S+7*32);//允许INT0,T0中断IE=0x83;IP=0x01;IT0=0x01;TH0=-50000/256;TL0=-50000%256;TR0=1;while(1);}。

51单片机万年历实验原理解析

51单片机万年历实验原理解析

51单片机万年历实验原理解析51单片机万年历(Real-time Clock)是一种集成电路,可以提供精确的日期和时间信息。

它是基于包含计时器和日历的时钟电路设计的。

本文将深入解析51单片机万年历实验的原理和实现过程。

1. 引言在现代科技领域中,人们对时间的准确性和精确度要求越来越高。

而万年历是一种可靠的工具,能够提供准确的日期和时间信息,因此被广泛应用在各种领域,如电子设备、通信系统和科学研究等。

51单片机万年历作为一种常用的设计方案,本文将对其原理和实验进行解析。

2. 51单片机概述51单片机是一种基于哈佛架构的芯片,常应用于嵌入式系统开发。

它具有易于编程、高性能和低功耗的特点,因此在电子行业中得到广泛应用。

而51单片机万年历则是在该芯片上实现的一种功能,它通过连接外部时钟电路和定时器模块,实现了精确的时间显示和日期计算。

3. 51单片机万年历实验原理我们需要连接一个可靠的时钟电路到51单片机上,以提供准确的时间基准。

这个时钟电路可以是一个晶体振荡器,它会产生一个稳定的频率信号,用来驱动定时器模块。

我们需要配置定时器模块,以便实现时间的计算和显示功能。

定时器可以设置定时时间和工作模式,例如计时模式和计数模式。

通过定时器中断,我们可以精确地控制和记录时间的变化。

接下来,我们需要编写一段程序来读取定时器的计数值,并将其转换为具体的日期和时间。

这个过程涉及到将计数值分解为年、月、日、时、分、秒,然后进行相应的转换和计算。

我们将通过数码管、液晶显示屏或其他输出设备来显示转换后的日期和时间。

这些输出设备可以根据需要进行相应的驱动和控制,以实现清晰和直观的显示效果。

4. 实验结果和应用通过上述步骤,我们成功实现了51单片机万年历的原理和功能。

该实验可以应用于各种领域,如电子产品、智能家居和计时设备等。

在电子产品中,51单片机万年历可以作为一个重要的功能模块,为用户提供准确的日期和时间信息。

它还可以和其他模块进行联动,实现更复杂的功能,如定时开关、闹钟和事件提醒等。

51单片机万年历实验原理

51单片机万年历实验原理

51单片机万年历实验原理
51单片机是一种常见的微控制器,可以实现多种应用程序。

万年历是一种实用的时间管理工具,它可以显示日期、时间、星期和节气等信息。

在51单片机万年历实验中,首先需要确定使用的硬件平台,例如STC89C52单片机、数码管、按键等。

然后,需要编写程序,实现以下功能:
1. 显示当前日期及时间:通过编写程序,可以读取单片机内部的定时器计数器的值,将其转换为实际的日期和时间信息,并在数码管上实时显示。

2. 显示当前星期和节气:通过计算当前日期,可以得到对应的星期和节气信息,然后在数码管上显示。

3. 调节日期和时间:通过按键输入,可以实现对日期和时间的调节,包括增加、减少、设置等操作。

4. 程序稳定性和可靠性:在编写程序时,需要考虑到单片机的稳定性和可靠性问题,尽可能避免程序的崩溃或出错。

总之,51单片机万年历实验是一种实用的应用程序,可以帮助我们更好地管理时间,同时也是学习单片机编程和应用的一个好的案例。

51单片机汇编语言万年历完美版.

51单片机汇编语言万年历完美版.

;**************万年历制作 BY----信工七班 ;**************************** ;***************************** ;----------------------------------------------------------------------------------------- RCK BIT P0.5 SCK BIT P0.4 DAT BIT P0.7 RST BIT P0.6 BUZZER BIT P1.3 ;蜂鸣器 BYTE EQU 40H ;用于给锁存器送入数据 GEWEI EQU 41H ;用于存放数码管显示的第一位 SHIWEI EQU 42H ;用于存放数码管显示的第二位 BAIWEI EQU 43H ;用于存放数码管显示的第三位 QIANWEI EQU 44H ;用于存放数码管显示的第四位 TEMP1 EQU 45H TEMP2 EQU 46H COUNT EQU 47H ;用于扩展定时器计数时间 KTIME EQU 49H TEMP EQU 50H DMS EQU 51H ;用于存放运动秒表的最低位 DSECOND EQU 52H ;用于存放运动秒表的秒 DMIN EQU 53H ;用于存放运动秒表的分钟 CLKMIN EQU 54H ;用于存放闹钟分钟 CLKHOUR EQU 55H ;用于存放闹钟时 CLKF EQU 56H ;用于闹钟开启的标志位 ;----------------------------------------------------------------------------------------- ORG 0000H AJMP MAIN ORG 000BH ;定时器0中断入口地址 AJMP T0_INT ORG 001BH ;定时器1中断入口地址 AJMPT1_INT ;********************************主程序************************************************* ;----------------------------------------------------------------------------------------- MAIN: MOV R4,#00 ;计数秒 MOVR5,#50 ;计数分 MOV R6,#15 ;计数时 MOV R0,#14H ;2013年 MOV R1,#0DH MOV R2,#6 ;6月 MOV R3,#18 ;18日 MOV COUNT,#0H MOV A,#5 ;开始使A不等于0,用于后面的判断 MOV CLKMIN,#0H MOV CLKHOUR,#0H MOV CLKF,#0H MOV SP,#60H MOV TMOD,#11H ;设置定时器0为工作模式1 MOV TH0, #03CH MOV TL0, #0B0H ;定时50000 us MOV TH1, #0D8H MOV TL1, #0F0H ;定时1000us=1MS SETB ET0 ;允许定时器中断 SETB ET1 SETB EA ;允许全局中断 SETB PT0 ;定时器中断设为高优先级 SETB EX0 ;允许外部中断 SETB EX1 SETB IT0 ;外部中断设为下降沿触发 SETB IT1 SETB TR0 ;启动定时器 ;--------------------------------------- START: MOV DPTR,#TABLE LJMP KEYSCAN ;首先进入时间显示,由于地址相差太远所以代码顺序有所改变 ;-------------------------------------- MARK2: LJMP KEYSCAN ;地址差跳远无法跳转,此处进行中间跳转到时间显示界面 KEYCLK: MOV A,CLKF ;此处为闹钟设置刚进入时的程序,由按键s12进入 JNZ KEYCLKF ;进入后通过CLKF来判断闹钟功能是否启动,未启动时正常 ;显示为SHOWCLKF,启动时显示SHOWCLKF1,此两种显示差一个数码管最低位标志的点 KEYCLK1: LCALL SHOWCLK ;此处判定未启动闹钟功能时的显示 LCALL S4 ;在闹钟界面查看有无切换显示模式(此处也可认为是确定 ;按键)的按键s4按下, JZ MARK2 ;按下后跳转到时间显示 LCALL S8 ;在闹钟显示界面下查看启动闹钟功能的键s8是否按下MOV A,CLKF JNZ KEYCLKF ;按下后显示SHOWCLKF1的显示 LCALL S16 ;未按下则显示没有闹钟标志的数码管显示,再查看有无进 ;入调节s16的键按下,CJNE A,#7EH,KEYCLK1 ;未按下继续闹钟界面显示 KEYCLK2: LCALL SCLKMIN ;按下进入调节 MOV A,CLKMIN ;显示设置分钟的调节 MOV TEMP,A LCALL KEYSUB1 ;通过加减键s8,s12来设置闹钟 LCALL KEYADD1 MOV A,TEMP SUBB A,#60 ;调节分钟不超过59 JC REMAIN0 MOV TEMP,#0 REMAIN0: MOV A,TEMP MOV CLKMIN,A LCALL S16 ;查看有无进入调节s16的键按下, CJNE A,#7EH,KEYCLK2 ;未按下继续显示分钟调节 KEYCLK3: LCALL SCLKHOUR ;按下进入显示时调节 MOV A,CLKHOUR MOV TEMP,A ;送入参数,通过加减键进行调节设置 LCALL KEYSUB2 LCALL KEYADD2 MOV A,TEMP SUBB A,#24 ;时的设置不超过24 JC REMAIN1 MOV TEMP,#0 ;超过24置0 REMAIN1: MOVA,TEMP MOV CLKHOUR,A LCALL S16 CJNE A,#7EH,KEYCLK3 ;再次判断有无调节的切换键(按3次为确定)按下 KEYCLK4: LCALL SHOWCLK ;按下后跳转为闹钟的界面正常显示 LCALL S4 ;再判断有无切换显示模式的键按下,按下跳转显示 JZ KEYSCAN LCALL S8 ;再判断有无启动(关闭)闹钟功能的键按下 MOV A,CLKF ;根据CLKF(闹钟功能启动)的标志位显示不同的闹钟界面 JNZ KEYCLKF ;闹钟功能启动,跳转到KEYCLKF显示闹钟启动标记 GOON: LCALL S16 ;未启动则又判断有无进入调节的键按下 CJNE A,#7EH,KEYCLK4 ;没有按下继续正常显示 AJMP KEYCLK2 ;按下后重复KEYCLK2开始的内容 KEYCLKF: LCALL SHOWCLK1 ;显示出闹钟功能启动后的标记(数码管最低位标记) LCALLS4 ;查看有无切换显示模式(闹钟设置确定后)键按下 JZ KEYSCAN ;按下后跳转到显示时间的界面 LCALL S8 ;未按则扫描开启(关闭)闹钟功能的键按下 MOV A,CLKF JZ KEYCLK4 ;根据闹钟功能的标记位跳转显示,若判断闹钟功能关闭则 ;跳转到KEYCLK4 显示无标志的闹钟 LCALL S16 ;若判断闹钟功能开启则扫描有无进入调节的按键s16按下CJNE A,#7EH,KEYCLKF ;未按下则继续显示有标记的闹钟界面 AJMP KEYCLK2 ;按下后则又进入调节界面KEYCLK2 ;-------------------------------------------------- MARK3: LJMP MARK1 ;地址差跳远无法跳转,此处进行中间跳转到闹钟界面 ;---------------------------------------------------- KEYSCAN: LCALL HOURMINUTE ;显示时间 PUSH ACC ;为s12的判断先把A入堆栈,否则s12出会出现判断错误LCALL S4 ;查看有无切换键s4按下,按下跳转显示秒 JZ KEYSCAN1 MOVA,CLKF ;在显示时间时判断闹钟功能是否开启,未开则跳转显示 JZ GO MOVA,R6 ;判断是否与闹钟设置的时间相等,R6---时 CJNE A,CLKHOUR,GO MOV A,R5 ;R5--分 CJNE A,CLKMIN,GO LCALL SOUND ;闹钟功能开启,时分相等,则闹铃响 ;-------------------------------------------------- GO: POP ACC ; 如果不pop,A=0一直成立,此时出现错误跳转 LCALL S12 ;查看有无进入闹钟设置的键按下 JZ MARK3 ; 按下则跳入显示闹钟设置界面 LCALL S16 ;查看有无进入调节键s16按下,按下进入调节 CJNE A,#7EH,KEYSCAN ;未按下则继续显示时间 SMINUTE: LCALL MINUTE ;s16按下后进入分调节显示 MOV TEMP,R5 ;将要调节的分钟送入函数参数 LCALL KEYADD1 ;进入调节后查看是否按下加法键s8,按下加一LCALL KEYSUB1 ;进入调节后查看是否按下减法键s8,按下减一 MOV A,TEMP SUBB A,#60 ;调节不超过60 JC REMAIN2 MOV TEMP,#0 REMAIN2: MOVR5,TEMP ;把运算完后的分钟送出显示 LCALL S16 CJNE A,#7EH,SMINUTE ;没有s16按下,继续显示分调节 SHOUR: LCALL HOUR ;按下后进入显示时调节 MOV TEMP,R6 ;R6为装时的寄存器,送入参数进行调节 LCALL KEYADD2 LCALL KEYSUB2 MOV A,TEMP SUBB A,#24 ;调节不超过24 JC REMAIN3 MOV TEMP,#0 REMAIN3: MOV R6,TEMP LCALL S16 ; 再次按下s16键可确定时间调节完成 CJNE A,#7EH,SHOUR AJMP KEYSCAN ;调节完后重新正常显示时间 ;--------------------------------------- ;--------------------------------------- KEYSCAN1: LCALL SHOWSECOND ;按切换键s4后进入的秒显示 LCALL S4 ;与时间显示的时候一样查看有无切换模式的键按下 JZ KEYSCAN2 ;按下则跳转显示日期 LCALL S12 ;此处为查看有无进入闹钟功能的键按下,有则跳转 JZ MARK1 LCALL S16 ;若无闹钟键按下,查看有无进入调节的键s16按下 CJNE A,#7EH,KEYSCAN1 SMS: LCALL MS ;调节键按下显示需要调节内容 MOV A,COUNT ;与之前的一样把调节参数送入进行调节,此处调姐秒显示的低位 MOV TEMP,A LCALL KEYADD1 LCALL KEYSUB1 MOV A,TEMP SUBB A,#60 ;调节不超过60 JC REMAIN4 MOV TEMP,#0 MOV A,TEMP REMAIN4: MOVA,TEMP MOV COUNT,A LCALL S16 ;查看有无切换调节内容的键s16按下CJNE A,#7EH,SMS ;没有s16键按下则显示原先调节内容 SSECOND: LCALL SECOND ;有键s16按下则显示进入秒的调节 MOV TEMP,R4 ;参数送入进行调节LCALL KEYADD2 LCALL KEYSUB2 MOV A,TEMP SUBB A,#60 ;调节不超过60 JC REMAIN9 MOV TEMP,#0 REMAIN9: MOV R4,TEMP LCALL S16 ; 再次按下s16键可确定时间调节完成 CJNE A,#7EH,SSECOND ;未按下则继续显示选中的调节内容 AJMP KEYSCAN1 ;---------------------------------------- MARK1: LJMP KEYCLK ;地址差跳远无法跳转,此处进行中间跳转到闹钟界面 ;---------------------------------------- KEYSCAN2: LCALL SHOWDAY ;此处为日期显示,当切换模式键按下两下后进入显示 LCALL S4 ;与时间显示的时候一样查看有无切换模式的键按下JZ KEYSCAN3 ;按下则跳转显示年份 LCALL S12 ;此处为查看有无进入闹钟功能的键按下,有则跳转 JZ MARK1 LCALL S16 ;若无闹钟键按下,查看有无进入调节的键s16按下 CJNE A,#7EH,KEYSCAN2 SDAY: LCALL DAY ;调节键按下显示需要调节内容,此处为日 MOV TEMP,R3 ; 把日期寄存器R2的值送入临时变量用于调节 LCALL KEYADD1 ;调用加减按键扫描,按下后进行操作 LCALL KEYSUB1 MOV A,TEMP SUBB A,#32 ;调节不超过31 JC REMAIN5 MOV TEMP,#0 REMAIN5: MOV R3,TEMP LCALL S16 ;查看有无切换调节内容的键s16按下 CJNE A,#7EH,SDAY ;没有s16键按下则显示原先调节内容 SSMOUNTH: LCALL MOUNTH ;有键s16按下则显示进入月的调节 MOV TEMP,R2 LCALL KEYADD2LCALL KEYSUB2 MOV A,TEMP SUBB A,#13 ;调节不超过12 JC REMAIN6 MOV TEMP,#0 REMAIN6: MOV R2,TEMP LCALL S16 ; 再次按下s16键可确定时间调节完成 CJNE A,#7EH,SSMOUNTH ;未按下则继续显示选中的调节内容 AJMP KEYSCAN2 ;--------------------------------------------- ;---------------------------------------------- KEYSCAN3: LCALL SHOWYEAR ;此处为日期显示,当切换模式键按下三下后进入显示 LCALL S4 JZ SHOW0 ;代码的内容除了显示的内容不同其他和以上的一样 LCALL S12 JZ MARK1 LCALL S16 CJNE A,#7EH,KEYSCAN3 SYEAR1: LCALL YEAR1 MOV TEMP,R1 LCALL KEYADD1 LCALL KEYSUB1 MOVA,TEMP SUBB A,#100 ;调节不超过99 JC REMAIN7 MOV TEMP,#0 REMAIN7: MOV R1,TEMP LCALL S16 ; CJNE A,#7EH,SYEAR1 SYEAR2: LCALL YEAR2 MOV TEMP,R0 LCALL KEYADD2 LCALL KEYSUB2 MOV A,TEMP SUBBA,#100 ;调节不超过99 JC REMAIN8 MOV TEMP,#0 REMAIN8: MOV R0,TEMP LCALL S16 CJNE A,#7EH,SYEAR2 AJMP KEYSCAN3 ;------------------------------------------ MARK: LJMP KEYSCAN ;地址差跳远无法跳转,此处进行中间跳转到时间显示界面 ;------------------------------------------ SHOW0: MOV DMS,#0 ;切换键按下四次后此时切换到运动秒表计时从0开始计时 MOV DMIN,#0 MOV DSECOND,#0 LCALL SHOWDD ; 刚进入运动秒表模式,显示全为0 LCALL S4 JZ MARK LCALL S16 CJNE A,#7EH,SHOW0 ;运动秒表开始键按下,则计时开始,否则继续显示0 SETB TR1 ;开启定时器1 SHOWD: LCALL SHOWDD ;开始键s16按下后显示变化的数字 LCALL S4 ;查看有无模式显示键的按下 JZ MARK ;按下则跳转显示LCALL S16 ;查看s16有无按下 CJNE A,#7EH,SHOWD ;再次按下该键s16,停止计时 CLR TR1 ;关闭定时器1 SHOWTING: LCALL SHOWDD ;显示为定时的内容LCALL S4 ;查看有无模式显示键的按下 JZ MARK LCALL S16 CJNEA,#7EH,SHOWTING ;再次按下s16,显示继续上次状态开始计时 SETB TR1 ;再次开启定时器 SHOWTING1: LCALL SHOWDD ;显示定时变化的定时内容 LCALL S4 JZ MARK LCALL S16 CJNE A,#7EH,SHOWTING1 ;再按一下s16再次进入暂停状态 CLR TR1 SHOWTING2: LCALL SHOWDD LCALL S4 JZ MARK LCALL S16CJNE A,#7EH,SHOWTING2 AJMP SHOW0 ;再按一下s16 内容清零,重新进入初始化运动秒表模式 ;---------------------------------------------此段主要为调节、显示的过程内容 ;************主程序结束****************************************************************** ;--------------出程序结束,一下为各个子函数 ;向74hc595发送一个字,并显示数据 ;----------------------------------------------------------------------------------------- SENDBYTE: MOV BYTE,A ;送入需要写入锁存器的参数 MOV A, #1 ;用1来移位选取各个位的数据ANL A,BYTE ;用与来选取数据 JNZ SEND CLR DAT ;与后结果为0则送入0 CLR SCK ;将写入的数据进行右移 SETB SCK AJMP LOOP ;跳转继续重复7次 SEND: SETB DAT ;与后结果不为0,则送入数据1 CLR SCK SETB SCK ;--------送入第一位数据 LOOP: MOV R7,#7 MOV A, #1 LOOP1: RL A MOV B,A ANL A,BYTE JNZ SEND1 SEND0: CLR DAT ;送0 AJMP SUOCUN SEND1: SETB DAT ;送1 AJMP SUOCUN SUOCUN: CLR SCK SETB SCK MOV A,B DJNZ R7,LOOP1 CLR RCK SETB RCK RET ;------------------------以上为数据进行输入锁存 DISPLAY: ACALL JISUAN DISPLAY1: MOV P0,#00H MOV A,GEWEI ACALL SENDBYTE ORLP0,#08H ;给出最左边数码管的位选 MOV R7,#10H LCALL DLY ;-----------显示最左边的数码管 MOV P0,#00H MOV R7,#03H LCALL DLY MOV A,SHIWEI ACALL SENDBYTE ORL P0,#04H ;给出第二位数码管的位选 MOV R7,#10H LCALL DLY ;--------------显示第二位数码管MOV P0,#00H MOV R7,#03H LCALL DLY MOV A,BAIWEI ACALL SENDBYTE ORL P0,#02H ;给出第三位数码管的位选 MOV R7,#10H LCALL DLY ;----------------显示第三位数码管 MOV P0,#00H MOV R7,#03H LCALL DLY MOV A,QIANWEI ACALL SENDBYTE ORL P0,#01H ;给出第三位数码管的位选 MOV R7,#10H LCALL DLY ;-------------------显示第四位数码管 RET ; ------------------------以上为数据显示 ;计算各位数的值把要显示的数进行分解 ;----------------------------------------- JISUAN: MOV A,TEMP1 MOV B,#10 DIV AB MOV TEMP1,B MOVC A,@A+DPTR MOV SHIWEI,A MOV A,TEMP1 MOVC A,@A+DPTR MOV GEWEI,A MOVA,TEMP2 MOV B,#10 DIV AB MOV TEMP2,B MOVC A,@A+DPTR MOVQIANWEI,A MOV A,TEMP2 MOVC A,@A+DPTR MOV BAIWEI,A RET ;-----------------以上为计算各个位数 ;----------------------------------------------------------------------------------------- ;显示高两位数(用于调节的时候显示) ;---------------------------------------------------------------------------------------- DISPLAY4: ACALL JISUAN MOV P0,#00H MOV A,BAIWEI ACALL SENDBYTE ORL P0,#02H MOV R7,#03H LCALL DLY ;----------------显示第三位数码管 MOV P0,#00H MOV R7,#03H LCALL DLY MOVA,QIANWEI ACALL SENDBYTE ORL P0,#01H MOV R7,#03H LCALL DLY ;-------------------显示第四位数码管 RET ;------------------------------------------------------------------------------------------ ;只显示低两位数(用于调节的时候显示) ;------------------------------------------------------------------------------------------ DISPLAY2: LCALL JISUAN MOV P0,#00H MOV A,GEWEI LCALL SENDBYTE ORL P0,#08H MOV R7,#03H LCALL DLY ;-----------显示最左边的数码管 MOV P0,#00H MOV R7,#03H LCALL DLY MOV A,SHIWEI LCALL SENDBYTE ORL P0,#04H MOV R7,#03H LCALL DLY ;--------------显示第二位数码管 MOV P0,#00H MOV R7,#03H LCALL DLY RET ;----------------------------------------------------------------------------------------- ;显示时间子程序 ;----------------------------------------------------------------------------------------- HOURMINUTE: MOV TEMP2,R6 MOV TEMP1,R5 LCALL JISUAN ORL BAIWEI,#01H ;--------第三个数码管显示小数点 LCALL DISPLAY1 RET ;由于只有四个数码管,此处显示时、分 SHOWSECOND: MOV TEMP2,R4 MOV A,COUNT MOV TEMP1,A LCALL JISUAN ORL BAIWEI,#01H LCALL DISPLAY1 RET ;此处单独显示秒 SHOWYEAR: MOV TEMP2,R0 MOV TEMP1,R1 LCALL DISPLAY RET SHOWDAY: MOV TEMP2,R2 MOV TEMP1,R3 LCALL DISPLAY RET SHOWCLK: MOV TEMP2,CLKHOUR MOV TEMP1,CLKMIN LCALL JISUAN ORL BAIWEI,#01H LCALL DISPLAY1 RET SHOWCLK1: MOV TEMP2,CLKHOUR MOV TEMP1,CLKMIN LCALL JISUAN ORL BAIWEI,#01H ORL GEWEI,#01H LCALL DISPLAY1 RET ;----------------------------------------------------------------------------------------- ;调节时间日期时独立显示每两位(用于调节的时候显示) ;---------------------------------------------------------------------------------------- MS: MOV TEMP1,COUNTLCALL DISPLAY2 RET SECOND: MOV TEMP2,R4 LCALL DISPLAY4 RET MINUTE: MOV TEMP1,R5 LCALL DISPLAY2 RET HOUR: MOV TEMP2,R6 LCALL DISPLAY4 RET DAY: MOV TEMP1,R3 LCALL DISPLAY2 RET MOUNTH: MOV TEMP2,R2 LCALL DISPLAY4 RET YEAR1: MOV TEMP1,R1 LCALL DISPLAY2 RET YEAR2: MOV TEMP2,R0 LCALL DISPLAY4 RET SCLKMIN: MOV TEMP1,CLKMIN LCALL DISPLAY2 RET SCLKHOUR: MOVTEMP2,CLKHOUR LCALL DISPLAY4 RET ;----------------------------------------------------------------------------------------- ;键盘扫描函数 ;---------------------------------------------------------------------------------------- ;切换调节显示内容键 S16: MOV P2,#0FFH CLRP2.7 JB P2.0,S16END MOV R7,#18H LCALL DLY JNB P2.0,$ ;当键盘松开时往下执行否则停留在这一步 MOV A,#7EH S16END: RET ;切换模式显示内容键 S4: MOV P2,#0FFH CLR P2.7 JB P2.3,S4END MOV R7,#18H LCALL DLY JNB P2.3,$ ;当键盘松开时往下执行否则停留在这一步 MOV A,#0H ;设置扫描标志位A=0 S4END: RET ;设置闹钟键扫描与减法键位同一键s12 S12: MOV P2,#0FFH CLR P2.7 JBP2.1,S12END MOV R7,#18H LCALL DLY JNB P2.1,$ ;当键盘松开时往下执行否则停留在这一步 MOV A,#0 ;设置扫描标志位A=0 S12END: RET ;用于确定启动闹钟功能的键盘扫描,与加法键位同一个 S8: MOV P2,#0FFH CLR P2.7 JB P2.2,S8END MOV R7,#18H LCALL DLY JNB P2.2,$ ;当键盘松开时往下执行否则停留在这一步MOV A,CLKF CPL A ;设置扫描标志位A=1 MOV CLKF,A S8END: RET ;单步、连续调节加法键 ;----------------------------------------------------------------------------------------- ;----------------------------------------------------------------------------------------- KEYADD2: MOV P2,#0FFH CLR P2.7 JB P2.2,ADDEND2 MOV R7,#18H LCALL DLY JT1: JNB P2.2,KT1 INC TEMP AJMP ADDEND2 KT1: INC KTIME MOV R7,#10H LCALL DLY ;用于调节高两位 MOV A,KTIME CJNEA,#30,JT1 ADD2: INC TEMP MOV A,TEMP CJNE A,#99,ON2 MOV TEMP,#0 ON2: MOV R7,TEMP MOV TEMP2,R7 LCALL DISPLAY4 MOV R7,#30H LCALL DLY JNB P2.2,ADD2 ADDEND2: RET KEYADD1: MOV P2,#0FFH CLR P2.7 JBP2.2,ADDEND1 MOV R7,#18H LCALL DLY JT2: JNB P2.2,KT2 INC TEMP AJMPADDEND1 ;用于调节低两位 KT2: INC KTIME MOV R7,#10H LCALL DLY MOV A,KTIME CJNE A,#30,JT2 ADD1: INC TEMP MOV A,TEMP CJNE A,#99,ON3 MOV TEMP,#0 ON3: MOV R7,TEMP MOV TEMP1,R7 LCALL DISPLAY2 MOV R7,#30H LCALL DLY JNB P2.2,ADD1 ADDEND1: RET ;----------------------------------------------------------------------------------------- ;单步、连续调节减法键 KEYSUB2: MOVP2,#0FFH CLR P2.7 JB P2.1,SUBEND2 MOV R7,#18H LCALL DLY JT3: JNBP2.1,KT3 DEC TEMP AJMP SUBEND2 KT3: INC KTIME MOV R7,#10H ;用于调节高两位 LCALL DLY MOV A,KTIME CJNE A,#30,JT3 SUB2: DEC TEMP MOVA,TEMP CJNE A,#0,ON MOV TEMP,#99 ON: MOV R7,TEMP MOV TEMP2,R7 LCALL DISPLAY4 MOV R7,#30H LCALL DLY JNB P2.1,SUB2 SUBEND2: RET ;----------------------------------------------------------------------------------------- KEYSUB1: MOV P2,#0FFH CLR P2.7 JB P2.1,SUBEND1 MOV R7,#18H LCALL DLY JT4: JNB P2.1,KT4 DEC TEMP AJMP SUBEND2 KT4: INC KTIME MOV R7,#10H ; LCALL DLY MOV A,KTIME CJNE A,#30,JT4 SUB1: DEC TEMP ;用于调节低两位 MOV A,TEMP CJNE A,#0,ON1 MOV TEMP,#99 ON1: MOV R7,TEMP MOV TEMP1,R7 LCALL DISPLAY2 MOV R7,#30H LCALL DLY JNB P2.1,SUB1 SUBEND1: RET ;蜂鸣器响的子程序 ;----------------------------------------------------------------------------------------- SOUND: CLR BUZZER MOV R7,#5H LCALL DLY SETB BUZZER MOVR7,#04H LCALL DLY RET ;----------------------------------------------------------------------------------------- ;延时子程序 ;----------------------------------------------------------------------------------------- DLY: PUSH 07H DY1: PUSH 07H DY2: PUSH 07H DY3: DJNZR7,DY3 POP 07H DJNZ R7,DY2 POP 07H DJNZ R7,DY1 POP 07H DJNZ R7,DLY RET ;----------------------------------------------------------------------------------------- ;定时器中断程序: ;----------------------------------------------------------------------------------------- T0_INT: MOV TH0,#3CH ;定时中断子程序。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

目录第1章总体方案论证及工作原理 (5)第2章硬件系统的设计 (6)第3章软件系统的设计 (12)第4章系统测试与仿真 (23)第5章设计总结 (24)参考文献 (24)1总体方案论证及工作原理1.1总体方案选择1.1.1 单片机芯片选择方案和论证采用AT89S52作为硬件核心。

片内ROM全部采用Flash ROM;以3V的超低压工作,与MCS-51系列单片机完全该芯片内部存储器为8KB ROM 存储空间,同样具有AT89C51的功能。

1.1.2 显示模块的选择和论证传统的LED数码管具有:低能耗、低损耗、低压、寿命长、耐老化、防晒、防潮、防火、防高(低)温,对外界环境要求低,易于维护,同时其精度比较高,称重轻,精度可靠,操作简单。

数码管采用BCD编码显示数字,程序编译容易,资源占用较少。

1.1.3 键盘模块的选择和论证独立式键盘是指直接用I/O口线构成的单个按键电路。

独立式按键电路配置灵活,软件结构简单。

1.1.4 总体方案论证该万年历电路由单片机AT98S52、键盘接口电路、显示接口电路及时钟电路和复位电路构成,总原理框图如图1.1所示。

图1.1 总原理图1.2功能要求说明及工作原理1.2.1 功能要求说明本次设计所设计的万年历在功能上具有一般万年历的固有功能,即能比较准确显示时间外,还具有温度计的功能。

1.2.2 工作原理万年历的运行主要是利用单片机定时/计数器的工作和中断服务的作用完成计时功能的。

首先时钟电路产生单片机工作时所需要的时钟信号,这是单片机能够正常工作的前提,而单片机有无定时以及定多长的时间,这些还需要我们人为的确定。

先要有“秒”的计时,而单片机内部定时器是达不到“秒”数量级的定时的,所以我要多次定时,我们人为在确定工作方式的之后,再计算出定时的初值,这就可以实现所谓的定时了。

如果定时时间到了的话,那么单片机会自动地产生中断使程序转向中断服务程序执行,中断服务程序执行完了就会返回原程序,等待下一次定时时间的到来再产生中断。

在此基础上,单片机就会按照人为设定的程序执行下去。

只完成对秒的计数,才能能完成其他时间量的计数。

当然,单片机如果要执行多种不同的计时功能的话,还需要选择多种不同的工作方式,这样才不会使单片机产生混乱。

万年历的基本计时单位是秒,而秒表的基本计时单位却是毫秒了,因而我们把定时器的初始时间设计为50ms,将其乘以20便可得到我们的时间秒单位。

本设计是采用复合定时方式,一个定时间一个就去计数,合作完成一秒的定时。

2 硬件系统的设计2.1硬件系统各模块功能介绍2.1.1 AT89S52芯片介绍AT89S52是一种低功耗高性能CHMOS 8位单片机,管脚如图所示。

片内含4Kbytes ISP的可反复擦写1000次Flash只读程序存储器,128bytes的随机存取数据存储器(RAM)。

AT89S52提供了8K字节Flash ,256字节RAM,32线I/O口,3个16位定时器/计数器,6向量两极中断,一个双工串行口,片内根据振荡器和始终电路等标准功能。

此外,AT89S52设有静态逻辑,并支持软件选择的两种节电运行方式、空闲方式使CPU停止工作,而允许RAM、定时器/计数器、串行口和中断系统继续工作。

掉电方式下,片内振荡器停止工作,由于之中被冻结,一切能都停止,只有片内RAM的内容被保存,直到硬件复位才恢复正常工作。

(1)AT89S52的结构框图AT89S52结构框图如图2.2所示:(2)引脚介绍:/输入/输出口线:P 0.0~P 0.7 :P0口8位双向口线;P 1.0~P 1.7 :P1口8位双向口线;P 2.0~P 2.7 :P2口8位双向口线;P 3.0~P 3.7 :P3口8位双向口线。

/ALE 地址锁存控制信号:在系统扩展时,ALE 用于控制把P 0口输出低8位地址送锁存器锁存起来,以实现低位地址和数据的隔离。

此外由于ALE 是以晶振六分之一的固定频率输出的正脉冲,因此可作为外部时钟或外部定时脉冲使用。

/PSEN 外部程序储器读选取通信号:在读外部ROM 时/PSEN 有效(低电平),以实现外部ROM 单元的读操作。

/EA 访问程序存储器控制信号:当/EA 信号为低电平时,对ROM 的读操作限定在外部程序存储器;而当/EA 信号为高电平时,则对ROM 的读操作是从内部程序存储器开始,并可延至外部程序存储器。

-RST 复位信号:当输入的复位信号延续2个机器周期以上高电平时即为有效,用以完成单片机的复位初始化操作。

-XTAL 1和XTAL 2 外接晶体引线端:当使用芯片内部时钟时,此二引线端用于外接石英晶体和微调电容;当使用外部时钟时,用于拉外部的时钟脉冲信号。

-GND 地线-VCC +5V 电源(3)信号引脚的第二功能:由于工艺及标准化等原因,芯片的引脚数目是有限制的,例如MCS —51系列把芯片引脚数目限定为40条,但单片机为实现其功能所需要的信号数目却远远超过此数,因此就出现了需要与可能的矛盾。

因此,给一些信号引脚赋以双重功能。

P 3的8条口线都定义有第二功能,如表2.1所示:表2.1 P3口第二功能图(4)总线结构AT89S52的管脚除了电源、复位、时钟接入、用户I/O口部分P3外,其余管脚都是为实现系统扩展而设置的。

这些管脚构成了三总线形式,即:1) 地址总线(AB):地址总线宽度为16位,因此,其外部存储器直接地址外围为64K字节。

16位地址总线由P经地址锁存器提供低8位地址(A0~A7);P2口直接提供高8位地址(A8~A15)。

2) 数据总线(DB):数据总线宽度为8位,由P口提供。

3) 控制总线(CB):由部分P3口的第二功能状态和4根独立控制线RESET、EA、ALE、PSEN组成。

2.1.2 时钟电路时钟电路用来产生单片机工作所需要的时钟信号,单片机本身就是一个复杂的同步时序电路,为了保证同步工作方式的实现,电路应在唯一的时钟信号控制下严格地按时序进行工作。

通过在芯片的外部XTAL1和XTAL2两个引脚跨接晶体振荡器和两个微调电容,形成反馈电路,就构成了一个稳定的自激振荡电路。

时钟电路为单片机产生时钟脉冲序列,本设计中采用的晶振频率为12MHz。

如图2.3所示。

图2.3 时钟电路2.1.3 复位电路复位是单片机的初始操作,其主要功能是把PC初始化为0000H,使单片机从0000H单元开始执行程序。

除了进入系统的正常初始化之外,当由于程序运行出错或操作错误使系统处于死锁状态时,为摆脱困境,也需安装复位键以重新启动。

RS T引脚是复位信号的输入端,复位信号是高电平有效,其有效时间应持续24个振荡脉冲周期(即2个机器周期)以上,本设计使用频率为12MHz 的晶振,所以复位信号持续时间应超过2μs才能完成复位操作。

复位操作有上电自动复位和按键手动复位两种方式。

在本设计中采用的是按键复位,按键复位是通过使复位端经电阻与Vcc电源而实现的,如图2.4所示。

图2.4 复位电路2.1.4 显示及显示驱动电路由于七段数码显示器在显示字形代码时需要有足够的功率,单片机口线的驱动能力明显不够,所以需在显示器前加显示驱动器,以提高其输出功率,满足显示器的需求。

LED显示器俗称数码管,在其内部是由8个发光二极管加限流电阻组成,其连接方式有共阴和共阳两种,在共阴极接法中,因公共端接地,只要给某一段加高电平,该段就会亮。

而在本设计中采用的是共阳极接法,公共端接+5V电源,在某一段上加低电平,该段就会亮。

在本次设计中,为了使硬件电路更简单化,我采用四位一体的LED数码管,显示原理与单个LED的显示原理完全相同。

但在它的内部把四个数码管的段控端对应的连在了一起与单个的数码管相比其外部电路连接更加简单,故它只有8个段控端和4个位控端,4个位控端分别对四个数码管进行控制。

如图2.5所示。

图2.5 显示电路2.1.5 控制电路在单片机控制电路中,可把单片机使用的键盘分为独立式和矩阵式两种。

独立式实际上就是一组独立的按键,这些按键可直接与单片机的I/O口连接,即每个按键独占一条口线,这种接法简单。

矩阵式键盘也称行列式键盘,因为键的数目较多,所以键按行列组成矩阵。

本设计中键盘数目较少,且为安装方便,因此在本设计中采用独立式接法。

如图2.6所示。

图2.6 控制电路按从一个键到键的功能被执行主要应包括两项工作:一是键的识别,即在键盘中找出被按的是哪个键,另一项是键功能的实现。

第一项工作是使用接口电路实现的,而第二项工作则是通过执行中断服务程序来完成。

具体来说,独立式键盘接口应完成以下操作功能:a 键盘扫描,以判定是否有键被按下(称之为“闭合键”)。

b 排除多键、串键(复键)及去抖动。

c 键识别,根据各口线的值判断按键的位置。

以上这些内容通常是以软硬件结合的方式来完成的,即在软件的配合下由接口电路来完成。

但具体哪些由硬件哪些由软件完成,要看接口电路的情况。

总的原则是,硬件复杂软件就简单,硬件简单软件就得复杂一些。

3软件系统的设计3.1程序设计流程图图3.1 设计流程图 左图是住程序流程 右图是循环程序流程3.2 程序清单/////////////////////////////////////////////////////////ORG 0000HLJMP STARTORG 0003HLJMP PROINT0 ;int0用来切换时钟调整位置ORG 0013H ;用来调整时间,只加不减LJMP PROINT1ORG 001BH ;50MS 的延迟,计数200次则为1秒LJMP PROTIMEORG 0030H ;主程序TABLE: DB 81H,0DBH,86H,0C2H,0D8H,0E0H,0A0H,0CBH,80H,0C0HORG 0050HSTART: MOV TCON,#05H ;中断初始化MOV IE ,#8DHMOV TMOD,#10HMOV TH1,#3CH ;定时器初始化MOV TL1,#60HMOV 31H,#00H ;00秒MOV 32H,#00H ;00分MOV 33H,#12H ;12点MOV 34H,#21H ;21号MOV 35H,#06H ;6月MOV 36H,#05H ;2005年MOV 37H,#14H;R7 存放切换标志 0 NORMAL , 1 HOUR ,2 MINUTE ,3 SECOND ,4 YEAR,5 MONTH,6 DAYMOV R1,#00H ;确定在调时不按键的最长时间,10秒后返回normal状态MOV R7,#00H ;切换标志MOV 40H,#00H ;十六进制转换BCD的高位MOV 41H,#00H ;十六进制转换BCD的低位MOV R6,#00H ;调时的位闪烁的时间间隔MOV R4,#00H ;用来计数50ms的中断次数,20次则一秒mov r3,#00hSETB TR1 ;开始计时AGAIN:ACALL PROSHOW ;显示AJMP AGAINPROSHOW:CJNE R3,#00H,SHOWDATE ;如果r3等于1就显示日期,等于0就显示时钟CJNE R7,#04H,DATE1 ;显示程序AJMP SHOWDATE ;showdate显示年月日DATE1: CJNE R7,#05H,DATE2AJMP SHOWDATEDATE2: CJNE R7,#06H,SHOWCLOCKAJMP SHOWDATEshowCLOCK:MOV R0,33H ;showclock显示时分秒,先显示时ACALL PROHTODCJNE R7,#01H,CLK1INC R6CJNE R6,#03H,CLK2 ;若处于调时状态,则该位闪烁MOV R6 ,#00HCLK1: clr P0.1mov a,41HMOV P2, a ;显示时的低位ACALL DELAY3MSCLK2: SETB P0.1CLR P0.0mov a,40HMOV P2,a ;显示时的高位ACALL DELAY3MSSETB P0.0MOV R0,32H ;显示分ACALL PROHTODCJNE R7,#02H,CLK3INC R6CJNE R6,#03H,CLK4 ;若处于调时状态,则该位闪烁MOV R6,#00HCLK3: CLR P0.3mov a,41HMOV P2, a ;显示分的低位ACALL DELAY3MSCLK4: SETB P0.3CLR P0.2mov a,40hMOV P2,a ;显示分的高位ACALL DELAY3MSSETB P0.2MOV R0,31H ;显示秒ACALL PROHTODCJNE R7,#03H,CLK5INC R6CJNE R6,#03H,CLK6 ;若处于调时状态,则该位闪烁MOV R6,#00HCLK5: CLR P0.5mov a,41HMOV P2, a ;显示秒的低位ACALL DELAY3MSCLK6: SETB P0.5CLR P0.4mov a,40hMOV P2,a ;显示秒的高位ACALL DELAY3MSSETB P0.4RETSHOWDATE:MOV R0,36H ;显示年ACALL PROHTODCJNE R7,#04H,DAY1INC R6CJNE R6,#03H,DAY2 ;若处于调时状态,则该位闪烁MOV R6,#00HDAY1: CLR P0.1MOV P2,41H ;显示年的低位ACALL DELAY3MSDAY2: SETB P0.1CLR P0.0MOV P2,40H ;显示年的高位ACALL DELAY3MSSETB P0.0MOV R0,35H ;显示月ACALL PROHTODCJNE R7,#05H,MONTH1INC R6CJNE R6,#03H,MONTH2 ;若处于调时状态,则该位闪烁MOV R6,#00HMONTH1: CLR P0.3MOV P2,41H ;显示月的低位ACALL DELAY3MSMONTH2: SETB P0.3CLR P0.2MOV P2,40H ;显示月的高位ACALL DELAY3MSSETB P0.2MOV R0,34H ;显示日ACALL PROHTODCJNE R7,#06H,YEAR1INC R6CJNE R6,#03H,YEAR2 ;若处于调时状态,则该位闪烁MOV R6,#00HYEAR1: CLR P0.5MOV P2,41HACALL DELAY3MSYEAR2: SETB P0.5CLR P0.4MOV P2,40HACALL DELAY3MSSETB P0.4RETPROHTOD:PUSH ACC ;十六进制数转换成bcd码,且可以直接输出p0口MOV A,R0DIV ABMOV DPTR,#0030HMOVC A,@A+DPTRMOV 40H,AMOV A,BMOVC A,@A+DPTRMOV 41H,APOP ACCRETDELAY3MS: ;DELAY3MSMOV 45H,#05HDELAY1: MOV 46H,#0FFHDELAY2: DJNZ 46H,DELAY2DJNZ 45H,DELAY1RETPROINT0:CLR EX0 ;切换键中断程序ACALL PROSHOWMOV C,P3.2JC IEXIT0MOV R1,#00HINC R7CJNE R7,#07H,IEXIT0MOV R7,#00HINT01: MOV C,P3.2JC INT02ACALL PROSHOWAJMP INT01INT02: ACALL PROSHOWIEXIT0: SETB EX0RETIPROINT1:CLR EX1ACALL PROSHOWJC IEXIT1LCALL ISYEAR ;判断平年闰年LCALL ISMONTH ;判断月份,确定最大日数MOV R1,#00HCJNE R7,#00H,NEXT1 ;若不是调时状态,按此键就是切换显示日期、时钟 INC R3CJNE R3,#02H,IEXIT1MOV R3,#00HAJMP IEXIT1NEXT1: mov r3,#00hCJNE R7,#03H,NEXT2 ;修改秒位INC 31HMOV A,31HCJNE A,#3CH,INT11 ;遇60变0MOV 31H,#00HAJMP IEXIT1NEXT2: CJNE R7,#02H,NEXT3 ;修改分位INC 32HMOV A,31HCJNE A,#3CH,INT11 ;遇60变0MOV 31H,#00HAJMP IEXIT1NEXT3: CJNE R7,#01H,NEXT4 ;修改时位INC 33HMOV A,33HCJNE A,#18H,INT11 ;遇24变0MOV 33H,#00HAJMP IEXIT1NEXT4: CJNE R7,#06H,NEXT5 ;修改日INC 34HMOV A,34HCJNE A,49H,INT11 ;到月底就返回月初MOV 34H,#01HAJMP IEXIT1NEXT5: CJNE R7,#05H,NEXT6 ;修改月INC 35HMOV A,35HCJNE A,#0DH,INT11 ;十二月过后就跳回1月MOV 35H,#01HAJMP IEXIT1NEXT6: CJNE R7,#04H,INT11 ;修改年INC 36HMOV A,36HCJNE A,#64H,INT11MOV 36H,#00HINT11: MOV C,P3.3JC INT12ACALL PROSHOWAJMP INT11INT12: ACALL PROSHOWIEXIT1: setb EX1RETI;/////////////////////////////////////PROTIME:MOV TMOD,#10HMOV TH1,#3CH ;定时器初始化MOV TL1,#60Hsetb tr1INC R4CJNE R4,#15H,EXITMOV R4,#00H ;计满1秒则清零CJNE R7,#00H,DIAOSHIAJMP NORMALDIAOSHI:INC R1 ;调时不按键的最长时间为10秒,在此期间又键按下重新计时CJNE R1,#0AH,EXITMOV R7,#00H ;到10秒则返回正常显示状态MOV R1,#00HAJMP EXITNORMAL: ACALL ISYEAR ;判断平闰年,返回标志48h,0为平年,1为闰年ACALL ISMONTH ;判断哪个月,返回该月的最大日数,存放在49hINC 31HMOV A,31H ;秒加一CJNE A,#3CH,EXITMOV 31H,#00HINC 32H ;分加一MOV A,32HCJNE A,#3CH,EXITMOV 32H,#00HINC 33H ;时加一MOV A,33HCJNE A,#18H,EXITMOV 33H,#00HINC 34H ;日加一MOV A,34HCJNE A,49H,EXITMOV 34H,#01HINC 35H ;月加一MOV A,35HCJNE A,#0DH,EXITMOV 35H,#01HINC 36H ;年加一MOV A,36HCJNE A,#64H,EXITMOV 36H,#00HEXIT:RETIISYEAR: MOV A,36H ;判断平闰年MOV B,#04HDIV ABMOV A,BCJNE A,#00H,EXITYEAR1MOV 48H,#01H ;闰年SJMP EXITYEAREXITYEAR1:MOV 48H,#00H ;平年EXITYEAR:RETIISMONTH:MOV A,35H ;开始检查月份CJNE A,#02H,NEXTMON1 ;判断二月MOV R2,48HCJNE R2,#00H,RUNNIANMOV 49H,#1DH ;平年为28天,赋29给49hAJMP EXITMONTHRUNNIAN:MOV 49H,#1EH ;闰年为29天,赋30天给49h AJMP EXITMONTHNEXTMON1:CJNE A,#04H,NEXTMON2AJMP XIAOYUENEXTMON2:CJNE A,#06H,NEXTMON3AJMP XIAOYUENEXTMON3:CJNE A,#09H,NEXTMON4AJMP XIAOYUENEXTMON4:CJNE A,#0BH,DAYUEXIAOYUE: MOV 49H,#1FH ;四,六,九,十一月是小月,30天,但应该赋31天给比较值49h,AJMP EXITMONTHDAYUE: MOV 49H,#20H ;其他月份为大月,31天,赋32天给49h EXITMONTH:RETIEND4 系统测试与仿真4.1仿真仿真原理图4.2测试电子万年历是多功能的数字型单片机应用产品,它可以显示当前日期,时间,还有温度。

相关文档
最新文档