单片机电子日历(电子时钟)程序

合集下载

单片机制作的12864液晶万年历_C语言程序

单片机制作的12864液晶万年历_C语言程序

#include<reg52.H>#include<intrins.h>#include<math.h>////////////////////////////////////////DS18B20#define uchar unsigned char#define uint unsigned intsbit DQ = P1 ^ 0; // 定义DS18B20的单总线#define Lcd_Bus P0sbit LCD_RS=P2^7; //数据/命令选择sbit LCD_RW=P2^6; //读写控制sbit LCD_EN=P2^5; //片选信号#define LCD_DA TA P0 //8 bit数据线#define LOW 0#define HIGH 1//初始化指令#define CLEAR_SCREEN 0x01 //清屏指令:清屏且AC值为00H#define AC_INIT 0x02 //将AC设置为00H。

且游标移到原点位置#define CURSE_ADD 0x06 //设定游标移到方向及图像整体移动方向(默认游标右移,图像整体不动)#define FUN_MODE 0x30 //工作模式:8位基本指令集#define DISPLAY_ON 0x0c //显示开,显示游标,且游标位置反白#define DISPLAY_OFF 0x08 //显示关#define CURSE_DIR 0x14 //游标向右移动:AC=AC+1#define SET_CG_AC 0x40 //设置AC,范围为:00H~3FH#define SET_DD_AC 0x80#define FUN_MODEK 0x36 //扩展指令集,8位指令#define X1address 0x80 //上半屏X轴起始地址#define X2address 0x88 //下半屏X轴起始地址#define Y address 0x80 //Y轴起始地址#define Set_Column 0x40#define Set_Page 0xB8uchar code shu[]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39};uchar code xingqi[]="星期";uchar code hanzishu[]="一二三四五六日";unsigned char TempData = 0;double DS18B20Data;uint jiemian=0;//////////////////////////////////////////DS1302sbit DS1302_RST = P1^4;sbit DS1302_IO = P1^3;sbit DS1302_SCK = P1^2;unsigned char table[]={0X00,0X18,0X0c,0X15,0X06,0X01,0X0a};//0s 24min 12hour 14ri 5yue 5zhou 2010nianunsigned char data table1[7];//uchar code table2[]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39};uchar code shuzi[]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,};unsigned char aa,bb;uchar miaoge,miaoshi,fenge,fenshi,shige,shishi,rige,rishi,yuege,yueshi,zhou,niange,nianshi;uchar shezhinum=0;//unsigned char shi,ge;////////////////////////////////////////////////键盘扫描sbit key_mnue = P3^7;sbit key_jia = P2^0;sbit key_jian = P2^1;sbit key_enter= P2^2;uchar key_number=0;//int nian,yue,ri,shi,fen;/////////////////////////////////////////////////红外sbit HW_IRQ = P3 ^ 2; // 定义38KHz一体化红外接收头与CPU的连接unsigned char DT;static unsigned char data IRCode[3],IRCON,IRCON2;//////////////////////////////////////////////////蜂鸣器sbit BEEP =P1^1;/****************************************************************************** *************** 函数名称:DS18B20_Delay()* 功能:DS18B20软件延时专用* 入口参数:count 延时参数,值越大,延时越长* 出口参数:无******************************************************************************* **************/void DS18B20_Delay(uint count) //延时函数{while(count--);}/****************************************************************************** *************** 函数名称:DS18B20_Init()* 功能:DS18B20初始化* 入口参数:无* 出口参数:返回值为1则初始化成功* 返回值为0则初始化失败******************************************************************************* **************/uchar DS18B20_Init(void){uchar x = 0;DQ = 1; // DQ复位DS18B20_Delay(8); // 稍做延时DQ = 0; // 单片机将DQ拉低DS18B20_Delay(80); // 精确延时,大于480usDQ = 1; // 拉高总线DS18B20_Delay(14); // 稍做延时后x = DQ; // 若x=0则初始化成功,若x=1则初始化失败DS18B20_Delay(20);return (~x);}/****************************************************************************** *************** 函数名称:DS18B20_Read1Byte()* 功能:从DS18B20读一个字节* 入口参数:无* 出口参数:从DS18B20读出的一个字节******************************************************************************* **************/uchar DS18B20_Read1Byte(void){uchar i = 0;uchar dat = 0;for(i=8;i>0;i--){DQ = 0; // 给脉冲信号dat >>= 1;DQ = 1; // 给脉冲信号if(DQ) dat |= 0x80;DS18B20_Delay(4);}return (dat);}/****************************************************************************** *************** 函数名称:DS18B20_Write1Byte()* 功能:向DS18B20写一个字节* 入口参数:dat 要写入DS18B20的一字节数据* 出口参数:无******************************************************************************* **************/void DS18B20_Write1Byte(uchar dat){uchar i = 0;for(i=8;i>0;i--){DQ = 0;DQ = dat&0x01;DS18B20_Delay(5);DQ = 1;dat>>=1;}}/****************************************************************************** *************** 函数名称:Read_Disp_Temperature()* 功能:读取并显示温度* 入口参数:无* 出口参数:无******************************************************************************* **************/double Read_Disp_Temperature(void){uint a = 0, b = 0, c = 0,d = 0,e = 0, t = 0;double tt = 0;DS18B20_Init();DS18B20_Write1Byte(0xCC); // 跳过读序号列号的操作DS18B20_Write1Byte(0x44); // 启动温度转换DS18B20_Init();DS18B20_Write1Byte(0xCC); // 跳过读序号列号的操作DS18B20_Write1Byte(0xBE); // 读取温度寄存器a = DS18B20_Read1Byte();b = DS18B20_Read1Byte();t = b;t <<= 8;t = t | a;//tt = t * 0.0625;return t;}//***************************************************************** //函数名称:delay(uint t)延时函数。

单片机制作数字钟(含万年历、秒表功能)

单片机制作数字钟(含万年历、秒表功能)

数字钟、万年历制作(基于单片机)电路原理图:程序://********************20131206****数字钟程序#pragma SMALL#include <reg51.h>#include <absacc.h>#include <intrins.h>//********************************************************* *********编译预处理void display(unsigned char *p); //显示函数,P为显示数据首地址unsigned char keytest(); //按键检测函数unsigned char search(); //按键识别函数void alarm(); //闹钟判断启动函数void ftion0(); //始终修改函数void ftion1(); //闹钟修改函数void ftion3(); //日期修改函数void cum(); //加1修改函数void minus(); //减1修改函数void jinzhi(); //进制修改函数void riqi(); //日期void stopwatch(); //秒表函数//********************************************************* *******函数声明sbit P2_7=P2^7;//********************************************************* *******端口定义unsigned char clockbuf[3]={0,0,0};unsigned char bellbuf[3]={0,0,0};unsigned char date[3]={1,1,1}; //日期存放数组unsigned char stop[3]={0,0,0};unsigned char msec1,msec2;unsigned char timdata,rtimdata,dtimdata;unsigned char count;unsigned char *dis_p;unsigned char or; //12进制控制标志unsigned char ri; //日期显示控制标志位unsigned char mb; //秒表控制标志位bit arm,rtim,rhour,rmin,hour,min,sec,day,mon,year; //定义位变量//********************************************************* *****全局变量定义void main(){unsigned char a;or=0; //12进制修改标志清零ri=0;mb=0;P2_7=0;arm=0;msec1=0;msec2=0;timdata=0;rtimdata=0;count=0;TMOD=0x12;TL0=0x06;TH0=0x06;TH1=(65536-10000)/256;TL1=(65536-10000)%256;EA=1;ET0=1;ET1=1;TR0=1;TR1=0;dis_p=clockbuf;while(1){a=keytest();if(a==0x78) //判断是否有键按下{display(dis_p);if(arm==1) alarm();}else{display(dis_p);a=keytest();if(a!=0x78){a=search();switch(a){case 0x00:ftion0();break;case 0x01:ftion1();break;case 0x02:cum();break;case 0x06:jinzhi();break;case 0x03:riqi();break;case 0x04:ftion3();break;case 0x05:minus();break;case 0x07:stopwatch();break;case 0x09:TR1=1;break;case 0x0a:TR1=0;break;case 0x0b:stop[0]=0;stop[1]=0;stop[2]=0;break;default:break;}}}}}//********************************************主函数【完】void display(unsigned char *p){unsigned char buffer[]={0,0,0,0,0,0};unsigned char k,i,j,m,temp;unsigned char led[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};buffer[0]=p[0]/10;buffer[1]=p[0]%10;buffer[2]=p[1]/10;buffer[3]=p[1]%10;buffer[4]=p[2]/10;buffer[5]=p[2]%10;if((sec==0)&&(min==0)&&(hour==0)&&(rmin==0)&&(rhour==0)&&( day==0)&&(mon==0)&&(year==0)) //没有修改标志,正常显示{for(k=0;k<3;k++){temp=0x01;for(i=0;i<6;i++){P0=0x00; //段选端口j=buffer[i];P0=led[j];P1=~temp; //位选端口temp<<=1;for(m=0;m<200;m++);}}}else //若有修改标志,则按以下标志分别显示{if(sec==1||day==1){P1=0x1f;i=buffer[5];P0=led[i];for(m=0;m<200;m++);P1=0x2f;j=buffer[4];P0=led[j];for(m=0;m<200;m++);}if(min==1||rmin==1||mon==1){P1=0x3b;i=buffer[2];P0=led[i];for(m=0;m<200;m++);P1=0x37;j=buffer[3];P0=led[j];for(m=0;m<200;m++);}if(hour==1||rhour==1||year==1) {P1=0x3e;i=buffer[0];P0=led[i];for(m=0;m<200;m++);P1=0x3d;j=buffer[1];P0=led[j];for(m=0;m<200;m++);}}}//**********************************LED显示函数【完】unsigned char keytest(){unsigned char c;P2=0x78; //检测是否有键按下c=P2;c=c&0x78;return(c);}//******************************************键盘检测函数【完】unsigned char search(){unsigned char a,b,c,d,e;c=0x3f;a=0; //行号while(1){P2=c;d=P2;d=d&0x07;if(d==0x03){b=0;break;} //列号else if(d==0x05){b=1;break;}else if(d==0x06){b=2;break;}a++;c>>=1;if(a==5){a=0;c=0x3f;}}e=a*3+b;do{display(dis_p);}while((d=keytest())!=0x78);return(e);}//***********************************************查键值函数【完】void alarm(){if((clockbuf[0]==bellbuf[0])&&(clockbuf[1]==bellbuf[1])){P2_7=1;rtim=1;if(count==10){count=0;P2_7=0;arm=0;rtim=0;}}}//****************************************闹钟判断启动函数【完】void ftion0(){TR0=0;rhour=0;rmin=0;dis_p=clockbuf;rtimdata=0;timdata++;switch(timdata){case 0x01:sec=1;break;case 0x02:sec=0;min=1;break;case 0x03:min=0;hour=1;break;case 0x04:timdata=0;hour=0;TR0=1;break;default:break;}}//*********************************************时钟设置函数【完】void ftion1(){if(TR0==0) TR0=1;sec=0;min=0;hour=0;dis_p=bellbuf;timdata=0;rtimdata++;switch(rtimdata){case 0x01:rmin=1;break;case 0x02:rmin=0;rhour=1;break;case 0x03:rtimdata=0;rhour=0;arm=1;dis_p=clockbuf;break;default:break;}}//*********************************************闹钟设置函数【完】void ftion3(){if(TR0==0) TR0=1;day=0;mon=0;year=0;dis_p=date;timdata=0;rtimdata=0;dtimdata++;switch(dtimdata){case 0x01:day=1;break;case 0x02:day=0;mon=1;break;case 0x03:mon=0;year=1;break;case 0x04:dtimdata=0;year=0;dis_p=clockbuf;break;default:break;}}//*************************************************日期修改函数【完】void minus(){if(sec==1){if(0==clockbuf[2]) clockbuf[2]=59;else clockbuf[2]--;}else if(min==1){if(0==clockbuf[1]) clockbuf[1]=59;else clockbuf[1]--;}else if(hour==1){if(or==0) //判断进制{if(0==clockbuf[0]) clockbuf[0]=23;else clockbuf[0]--;}if(or==1){if(1==clockbuf[0]) clockbuf[0]=12;else clockbuf[0]--;}}else if(rmin==1){if(bellbuf[1]==0) bellbuf[1]=59;else bellbuf[1]--;}else if(rhour==1){if(or==0){if(bellbuf[0]==0) bellbuf[0]=23;else bellbuf[0]--;}if(or==1){if(bellbuf[0]==1) bellbuf[0]=12;else bellbuf[0]--;}}else if(day==1){if(date[2]==1) date[2]=31;else date[2]--;}else if(mon==1){if(date[1]==1) date[1]=12;else date[1]--;}else if(year==1){if(date[0]==1) date[0]=99;else date[0]--;}}//*************************************减1修改功能函数【完】void cum(){if(sec==1){if(59==clockbuf[2]) clockbuf[2]=0;else clockbuf[2]++;}else if(min==1){if(59==clockbuf[1]) clockbuf[1]=0;else clockbuf[1]++;}else if(hour==1){if(or==0) //判断进制{if(23==clockbuf[0]) clockbuf[0]=0;else clockbuf[0]++;}if(or==1){if(12==clockbuf[0]) clockbuf[0]=1;else clockbuf[0]++;}}else if(rmin==1){if(bellbuf[1]==59) bellbuf[1]=0;else bellbuf[1]++;}else if(rhour==1){if(or==0){if(bellbuf[0]==23) bellbuf[0]=0;else bellbuf[0]++;}if(or==1){if(bellbuf[0]==12) bellbuf[0]=1;else bellbuf[0]++;}}else if(day==1){if(date[2]==31) date[2]=1;else date[2]++;}else if(mon==1){if(date[1]==12) date[1]=1;else date[1]++;}else if(year==1){if(date[0]==99) date[0]=0;else date[0]++;}}//*************************************加1修改功能函数【完】void jinzhi(){if(or==0) or=1;else or=0;}//***********************************进制修改控制函数【完】void riqi(){if(ri==0){dis_p=date;}if(ri==1){dis_p=clockbuf;}ri++;if(ri==2) ri=0;}//********************************日期控显示函数【完】void stopwatch(){if(mb==0){dis_p=stop;mb=1;}else{mb=0;dis_p=clockbuf;}}//************秒表**********秒表**********秒表函数【完】void clock() interrupt 1{EA=0;if(msec1!=0x14) msec1++; //6MHz晶振定时10mselse{msec1=0;if(msec2!=100) msec2++; //定时1selse{if(rtim==1) count++; //闹钟启动标志计时10smsec2=0;if(clockbuf[2]!=59) clockbuf[2]++;else{clockbuf[2]=0;if(clockbuf[1]!=59) clockbuf[1]++;else{clockbuf[1]=0;if(or==0){if(clockbuf[0]!=23) clockbuf[0]++;else{clockbuf[0]=0;if((date[1]==1)||(date[1]==1)||(date[1]==1)||(date[1]==3)||(date[ 1]==5)||(date[1]==7)||(date[1]==8)||(date[1]==10)||(date[1]==12)){if(date[2]!=30) date[2]++;else{date[2]=1;if(date[1]!=11) date[1]++;else{date[1]=1;date[0]++;}}}if((date[1]==4)||(date[1]==6)||(date[1]==9)||(date[1]==11)){if(date[2]!=29) date[2]++;else{date[2]=1;if(date[1]!=11) date[1]++;else{date[1]=1;date[0]++;}}}if(date[1]==2){if((((date[0]%4==0)&&(date[0]%100!=0))||(date[0]%400==0))){if(date[2]!=28) date[2]++;else{date[2]=1;if(date[1]!=11) date[1]++;else{date[1]=1;date[0]++;}}}else{if(date[2]!=27) date[2]++;else{date[2]=1;if(date[1]!=11) date[1]++;else{date[1]=1;date[0]++;}}}}}}if(or==1){if(clockbuf[0]!=12) clockbuf[0]++;else{clockbuf[0]=0;if((date[1]==1)||(date[1]==1)||(date[1]==1)||(date[1]==3)||(date[ 1]==5)||(date[1]==7)||(date[1]==8)||(date[1]==10)||(date[1]==12)){if(date[2]!=30) date[2]++;else{date[2]=1;if(date[1]!=11) date[1]++;else{date[1]=1;date[0]++;}}}if((date[1]==4)||(date[1]==6)||(date[1]==9)||(date[1]==11)){if(date[2]!=29) date[2]++;else{date[2]=1;if(date[1]!=11) date[1]++;else{date[1]=1;date[0]++;}}}if(date[1]==2){if((((date[0]%4==0)&&(date[0]%100!=0))||(date[0]%400==0))){if(date[2]!=28) date[2]++;else{date[2]=1;if(date[1]!=11) date[1]++;else{date[1]=1;date[0]++;}}}else{if(date[2]!=27) date[2]++;else{date[2]=1;if(date[1]!=11) date[1]++;else{date[1]=1;date[0]++;}}}}}}}}}}EA=1;}//*******************************定时器0中断函数【完】void miaobiao() interrupt 3{TH1=(65536-10000)/256;TL1=(65536-10000)%256;if(stop[2]!=99) stop[2]++;else{stop[2]=0;if(stop[1]!=59) stop[1]++;else{stop[1]=0;if(stop[0]!=59) stop[0]++;else stop[0]=0;}}}//***********************************定时器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("简洁界面");}。

单片机万年历C语言程序完整

单片机万年历C语言程序完整
sbit out = P2^3; //立刻跳出调整模式按钮
sbit DQ = P3^0;
char done,count,temp,flag,up_flag,down_flag,t_value;
uchar TempBuffer[5],week_value[2];
void show_time(); //液晶显示程序
unsigned char Day;
unsigned char Month;
unsigned char Year;
unsigned char DateString[11];
unsigned char TimeString[9];
}SYSTEMTIME;//定义的时间类型
#define AM(X)X
#define PM(X)(X+12)//转成24小时制
{
unsigned char ucData;
DS1302_RST = 0;
DS1302_CLK = 0;
DS1302_RST = 1;
DS1302InputByte(ucAddr|0x01); //地址,命令
ucData = DS1302OutputByte(); //读1Byte数据
DS1302_CLK = 1;
#define DS1302_SECOND0x80 //时钟芯片的寄存器位置,存放时间
#define DS1302_MINUTE0x82
#define DS1302_HOUR0x84
#define DS1302_WEEK0x8A
#define DS1302_DAY0x86
#define DS1302_MONTH0x88
#define uchar unsigned char

自己制作的单片机万年历程序+原理图

自己制作的单片机万年历程序+原理图

自己制作的单片机万年历程序+原理图单片机万年历仿真原理图如下仿真Altium Designer画的万年历原理图和PCB图如下:PCB原理图基于51单片机,可以完成时钟显示、公历显示、农历显示、温度显示、闹钟报警定时的LCD时钟PPT内容预览:本设计使用AT89C51来做主控芯片,其强大的功能足够实现我们设计的所有功能。

使用LCD1602的液晶显示器来进行显示。

使用Keil uVision5进行编程。

通过Proteus8.6来进行仿真。

点击一次K1进入时钟设置页面,通过点击K2切换时、秒、分、星期、年、月、日,通过K3与K4实现加减来完成时钟的设置点击两次K1进入闹钟设置页面,通过点击K2切换开关、时、秒、分,通过K3与K4实现加减完成闹钟的设置。

单片机源程序如下注释是很全的#include //调用单片机头文件#define uchar unsigned char //无符号字符型宏定义变量范围0~255#define uint unsigned int //无符号整型宏定义变量范围0~65535#include "eeprom52.h"#include "nongli.h"#include "intrins.h"bit flag_200ms ;bit flag_100ms ;sbit beep = P3^7; //蜂鸣器定义bit flag_beep_en;uint clock_value; //用作闹钟用的sbit dq = P3^1; //18b20 IO口的定义uint temperature ; //温度变量uchar flag_nl; //农历阳历显示标志位uchar menu_1,menu_2;uchar key_time,flag_value; //用做连加的中间变量bit key_500ms ;uchar n_nian,n_yue,n_ri; //农历显示的函数#include "ds1302.h"#include "lcd1602.h"/******************把数据保存到单片机内部eeprom中******************/void write_eeprom(){SectorErase(0x2000);byte_write(0x2000, fen1);byte_write(0x2001, shi1);byte_write(0x2002, open1);byte_write(0x2058, a_a);}/******************把数据从单片机内部eeprom中读出来*****************/void read_eeprom(){fen1 = byte_read(0x2000);shi1 = byte_read(0x2001);open1 = byte_read(0x2002);a_a = byte_read(0x2058);}/**************开机自检eeprom初始化*****************/void init_eeprom(){read_eeprom(); //先读if(a_a != 1) //新的单片机初始单片机内问eeprom{fen1 = 3;shi1 = 8;a_a = 1;write_eeprom(); //保存数据}}/***********************18b20初始化函数*****************************/void init_18b20(){bit q;dq = 1; //把总线拿高delay_uint(1); //15usdq = 0; //给复位脉冲delay_uint(80); //750usdq = 1; //把总线拿高等待delay_uint(10); //110usq = dq; //读取18b20初始化信号delay_uint(20); //200usdq = 1; //把总线拿高释放总线}/*************写18b20内的数据***************/void write_18b20(uchar dat){uchar i;for(i=0;i<8;i++){ //写数据是低位开始dq = 0; //把总线拿低写时间隙开始dq = dat & 0x01; //向18b20总线写数据了delay_uint(5); // 60usdq = 1; //释放总线}}/*************读取18b20内的数据***************/uchar read_18b20(){uchar i,value;for(i=0;i<8;i++){dq = 0; //把总线拿低读时间隙开始value >>= 1; //读数据是低位开始dq = 1; //释放总线if(dq == 1) //开始读写数据value |= 0x80;delay_uint(5); //60us 读一个时间隙最少要保持60us 的时间}return value; //返回数据}/*************读取温度的值读出来的是小数***************/uint read_temp(){uint value;uchar low; //在读取温度的时候如果中断的太频繁了,就应该把中断给关了,否则会影响到18b20的时序init_18b20(); //初始化18b20write_18b20(0xcc); //跳过64位ROMwrite_18b20(0x44); //启动一次温度转换命令delay_uint(50); //500usinit_18b20(); //初始化18b20write_18b20(0xcc); //跳过64位ROMwrite_18b20(0xbe); //发出读取暂存器命令EA = 0;low = read_18b20(); //读温度低字节value = read_18b20(); //读温度高字节EA = 1;value <<= 8; //把温度的高位左移8位value |= low; //把读出的温度低位放到value的低八位中value *= 0.625; //转换到温度值小数return value; //返回读出的温度带小数}/******************1ms 延时函数*******************/void delay_1ms(uint q){uint i,j;for(i=0;i<>< p=""><>for(j=0;j<120;j++);}/******************写星期函数*******************/void write_week(uchar hang,uchar add,uchar week)//写星期函数{if(hang==1)write_com(0x80+add);elsewrite_com(0x80+0x40+add);。

单片机C语言电子钟显示年月日星期及时间(带注释)

单片机C语言电子钟显示年月日星期及时间(带注释)

#include<reg52.h>#define uchar unsigned char#define uint unsigned intuchar code table[]=" 2011-12-30 SA T";uchar code table1[]=" 23:59:55 ";uchar code week1[][3]={"MON","TUE","WEN","THU","FRI","SA T","SUN"}; /*uchar code week2[]="TUE";uchar code week3[]="WEN";uchar code week4[]="THU";uchar code week5[]="FRI";uchar code week6[]="SA T";uchar code week7[]="SUN"; */uchar count,shi,fen,miao,dnum,year,month,day,week,a=5;sbit rs=P2^0; //数据命令sbit rw=P2^1; //读写sbit en=P2^2; //使能sbit d1=P3^1; //独立键盘sbit d2=P3^2;sbit d3=P3^3;sbit d4=P3^4;void delay(uchar z) //延时{uint x,y;for(x=110;x>0;x--)for(y=z;z>0;z--);}void write_com(uchar com) //写指令{rs=0;rw=0;en=0;P0=com;delay(5);en=1;delay(5);en=0;}void write_date(uchar date) //写数据{rs=1;rw=0;en=0;P0=date;delay(5);en=1;delay(5);en=0;}void write_weekday (uchar a){uchar x;write_com(0x80+13);for(x=0;x<3;x++){write_date(week1[a][x]);}}void weekday(uint i){write_weekday(i%7);}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); //0x30代表的数字是0,+shi表示shi的数字write_date(0x30+ge); //ge的数字}void write_ymd(uchar add,uchar date){uchar shi,ge;shi=date/10;ge=date%10;write_com(0x80+add); //指向要写的地址write_date(0x30+shi); //0x30代表的数字是0,+shi表示shi的数字write_date(0x30+ge); //ge的数字}void unit(){uchar num;en=0;write_com(0x38); //显示write_com(0x0c); //光标不显示write_com(0x06); //指针加1,整屏不移动write_com(0x01); //清屏write_com(0x80); //指针指向0x80for(num=0;num<16;num++) //第一行显示table数组{write_date(table[num]);delay(20);}write_com(0x80+0x40);for(num=0;num<16;num++) //第二行显示table1数组{write_date(table1[num]);delay(20);}TMOD=0X01;TH0=(65536-50000)/256; //开启中断TL0=(65536-50000)%256;EA=1;ET0=1;TR0=1;shi=23;fen=59;miao=55;year=11;month=12;day=30;}void jishu() //计数{if(count==20){count=0;miao++; //秒加if(miao==60){miao=0;fen++; //分加if(fen==60){fen=0;shi++;if(shi==24){shi=0;day++;a++;weekday(a);//时加}write_sfm(3,shi);write_ymd(9,day);if(day==31){day=0x01;write_ymd(9,day);month++;write_ymd(6,month);if(month==13){month=0x01;write_ymd(6,month);year++;write_ymd(3,year);}}}write_sfm(6,fen);}write_sfm(9,miao);}}void change(){d4=0;if(d1==0) //移光标{delay(10);if(d1==0){while(!d1);dnum++;if(dnum==1){TR0=0;write_com(0x0f);write_com(0x80+0x40+10);}if(dnum==2){write_com(0x80+0x40+7);}if(dnum==3){write_com(0x80+0x40+4);}if(dnum==4){write_com(0x80+10);}if(dnum==5){write_com(0x80+7);}if(dnum==6){write_com(0x80+4);}if(dnum==7){dnum=0;TR0=1;write_com(0x0c);}}}if(d2==0) //加数据{delay(10);if(d2==0){while(!d2);if(dnum==1){miao++;if(miao==60)miao=0;write_sfm(9,miao); //顺序不能换write_com(0x80+0x40+10); //顺序不能换}if(dnum==2){fen++;if(fen==60)fen=0;write_sfm(6,fen);write_com(0x80+0x40+7);}if(dnum==3){shi++;if(shi==24){shi=0;}write_sfm(3,shi);write_com(0x80+0x40+4);}if(dnum==4){day++;a++;weekday(a);if(day==31)day=1;write_ymd(9,day);write_com(0x80+10);}if(dnum==5){month++;if(month==13)month=1;write_ymd(6,month);write_com(0x80+7);}if(dnum==6){year++;write_ymd(3,year%100);write_com(0x80+4);}}}if(d3==0) //减数据{delay(10);if(d3==0){while(!d3);if(dnum==1){miao--;if(miao==-1)miao=59;write_sfm(9,miao);write_com(0x80+0x40+10);}if(dnum==2){fen--;if(fen==-1)fen=59;write_sfm(6,fen);write_com(0x80+0x40+7);}if(dnum==3){shi--;if(shi==-1)shi=23;write_sfm(3,shi);write_com(0x80+0x40+4);}if(dnum==4){day--;a--;weekday(a);if(day==0)day=30;write_ymd(9,day);write_com(0x80+10);}if(dnum==5){month--;if(month==0)month=12;write_ymd(6,month);write_com(0x80+7);}if(dnum==6){year--;write_ymd(3,year%100);write_com(0x80+4);}}}}void main(){unit();while(1){jishu();change();}}void timer0()interrupt 1{TH0=(65536-50000)/256;TL0=(65536-50000)%256;count++;}#include<reg52.h>#define uchar unsigned char //宏定义#define uint unsigned int //宏定义sbit rs=P3^5; //液晶数据/指令选择端:1-数据,0-指令sbit lcden=P3^4; //液晶使能控制端:1-有效,0-无效sbit shift_key=P3^2;//位置移动键sbit up_key=P3^3;//增加键uchar temp=0;//定义定时器溢出计数变量,每隔50ms产生1次溢出,temp加1uint year=2011;//定义年变量并赋初值2011年uchar month=06,day=01,week;//定义月、日、星期变量,并赋初值5月23日uchar hour=23,minute=59,second=58;//定义时、分、秒变量,并赋初值12时00分00秒uchar code week_string[7][4]={"MON","TUE","WED","THU","FRI","SA T","SUN"};//定义星期英文缩写表uchar data month_day[12]={31,0,31,30,31,30,31,31,30,31,30,31};//定义每月天数表/*--定时计数器T0及中断初始化函数--*/void init(void){TMOD=0x01;//设置定时器0为工作方式1TH0=(65536-50000)/256;//16位计数初值除以256得到高8位初值TL0=(65536-50000)%256;//16位计数初值除以256的余数得到低8位初值EA=1;//开总中断ET0=1;//开启定时器0中断EX0=1;//开启外部中断,外部中断用于调整时间PT0=1;//将定时器0中断设置高优先级,调整时间期不停止计时TR0=1;//启动定时器0}/*----------1ms延时函数----------*/void delay(uint n){uint i,j;for(i=n;i>0;i--)for(j=114;j>0;j--);}/*-------LCD1602写指令函数-----*/void LCD1602_write_com(uchar com){rs=0;//rs=0,置指令输入状态P0=com;//输出指令码delay(1);//延时1mslcden=1;//lcden=1,使能端有效delay(1);//延时1mslcden=0;//lcden=0,使能端无效}/*-------LCD1602写数据函数-----*/void LCD1602_write_dat(uchar dat){rs=1;//rs=1,置数据输入状态P0=dat; //输出待显示字符的字符码(ASCII码)delay(1);//延时1mslcden=1;//lcden=1,使能端有效delay(1);//延时1mslcden=0;//lcden=0,使能端无效}/*********************公历平年的2月只有28天,公历闰年的2月有29天。

单片机设计电子日历和温度表的设计

单片机设计电子日历和温度表的设计

单片机设计电子日历和温度表的设计
一、背景介绍
在现代社会,电子设备的应用越来越普遍,单片机是一种微型计算机,具有内
部存储器、输入输出设备和计算功能,被广泛应用于各种嵌入式系统中。

本文将介绍如何使用单片机设计电子日历和温度表的原理和实现方法。

二、电子日历设计
电子日历是一种能够自动显示年、月、日的设备,可以帮助人们方便地查看日期。

在单片机设计电子日历时,需要考虑如何获取当前时间并显示在屏幕上。

一种常见的实现方法是通过单片机的定时器模块来实现时钟功能,通过按钮设置年、月、日,并在液晶屏上显示出来。

三、温度表设计
温度表是一种可以测量和显示温度的设备,能够帮助人们监测环境温度。

在单
片机设计温度表时,需要接入温度传感器并通过单片机的模数转换功能读取温度数值,再将温度信息转换成数字格式并显示在液晶屏上。

同时,还可以设置警报功能,当温度超过一定阈值时发出警报提醒用户。

四、系统整合
将电子日历和温度表的功能整合在一起,可以设计一个多功能的单片机系统。

用户可以通过按钮切换显示模式,既能查看日期又能监测温度。

通过合理的界面设计和按钮设置,提高系统的易用性,让用户更方便地操作和获取信息。

五、总结
通过单片机设计电子日历和温度表的实例,我们可以看到单片机在嵌入式系统
中的广泛应用。

通过合理设计硬件和软件,可以实现多种功能,提高系统的灵活性和实用性。

未来的发展中,随着技术的不断进步,单片机系统会变得更加智能化和便捷,为人们的生活带来更多便利。

单片机实验四 基于PROTEUS的电子日历设计

单片机实验四  基于PROTEUS的电子日历设计

实验四基于PROTEUS的电子日历设计一、实验目的:熟悉Proteus软件的使用环境,掌握电子日历的程序设计及实现方法。

二、实验设备:装有Keil C51软件和Proteus软件的计算机三、实验内容及要求:时钟功能,动态显示时分秒调时功能:可依据标准时钟调校时间利用单片机与DS1302(时钟芯片)实现。

四、实验程序:#include <reg52.h>#include <intrins.h>#include <string.h>#define uint unsigned int#define uchar unsigned charsbit IO = P1^0;sbit SCLK = P1^1;sbit RST = P1^2;sbit RS = P2^0;sbit RW = P2^1;sbit EN = P2^2;uchar *WEEK[]={"SUN","***","MON","TUS","WEN","THU","FRI","SAT"};uchar LCD_DSY_BUFFER1[]={"DATE 00-00-00 "};uchar LCD_DSY_BUFFER2[]={"TIME 00:00:00 "};uchar DateTime[7];void DelayMS(uint ms){uchar i;while(ms--){for(i=0;i<120;i++);}}void Write_A_Byte_TO_DS1302(uchar x){uchar i;for(i=0;i<8;i++){IO=x&0x01;SCLK=1;SCLK=0;x>>=1;}}uchar Get_A_Byte_FROM_DS1302(){uchar i,b=0x00;for(i=0;i<8;i++){b |= _crol_((uchar)IO,i);SCLK=1;SCLK=0;}return b/16*10+b%16;}uchar Read_Data(uchar addr){uchar dat;RST = 0;SCLK=0;RST=1;Write_A_Byte_TO_DS1302(addr);dat = Get_A_Byte_FROM_DS1302();SCLK=1;RST=0;return dat;}void GetTime(){uchar i,addr = 0x81;for(i=0;i<7;i++){DateTime[i]=Read_Data(addr);addr+=2; }}uchar Read_LCD_State(){uchar state;RS=0;RW=1;EN=1;DelayMS(1);state=P0;EN = 0;DelayMS(1);return state;}void LCD_Busy_Wait(){while((Read_LCD_State()&0x80)==0x80);DelayMS(5);}void Write_LCD_Data(uchar dat){LCD_Busy_Wait();RS=1;RW=0;EN=0;P0=dat;EN=1;DelayMS(1);EN=0; }void Write_LCD_Command(uchar cmd){LCD_Busy_Wait();RS=0;RW=0;EN=0;P0=cmd;EN=1;DelayMS(1);EN=0; }void Init_LCD(){Write_LCD_Command(0x38);DelayMS(1);Write_LCD_Command(0x01);DelayMS(1);Write_LCD_Command(0x06);DelayMS(1);Write_LCD_Command(0x0c);DelayMS(1);}void Set_LCD_POS(uchar p){Write_LCD_Command(p|0x80);}void Display_LCD_String(uchar p,uchar *s){uchar i;Set_LCD_POS(p);for(i=0;i<16;i++){Write_LCD_Data(s[i]);DelayMS(1);}}void Format_DateTime(uchar d,uchar *a){a[0]=d/10+'0';a[1]=d%10+'0';}void main(){Init_LCD();while(1){GetTime();Format_DateTime(DateTime[6],LCD_DSY_BUFFER1+5);Format_DateTime(DateTime[4],LCD_DSY_BUFFER1+8);Format_DateTime(DateTime[3],LCD_DSY_BUFFER1+11);strcpy(LCD_DSY_BUFFER1+13,WEEK[DateTime[5]]);Format_DateTime(DateTime[2],LCD_DSY_BUFFER1+5);Format_DateTime(DateTime[1],LCD_DSY_BUFFER1+8);Format_DateTime(DateTime[0],LCD_DSY_BUFFER1+11);Display_LCD_String(0x00,LCD_DSY_BUFFER1);Display_LCD_String(0x40,LCD_DSY_BUFFER2);}}五、实验截图:。

基于51单片机ds1302和ds18b20芯片设计的电子日历

基于51单片机ds1302和ds18b20芯片设计的电子日历

液晶 1602设计的电子日历, proteus 仿真及 C 程序.#include<reg51.h> // 包含单片机寄存器的头文件#include<intrins.h> //包含 _nop_()函数定义的头文件 #define uchar unsigned char #define uint unsigned intsbit DQ=P3^7;//ds18b20 和单片机连接口uchar data disdata[5];uint tvalue;//温度值uchar tflag;//温度正负标志unsigned char code digit[10]={"0123456789"}; //定义字符数组显示用 DS1302 时钟芯片、 AT89C51 单片机、 温度传感器 DS18B20、LCD数字sbit DATA=P3^6; //位定义1302 芯片的接口,数据输出端定义在P1.1引脚sbit RST=P3^4;//位定义1302 芯片的接口,复位端口定义在P1.1引脚sbit SCLK=P3^5; //位定义1302 芯片的接口,时钟输出端口定义在P1.1引脚//液晶引脚定义sbit RS=P2^0; //寄存器选择位,将RS位定义为P2.0 引脚sbit RW=P2^1; //读写选择位,将RW 位定义为P2.1 引脚sbit E=P2^2; //使能信号位,将E 位定义为P2.2 引脚sbit BF=P0^7;/*****************************************************函数功能:延时若干微秒入口参数:n void delaynus(unsigned char n) {unsigned char i;for(i=0;i<n;i++);}void Write1302(unsigned char dat)unsigned char i;SCLK=0; //拉低SCLK ,为脉冲上升沿写入数据做好准备delaynus(2); // 稍微等待,使硬件做好准备for(i=0;i<8;i++){DATA=dat&0x01; //取出dat的第0 位数据写入1302 delaynus(2); // 稍微等待,使硬件做好准备SCLK=1;delaynus(2); // 稍微等待,使硬件做好准备SCLK=0; //重新拉低SCLK ,形成脉冲dat>>=1;}}/***************************************************** 函数功能:根据命令字,向1302 写一个字节数据入口参数:Cmd,储存命令字;dat,储存待写的数据***************************************************/ void WriteSet1302(unsigned char Cmd,unsigned char dat)RST=0; //禁止数据传递SCLK=0; // 确保写数居前SCLK 被拉低RST=1; //启动数据传输delaynus(2); //稍微等待,使硬件做好准备Write1302(Cmd); // 写入命令字Write1302(dat); //写数据SCLK=1; //将时钟电平置于已知状态RST=0; //禁止数据传递}unsigned char Read1302(void){unsigned char i,dat;delaynus(2); //稍微等待,使硬件做好准备for(i=0;i<8;i++)//连续读8 个二进制位数据{dat>>=1;// 将dat 的各数据位右移1 位,因为先读出的是字节的最低位if(DATA==1) //如果读出的数据是1dat|=0x80; //将1 取出,写在dat的最高位SCLK=1; //将SCLK 置于高电平,为下降沿读出delaynus(2); //稍微等待SCLK=0; //拉低SCLK ,形成脉冲下降沿delaynus(2); //稍微等待}return dat; //将读出的数据返回//dat 已经是一位一位的存在单}// 片集中unsigned char ReadSet1302(unsigned char Cmd){unsigned char 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,((0/10)<<4|(0%10))); WriteSet1302(0x84,((12/10)<<4|(12%10)));WriteSet1302(0x86,((16/10)<<4|(16%10)));WriteSet1302(0x88,((11/10)<<4|(11%10)));WriteSet1302(0x8c,((8/10)<<4|(8%10)));}/*****************************************************函数功能:延时1ms(3j+2)*i=(3 × 33+2)×10=1010(微秒),可以认为是1 毫秒***************************************************/void delay1ms(){unsigned char i,j;for(i=0;i<10;i++)for(j=0;j<33;j++)}/*****************************************************函数功能:延时若干毫秒入口参数:n***************************************************/void delaynms(unsigned char n)unsigned char i;{for(i=0;i<n;i++)delay1ms();}bit BusyTest(void){bit result;RS=0;RW=1;E=1;_nop_();_nop_();_nop_();_nop_();result=BF;E=0;return result;}void WriteInstruction (unsigned char dictate) {while(BusyTest()==1);RS=0;RW=0;E=0;_nop_();_nop_();P0=dictate;_nop_();_nop_();_nop_();_nop_();E=1;_nop_();_nop_();_nop_();_nop_();E=0;}/void WriteAddress(unsigned char x) {WriteInstruction(x|0x80);}void WriteData(unsigned char y) {while(BusyTest()==1);RS=1;RW=0;E=0;P0=y;_nop_();_nop_();_nop_();_nop_();E=1;_nop_();_nop_();_nop_();_nop_();E=0;}void LcdInitiate(void){delaynms(15);WriteInstruction(0x38); delaynms(5);WriteInstruction(0x38);delaynms(5);WriteInstruction(0x38); delaynms(5); WriteInstruction(0x0c); delaynms(5); WriteInstruction(0x06); delaynms(5); WriteInstruction(0x01); delaynms(5);}void DisplaySecond(unsigned char x){unsigned char i,j;i=x/10;// 取十位j=x%10;// 取个位WriteAddress(0x49);WriteData(digit[i]);WriteData(digit[j]);delaynms(50);}void DisplayMinute(unsigned char x) unsigned char i,j; i=x/10;// 取十位j=x%10;// 取个位WriteAddress(0x46);WriteData(digit[i]);WriteData(digit[j]);delaynms(50); //延时1ms 给硬件一点反应时间{}void DisplayHour(unsigned char x){unsigned char i,j; //j,k,l 分别储存温度的百位、十位和个位i=x/10;j=x%10;WriteAddress(0x43);WriteData(digit[i]);WriteData(digit[j]); delaynms(50);}void delay_18B20(unsigned int i)//延时1 微秒{while(i--);}voidds1820rsδ=ds1820M^*/宀UnSignedChar X H P DQHI-=DQM tξp deωyl18B20(4x1Mt卑O O H O -deωyl18B20(10sDQMdeωyl18B20(4sUChardsl820rd()Λ⅛^≡*/ 宀UnSignedChar -H o -UnSignedChard s-HO -for("8v0 〒—)宀O O H o - ⅛⅛φdat>VMDQHIS龄奚⅛≡F Φif(DQ)dafll0x80八return(dat);}void ds1820wr(uchar wdata)/*写数据*/ {unsigned char i=0;for (i=8; i>0; i--){DQ = 0;DQ = wdata&0x01;delay_18B20(10);DQ = 1; wdata>>=1;}}read_temp(){ uchar a,b;ds1820rst(); ds1820wr(0xcc);ds1820wr(0x44); ds1820rst();ds1820wr(0xcc); ds1820wr(0xbe);a=ds1820rd();b=ds1820rd();tvalue=b;tvalue<<=8;tvalue=tvalue|a;if(tvalue<0x0fff)tflag=0;else{ tvalue=~tvalue+1;tflag=1;}tvalue=tvalue*(0.625);return(tvalue);}void ds1820disp(){ uchar flagdat;disdata[0]=tvalue/1000+0x30;disdata[1]=tvalue%1000/100+0x30;disdata[2]=tvalue%100/10+0x30;disdata[3]=tvalue%10+0x30;if(tflag==0)flagdat=0x20;elseflagdat=0x2d;if(disdata[0]==0x30){disdata[0]=0x20;if(disdata[1]==0x30){disdata[1]=0x20;}}WriteAddress (0x80); WriteData (flagdat);WriteAddress (0x81);WriteData (disdata[0]);WriteAddress (0x82);WriteData (disdata[1]);WriteAddress (0x83);WriteData (disdata[2]);WriteAddress (0x84);WriteData (0x2e);WriteAddress (0x85);WriteData (disdata[3]);}/*结束*/ void main(void){unsigned char second,minute,hour; // 分别储存苗、分、小时,unsigned char ReadValue; //储存从1302 读取的数据LcdInitiate(); //将液晶初始化WriteAddress(0x45); //写小时和分钟分隔符的显示地址,显示在第2 行第6 列WriteData(':'); //将字符常量写入LCDWriteAddress(0x48); //写分钟和秒分隔符的显示地址,显示在第2 行第9 列WriteData(':'); //将字符常量写入LCDInit_DS1302(); //将1302 初始化while(1){read_temp();//读取温度ds1820disp();//显示ReadValue = ReadSet1302(0x81); //从秒寄存器读数据second=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);DisplaySecond(second); // 显示秒ReadValue = ReadSet1302(0x83); //从分寄存器读minute=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); // 将读出数据转化DisplayMinute(minute); // 显示分ReadValue = ReadSet1302(0x85); //从分寄存器读hour=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); // 将读出数据转化DisplayHour(hour); // 显示小时} }。

单片机电子时钟设计程序

单片机电子时钟设计程序

单片机电子时钟设计程序
1.引用头文件和定义全局变量
首先需要引用相应的头文件,例如`reg52.h`,并定义全局变量用于
存储时间、闹钟时间以及其他相关参数。

2.初始化时钟
在主函数中,首先进行时钟的初始化。

这包括设置定时器和中断相关
的寄存器,以及初始化显示屏和按钮等外设。

3.时间更新
编写一个中断服务函数,用于根据定时器的中断来更新时间。

在该中
断服务函数中,需要将全局变量中的时间进行递增,并考虑到分钟、小时、日期和星期等的进位和换算。

4.按钮输入
设置一个子函数用于读取按钮输入,并根据按钮的状态来进行相应的
操作,比如切换时钟显示模式、设置闹钟等。

5.显示时间
编写一个子函数用于将时间信息显示在数码管上。

这需要先将时间信
息转换为数码管的显示格式,然后通过IO口输出控制数码管的显示。

6.闹钟设置
使用按钮输入的功能,可以设置闹钟时间和开关闹钟功能。

当闹钟时
间到达时,可以通过控制蜂鸣器发声或点亮LED等方式来进行提醒。

7.主函数
在主函数中,循环执行按钮输入的检测和相应操作,以及时间的更新和显示等功能。

可以通过一个状态机来控制整个程序的流程。

以上是一个简要的单片机电子时钟设计程序的概述。

实际的程序设计过程中,还需要考虑到各个模块之间的交互、错误处理、电源管理以及代码的优化等细节问题。

具体的程序实现可以根据具体需求和硬件平台的差异进行适当的修改和扩展。

51单片机电子日历(电子时钟)程序

51单片机电子日历(电子时钟)程序

51单片机电子日历(电子时钟)程序经过两天的调试,完成了51单片机电子日历课程设计,现在把C程序源代码帖出来纪念一下:~硬件实验箱是伟福LAB2000实验箱。

程序代码:/****************************************************************************//* 电子日历,有时间显示、闹铃、日期、秒表及键盘设置功能*//* 功能键A: 设置位数字+1 闹钟模式下为闹钟开关秒表模式下为记时开关*//* 功能键B: 设置位数字-1 闹钟模式下为闹钟开关*//* 功能键C:设置模式及设置位选择秒表模式下为清零键*//* 功能键D:在四种工作模式下切换设置闹钟开关*//* 曹宇03电子0201029 *//* 2006.6.3 更新*//****************************************************************************/#include#include/***************这里设置程序初始化时显示的时间****************/#define SET_HOUR 12 /*设置初始化小时*/#define SET_MINUTE 00 /*设置初始化分钟*/#define SET_SECOND 00 /*设置初始化秒数*//*************************系统地址****************************/#define BASE_PORT 0x8000 /*选通基地址*/#define KEY_LINE BASE_PORT+1 /*键盘行线地址*/#define KEY_COLUMN BASE_PORT+2 /*键盘列线地址*/#define LED_SEG BASE_PORT+4 /*数码管段选地址*/#define LED_BIT BASE_PORT+2 /*数码管位选地址*/#define LED_ON(x) XBYTE[LED_BIT]=(0x01<<X)&NBSP; *6位led的位选通,带参数宏,参数为0~5*=""#define LED_OFF XBYTE[LED_SEG]=0x00 /*LED显示空*//**************在设置模式下对秒分时的宏定义*****************/#define SECOND 0 /*对应数码管右边两位*/#define MINUTE 1 /*对应数码管中间两位*/#define HOUR 2 /*对应数码管左边两位*//********************定义四种工作模式***********************/#define CLOCK clockstr /*时钟模式*/#define ALART alartstr /*闹钟模式*/#define DATE datestr /*日期模式*/#define TIMER timerstr /*秒表模式*//****************以下是所有子函数的声明*********************/void sys_init(void); /*系统的初始化程序*/void display(void); /*动态刷新一次数码管子程序*/void clockplus(void); /*时间加1S的子程序*/void update_clockstr(void); /*更新时间显示编码*/void update_alartstr(void); /*更新闹钟时间的显示编码*/void update_datestr(void); /*更新日期显示编码*/void update_timerstr(void); /*更新秒表时间的显示编码*/void deley(int); /*延时子程序*/void update_dispbuf(unsigned char *); /*更新显示缓冲区*/unsigned char getkeycode(void); /*获取键值子程序*/void keyprocess(unsigned char); /*键值处理子程序*/unsigned char getmonthdays(unsigned int,unsigned char);/*计算某月的天数子程序*//*功能键功能子函数*/void Akey(void); /*当前设置位+1 开关闹钟开关秒表*/void Bkey(void); /*当前设置位-1 开关闹钟*/void Ckey(void); /*设置位选择秒表清零*/void Dkey(void); /*切换四种工作模式*//**********************全局变量声明部分*********************/unsigned char led[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};/*从0~9的LED编码*/unsigned char ledchar[3]={0x5c,0x54,0x71};/*o n f*///unsigned char key[24]={ /* 键值代码数组对应键位:*/// 0x70,0x71,0x72,0x73,0x74,0x75, /* 7 8 9 A TRACE RESET*/// 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5, /* 4 5 6 B STEP MON */// 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5, /* 1 2 3 C HERE LAST */// 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5}; /* 0 F E D EXEC NEXT */struct{ /*时间结构体变量*/unsigned char s;unsigned char m;unsigned char h;}clock={SET_SECOND,SET_MINUTE,SET_HOUR};struct{ /*闹铃时间结构体变量*/unsigned char m;unsigned char h;}alart={SET_MINUTE,SET_HOUR};struct{ /*日期结构体变量*/unsigned int year;unsigned char month;unsigned char day;}date={6,1,1};struct{ /*秒表时间结构体变量*/unsigned char ms;unsigned char s;unsigned char m;}timer={0,0,0};unsigned char dispbuf[6]; /*显示缓冲区数组*/unsigned char clockstr[6]; /*时间显示的数码管编码数组*/unsigned char alartstr[6]; /*闹钟显示的数码管编码数组*/unsigned char datestr[6]; /*日期显示的数码管编码数组*/unsigned char timerstr[6]; /*秒表显示的数码管编码数组*/unsigned int itime=0,idot; /*定时器0中断计数*/unsigned char itime1=0; /*定时器1中断计数*/sbit P3_1=P3^1; /*外接蜂鸣器的管脚*/bdata bit IsSet=0; /*设置模式标志位0:正常走时1:设置模式*/bdata bit Alart_EN=0; /*闹铃功能允许位0:禁止闹铃1:允许闹铃*/bdata bit IsBeep=0; /*响铃标志位0:未响铃1:正在响铃*/unsigned char SetSelect=0; /*在设置模式IsSet=1时,正在被设置的位,对应上面的宏*/unsigned char *CurrentMode; /*标志当前正设置的功能,如CurrentMode=CLOCK或CurrentMode=A LART等*/void timerplus(void);/**************************函数部分*************************/void main(void){sys_init();while(1){XBYTE[KEY_COLUMN,0x00]; /*给键盘列线赋全零扫描码,判断是否有键按下*/while((XBYTE[KEY_LINE]&0x0f)==0x0f) /*检测是否有键按下,无则一直进行LED的刷新显示*/ {if(Alart_EN&&(clock.h==alart.h)&&(clock.m==alart.m)) {IsBeep=1;}else{ IsBeep=0;P3_1=0;}display();}keyprocess(getkeycode()); /*有键按下时得到键值,并送入键值处理程序*/display(); /*可要可不要*/}}void sys_init(void){TMOD=0x22; /*定时器0和1都设置为工作方式2,基准定时250×2=500us=0.5ms*/TH0=6; /*定时器0中断服务用来产生1秒时钟定时及闹钟蜂鸣器蜂鸣脉冲*/TL0=6; /*定时器1中断服务留给秒表使用,产生1/100秒定时*/TH1=6;TL1=6;ET0=1;ET1=1;EA=1;TR0=1;update_clockstr(); /*初始化时钟显示编码数组*/update_alartstr(); /*初始化闹钟显示编码数组*/update_datestr(); /*初始化日期显示编码数组*/update_timerstr(); /*初始化秒表显示编码数组*/update_dispbuf(clockstr);/*初始化显示缓冲数组*/CurrentMode=CLOCK; /*默认的显示摸式为时钟*/P3_1=0; /*蜂鸣器接线引脚复位*/}void timer0(void) interrupt 1 using 1 /*定时器0中断服务器,用来产生1秒定时*/{itime++;if(itime==1000){if(IsSet) /*在设置模式下,对正在设置的位闪烁显示*/{dispbuf[SetSelect*2]=0; /*对正在设置的位所对应的显示缓冲区元素赋0,使LED灭*/ dispbuf[SetSelect*2+1]=0;}if(IsBeep) P3_1=!P3_1; /*闹钟模式时,产生峰鸣器响脉冲*/if(CurrentMode==CLOCK){dispbuf[2]=dispbuf[2]&0x7f;dispbuf[4]=dispbuf[4]&0x7f;}}if(itime==2000) /*两千次计数为1S 2000×0.5ms=1s*/{itime=0; /*定时1s时间到,软计数清零*/clockplus(); /*时间结构体变量秒数加1 */update_clockstr(); /* 更新时间显示编码数组*/if(CurrentMode!=TIMER) update_dispbuf(CurrentMode); /* 用时间编码数组更新显示缓冲区* /}}void timer1(void) interrupt 3 using 2 /*定时器1中断服务器,用来产生1/100秒定时*/{idot++;if(++itime1==20) /*20*0.5ms=10ms*/{itime1=0;timerplus();update_timerstr();if(CurrentMode==TIMER){update_dispbuf(timerstr);dispbuf[2]=dispbuf[2]&0x7f; /*关闭小数点的显示*/dispbuf[4]=dispbuf[4]&0x7f;if(idot<1000) /*闪烁显示小数点*/{dispbuf[2]=dispbuf[2]|0x80;dispbuf[4]=dispbuf[4]|0x80;}else{dispbuf[2]=dispbuf[2]&0x7f;dispbuf[4]=dispbuf[4]&0x7f;}}}if(idot==2000) idot=0;}/*功能模块子函数*/void clockplus(void) /*时间加1s判断分,时子函数*/{if(++clock.s==60) /*秒位判断*/{clock.s=0;if(++clock.m==60) /*分位判断*/{clock.m=0;if(++clock.h==24) /*时位判断*/{clock.h=0;if(++date.day==(getmonthdays(date.year,date.month)+1)){date.day=1;if(++date.month==13) date.month=1;}}}}}void timerplus() /*秒表1/100秒位加1,判断秒、分子程序*/ {if(++timer.ms==100){timer.ms=0;if(++timer.s==60){timer.s=0;if(++timer.m==60){timer.m=0;}}}}void update_clockstr(void) /*更新时钟显示代码数组clockstr*/{clockstr[0]=led[clock.s%10]; /*给元素0赋相应数码管显示编码,编码序号是秒数的个位*/clockstr[1]=led[(int)(clock.s/10)]; /*给元素1赋相应数码管显示编码,编码序号是秒数的十位*/ clockstr[2]=led[clock.m%10]; /*以下类推*/clockstr[3]=led[(int)(clock.m/10)];clockstr[4]=led[clock.h%10];clockstr[5]=led[(int)(clock.h/10)];}void update_alartstr(void) /*更新闹钟显示代码数组alartstr*/{ /*右边两位显示on:闹钟开启of:闹钟关闭*/if(Alart_EN) alartstr[0]=ledchar[1];/*显示字母n*/else alartstr[0]=ledchar[2]; /*显示字母f*/alartstr[1]=ledchar[0]; /*显示字母o*/alartstr[2]=led[alart.m%10];alartstr[3]=led[(int)(alart.m/10)];alartstr[4]=led[alart.h%10];alartstr[5]=led[(int)(alart.h/10)];}void update_datestr(void) /*更新日期显示代码数组datestr*/{datestr[0]=led[date.day%10];datestr[1]=led[(int)(date.day/10)];datestr[2]=led[date.month%10];datestr[3]=led[(int)(date.month/10)];datestr[4]=led[date.year%10];datestr[5]=led[(int)(date.year/10)];}void update_timerstr(void) /*更新秒表显示代码数组timerstr*/{timerstr[0]=led[timer.ms%10];timerstr[1]=led[(int)(timer.ms/10)];timerstr[2]=led[timer.s%10];timerstr[3]=led[(int)(timer.s/10)];timerstr[4]=led[timer.m%10];timerstr[5]=led[(int)(timer.m/10)];}void display(void) /*刷新显示六位LED一次*/{unsigned char i;for(i=0;i<6;i++){LED_ON(i); /*选通相应位*/XBYTE[LED_SEG]=dispbuf[i]; /*写显示段码*/deley(50); /*延时显示*/LED_OFF; /*写LED全灭段码*/}}void update_dispbuf(unsigned char *str) /*更新显示缓冲区子函数,参数为要用来更新缓冲区的源字符数组的首地址*/{dispbuf[0]=str[0]; /*将要更新的源字符数组内容COPY至dispbuf数组,用作显示缓冲区*/dispbuf[1]=str[1];dispbuf[2]=str[2]|0x80; /*默认把时位和分位后面的小数点显示出来,根据需要再取舍*/dispbuf[3]=str[3];dispbuf[4]=str[4]|0x80;dispbuf[5]=str[5];}void deley(int i) /*延时子函数*/{while(i--);}unsigned char getkeycode(void) /*键盘扫描子程序,返回获得的键码*/{unsigned char keycode; /*键码变量,一开始存行码*/unsigned char scancode=0x20; /*列扫描码*/unsigned char icolumn=0; /*键的列号*/display(); /*用刷新数码管显示的时间去抖*/XBYTE[KEY_COLUMN]=0x00;keycode=XBYTE[KEY_LINE]&0x0f; /*从行端口读入四位行码*/while((scancode&0x3f)!=0) /*取scancode的低六位,只要没变为全0,则执行循环*/{XBYTE[KEY_COLUMN]=(~scancode)&0x3f; /*给列赋扫描码,第一次为011111*/if((XBYTE[KEY_LINE]&0x0f)==keycode) break; /*检测按键所在的列跳出循环*/scancode=scancode>>1; /*列扫描码右移一位*/icolumn++; /*列号加1*/}keycode=keycode<<4; /*把行码移到高四位*/keycode=keycode|icolumn; /*由行码和列码组成键码*///等待按键放开XBYTE[KEY_COLUMN]=0x00;while((XBYTE[KEY_LINE]&0x0f)!=0x0f) display();return keycode;}void keyprocess(unsigned char keycode) /*键值处理函数*/{switch (keycode){case 0x73: Akey();break;case 0xB3: Bkey();break;case 0xD3: Ckey();break;case 0xE3: Dkey();break;default: break;}update_dispbuf(CurrentMode);}unsigned char getmonthdays(unsigned int year,unsigned char month)/*得到某月的天数*/ {unsigned char days;switch (month){case 4:case 6:case 9:case 11:days=30;break;case 2: if(year%4==0) days=29;else days=28;break;default:days=31;break;}return days;}/*功能键子函数部分*/void Akey(void) /*对当前设置位进行加一操作,如果设置秒位,则给秒位清零*/{if(CurrentMode==TIMER) /*秒表模式下启闭走时*/{ TR1=!TR1;return;}if(!IsSet) return; /*如果不是设置模式退出*/switch (SetSelect){case SECOND:if(CurrentMode==CLOCK){clock.s=0; /*如果当前被设置位是秒位,则清零秒位*/update_clockstr();}if(CurrentMode==ALART){Alart_EN=!Alart_EN;update_alartstr();}if(CurrentMode==DATE){if(++date.day==(getmonthdays(date.year,date.month)+1)) date.day=1;update_datestr();}if(CurrentMode==TIMER){TR1=!TR1;}break;case MINUTE:if(CurrentMode==CLOCK){if(++clock.m==60) clock.m=0; /*如果当前被设置分位,则分位加1*/ update_clockstr();}if(CurrentMode==ALART){if(++alart.m==60) alart.m=0;update_alartstr();}if(CurrentMode==DATE){if(++date.month==13) date.month=1;update_datestr();}break;case HOUR: if(CurrentMode==CLOCK){if(++clock.h==24) clock.h=0; /*如果当前被设置时位,则时位加1*/ update_clockstr();}if(CurrentMode==ALART){if(++alart.h==24) alart.h=0;update_alartstr();}if(CurrentMode==DATE){if(++date.year==100) date.year=0;update_datestr();}break;default: break;}update_dispbuf(CurrentMode);}void Bkey(void) /*对当前设置位进行减一操作,如果设置秒分,则给秒位清零,类比Akey()函数*/ {if(!IsSet) return;switch (SetSelect){case SECOND:if(CurrentMode==CLOCK){clock.s=0;update_clockstr();}if(CurrentMode==ALART){Alart_EN=!Alart_EN;update_alartstr();}if(CurrentMode==DATE){if(--date.day==0x00) date.day=getmonthdays(date.year,date.month);update_datestr();}break;case MINUTE:if(CurrentMode==CLOCK){if(--clock.m==0xff) clock.m=59;update_clockstr();}if(CurrentMode==ALART){if(--alart.m==0xff) alart.m=59;update_alartstr();}if(CurrentMode==DATE){if(--date.month==0x00) date.month=12;update_datestr();}break;case HOUR: if(CurrentMode==CLOCK){if(--clock.h==0xff) clock.h=23;update_clockstr();}if(CurrentMode==ALART){if(--alart.h==0xff) alart.h=23;update_alartstr();}if(CurrentMode==DATE){if(--date.year==0xffff) date.year=99;update_datestr();}break;default: break;}update_dispbuf(CurrentMode);}void Ckey(void) /*正常走时模式和设置模式的切换*/{if(CurrentMode==TIMER){TR1=0; /*初始化定时器1设置,停止秒表记时*/ TH1=6;TL1=6;timer.ms=0; /*初始化秒表数组*/timer.s=0;timer.m=0;update_timerstr();}else{if(IsSet==0) /*在非秒表模式下,第一次按下C键进入设置模式,设置时位*/{IsSet=1; /*置位标志位,进入设置模式*/SetSelect=HOUR;return;} /*第二次按C键设置分位,第三次按键设置秒位,第四次按键完成退出设置*/if(SetSelect==0) /*按到第四次,即设置完秒位后,将标志位IsSet置0,完成设置*/{IsSet=0; /*复位标志位,进入正常走时模式*/return;}if(SetSelect>0) SetSelect--; /*设置位的标志变量SetSelect=0:时位1:分位2:秒位*/ }}void Dkey(void) /*工作状态切换:时钟、闹钟、日期、秒表*/{if(CurrentMode==CLOCK) /*切换至闹钟,同时开关闹钟*/{ CurrentMode=ALART;Alart_EN=!Alart_EN;update_alartstr();return;}if(CurrentMode==ALART) /*切换至日期*/{ CurrentMode=DATE;return;}if(CurrentMode==DATE) /*切换至秒表,同时关闭设置模式*/{CurrentMode=TIMER;IsSet=0;return;}if(CurrentMode==TIMER) /*切换至时钟*/{CurrentMode=CLOCK;return;}}当我被上帝造出来时,上帝问我想在人间当一个怎样的人,我不假思索的说,我要做一个伟大的世人皆知的人。

单片机电子万年历(含程序)

单片机电子万年历(含程序)

CHANGZHOU INSTITUTE OF TECHNOLOGY科研实践项目名称:电子万年历设计二级学院:电子信息与电气工程学院专业:电气工程及其自动化班级: 10 电二学生姓名:祝学东学号: 10020442 指导教师:庄志红职称:副教授起止时间: 2013年12月9日—2013年12月20日摘要本设计是电子万年历。

具备三个功能:能显示:年、月、日、时、分、秒、星期,并具有可调整日期和时间功能。

该电子万年历使用12MHZ晶振与单片机AT89C52相连接,通过软件编程的方法实现了以24小时为一个周期,同时显示小时、分钟和秒的要求。

利用单片机定时器及计数器产生定时效果通过编程形成数字钟效果,再利用数码管动态扫描显示单片机内部处理的数据。

同时通过端口读入当前外部控制状态来改变程序的不同状态,实现不同功能。

电子万年历设计与制作可采用数字电路实现,也可以采用单片机来完成。

若用数字电路完成,所设计的电路相当复杂,大概需要十几片数字集成块,其功能也主要依赖于数字电路的各功能模块的组合来实现,焊接的过程比较复杂,成本也非常高。

若用单片机来设计制作完成,由于其功能的实现主要通过软件编程来完成,这样一来就降低了硬件电路的复杂性,从而使得其成本降低,更适合我们大学生自主研发。

AT89C52是一个低电压,高性能CMOS 8位单片机,片内含8k bytes的可反复擦写的Flash只读程序存储器和256 bytes的随机存取数据存储器(RAM),器件采用ATMEL公司的高密度、非易失性存储技术生产,兼容标准MCS-51指令系统,片内置通用8位中央处理器和Flash存储单元,AT89C52单片机在电子行业中有着广泛的应用。

关键词:单片机数字显示动态扫描时间日期可调目录第一章设计论证及要求 (1)1.1设计应用意义 (1)1.2设计方案论证 (1)1.2.1 单片机芯片选择 (1)1.2.2显示模块选择 (1)1.2.3时钟芯片选择 (2)1.3设计流程 (2)第二章系统硬件电路设计 (3)2.1 CPU时钟 (3)2.2 主控芯片AT89C52模块 (3)2.3 显示控制电路的设计及原理 (4)2.4 按键电路设计 (6)第三章系统软件设计 (7)3.1 软件主流程 (7)3.2初始化程序及宏定义 (9)3.3主程序 (10)3.4显示子程序 (12)3.5 按键子程序 (15)3.6 延时子程序 (16)第四章系统调试与分析 (17)第五章设计总结 (20)第六章参考文献 (21)附一元件清单 (22)附二仿真原理图 (23)附三程序清单 (24)附四实物图 (35)第一章设计论证及要求1.1设计应用意义二十一世纪是数字化技术高速发展的时代,而单片机在数字化高速发展的时代扮演着极为重要的角色。

基于单片机的电子时钟万年历设计

基于单片机的电子时钟万年历设计

(2)31 8 位暂存数据存储RAM(3)串行 I/O 口方式使得管脚数量最少(4)宽范围工作电压2.0 5.5V(5)工作电流 2.0V 时,小于300nA(6)读/写时钟或RAM 数据时有两种传送方式单字节传送和多字节传送字符组方式(7)8 脚DIP 封装或可选的8 脚SOIC 封装根据表面装配(8)简单 3 线接口(9)与 TTL 兼容Vcc=5V(10)可选工业级温度范围-40~+85优点:串行接口的日历时钟芯片,使用简单,接口容易,与微型计算机连线较少等特点,在单片机系统尤其是手持式信息设备中己得到了广泛的应用。

所以,最终选择串行时钟芯片DS1302,DS1302的管脚图如图2所示。

图2 DS1302管脚图1.2显示模块选择方案一:LED数码管显示数码管显示比较常用的是采用CD4511和74LS138实现数码转换,数码显示分动态显示和静态显示,静态显示具有锁存功能,可以使数据显示得很清楚,但浪费了一些资源。

目前单片机数码管普通采用动态显示。

编程简单,但只能显示数字,不能显示中文。

方案二:LCD1602能够显示英文和数字。

1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,这些字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是01000001B(41H),显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到字母“A”。

所以最终选择LCD1602。

2.项目功能模块2.1 89C51模块Mcs-51单片机管脚图图如图3所示:单片机管脚图2.2 1602液晶显示模块1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,这些字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是01000001B(41H),显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到字母“A”。

电子实时时钟万年日历系统-单片机课程设计(含电路图、流程图、汇编语言)

电子实时时钟万年日历系统-单片机课程设计(含电路图、流程图、汇编语言)

一、题目:电子实时时钟/万年日历系统二、功能要求:1.基本要求:⑴显示准确的北京时间(时、分、秒),可用24小时制式;⑵随时可以调校时间。

2.发挥要求:⑴增加公历日期显示功能(年、月、日),年号只显示最后两位;⑵随时可以调校年、月、日;⑶允许通过转换功能键转换显示时间或日期。

三、方案考虑:1、硬件方案:⑴显示器采用6位LED数码管(共阳),可分别显示时间或日期。

⑵显示器的驱动采用动态扫描电路形式,以达到简化电路的目的。

但要注意所需的驱动电流比静态驱动时要大,因此要增加驱动电路。

可采用74LS244或者晶体管;其中74ls244是用来驱动段选码,晶体管是驱动位选码。

⑶采用“一键多用方案”,以减少按键数目。

本方案采用了4按键。

⑷整体上要考虑:结构简单、布局美观、操作方便、成本低廉。

2、设计电路图如下:3、元件清单:(我们使用的是TX-1C开发板)⑴ 89C52 1个⑵IC座(40脚) 3个(其中1个用于接插89C51、2个用于接插LED段数码管)。

⑶ 74LS244 1个(用于驱动6个共阳的LED段数码管)。

⑷ IC座(20脚) 1个(用于接插74LS244)。

(5)显示器:LED_8段数码管(共阳型)6个三极管:(6)PNP(8550)6个(用于驱动6个共阳型LED段数码管)。

(7)微型开关:3个(其中1个用于复位电路、其它用于键盘)。

(8)晶体振荡器(12MHz):1个(用于振荡电路)。

(9)电阻器:⑴ 3KΩ 1个(用于系统复位电路)。

⑵ 1KΩ 6个(用作PNP三极管基极电阻)。

⑶ 100Ω 7个(驱动器用作74LS244输出限流电阻)。

(10)电容器:⑴ 10μF1个(用于系统复位电路)。

⑵ 30 pF 2个(用于系统振荡电路)。

(11)其它:⑴万能电路板(10×15):1块⑵焊锡条: 2米⑶带插头、座的电源端子: 1条⑷各种颜色外皮的导线:各1米(12)工具:1.电烙铁:1把2.剪钳:1把3.镊子:1把4.万用表:1个(13)设备:编程器(MEP300或TOP851)6个4、软件方案:(1)使用全汇编编写(2)时钟基准时间由单片机内部定时中断来提供,定时时间应该乘以一个整数得到,且不宜太长或太短,最长不能超过16位定时器的最长定时时间,最短不能少于定时中断服务程序的执行时间。

单片机万年历程序(带闹钟)

单片机万年历程序(带闹钟)

第一章设计方案1.1.硬件设计1.1.1设计要求实现年月日、时分秒、星期的显示功能,用两个按键来实现日期和时间的调整功能,调整要求星期能自动更新,且能实现位调。

显示格式:四位年,两位月,两位日,星期字母前三位,两位时,两位分,两位秒。

比如:YYYY-MM-DD WEEKHH:MM:SS1.1.2硬件框图图1-1-硬件框图日期时间由硬件软件结合产生;按键之间相互配合完成当前日期时间的调整功能。

过程与结果由控制芯片分别输出到显示器上。

本设计附加了播放音乐的功能。

音乐从蜂鸣器产生。

1.1.3硬件选择1).显示模块本设计具体选用与实际应用与消耗资源相关。

万年历用到的地方大多都在室内。

现市场上与许多显示器,在日常生活中最常见的有数码管,led点阵屏,lcd液晶显示器等。

八段数码管的优点:亮度高,显示大。

驱动部份的软件简单;缺点:与液晶相比,耗电及体积大。

数码管只能单纯的显示数字,不能生动的表达各个参数的信息,消耗电力也比led液晶显示器大。

LCD液晶显示器它是一种专门用来显示字母、数字、符号等的点阵型液晶模块,在单片机系统中应用晶液显示器作为输出器件有以下几个优点:显示质量高,由于液晶显示器每一个点在收到信号后就一直保持那种色彩和亮度,恒定发光,而不像阴极射线管显示器(CRT)那样需要不断刷新新亮点。

因此,液晶显示器画质高且不会闪烁。

数字式接口,液晶显示器都是数字式的,和单片机系统的接口更加简单可靠,操作更加方便。

体积小、重量轻,液晶显示器通过显示屏上的电极控制液晶分子状态来达到显示的目的,在重量上比相同显示面积的传统显示器要轻得多。

功耗低,相对而言,液晶显示器的功耗主要消耗在其内部的电极和驱动IC上,因而耗电量比其它显示器要少得多。

Lcd液晶能一屏把本设计所要显示的信息表达完整。

而且lcd耗电小,体积小很适合与室内使用。

本设计的要求日期时间以数字表示、星期用3位英文字符表示共21个字符,lcd1602能显示32个字表 1-1 lcd1602引脚及功能2).按键与蜂鸣器本设计选用轻触按钮,型号为XDJT1102S。

基于单片机的电子时钟的设计与实现

基于单片机的电子时钟的设计与实现

基于单片机的电子时钟的设计与实现电子时钟是一种使用微处理器或单片机作为主控制器的数字时钟。

它不仅能够显示当前时间,还可以具备其他附加功能,如闹钟、日历、温度显示等。

一、设计目标设计一个基于单片机的电子时钟,实现以下功能:1.显示时间:小时、分钟和秒钟的显示,采用7段LED数码管来显示。

2.闹钟功能:设置闹钟时间,到达设定的时间时会发出提示音。

3.日历功能:显示日期、星期和月份。

4.温度显示:通过温度传感器获取当前环境温度,并显示在LED数码管上。

5.键盘输入和控制:通过外部键盘进行时间、日期、闹钟、温度等参数的设置和调整。

二、硬件设计1.单片机选择:选择一款适合的单片机作为主控制器,应具备足够的输入/输出引脚、中断和定时器等功能,如STC89C522.时钟电路:使用晶振为单片机提供稳定的时钟源。

3.7段LED数码管:选择合适的尺寸和颜色的数码管,用于显示小时、分钟和秒钟。

4.温度传感器:选择一款适合的温度传感器,如DS18B20,用于获取环境温度。

5.喇叭:用于发出闹钟提示音。

6.外部键盘:选择一款适合的键盘,用于设置和调整时间、日期、闹钟等参数。

三、软件设计1.初始化:设置单片机定时器、外部中断和其他必要的配置。

2.时间显示:通过定时器中断,更新时间,并将小时、分钟和秒钟分别显示在相应的LED数码管上。

3.闹钟功能:设置闹钟时间,定时器中断检测当前时间是否与闹钟时间一致,若一致则触发警报。

4.日历功能:使用定时器中断,更新日期、星期和月份,并将其显示在LED数码管上。

5.温度显示:通过定时器中断,读取温度传感器的数据,并将温度显示在LED数码管上。

6.键盘输入和控制:通过外部中断,读取键盘输入,并根据输入进行相应的操作,如设置时间、闹钟、日期等。

7.警报控制:根据设置的闹钟时间,触发警报功能,同时根据用户的设置进行控制。

四、测试与调试完成软件设计后,进行系统测试与调试,包括验证显示时间、日期、温度等功能的准确性,以及闹钟和警报功能的触发与控制。

单片机实现电子钟万年历秒表闹铃

单片机实现电子钟万年历秒表闹铃
sbit kaig=P1^0; /*启动/调制键*/
sbit ksec=P1^1; /*调整秒/日/秒表开关*/
sbit kmin=P1^2; /*调整分/月/显示秒表*/
sbit khour=P1^3; /*调整时/年的低两位*/
sbit date=P1^4; /*显示日期开关*/
sbit bai=P1^5; /*调整年高二位/整点闹钟开关*/
P2=0xff;
P2=0x0bf;
P0=table[shige]-0x80;//显示.隔时和分
delay(1);
P2=0xff;
P2=0x7f;
P0=table[shishi];delay(1ຫໍສະໝຸດ ;P2=0xff;}
if((i==1)&&(dx==1)&&(j==0))//显示年月日
{
dayge=day%10;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
TH1=(65536-10000)/256;
TL1=(65536-10000)%256;
EA=1; /*开启中断总开关*/
ET0=1;/*开启定时器0中断*/
i=0;/*控制显示,开关是否开启过*/
TR0=0;/*关闭定时器*/
void display()
{ if((i==1)&&(j==0)&&(dx==0))//显示时间
{secge=sec%10;
secshi=sec/10;
minge=min%10;
minshi=min/10;
hourge=hour%10;
hourshi=hour/10;

单片机课程设计报告--基于STC89C52单片机的电子时钟(日历)

单片机课程设计报告--基于STC89C52单片机的电子时钟(日历)

目录目录------------------------------------------------------------------------------1 摘要------------------------------------------------------------------------------2一、实验要求----------------------------------------------------------------2二、实验主要元器件介绍-------------------------------------------------32.1 STC89C52单片机简介---------------------------------------------3 2.2 LCD1602简介-------------------------------------------------------62.3 软件平台--------------------------------------------------------------7三、实验原理与设计内容-------------------------------------------------73.1 实验原理--------------------------------------------------------------7 3.2 三个组成部分--------------------------------------------------------73.3 键盘控制模块--------------------------------------------------------8四、调试过程----------------------------------------------------------------84.1 硬件调试--------------------------------------------------------------8 4.2 软件调试--------------------------------------------------------------94.3 测试数据与数据分析-----------------------------------------------9五、程序流程图-------------------------------------------------------------10六、任务分工与成果展示-------------------------------------------------116.1前期准备--------------------------------------------------------------11 6.2课程设计过程--------------------------------------------------------11 6.3个人主要工作及遇到问题-----------------------------------------116.4成果展示--------------------------------------------------------------12七、课程设计总结思考与致谢-------------------------------------------13八、参考文献----------------------------------------------------------------14 附录一:(程序)-------------------------------------------------------------15 附录二:(原理图)----------------------------------------------------------25 附录三:(实物图)----------------------------------------------------------25 附录四:(元件清单)-------------------------------------------------------26摘要:数字电子钟系统设计已经成熟,但是目前系统设计时基本都是采用LED 作为显示电路,造成硬件电路复杂、功耗高、产品体积庞大等特点;液晶显示模块由于具有低功耗、寿命长、体积小、显示内容丰富、价格低、接口控制方便等优点,因此在各类电子产品中被极广泛地推广和应用。

单片机万年历程序代码

单片机万年历程序代码

单片机万年历程序代码以下是一个示例单片机万年历的程序代码:```c#include <reg51.h>typedef unsigned char uchar;typedef unsigned int uint;sbit K1 = P2^0; // 显示年份sbit K2 = P2^1; // 显示月份sbit K3 = P2^2; // 显示日期uchar code year_tab[] = {31,28,31,30,31,30,31,31,30,31,30,31}; uchar code week_tab[] = {0x06,0x07,0x01,0x02,0x03,0x04,0x05}; uchar year, month, day, week;void delay(uint ms){uint i, j;for(i=ms;i>0;i--)for(j=110;j>0;j--);}uchar getKey(){if(K1==0) {delay(5);if(K1==0)return 1;while(!K1);}if(K2==0) {delay(5);if(K2==0)return 2;while(!K2);}if(K3==0) {delay(5);if(K3==0)return 3;while(!K3);}return 0;}void display(uchar num) {P0 = num;delay(1);P0 = 0x00;}void init(){TMOD=0x01;TH0=0xFC;TL0=0x67;EA=1;ET0=1;TR0=1;}void main(){init();while(1) {uchar key = getKey();if(key == 1) {year++;if(year == 100)year = 0;}else if(key == 2) {month++;if(month == 13)month = 1;}else if(key == 3) {day++;if(day > year_tab[month-1]) { day = 1;}}display(year / 10);display(year % 10);display(month / 10);display(month % 10);display(day / 10);display(day % 10);display(week);}}void timer0() interrupt 1{TH0=0xFC;TL0=0x67;week++;if(week == 7)week = 0;}```该代码的主要思路是通过外部三个按键模拟年、月和日的调节,通过一个定时器不断更新星期的计数,然后将年、月、日和星期分别在数码管上显示出来。

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

51单片机电子日历(电子时钟)程序经过两天的调试,完成了51单片机电子日历课程设计,现在把C程序源代码帖出来纪念一下:~硬件实验箱是伟福LAB2000实验箱。

程序代码:/****************************************************************************/ /* 电子日历,有时间显示、闹铃、日期、秒表及键盘设置功能*//* 功能键A: 设置位数字+1 闹钟模式下为闹钟开关秒表模式下为记时开关*//* 功能键B: 设置位数字-1 闹钟模式下为闹钟开关*//* 功能键C:设置模式及设置位选择秒表模式下为清零键*/ /* 功能键D:在四种工作模式下切换设置闹钟开关*//* 曹宇03电子0201029 *//* 2006.6.3 更新*//* 中央民族大学*/***********************************************************************/#include <reg51.h>#include <studio.h>/***************这里设置程序初始化时显示的时间****************/#define SET_HOUR 12 /*设置初始化小时*/#define SET_MINUTE 00 /*设置初始化分钟*/#define SET_SECOND 00 /*设置初始化秒数*//*************************系统地址****************************/#define BASE_PORT 0x8000 /*选通基地址*/#define KEY_LINE BASE_PORT+1 /*键盘行线地址*/#define KEY_COLUMN BASE_PORT+2 /*键盘列线地址*/#define LED_SEG BASE_PORT+4 /*数码管段选地址*/#define LED_BIT BASE_PORT+2 /*数码管位选地址*/#define LED_ON(x) XBYTE[LED_BIT]=(0x01<<1)<X)&NBSP; *6位led的位选通,带参数宏,参数为0~5*=""#define LED_OFF XBYTE[LED_SEG]=0x00 /*LED显示空*//**************在设置模式下对秒分时的宏定义*****************/#define SECOND 0 /*对应数码管右边两位*/#define MINUTE 1 /*对应数码管中间两位*/#define HOUR 2 /*对应数码管左边两位*//********************定义四种工作模式***********************/#define CLOCK clockstr /*时钟模式*/#define ALART alartstr /*闹钟模式*/#define DATE datestr /*日期模式*/#define TIMER timerstr /*秒表模式*//****************以下是所有子函数的声明*********************/void sys_init(void); /*系统的初始化程序*/void display(void); /*动态刷新一次数码管子程序*/void clockplus(void); /*时间加1S的子程序*/void update_clockstr(void); /*更新时间显示编码*/void update_alartstr(void); /*更新闹钟时间的显示编码*/void update_datestr(void); /*更新日期显示编码*/void update_timerstr(void); /*更新秒表时间的显示编码*/void deley(int); /*延时子程序*/void update_dispbuf(unsigned char *); /*更新显示缓冲区*/unsigned char getkeycode(void); /*获取键值子程序*/void keyprocess(unsigned char); /*键值处理子程序*/unsigned char getmonthdays(unsigned int,unsigned char);/*计算某月的天数子程序*//*功能键功能子函数*/void Akey(void); /*当前设置位+1 开关闹钟开关秒表*/void Bkey(void); /*当前设置位-1 开关闹钟*/void Ckey(void); /*设置位选择秒表清零*/void Dkey(void); /*切换四种工作模式*//**********************全局变量声明部分*********************/unsigned char led[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};/*从0~9的LED编码*/unsigned char ledchar[3]={0x5c,0x54,0x71};/*o n f*///unsigned char key[24]={ /* 键值代码数组对应键位:*/// 0x70,0x71,0x72,0x73,0x74,0x75, /* 7 8 9 A TRACE RESET*/// 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5, /* 4 5 6 B STEP MON */// 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5, /* 1 2 3 C HERE LAST */// 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5}; /* 0 F E D EXEC NEXT */struct{ /*时间结构体变量*/unsigned char s;unsigned char m;unsigned char h;}clock={SET_SECOND,SET_MINUTE,SET_HOUR};struct{ /*闹铃时间结构体变量*/unsigned char m;unsigned char h;}alart={SET_MINUTE,SET_HOUR};struct{ /*日期结构体变量*/unsigned int year;unsigned char month;unsigned char day;}date={6,1,1};struct{ /*秒表时间结构体变量*/unsigned char ms;unsigned char s;unsigned char m;}timer={0,0,0};unsigned char dispbuf[6]; /*显示缓冲区数组*/unsigned char clockstr[6]; /*时间显示的数码管编码数组*/unsigned char alartstr[6]; /*闹钟显示的数码管编码数组*/unsigned char datestr[6]; /*日期显示的数码管编码数组*/unsigned char timerstr[6]; /*秒表显示的数码管编码数组*/unsigned int itime=0,idot; /*定时器0中断计数*/unsigned char itime1=0; /*定时器1中断计数*/sbit P3_1=P3^1; /*外接蜂鸣器的管脚*/bdata bit IsSet=0; /*设置模式标志位0:正常走时1:设置模式*/bdata bit Alart_EN=0; /*闹铃功能允许位0:禁止闹铃1:允许闹铃*/bdata bit IsBeep=0; /*响铃标志位0:未响铃1:正在响铃*/unsigned char SetSelect=0; /*在设置模式IsSet=1时,正在被设置的位,对应上面的宏*/ unsigned char *CurrentMode; /*标志当前正设置的功能,如CurrentMode=CLOCK或CurrentMode=ALART等*/void timerplus(void);/**************************函数部分*************************/void main(void){sys_init();while(1){XBYTE[KEY_COLUMN,0x00]; /*给键盘列线赋全零扫描码,判断是否有键按下*/while((XBYTE[KEY_LINE]&0x0f)==0x0f) /*检测是否有键按下,无则一直进行LED的刷新显示*/{if(Alart_EN&&(clock.h==alart.h)&&(clock.m==alart.m)) {IsBeep=1;}else{ IsBeep=0;P3_1=0;}display();}keyprocess(getkeycode()); /*有键按下时得到键值,并送入键值处理程序*/display(); /*可要可不要*/}}void sys_init(void){TMOD=0x22; /*定时器0和1都设置为工作方式2,基准定时250×2=500us=0.5ms*/TH0=6; /*定时器0中断服务用来产生1秒时钟定时及闹钟蜂鸣器蜂鸣脉冲*/TL0=6; /*定时器1中断服务留给秒表使用,产生1/100秒定时*/TH1=6;TL1=6;ET0=1;ET1=1;EA=1;TR0=1;update_clockstr(); /*初始化时钟显示编码数组*/update_alartstr(); /*初始化闹钟显示编码数组*/update_datestr(); /*初始化日期显示编码数组*/update_timerstr(); /*初始化秒表显示编码数组*/update_dispbuf(clockstr);/*初始化显示缓冲数组*/CurrentMode=CLOCK; /*默认的显示摸式为时钟*/P3_1=0; /*蜂鸣器接线引脚复位*/}void timer0(void) interrupt 1 using 1 /*定时器0中断服务器,用来产生1秒定时*/{itime++;if(itime==1000){if(IsSet) /*在设置模式下,对正在设置的位闪烁显示*/{dispbuf[SetSelect*2]=0; /*对正在设置的位所对应的显示缓冲区元素赋0,使LED灭*/dispbuf[SetSelect*2+1]=0;}if(IsBeep) P3_1=!P3_1; /*闹钟模式时,产生峰鸣器响脉冲*/if(CurrentMode==CLOCK){dispbuf[2]=dispbuf[2]&0x7f;dispbuf[4]=dispbuf[4]&0x7f;}}if(itime==2000) /*两千次计数为1S 2000×0.5ms=1s*/{itime=0; /*定时1s时间到,软计数清零*/clockplus(); /*时间结构体变量秒数加1 */update_clockstr(); /* 更新时间显示编码数组*/if(CurrentMode!=TIMER) update_dispbuf(CurrentMode); /* 用时间编码数组更新显示缓冲区*/}}void timer1(void) interrupt 3 using 2 /*定时器1中断服务器,用来产生1/100秒定时*/ {idot++;if(++itime1==20) /*20*0.5ms=10ms*/{itime1=0;timerplus();update_timerstr();if(CurrentMode==TIMER)update_dispbuf(timerstr);dispbuf[2]=dispbuf[2]&0x7f; /*关闭小数点的显示*/dispbuf[4]=dispbuf[4]&0x7f;if(idot<1000) /*闪烁显示小数点*/{dispbuf[2]=dispbuf[2]|0x80;dispbuf[4]=dispbuf[4]|0x80;}else{dispbuf[2]=dispbuf[2]&0x7f;dispbuf[4]=dispbuf[4]&0x7f;}}}if(idot==2000) idot=0;}/*功能模块子函数*/void clockplus(void) /*时间加1s判断分,时子函数*/{if(++clock.s==60) /*秒位判断*/{clock.s=0;if(++clock.m==60) /*分位判断*/{clock.m=0;if(++clock.h==24) /*时位判断*/{clock.h=0;if(++date.day==(getmonthdays(date.year,date.month)+1)){date.day=1;if(++date.month==13) date.month=1;}}}}}void timerplus() /*秒表1/100秒位加1,判断秒、分子程序*/ {if(++timer.ms==100){timer.ms=0;if(++timer.s==60)timer.s=0;if(++timer.m==60){timer.m=0;}}}}void update_clockstr(void) /*更新时钟显示代码数组clockstr*/{clockstr[0]=led[clock.s%10]; /*给元素0赋相应数码管显示编码,编码序号是秒数的个位*/ clockstr[1]=led[(int)(clock.s/10)]; /*给元素1赋相应数码管显示编码,编码序号是秒数的十位*/clockstr[2]=led[clock.m%10]; /*以下类推*/clockstr[3]=led[(int)(clock.m/10)];clockstr[4]=led[clock.h%10];clockstr[5]=led[(int)(clock.h/10)];}void update_alartstr(void) /*更新闹钟显示代码数组alartstr*/{ /*右边两位显示on:闹钟开启of:闹钟关闭*/if(Alart_EN) alartstr[0]=ledchar[1];/*显示字母n*/else alartstr[0]=ledchar[2]; /*显示字母f*/alartstr[1]=ledchar[0]; /*显示字母o*/alartstr[2]=led[alart.m%10];alartstr[3]=led[(int)(alart.m/10)];alartstr[4]=led[alart.h%10];alartstr[5]=led[(int)(alart.h/10)];}void update_datestr(void) /*更新日期显示代码数组datestr*/{datestr[0]=led[date.day%10];datestr[1]=led[(int)(date.day/10)];datestr[2]=led[date.month%10];datestr[3]=led[(int)(date.month/10)];datestr[4]=led[date.year%10];datestr[5]=led[(int)(date.year/10)];}void update_timerstr(void) /*更新秒表显示代码数组timerstr*/{timerstr[0]=led[timer.ms%10];timerstr[1]=led[(int)(timer.ms/10)];timerstr[2]=led[timer.s%10];timerstr[3]=led[(int)(timer.s/10)];timerstr[4]=led[timer.m%10];timerstr[5]=led[(int)(timer.m/10)];}void display(void) /*刷新显示六位LED一次*/{unsigned char i;for(i=0;i<6;i++){LED_ON(i); /*选通相应位*/XBYTE[LED_SEG]=dispbuf[i]; /*写显示段码*/deley(50); /*延时显示*/LED_OFF; /*写LED全灭段码*/}}void update_dispbuf(unsigned char *str) /*更新显示缓冲区子函数,参数为要用来更新缓冲区的源字符数组的首地址*/{dispbuf[0]=str[0]; /*将要更新的源字符数组内容COPY至dispbuf数组,用作显示缓冲区*/dispbuf[1]=str[1];dispbuf[2]=str[2]|0x80; /*默认把时位和分位后面的小数点显示出来,根据需要再取舍*/ dispbuf[3]=str[3];dispbuf[4]=str[4]|0x80;dispbuf[5]=str[5];}void deley(int i) /*延时子函数*/{while(i--);}unsigned char getkeycode(void) /*键盘扫描子程序,返回获得的键码*/{unsigned char keycode; /*键码变量,一开始存行码*/unsigned char scancode=0x20; /*列扫描码*/unsigned char icolumn=0; /*键的列号*/display(); /*用刷新数码管显示的时间去抖*/XBYTE[KEY_COLUMN]=0x00;keycode=XBYTE[KEY_LINE]&0x0f; /*从行端口读入四位行码*/while((scancode&0x3f)!=0) /*取scancode的低六位,只要没变为全0,则执行循环*/{XBYTE[KEY_COLUMN]=(~scancode)&0x3f; /*给列赋扫描码,第一次为011111*/if((XBYTE[KEY_LINE]&0x0f)==keycode) break; /*检测按键所在的列跳出循环*/ scancode=scancode>>1; /*列扫描码右移一位*/icolumn++; /*列号加1*/}keycode=keycode<<4; /*把行码移到高四位*/keycode=keycode|icolumn; /*由行码和列码组成键码*///等待按键放开XBYTE[KEY_COLUMN]=0x00;while((XBYTE[KEY_LINE]&0x0f)!=0x0f) display();return keycode;}void keyprocess(unsigned char keycode) /*键值处理函数*/{switch (keycode){case 0x73: Akey();break;case 0xB3: Bkey();break;case 0xD3: Ckey();break;case 0xE3: Dkey();break;default: break;}update_dispbuf(CurrentMode);}unsigned char getmonthdays(unsigned int year,unsigned char month)/*得到某月的天数*/ {unsigned char days;switch (month){case 4:case 6:case 9:case 11:days=30;break;case 2: if(year%4==0) days=29;else days=28;break;default:days=31;break;}return days;}/*功能键子函数部分*/void Akey(void) /*对当前设置位进行加一操作,如果设置秒位,则给秒位清零*/ {if(CurrentMode==TIMER) /*秒表模式下启闭走时*/{ TR1=!TR1;return;}if(!IsSet) return; /*如果不是设置模式退出*/switch (SetSelect){case SECOND:if(CurrentMode==CLOCK){clock.s=0; /*如果当前被设置位是秒位,则清零秒位*/ update_clockstr();}if(CurrentMode==ALART){Alart_EN=!Alart_EN;update_alartstr();}if(CurrentMode==DA TE){if(++date.day==(getmonthdays(date.year,date.month)+1)) date.day=1;update_datestr();}if(CurrentMode==TIMER){TR1=!TR1;}break;case MINUTE:if(CurrentMode==CLOCK){if(++clock.m==60) clock.m=0; /*如果当前被设置分位,则分位加1*/ update_clockstr();}if(CurrentMode==ALART){if(++alart.m==60) alart.m=0;update_alartstr();}if(CurrentMode==DA TE){if(++date.month==13) date.month=1;update_datestr();}break;case HOUR: if(CurrentMode==CLOCK){if(++clock.h==24) clock.h=0; /*如果当前被设置时位,则时位加1*/ update_clockstr();}if(CurrentMode==ALART){if(++alart.h==24) alart.h=0;update_alartstr();}if(CurrentMode==DA TE){if(++date.year==100) date.year=0;update_datestr();}break;default: break;}update_dispbuf(CurrentMode);}void Bkey(void) /*对当前设置位进行减一操作,如果设置秒分,则给秒位清零,类比Akey()函数*/{if(!IsSet) return;switch (SetSelect){case SECOND:if(CurrentMode==CLOCK){clock.s=0;update_clockstr();}if(CurrentMode==ALART){Alart_EN=!Alart_EN;update_alartstr();}if(CurrentMode==DA TE){if(--date.day==0x00) date.day=getmonthdays(date.year,date.month);update_datestr();}break;case MINUTE:if(CurrentMode==CLOCK){if(--clock.m==0xff) clock.m=59;update_clockstr();}if(CurrentMode==ALART){if(--alart.m==0xff) alart.m=59;update_alartstr();}if(CurrentMode==DA TE){if(--date.month==0x00) date.month=12;update_datestr();}break;case HOUR: if(CurrentMode==CLOCK){if(--clock.h==0xff) clock.h=23;update_clockstr();}if(CurrentMode==ALART){if(--alart.h==0xff) alart.h=23;update_alartstr();}if(CurrentMode==DA TE){if(--date.year==0xffff) date.year=99;update_datestr();}break;default: break;}update_dispbuf(CurrentMode);}void Ckey(void) /*正常走时模式和设置模式的切换*/{if(CurrentMode==TIMER){TR1=0; /*初始化定时器1设置,停止秒表记时*/ TH1=6;TL1=6;timer.ms=0; /*初始化秒表数组*/timer.s=0;timer.m=0;update_timerstr();}else{if(IsSet==0) /*在非秒表模式下,第一次按下C键进入设置模式,设置时位*/{IsSet=1; /*置位标志位,进入设置模式*/SetSelect=HOUR;return;} /*第二次按C键设置分位,第三次按键设置秒位,第四次按键完成退出设置*/if(SetSelect==0) /*按到第四次,即设置完秒位后,将标志位IsSet置0,完成设置*/{IsSet=0; /*复位标志位,进入正常走时模式*/return;}if(SetSelect>0) SetSelect--; /*设置位的标志变量SetSelect=0:时位1:分位2:秒位*/ }}void Dkey(void) /*工作状态切换:时钟、闹钟、日期、秒表*/{if(CurrentMode==CLOCK) /*切换至闹钟,同时开关闹钟*/{ CurrentMode=ALART;Alart_EN=!Alart_EN;update_alartstr();return;}if(CurrentMode==ALART) /*切换至日期*/{ CurrentMode=DATE;return;}if(CurrentMode==DATE) /*切换至秒表,同时关闭设置模式*/{CurrentMode=TIMER;IsSet=0;return;}if(CurrentMode==TIMER) /*切换至时钟*/{CurrentMode=CLOCK;return;}}。

相关文档
最新文档