51单片机制作万年历
- 格式:doc
- 大小:213.50 KB
- 文档页数:25
基于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语言源程序;希望大家稀饭: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("简洁界面");}。
;真正的万年历: 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单片机实现万年历利用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_(uchar ){lcdrs=0;P0=;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_(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_(0x80+add);write_date(0x30+shi);write_date(0x30+ge);}void write_zhou(uchar add,uchar date) {write_(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_(0x80+0x40+0x0a);write_(0x0f);}if(numfun==2){write_(0x80+0x40+0x07);write_(0x0f);}if(numfun==3){write_(0x80+0x40+0x04);write_(0x0f);}if(numfun==4){write_(0x80+0x0f);write_(0x0f);}if(numfun==5){write_(0x80+0x09);write_(0x0f);}if(numfun==6){write_(0x80+0x06);write_(0x0f);}if(numfun==7){write_(0x80+0x03);write_(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_(0x80+0x40+9);write_ds(0,miao);}if(numfun==2){fen++;if(fen==60)fen=0;write_sfm(6,fen);write_(0x80+0x40+6);write_ds(2,fen);}if(numfun==3){shi++;if(shi==24)shi=0;write_sfm(3,shi);write_(0x80+0x40+3);write_ds(4,shi);}if(numfun==4){week++;if(week==8)week=1;write_zhou(0x0f,week);write_(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_(0x80+0x08);write_ds(7,ri);}if(numfun==6){yue++;if(yue==13)yue=0;write_nyr(5,yue);write_(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_(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_(0x80+0x40+9);write_ds(0,miao);}if(numfun==2){fen--;if(fen==-1)fen=59;write_sfm(6,fen);write_(0x80+0x40+6);write_ds(2,fen);}if(numfun==3){shi--;if(shi==-1)shi=23;write_sfm(3,shi);write_(0x80+0x40+3);write_ds(4,shi);}if(numfun==4){week--;if(week==0)week=7;write_zhou(0x0f,week);write_(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_(0x80+0x08);write_ds(7,ri);}if(numfun==6){yue--;if(yue==-1)yue=12;write_nyr(5,yue);write_(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_(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_(0x80+0x40+0x0a);write_(0x0f);}if(anumfun==2){flag=1;write_(0x80+0x40+0x07);write_(0x0f);}if(anumfun==3){flag=1;write_(0x80+0x40+0x04);write_(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_(0x80+0x40+9);write_ds(1,amiao);}if(anumfun==2){afen++;if(afen==60)afen=0;write_sfm(6,afen);write_(0x80+0x40+6);write_ds(3,afen);}if(anumfun==3){ashi++;if(ashi==24)ashi=0;write_sfm(3,ashi);write_(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_(0x80+0x40+9);write_ds(1,amiao);}if(anumfun==2){afen--;if(afen==-1)afen=59;write_sfm(6,afen);write_(0x80+0x40+6);write_ds(3,afen);}if(anumfun==3){ashi--;if(ashi==-1)ashi=23;write_sfm(3,ashi);write_(0x80+0x40+3);write_ds(5,ashi);}}}}void init(){EA=1;//开总中断EX0=1;//开外部中断0IT0=1;//设定触发方式为负跳变沿有效lcden=0;//选通液晶显示屏ledrw=0;//设定液晶显示屏的读写方式为读write_(0x38);//设置液晶显示模式为16*2显示,5*7点阵,8位数据接口 write_(0x0c);//打开显示,并使光标不显示也不闪烁write_(0x06);//光标指针每次自动加1write_(1);//清屏write_(0x80);//送地址指针for(num=0;num<16;num++){write_date(table[num]);delay(5);}write_(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、单片机选型选用常见的 51 单片机,如 STC89C52 单片机,它具有性能稳定、价格低廉、易于编程等优点。
2、时钟芯片选择 DS1302 时钟芯片,该芯片能够提供高精度的实时时钟,具有闰年补偿功能,并且可以通过串行接口与单片机进行通信。
3、液晶显示屏采用 1602 液晶显示屏,能够清晰地显示字符和数字,满足万年历的显示需求。
4、按键电路设计四个按键,分别用于时间设置、功能切换、加和减操作。
三、软件设计1、主程序流程系统上电后,首先进行初始化操作,包括单片机端口初始化、时钟芯片初始化、液晶显示屏初始化等。
然后读取时钟芯片中的时间数据,并在液晶显示屏上显示出来。
接着进入循环,不断检测按键状态,根据按键操作执行相应的功能,如时间设置、功能切换等。
2、时钟芯片驱动程序通过单片机的串行接口向 DS1302 发送命令和数据,实现对时钟芯片的读写操作,获取准确的时间信息。
3、液晶显示屏驱动程序编写相应的函数,实现对1602 液晶显示屏的字符和数字显示控制。
4、按键处理程序采用扫描方式检测按键状态,当检测到按键按下时,执行相应的按键处理函数,实现时间设置和功能切换等操作。
四、时间设置功能通过按键操作进入时间设置模式,可以分别设置年、月、日、时、分、秒等信息。
在设置过程中,液晶显示屏会显示当前设置的项目和数值,并通过加、减按键进行调整。
设置完成后,将新的时间数据保存到时钟芯片中。
五、显示功能万年历的显示内容包括年、月、日、星期、时、分、秒等信息。
通过合理的排版和显示控制,使这些信息在液晶显示屏上清晰、直观地呈现给用户。
六、系统调试在完成硬件和软件设计后,需要对系统进行调试。
该程序为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;}}}}}。
#include<reg52.h> typedef unsigned char u8; typedef unsigned int u16; sbit A=P2^0;sbit BA=P2^1;sbit C=P2^2;sbit led = P3^0;sbit s7=P3^7;/*k1设置时间,k2定时。
k1,k2使用不自动弹起按键。
k3时分秒选择,k4加数字,k5减数字。
*/sbit k1=P1^0;sbit k2=P1^1;sbit k3=P1^2;sbit k4=P1^3;sbit k5=P1^4;u8 count=0,sec,min=44,hour=8,mon=9,day=28,ss=0;s=60,m=60,h=24,month=12,d=31; u16 year=2015,y=9999;#define DATA P0u16 code table[]={ 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//共阴数码管0-F编码void delay(u16 z){u16 x,y;for(x=z;x>0;x--)for(y=110;y>0;y--);}/*通过count获得hour,min,sec变量值*/ void timecontrol(){sec++;if(sec==60){sec=0;min++;if(min==60){min=0;hour++;if(hour>=24)//1d{hour=0;day++;switch(mon) {case 1:case 3:case 5:case 7:case 8:case 10:case 12:if(day==32){//一个月day=0;mon++;}break;case 4:case 6:case 9:case 11:if(day==31){//一个月day=0;mon++;}break;default: //2月if((year%4==0 && year%100!=0 ) || (year%100==0 && year%400==0))//闰年{if(day==30){day=0;mon++;}}else{if(day==29){day=0;mon++;}}break;}}if(mon>=12) //1年{mon=0;year++;if(year>=9999)year=0;}}}}void display(u16 year1,u8 mon1,u8 day1,u8 zs,u8 zm, u8 zh) {led=1;DATA=0x00;A=0;BA=0;C=0;DATA=table[zh/10];delay(3);DATA=0x00;A=1;BA=0;C=0;led=1;DATA=table[zh%10]|0x80;delay(3);DATA=0x00;A=0;BA=1;C=0;led=1;DATA=table[zm/10];delay(3);DATA=0x00;A=1;BA=1;C=0;led=1;DATA=table[zm%10]|0x80;delay(3);DATA=0x00;A=0;BA=0;C=1;led=1;DATA=table[zs/10];delay(3);DATA=0x00;A=1;BA=0;C=1;led=1;DATA=table[zs%10]|0x80;delay(3);DATA=0x00;led=0;A=0;BA=0;C=0;DATA=table[year1/1000]; delay(3);DATA=0x00;A=1;BA=0;C=0;led=0;DATA=table[year1%1000/100]; delay(3);DATA=0x00;A=0;BA=1;C=0;led=0;DATA=table[year1%1000%100/10]; delay(3);DATA=0x00;A=1;BA=1;C=0;led=0;DATA=table[year1%10];delay(3);DATA=0x00;A=0;BA=0;C=1;led=0;DATA=table[mon1/10]; delay(3);DATA=0x00;A=1;BA=0;C=1;led=0;DATA=table[mon1%10]; delay(3);DATA=0x00;A=0;BA=1;C=1;led=0;DATA=table[day1/10]; delay(3);DATA=0x00;A=1;BA=1;C=1;led=0;DATA=table[day1%10]; delay(3);void keyscan_settime() //时间设置模块{u16 ye;u8 mo,da, st,mt,ht;if(k1==0){delay(10);if(k1==0){st=sec,mt=min,ht=hour,ye=year,mo=mon,da=day;TR0=0; //关闭定时器while(k1==0) //等待用户按键{display(ye,mo,da,st,mt,ht);if(k3==0){delay(10);if(k3==0){while(!k3);ss++;if(ss==6) ss=0;}}/*通过ss选择时分秒设置*/if(k4==0) //加数{delay(10);if(k4==0){while(!k4);switch(ss){case 0:st++;if(st==60)st=0;break;case 1:mt++;if(mt==60)mt=0;break;case 2:ht++;if(ht==24)ht=0;break;case 3:ye++;if(ye==9999) ye=0;break;case 4:mo++;if(mo==13) mo=0;break;case 5:da++;if(da==32) da=0;break;default :;}}}if(k5==0) //减数{delay(10);if(k5==0){while(!k5);switch(ss){case 0:if(st>0)st--;else st=0;break;case 1:if(mt>0)mt--;else mt=0;break;case 2:if(ht>0)ht--;else ht=0;break;case 3:if(ye>0) ye--;else ye=0;break;case 4:if(mo>0) mo--;elsemo=0;break;case 5:if(da>0) da--;elseda=0;break;default : ;}}}}TR0=1;sec=st,min=mt,hour=ht,day=da,mon=mo,year=ye;}}display(year,mon,day,sec,min,hour);}void keyscan_time() //用户定时模块{if(k2==0){delay(10);if(k2==0){s=sec;m=min;h=hour,y=year,month=mon,d=day;while(k2==0) //开始定时设置{display(y,month,d,s,m,h);if(k3==0){delay(10);if(k3==0){while(!k3);ss++;if(ss==6) ss=0;}}/*通过ss选择时分秒设置*/if(k4==0) //加数{delay(10);if(k4==0){while(!k4);switch(ss){case 0:s++;if(s==60)s=0;break;case 1:m++;if(m==60)m=0;break;case 2:h++;if(h==24)h=0;break;case 3:y++;if(y==9999) y=0;break;case 4:month++;if(month==13) month=0;break;case 5:d++;if(d==32) d=0;break;default :;}}}if(k5==0) //减数{delay(10);if(k5==0){while(!k5);switch(ss){case 0:if(s>0)s--;else s=0;break;case 1:if(m>0)m--;else m=0;break;case 2:if(h>0)h--;else h=0;break;case 3:if(y>0) y--;else y=0;break;case 4:if(month>0) month--;elsemonth=0;break;case 5:if(d>0) d--;else d=0;break;default : ;}}}}}}}void buz(){if((year==y)&&(mon==month)&&(day==d)&&(hour==h)&&(min==m)&&(sec==s)) {s7=0;delay(1000);s7=1;}}void time0_init(){TMOD=0x01;TH0=0x4b;TL0=0xfe;EA=1;ET0=1;TR0=1;}void main(void){time0_init();while(1){keyscan_settime();. . .. . .keyscan_time();buz();}}void Time0() interrupt 1{TH0=0x4b;TL0=0xfe;count++;if(count==20){count=0;timecontrol();}}. 专业.专注.。
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显示屏是否正常显示日期和时间信息。
C51单片机模块化编程万年历设计程序如下:main.h#ifndef __MAIN_H__#define __MAIN_H__#include<regx52.h>#include<intrins.h>#include<absacc.h>#define uchar unsigned char #define uint unsigned int#define DQ P3_7#endifds18b20.h#include "main.h"uint sec;uint min=41;uint hour=18;uint day=20;uint month=4;uint yearl=11;uint yearh=20;uint tcnt;uint cursor=0;uchar a=0xff;uchar code Seg[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};void delay(uint t){uint i;while(t--){for (i=0;i<125;i++);}}void Tdelay(unsigned int i){while(i--);}void Kdelay(unsigned int z){uchar i,j;for(i=0;i<z;i++)for(j=248;j>0;j--);}Init_DS18B20(void){unsigned char x = 0;DQ = 1;Tdelay(200);DQ=0;Tdelay(80);DQ=1;Tdelay(200);Tdelay(200);}//读一个字节ReadOneChar(void){unsigned char i=0;unsigned char dat = 0;for (i=8;i>0;i--){DQ = 0;dat>>=1;DQ = 1;if(DQ)dat|=0x80;Tdelay(4);}return(dat);}//写一个字节WriteOneChar(unsigned char dat) {unsigned char i=0;for (i=8; i>0; i--){DQ = 0;DQ = dat&0x01;Tdelay(5);DQ = 1;dat>>=1;}}//读取温度ReadTemperature(void){unsigned char a=0;unsigned char b=0;unsigned int t=0;float tt=0;Init_DS18B20();WriteOneChar(0xCC); WriteOneChar(0x44);Init_DS18B20();WriteOneChar(0xCC); WriteOneChar(0xBE);a=ReadOneChar();b=ReadOneChar();t=b;t<<=8;t=t|a;tt=t*0.0625;t= tt*10+0.5;return(t);}void display(uchar L1,uchar L2,uchar L3,uchar L4,uchar L5,uchar L6,uchar L7,ucharL8,uchar L9,uchar L10,uchar L11,uchar L12,uchar L13,uchar L14,uchar L15,uchar L16) {P2=0x7F;P0=L1;delay(1); //yearhP2=0xBF;P0=L2;delay(1); //yearhif(cursor==6){P2=0xDF;P0=L3;delay(1);}else{P2=0xDF;P0=L3;delay(1);} //yearl if(cursor==6){P2=0xEF;P0=L4;delay(1);}else{P2=0xEF;P0=L4;delay(1);} //yearl if(cursor==5){P2=0xF7;P0=L5;delay(1);}else{P2=0xF7;P0=L5;delay(1);} //month if(cursor==5){P2=0xFB;P0=L6;delay(1);}else{P2=0xFB;P0=L6;delay(1);} //month if(cursor==4){P2=0xFD;P0=L7;delay(1);}else{P2=0xFD;P0=L7;delay(1);} //dayif(cursor==4){P2=0xFE;P0=L8;delay(1);}else{P2=0xFE;P0=L8;delay(1);} //dayP2=0xFF;if(cursor==3){P1=0x7F;P0=L9;delay(1);}else{P1=0x7F;P0=L9;delay(1);} //hourif(cursor==3){P1=0xBF;P0=L10;delay(1);}else{P1=0xBF;P0=L10;delay(1);} //hour if(cursor==2){P1=0xDF;P0=L11;delay(1);}else{P1=0xDF;P0=L11;delay(1);} //minif(cursor==2){P1=0xEF;P0=L12;delay(1);}else{P1=0xEF;P0=L12;delay(1);} //minif(cursor==1){P1=0xF7;P0=L13;delay(1);}else{P1=0xF7;P0=L13;delay(1);} //secif(cursor==1){P1=0xFB;P0=L14;delay(1);}else{P1=0xFB;P0=L14;delay(1);} //secP1=0xFD;P0=L15;delay(1); //tempP1=0xFE;P0=L16;delay(1); //tempP1=0xFF;}main.c#include "main.h"#include "ds18B20.h"void delay(uint t);void Tdelay(unsigned int i);void Kdelay(unsigned int z);Init_DS18B20(void);ReadOneChar(void);WriteOneChar(unsigned char dat);ReadTemperature(void);void display(uchar L1,uchar L2,uchar L3,uchar L4,uchar L5,uchar L6,uchar L7,ucharL8,uchar L9,uchar L10,uchar L11,uchar L12,uchar L13,uchar L14,uchar L15,uchar L16); main(){uint i;TMOD=0x02; //设置模式为定时器T0的模式2 (8位自动重装计数初值的计数TH0=0x06; //设置计数器初值,靠TH0存储重装的计数值X0=256-250=6 TL0=0x06;TR0=1; //启动T0ET0=1; //开启定时器T0中断允许EA=1; //开启中断总控制while(1){if(P3_0==0){Kdelay(200);if(P3_0==0){cursor++;if(cursor>=7){cursor=0;}}}if(P3_1==0){Kdelay(200);if(P3_1==0){if(cursor==1){sec++;if(sec==60)sec=0;}if(cursor==2){min++;if(min==60)min=0;}if(cursor==3){hour++;if(hour==24)hour=0;}if(cursor==4){day++;if(day==31)day=0;}if(cursor==5){month++;if(month==12)month=0;}if(cursor==6){yearl++;if(yearl==100)yearl=0;}if(cursor==7){yearh++;if(yearh==30)yearh=20;}}}if(P3_2==0){Kdelay(200);if(P3_2==0){if(cursor==1){sec--;}if(cursor==2){min--;}if(cursor==3){hour--;}if(cursor==4){day--;}if(cursor==5){month--;}if(cursor==6){yearl--;}if(cursor==7){yearh--;}}i=ReadTemperature();display(Seg[yearh/10],Seg[yearh],Seg[yearl/10],Seg[yearl],Seg[month/10],Seg [month],Seg[day/10],Seg[day],Seg[hour/10],Seg[hour],Seg[min/10],Seg[min],Seg[sec/10 ],Seg[sec],Seg[i/100],Seg[i/10]);}}void t0(void)interrupt 1 using 0 //t0的中断程序{tcnt++;if(tcnt==4000)//定时器的定时计数,4000次250us为1秒{tcnt=0;P3_3=~P3_3;a=~a;sec++;if(sec==60){sec=0;min++;if(min==60){min=0;hour++;if(hour==24){hour=0;day++;if(month==2&&((yearl==0&&yearh%4==0)||(yearl!=0&&yearl%4==0))&& day==30)day=1;else if(month==2&&day==29)day=1;elseif((month==4||month==6||month==9||month==11)&&day==31)day=1;else if(day==32)day=1;if(day==1){month++;if(month==13){month=1;yearl++;if(yearl==100){yearl=0;yearh++;if(yearh==100) {yearh=20; }}}}}}}}}。
基于51单片机的万年历设计流程
基于51单片机的万年历设计流程可以分为以下几个步骤:
1. 确定需求:首先,你需要明确你的万年历需要有哪些功能。
例如,是否需要显示日期、时间、星期,是否需要闹钟功能,是否需要手动或自动校准等。
2. 选择硬件:选择合适的单片机作为主控制器。
常用的单片机有8051系列,如AT89C51、AT89S52等。
此外,还需要选择适当的显示模块、按键模块、实时时钟模块等。
3. 设计硬件电路:根据选择的硬件设备,设计电路原理图和PCB图。
需要
考虑单片机的引脚连接、电源供给、时钟源、外部扩展等问题。
4. 编写软件程序:根据硬件电路和需求,编写相应的软件程序。
这包括初始化程序、主程序、中断服务程序等。
5. 调试和测试:将编写好的程序下载到单片机中,进行实际测试。
根据测试结果,对程序进行调试和修改,直到满足设计要求。
6. 生产:完成调试后,就可以进行批量生产了。
在生产过程中,还需要对产品进行质量检测,确保每个产品都能正常工作。
7. 后期维护:在产品上市后,可能需要对产品进行维护或升级。
例如,如果用户在使用过程中发现了问题,或者有新的需求,就需要对产品进行改进或升级。
以上是基于51单片机的万年历设计的基本流程,但具体的步骤可能会根据具体的需求和硬件设备有所不同。
单片机课程设计--基于51单片机的万年历单片机课程设计基于 51 单片机的万年历一、引言在现代生活中,时间的准确记录和显示对于我们的日常生活和工作具有重要意义。
万年历作为一种能够同时显示年、月、日、星期、时、分、秒等信息的设备,给人们带来了极大的便利。
本次课程设计旨在利用 51 单片机实现一个简单实用的万年历系统。
二、系统设计方案(一)硬件设计1、单片机选型选择经典的 51 单片机,如 STC89C52 单片机,其具有性能稳定、价格低廉、资源丰富等优点,能够满足本设计的需求。
2、显示模块采用液晶显示屏(LCD1602)作为显示设备,能够清晰地显示数字和字符信息。
3、时钟芯片选用DS1302 时钟芯片,它可以提供精确的实时时钟数据,包括年、月、日、星期、时、分、秒等。
4、按键模块设置三个按键,分别用于调整时间、选择调整项(年、月、日、时、分、秒等)以及切换显示模式(正常显示和设置模式)。
(二)软件设计1、主程序流程系统初始化后,首先读取 DS1302 中的时间数据,并将其显示在LCD1602 上。
然后进入循环,不断检测按键状态,根据按键操作进行相应的时间调整和显示模式切换。
2、时间读取与显示程序通过与 DS1302 进行通信,读取实时时间数据,并将其转换为适合LCD1602 显示的格式进行显示。
3、按键处理程序检测按键的按下状态,根据不同的按键执行相应的操作,如调整时间、切换显示模式等。
三、硬件电路设计(一)单片机最小系统单片机最小系统包括单片机芯片、晶振电路和复位电路。
晶振电路为单片机提供时钟信号,复位电路用于系统初始化时将单片机的状态恢复到初始值。
(二)显示电路LCD1602 显示屏通过数据总线和控制总线与单片机相连。
数据总线用于传输要显示的数据,控制总线用于控制显示屏的读写操作和显示模式。
(三)时钟电路DS1302 时钟芯片通过串行通信接口与单片机进行通信。
单片机通过发送特定的指令和数据,对 DS1302 进行读写操作,获取或设置时间信息。
一、引言万年历是一种日历工具,能够显示任何一个公历日期的星期、年、月和日,并且能够自动判断闰年。
在本设计中,我们将使用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单片机的万年历摘要:电子万年历是一种非常广泛日常计时工具,对现代社会越来越流行。
它可以对年、月、日、周日、时、分、秒进行计时,使用寿命长,误差小。
对于数字电子万年历采用直观的数字显示,可以同时显示年、月、日、周日、时、分、秒和温度等信息,还具有时间校准等功能。
该电路采用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的双向通讯,使用时不需要额外的外围电路。
c51单片机万年历的c程序c51单片机万年历的c程序求一个单片机可以显示阳历的年、月、日、星期、小时.分.秒。
阴历也能显示,标明是否为闰年。
用LCD液晶显示,可以调整时间。
这有个数码管显示的程序以前做的,。
你可以在我这个程序上修改修改包括键盘扫描,还有动态显示。
【。
】#include <REG51.H>//常量参数#define TMODW 0x01;#define SCONW 0x00;#define xplay 0x04;//显示分频系数//显示位选unsigned char data stb;//键值缓存,0xFF无键命令unsigned char data keynum;//显示字型变量unsigned char data play[8];//工作参数unsigned char data l,m;//字型码unsigned char code BCDPC[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};//字位码unsigned char code STBCODE[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80 };//400Hz xplay分频计数unsigned char data cttime;//时钟参数unsigned char data hr,min,sec,sec100;//调整时钟参数(时钟“走”)void ct1(){sec100++;if (sec100==100){sec100=0;sec++;if (sec==60){sec=0;min++;if (min==60){min=0;hr++;if (hr==24) hr=0;}}}}//时钟参数→LED 显示缓存7段参数转换函数;void xcplay(){play[0]=BCDPC[hr/10];play[1]=BCDPC[hr%10];play[2]=BCDPC[min/10];play[3]=BCDPC[min%10];play[4]=BCDPC[sec/10];play[5]=BCDPC[sec%10];play[6]=BCDPC[sec100/10]; play[7]=BCDPC[sec100%10];}//显示扫描void cplay(){T0=1;//T0-高电平消隐T1=0;//T1-低电平准备发脉冲前沿TI=0;//?P1=0;//?SBUF=STBCODE[stb];while (TI==0){};TI=0;SBUF=play[stb];while (TI==0){};T1=1;T0=0;stb=++stb&0x07;}extern void cthl0();//定时器0中断处理程序void ct0(void) interrupt 1 using 1 {cthl0();cttime--;if (cttime==0){cttime=xplay;ct1();//调用时钟“走”函数xcplay();//调用时钟参数→Led显示缓存转换函数};cplay();}void w20ms(){for (l=0;l<41;l++){for (m=0;m<81;m++){}}}void tkey(){P1=0xF0;keynum=0xFF;if (P1!=0xF0){w20ms();P1=0xF0;if (P1!=0xF0){P1=0xFE;switch (P1){case 0xEE:keynum=0;break;case 0xDE:keynum=1;break;case 0xBE:keynum=2;break;case 0x7E:keynum=3;break;}P1=0xFD;switch (P1){case 0xED:keynum=4;break;case 0xDD:keynum=5;break;case 0xBD:keynum=6;break; case 0x7B:keynum=7;break; }P1=0xFB;switch (P1){case 0xEB:keynum=8;break; }};};P1=0x00;}void command(){switch (keynum){case 0:{hr=hr+1;if (hr==24)hr=0;}break;case 1:{min=min+1;if (min==60)min=0;}break;case 2:{sec=sec+1;if (sec==60)sec=0;}break;case 3:{sec100=0; }break;case 4:{while(!(P1=0xED)) {hr=0;min=0;sec=0;}}break;case 5:{hr=hr-1;if (hr==00)hr=24;}break;case 6:{min=min-1; if (min==00)min=59;}break;case 7:{sec=sec-1; if (sec==00)sec=0;}break;case 0xFF:break; }keynum=0xFF; }main (){ hr=8;min=5;sec=8;sec100=0; TMOD=TMODW; SCON=SCONW; ET0=1;TR0=1;EA=1;cttime=xplay; while (1){w20ms();tkey(); command();};}。
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寄存器。
万年历一、题目要求:1、实现目标:用液晶屏显示时间、日期、星期和温度,时间、日期可调,且可以设置闹钟。
2、所用功能:1602液晶屏,独立按键,矩阵键盘,DS18B20温度传感器,1302时钟器,蜂鸣器,定时、中断。
二、程序框图:主程序框图计算阳历程序图三、程序:;==================变量和管脚的定义=================== LCD_RW EQU P2.5LCD_RS EQU P2.6LCD_EN EQU P2.7 ; LCD液晶显示控制端接口RS BIT P2.0RW BIT P2.1E BIT P2.2LCD EQU P0JIDIANQI EQU P2.3BEER EQU P2.4H_BIT EQU 20HM_BIT EQU 21HS_BIT EQU 22HHH EQU 23HMM EQU 24HSS EQU 25HHH_BIT EQU 26HMM_BIT EQU 27HSS_BIT EQU 28HBUF EQU 30H ; 30H-33H保存解码结果FLAG1 BIT F0 ;DS18B20存在标志位DQ BIT P3.4 ;DS18B20占用的总线TEMPER_L EQU 29HTEMPER_H EQU 28HROM1 EQU 2AHROM2 EQU 2BHROM3 EQU 2CHROM4 EQU 2DHROM5 EQU 2EHROM6 EQU 2FHROM7 EQU 30HROM8 EQU 31HA_BIT EQU 35HB_BIT EQU 36HLG EQU 45HLG1 EQU 46H ; LCD1602液晶显示位ORG 0000HLJMP INTIORG 000BH;===================================================; 初始化;=================================================== ORG 1000HINTI:MOV LG, #35HMOV LG1, #34H ; LCD1602液晶显示初值MOV TMOD, #11H ; 定时器方式1和0MOV TH0, #4CHMOV TL0, #B0H ; 定时器0初值,控制中断时间MOV TH1, #D8H ;设定时1初值MOV TL1, #F0HMOV TCON, #50HMAIN:LCALL LCD_INITLCALL LCDSET1 ; LCD1602液晶显示初始化SETB ET0 ; 打开定时器中断SETB EA ; 打开总中断SETB TR0 ; 开定时器SETB TR1 ; 开定时器MOV SP, #60HMOV P1, #00HMOV R5, #00HMOV H_BIT, #00HMOV M_BIT, #00HMOV S_BIT, #00HMOV HH_BIT, #00HMOV MM_BIT, #00HMOV SS_BIT, #00HMOV HH, #00HMOV MM, #00HMOV SS, #00HMOV TMOD, #01HMOV TH0, #3CHMOV TL0, #0B0HMOV LCD, #01HLCALL LCDWCLCALL INIT_18B20 ;复位程序LCALL GET_TEMPER ;读转换后的温度AJMP CHANGEMOV SP, #70H ;堆栈指针设到70H的地方MOV R7, #10ACALL DELAY_MSMOV DPTR, #MSG1CALL DISPLAY_LINE1;在第一行显示MOV DPTR, #MSG2CALL DISPLAY_LINE2;在第二行显示HERE:LCALL KEYJMP HERE ; 按键标志,不断循环KEY:ORL P1, #11111111B ; 拉高独立按键MOV A, P1CPL AANL A, #0CFHJZ KEY0 ; 若为0,跳到KEY0LJMP KEY1KEY0:LJMP KEY2KEY1:JB P1.2, KEY2CLR EA ; 开中断MOV A, #02H ; 清除屏幕ACALL LCD_CMD ; 进行LCD忙检测MOV A, #80HLCALL LCD_CMDMOV A, #53HLCALL LCD_WDATA ; 查表,得到显示数MOV A, #81HLCALL LCD_CMDMOV A, #51HLCALL LCD_WDATAMOV A, #82HLCALL LCD_CMDMOV A, #52HLCALL LCD_WDATAMOV A, #85HLCALL LCD_CMDMOV A, #46HLCALL LCD_WDATAMOV A, #86HLCALL LCD_CMDMOV A, #30HLCALL LCD_WDATAMOV A, #87HLCALL LCD_CMDMOV A, #37HLCALL LCD_WDATAMOV A, #89HLCALL LCD_CMDMOV A, #41HLCALL LCD_WDATAMOV A, #8AHLCALL LCD_CMDMOV A, #32HLCALL LCD_WDATAMOV A, #8BHLCALL LCD_CMDMOV A, #34HLCALL LCD_WDATAMOV A, #8CHLCALL LCD_CMDMOV A, #30HLCALL LCD_WDATASETB EA ; 开中断LJMP KEY7D1MS:MOV R5, #10D1:MOV R6, #250DJNZ R6, $DJNZ R5, D1RET;=================================================== ; 延时10MS; 占用资源:R5, R6;=================================================== D10MS:MOV R5, #3D2:MOV R6, #200DJNZ R6, $DJNZ R5, D2RET;=================================================== ; 检测LCD控制器忙状态; 读数据; RS=L,RW=H,E=H,输出:D0-D7=数据;=================================================== CHECKBUSY:PUSH ACCMOV P0, #0FFHCLR LCD_RSSETB LCD_RWSETB LCD_ENBUSYLOOP:NOPJB P0.7, BUSYLOOPCLR LCD_ENPOP ACCRET;=================================================== ; 写显示数据到LCD; RS=H,RW=L,D0-D7=数据,E=高脉冲;=================================================== LCD_WDATA:ACALL CHECKBUSY; 高4字节SETB LCD_RSCLR LCD_RWCLR LCD_ENMOV P0, ANOPNOPNOPNOPSETB LCD_ENNOPNOPNOPNOPCLR LCD_EN; 低4字节SETB LCD_RSCLR LCD_RWCLR LCD_ENNOPNOPNOPNOPANL A, #0FHSWAP AMOV P0, ANOPNOPNOPNOPSETB LCD_ENNOPNOPNOPNOPCLR LCD_ENRET;=================================================== ; 写指令数据到LCD; RS=L,RW=L,D0-D7=指令码,E=高脉冲;=================================================== LCD_CMD:ACALL CHECKBUSYLCD_CMD_NC:; 高4字节CLR LCD_RSCLR LCD_RWCLR LCD_ENNOPNOPMOV P0, ANOPNOPNOPNOPSETB LCD_ENNOPNOPNOPNOPCLR LCD_EN; 低4字节ANL A, #0FHSW AP AMOV P0, ANOPNOPNOPNOPSETB LCD_ENNOPNOPNOPNOPCLR LCD_ENRET;=================================================== ; 写8位指令数据到LCD; RS=L,RW=L,D0-D7=指令码,E=高脉冲;=================================================== LCD_CMD_8BIT:ACALL CHECKBUSYLCD_CMD_8BIT_NC:CLR LCD_RSCLR LCD_RWCLR LCD_ENNOPNOPMOV P0, ANOPNOPNOPNOPSETB LCD_ENNOPNOPNOPNOPCLR LCD_ENRET;===================================================; LCD初始化设定子程序;===================================================LCD_INIT:ACALL D1MS ; 延时15MSACALL D1MS ; 等待LCD电源稳定ACALL D1MSMOV A, #38H ; 16*2显示,5*7点阵,8位数据ACALL LCD_CMD_8BIT_NC ; 不进行LCD忙检测ACALL D1MSMOV A, #38H ; 16*2显示,5*7点阵,8位数据ACALL LCD_CMD_8BIT_NC ; 不进行LCD忙检测ACALL D1MSMOV A, #28H ; 16*2显示,5*7点阵,8位数据ACALL LCD_CMD_8BIT_NC ; 不进行LCD忙检测ACALL D1MS; 转4位界面MOV A, #28H ; 16*2显示,5*7点阵,8位数据ACALL LCD_CMD ; 不进行LCD忙检测ACALL D1MSMOV A, #0cH ; 显示关ACALL LCD_CMD ; 进行LCD忙检测ACALL D1MSMOV A, #02H ; 清除屏幕ACALL LCD_CMD ; 进行LCD忙检测ACALL D1MSMOV A, #01H ; 移动光标ACALL LCD_CMD ; 进行LCD忙检测ACALL D1MSRET;===================================================; 显示位置与移动光标设定;===================================================LCDSET1:MOV A, #01H ; 清除屏幕ACALL LCD_CMDACALL D1MSMOV A, #06H ; 移动光标(光标加1)ACALL LCD_CMDACALL D1MSMOV A, #87H ; 显示第一行左边第一位位置ACALL LCD_CMDACALL D1MSRET;===================================================LOOP:LCALL EYLCALL KEYLCALL EYYLJMP LOOP;***************************时钟显示***************************************;===================子程序=================EY:LCALL LOOP1LCALL LCDSETMOV DPTR,#TAB1MOV A,H_BITLCALL DISPMOV A,HH_BITLCALL DISPMOV A,#58MOV LCD,ALCALL WRRMOV A,M_BITLCALL DISPMOV A,MM_BITLCALL DISPMOV A,#58MOV LCD,ALCALL WRRMOV A,S_BITLCALL DISPMOV A,SS_BITLCALL DISPRET;=======BCD码转换子程序=============== LOOP1:MOV A,SSMOV B,#10DIV ABMOV S_BIT,AMOV SS_BIT,BMOV A,MMMOV B,#10DIV ABMOV M_BIT,AMOV MM_BIT,BMOV A,HHMOV B,#10DIV ABMOV H_BIT,AMOV HH_BIT,BRET;==========中断子程序================= TIME0:PUSH ACCPUSH PSWMOV TH0,#3CHMOV TL0,#0B0HINC R5CJNE R5,#20,LOOP2MOV R5,#00HINC SSMOV A,SSCJNE A,#60,LOOP2MOV SS,#00HINC MMMOV A,MMCJNE A,#60,LOOP2MOV MM,#00HINC HHMOV A,HHCJNE A,#24,LOOP2MOV HH,#00HLOOP2:POP PSWPOP ACCRETI;=====按键检测子程序==================== KEY:clr eaJNB P3.2,SS_KEYKEY1:setb eaRET;========秒钟调整子程序================SS_KEY:LCALL EY1LCALL DIS1JNB P3.2,SS_KEYSSA:LCALL EY1JNB P3.3,S_ADDKEYJNB P3.4,S_DECKEYLCALL DIS1JNB P3.2,MM_KEYJNB P3.5,KEY3LJMP SSAKEY3:LJMP KEY1;=========秒加1========================== S_ADDKEY:lcall ey1LCALL DIS1JNB P3.3,S_ADDKEYINC SSMOV A,SSCJNE A,#60,SS_KEY1MOV SS,#00HSS_KEY1:LJMP SSA;=========秒减1=========================lcall ey1LCALL DIS1JNB P3.4,S_DECKEYMOV A,SSCJNE A,#00,SS_KEY2MOV SS,#60SS_KEY2:DEC SSLJMP SS_KEY1;=========分钟调整子程序=============== MM_KEY:LCALL EY2LCALL DIS1JNB P3.2,MM_KEYMMA:LCALL EY2JNB P3.3,M_ADDKEYJNB P3.4,M_DECKEYLCALL DIS1JNB P3.2,HH_KEYJNB P3.5,KEY4LJMP MMAKEY4:LJMP KEY1;============分加1==================== M_ADDKEY:lcall ey2LCALL DIS1JNB P3.3,M_ADDKEYINC MMMOV A,MMCJNE A,#60,MM_KEY1MOV MM,#00HMM_KEY1:LJMP MMA;===========分减1==================== M_DECKEY:lcall ey2LCALL DIS1JNB P3.4,M_DECKEYMOV A,MMCJNE A,#00,MM_KEY2MOV MM,#60DEC MMLJMP MM_KEY1;=======时钟调整子程序============== HH_KEY:LCALL EY3LCALL DIS1JNB P3.2,HH_KEY HHA:LCALL EY3JNB P3.3,H_ADDKEYJNB P3.4,H_DECKEYLCALL DIS1JNB P3.2,SSBJNB P3.5,KEY5LJMP HHAKEY5:LJMP KEY1;==========时加1================== H_ADDKEY:lcall ey3LCALL DIS1JNB P3.3,H_ADDKEYINC HHMOV A,HHCJNE A,#24,HH_KEY1MOV HH,#00HHH_KEY1:LJMP HHA;==========时减1================= H_DECKEY:lcall ey3LCALL DIS1JNB P3.4,H_DECKEYMOV A,HHCJNE A,#00,HH_KEY2MOV HH,#24HH_KEY2:DEC HHLJMP HH_KEY1SSB:LJMP SS_KEYDISP:MOVC A,@A+DPTRMOV LCD,ALCALL WRRRET;======================== LCDSET:MOV LCD,#38HLCALL LCDWCMOV LCD,#06HLCALL LCDWCMOV LCD,#0CHLCALL LCDWCMOV LCD,#0C4HLCALL LCDWCRET;============================ LCDWC:CLR RSCLR RWCLR ELCALL LCDBFSETB ERET;=========================== WRR:SETB RSCLR RWCLR ELCALL LCDBFSETB ERET;================================ LCDBF:MOV LCD,#0FFHCLR RSSETB RWCLR ENOPSETB EJB LCD.7,LCDBFRET;================================ EYY:MOV LCD,#80HLCALL LCDWCMOV DPTR,#TAB2MOV R2,#16MOV R1,#00H EYY1:MOV A,R1LCALL DISPINC R1DJNZ R2,EYY1RET;========================== EY1:MOV LCD,#0C4HLCALL LCDWCMOV R4,#02EY11:LCALL HINDDJNZ R4,EY11LCALL LOOP1MOV A,S_BITLCALL DISPMOV A,SS_BITLCALL DISPRET;========================== EY2:MOV LCD,#0C4HLCALL LCDWCLCALL HINDLCALL LOOP1MOV A,M_BITLCALL DISPMOV A,MM_BITLCALL DISPLCALL HINDRET;=======================EY3:MOV LCD,#0C4HLCALL LCDWCLCALL LOOP1MOV A,H_BITLCALL DISPMOV A,HH_BITLCALL DISPMOV R4,#02EY33:LCALL HINDDJNZ R4,EY33RET;==============================HIND:MOV R3,#3HIND1:MOV A,#' 'MOV LCD,ALCALL WRRDJNZ R3,HIND1RET;==========延时程序=============DIS1:MOV R6,#20DJNZ R6,$RET;=======段码表=====================TAB1:DB 30H,31h,32H,33H,34H,35H,36H,37H,38H,39HTAB2: DB "TIM";******************************************************************** ; 读取数据表并将数据写入子程序;******************************************************************** WRITE1:MOVC A,@A+DPTR ;查表LCALL WR_DATARET;******************************************************************** ; 写数据子程序;******************************************************************** WR_DATA:MOV P0,ASETB RS ;RS=1CLR RW ;RW=0 ;准备写入数据CLR E ;E=0 ;执行显示命令LCALL BUSY ;判断液晶模块是否忙?SETB E ;E=1 ;显示完成,程序停车RET;********************************************************************; 写命令子程序;******************************************************************** WR_CODE:CLR RS ;写入控制命令的子程序CLR RWCLR ELCALL BUSYSETB ERET;********************************************************************; 判断忙碌子程序;******************************************************************** BUSY:MOV P0,#0FFH ;判断液晶显示器是否忙的子程序CLR RSSETB RWCLR ENOPSETB EJB P0.7,BUSY ;如果P1.7为高电平表示忙就循环等待RET;****************** HEX转BCD碼****************************hex_BCD:mov a,hexadd a,#00hda aret;***************BCD碼转dec*********************************bcd_dec:mov a,bcdmov b,#16div ab ;a中放置十位,b中放置个位swap aadd a,bret;***************** 温度显示**************************************** common:mov scon,#50h ;串口方式1,允许接收mov 87h,#00h ;PCON设置(将SMOD置0,使波特率不加倍)setb tr1 ;启动计时;********************************************************************;**********DS18B20复位程序*****************INIT_18B20: ;SETB DQ ;DS18B20占用的总线;NOPCLR P1.0 ;二极管指示用于观察调试CLR DQ ;DS18B20占用的总线MOV R0,#0FBHTSR1: DJNZ R0,TSR1 ;延时SETB DQMOV R0,#25HTSR2: ;JNB DQ ,TSR3 ;延时DJNZ R0,TSR2TSR3: SETB FLAG1 ;置标志位,表明DS18B20存在;AJMP TSR5;TSR4: CLR FLAG1;LJMP TSR7TSR5: MOV R0,#06BH ;yf延时TSR6: DJNZ R0,TSR6;TSR7: SETB DQ ;表明不存在SETB P1.0 ;二极管指示用于观察调试RET;********************设定DS18B20暂存器设定值**************RE_CONFIG:JB FLAG1,RE_CONFIG1RETRE_CONFIG1: MOV A,#0CCH ;放跳过ROM命令LCALL WRITE_18B20MOV A,#4EHLCALL WRITE_18B20 ;写暂存器命令MOV A,#00H ;报警上限中写入00HLCALL WRITE_18B20MOV A,#00H ;报警下限中写入00HLCALL WRITE_18B20MOV A,#1FH ;选择九位温度分辨率LCALL WRITE_18B20RET;*****************读转换后的温度值****************GET_TEMPER:SETB DQLCALL INIT_18B20 ;yf复位JB FLAG1,TSS2 ;yf若FLAG1位为1则跳转RET ;若不存在则返回TSS2: MOV A,#033H ;读ROMLCALL WRITE_18B20MOV A,#44H ;发出温度转换命令LCALL WRITE_18B20LCALL DISPLAY ;延时LCALL INIT_18B20MOV A,#0CCH ;跳过ROMLCALL WRITE_18B20MOV A,#0BEH ;发出读温度换命令LCALL WRITE_18B20LCALL READ2_18B20 ;读两个字节的温度RET;***************写DS18B20命令程序************WRITE_18B20:MOV R2,#8CLR CWR1:CLR DQMOV R3,#6 ;yf延时DJNZ R3,$RRC A ;yf带进位右移MOV DQ,C ;yf象总线写一位数MOV R3,#23 ;yf延时DJNZ R3,$SETB DQNOPDJNZ R2,WR1 ;yf判断8位是否发完SETB DQRET;***********读18B20程序,读出两个字节的温度*********READ2_18B20:CLR P1.1 ;二极管指示用于观察调试yfMOV R4,#2 ;给2字节数,低位存在29 H,高位存在28HMOV R1,#29H ;yf给地址初值RE00: MOV R2,#8 ;yf给R2给一字节循环数RE01: CLR CSETB CNOPNOPCLR DQNOPNOPNOPSETB DQMOV R3,#7 ;yf延时DJNZ R3,$MOV C,DQ ;yf将读得的数传给CMOV R3,#23 ;yf延时DJNZ R3,$RRC A ;yf右移一位,移位8次后A中的值即为所采得的数值DJNZ R2,RE01 ;yf一字节数采集够MOV @R1,A ;yf将累加器值存入间接地址mov sbuf,a ;将29H单元采集的数据传到串口用于调试yfjnb ti,$clr tiDEC R1 ;yf地址减1DJNZ R4,RE00 ;yf第一字节采集完后采集第二字节SETB P1.1 ;二极管指示用于观察调试yfRET;************读出的温度进行数据转换**************CHANGE: MOV A,29HMOV C,28H.0 ;将28H中的最低位移入CRRC AMOV C,28H.1RRC AMOV C,28H.2RRC AMOV C,28H.3RRC AMOV 29H,ALCALL DISPLAY ;调用数码管显示子程序LJMP MAIN;*******************DISPLAY******DISPLAY: mov a,29H ;将29H中的十六进制数转换成10进制mov b,#10 ;待转换的数/10=10进制div abmov b_bit,a ;十位在amov a_bit,b ;个位在bmov dptr,#TAB ;指定查表启始地址mov r0,#4dpl1: mov r1,#250 ;显示1000次dplop: mov a,a_bit ;取个位数MOVC A,@A+DPTR ;查个位数的7段代码mov p0,a ;送出个位的7段代码clr p2.5 ;开个位显示acall d1ms ;显示1mssetb p2.5mov a,b_bit ;取十位数MOVC A,@A+DPTR ;查十位数的7段代码mov p0,a ;送出十位的7段代码clr p2.4 ;开十位显示acall d1ms ;显示1mssetb p2.4djnz r1,dplop ;100次没完循环djnz r0,dpl1 ;4个100次没完循环ret;============================================;测量低电平时间,50US采样一次,R7加1一次,比如低电平时间为9000US,测得R7的结果为180(0B4H);OUTPUT: R7GET_LOW:MOV R7,#00HGET_LOW_NEXT:MOV R6,#20 ;在晶振为11.0592M时,延50US需要46个机器周期,DJNZ R6,$ ;这条指令执行需要2个机器周期JB IRR,GET_LOW_RTN ;接收头为高电平,结束测量INC R7MOV A,R7JNZ GET_LOW_NEXT ;看R7是否有溢出GET_LOW_RTN:RET;============================================;测量高电平时间,50US采样一次,R7加1一次,比如高电平时间为4500US,测得R7的结果为90;OUTPUT: R7GET_HIGH:MOV R7,#00HGET_HIGH_NEXT:MOV R6,#20 ;在晶振为11.0592M时,延50US需要46个机器周期,DJNZ R6,$ ;这条指令执行需要2个机器周期JNB IRR,GET_HIGH_RTN ;接收头为低电平,结束测量INC R7MOV A,R7GET_HIGH_RTN:RET;============================================;============================================DELAY_MS:MOV R6,#250DELAY_MS_NEXT:NOPNOPDJNZ R6,DELAY_MS_NEXTDJNZ R7,DELAY_MSRET;============================================;INPUT: R7DELAY:DJNZ R7,$RET;============================================;向LCD写一个命令字节;INPUT: ACCSEND_COMMAND_BYTE:CLR RSCLR RWMOV P0,ASETB ENOPNOPNOPNOPNOPNOPCLR EMOV R7,#100ACALL DELAYRET;===============================================;向LCD写一个数据字节;INPUT: ACCSEND_DATA_BYTE:SETB RSCLR RWMOV P0,ASETB ENOPNOPNOPNOPNOPNOPCLR EMOV R7,#100ACALL DELAYRET;===================================================;初始化LCDINIT_LCD:MOV A,#30HACALL SEND_COMMAND_BYTEACALL SEND_COMMAND_BYTEACALL SEND_COMMAND_BYTEMOV A,#38H ;设置工作方式ACALL SEND_COMMAND_BYTEMOV A,#0CH ;显示状态设置ACALL SEND_COMMAND_BYTEMOV A,#01H ;清屏ACALL SEND_COMMAND_BYTEMOV A,#06H ;输入方式设置ACALL SEND_COMMAND_BYTERET;===================================================;在第一行显示;INPUT: DPTR指向要显示的内容DISPLAY_LINE1:MOV A,#080HDISPLAY_LINE1_A:ACALL SEND_COMMAND_BYTE ;设置DDRAM地址MOV R6,#20DISPLAY_LINE1_NEXT:CLR AMOVC A,@A+DPTRACALL SEND_DATA_BYTEINC DPTRDJNZ R6,DISPLAY_LINE1_NEXTMOV R7,#100ACALL DELAYRET;===================================================;在第二行显示;INPUT: DPTR指向要显示的内容DISPLAY_LINE2:MOV A,#0C0HAJMP DISPLAY_LINE1_A;===================================================END四、程序说明:此程序是一个比较简单和基本的程序,没有太多功能,可以实现:用液晶屏显示时间、日期、星期和温度,时间、日期可调,且可以设置闹钟。