最全最好的课程设计-51单片机电子日历时钟( 含源程序)

合集下载

51电子时钟课程设计

51电子时钟课程设计

51电子时钟课程设计一、课程目标知识目标:1. 学生能理解51单片机的内部结构及其工作原理;2. 学生能掌握电子时钟的基本原理,包括时钟芯片的初始化和使用方法;3. 学生能运用C语言编写程序,实现电子时钟的基本功能,如时、分、秒显示。

技能目标:1. 学生能运用已学的电子知识和编程技巧,完成51电子时钟的电路设计和程序编写;2. 学生通过实际操作,培养动手能力,提高解决实际问题的能力;3. 学生能通过课程学习,掌握基本的焊接技能,完成电子时钟的制作。

情感态度价值观目标:1. 学生在课程学习过程中,培养对电子技术和编程的兴趣,提高主动学习的积极性;2. 学生通过团队协作,培养沟通与合作的意识,增强团队精神;3. 学生在作品展示环节,学会欣赏他人的优点,提高自信心,培养创新精神和实践能力。

课程性质:本课程为实践性较强的课程,结合51单片机技术和电子时钟原理,注重培养学生的动手能力和实际问题解决能力。

学生特点:学生在前期课程中已掌握基本的电子知识和编程技巧,具备一定的实践基础。

教学要求:教师需引导学生运用所学知识,完成电子时钟的设计与制作,注重培养学生的创新思维和团队协作能力。

在教学过程中,关注学生的个体差异,提供个性化的指导。

通过课程目标的分解,确保学生能够实现预期的学习成果。

二、教学内容本课程教学内容主要包括以下几部分:1. 51单片机基础:复习51单片机的内部结构、工作原理,重点掌握时钟电路、复位电路和I/O口的使用。

2. 电子时钟原理:介绍电子时钟的基本构成,包括时钟芯片、晶振、显示屏等,分析时钟芯片的初始化和使用方法。

3. C语言编程:回顾C语言基础知识,重点讲解51单片机编程的语法和技巧,为编写电子时钟程序打下基础。

4. 电路设计与制作:指导学生进行电子时钟的电路设计,包括元器件的选择、电路图的绘制和PCB板的设计。

5. 程序编写与调试:教授学生编写电子时钟程序,实现时、分、秒的显示功能,并进行程序调试。

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

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

自己制作的单片机万年历程序+原理图单片机万年历仿真原理图如下仿真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);。

基于51单片机的万年历

基于51单片机的万年历
二、系统的硬件设计与实现
洞洞板/万能板成品
图片左下角有地址-有录像
2.1电路设计框图
2.2 系统硬件概述
本电路是由AT89C52单片机为控制核心,具有在线编程功能,低功耗,能在3V超低压工作;本设计直接采用单片机定时计数器提供秒信号,它可以对年、月、日、星期、时、分、秒进行计时,具有闰年补偿功能,工作电压为2.5V~5.5V。显示部份由LCD1602完成。
写指令38H(不检测忙信号)以后每次写指令、读/写数据操作均需要检测忙信号
写指令38H:显示模式设置写指令08H:显示关闭写指令01H:显示清屏
写指令06H:显示光标移动设置写指令0CH:显示开及光标设置
三、系统的软件设计
3.1 程序流程框图
否否否
是是是
否否否
是是是
四、总结
在整个设计过程中,遇到了很多问题,但在自己的努力和同学的帮助下得到了解决,较好的完成了作品,勉强达到了预期的目的。并且在这一过程中也学到了许多之前没学过的知识。在电路焊接时虽然没什么大问题,但从中也知道了焊接在整个作品中的重要性,对电路的设计、布局要先有一个好的构思,然后再焊才可以使电路板美观并且可以减少飞线的使用,并且最好焊接一部分测试一部分。通过这次设计,特别是通过程序的编写,更深入地了解了单片机的内部结构和外围器件的应用。
sbit s1=P2^3;
sbit s2=P2^2;
sbit s3=P2^0;
unsigned char tt,s1num;
char miao,fen,shi,yue=1,ri=1,week,nian;
unsigned char a[]="2000-01-01MON";
char b[]=" 00:00:00";

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

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

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

51单片机课程设计——电子万年历

51单片机课程设计——电子万年历

电子万年历的设计学院计算机与控制工程学院专业班级自动化学生姓名指导教师2010年6月25日引言随着社会、科技的发展,人类得知时间,从观太阳、摆钟到现在电子钟,不断研究、创新。

为了在观测时间的同时,能够了解其它与人类密切相关的信息,比如温度、星期、日期等,电子万年历诞生了,它集时间、日期、星期和温度功能于一身,具有读取方便、显示直观、功能多样、电路简洁等诸多优点,符合电子仪器仪表的发展趋势,具有广阔的市场前景。

二十一世纪的今天,最具代表性的计时产品就是电子万年历,它是近代世界钟表业界的第三次革命。

第一次是摆和摆轮游丝的发明,相对稳定的机械振荡频率源使钟表的走时差从分级缩小到秒级,代表性的产品就是带有摆或摆轮游丝的机械钟或表。

第二次革命是石英晶体振荡器的应用,发明了走时精度更高的石英电子钟表,使钟表的走时月差从分级缩小到秒级。

第三次革命就是单片机数码计时技术的应用(电子万年历),使计时产品的走时日差从分级缩小到1/600万秒,从原有传统指针计时的方式发展为人们日常更为熟悉的夜光数字显示方式,直观明了,并增加了全自动日期、星期、温度以及其他日常附属信息的显示功能,它更符合消费者的生活需求!因此,电子万年历的出现带来了钟表计时业界跨跃性的进步……我国生产的电子万年历有很多种,总体上来说以研究多功能电子万年历为主,使万年历除了原有的显示时间,日期等基本功能外,还具有闹铃,报警等功能。

商家生产的电子万年历更从质量,价格,实用上考虑,不断的改进电子万年历的设计,使其更加的具有市场。

本设计主要采用AT89C51单片机作为主控核心,由DS1302时钟芯片提供时钟、LED 动态扫描显示屏显示。

AT89C51单片机是由Atmel公司推出的,功耗小,电压可选用4~6V电压供电;DS1302时钟芯片是美国DALLAS公司推出的具有涓细电流充电功能的低功耗实时时钟芯片,它可以对年、月、日、星期、时、分、秒进行计时,还具有闰年补偿等多种功能,而且DS1302的使用寿命长,误差小;数字显示是采用的LED液晶显示屏来显示,可以同时显示年、月、日、星期、时、分、秒和温度等信息。

51单片机电子时钟课程设计

51单片机电子时钟课程设计

一、设计要求1、准确计时,以数字形式显示时、分、秒地时间.2、小时以24小时计时形式,分秒计时为60进位.3、校正时间功能,即能随意设定走时时间.4、闹钟功能,一旦走时到该时间,能以声或光地形式告警提示.5、设计5V直流电源,系统时钟电路、复位电路.6、能指示秒节奏,即秒提示.7、可采用交直流供电电源,且能自动切换.二、设计方案和论证本次设计时钟电路,使用了ATC89C51单片机芯片控制电路,单片机控制电路简单且省去了很多复杂地线路,使得电路简明易懂,使用键盘键上地按键来调整时钟地时、分、秒,用一扬声器来进行定时提醒,同时使用汇编语言程序来控制整个时钟显示,使得编程变得更容易,这样通过四个模块:键盘、芯片、扬声器、LED显示即可满足设计要求. 2.1、总设计原理框图如下图所示:2.2、设计方案地选择1.计时方案方案1:采用实时时钟芯片现在市场上有很多实时时钟集成电路,如DS1287、DS12887、DS1302等.这些实时时钟芯片具备年、月、日、时、分、秒计时功能和多点定时功能,计时数据地更新每秒自动进行一次,不需要程序干预.因此,在工业实时测控系统中多采用这一类专用芯片来实现实时时钟功能.方案2:使用单片机内部地可编程定时器.利用单片机内部地定时计数器进行中端定时,配合软件延时实现时、分、秒地计时.该方案节省硬件成本,但程序设计较为复杂.2.显示方案对于实时时钟而言,显示显然是另一个重要地环节.通常LED显示有两种方式:动态显示和静态显示.静态显示地优点是程序简单、显示亮度有保证、单片机CPU地开销小,节约CPU地工作时间.但占有I/O口线多,每一个LED都要占有一个I/O口,硬件开销大,电路复杂.需要几个LED就必须占有几个并行口,比较适用于LED数量较少地场合.当然当LED数量较多地时候,可以使用单片机地串行口通过移位寄存器地方式加以解决,但程序编写比较麻烦.LED动态显示硬件连接简单,但动态扫描地显示方式需要占有CPU较多地时间,在单片机没有太多实时测控任务地情况下可以采用.本系统需要采用6位LED数码管来分别显示时、分、秒,因数码管个数较多,故本系统选择动态显示方式.2.3硬件部分1、STC89C51单片机介绍STC89C51单片机是由深圳宏晶公司代理销售地一款MCU,是由美国设计生产地一种低电压、高性能CMOS 8位单片机,片内含8kbytes地可反复写地FlashROM和128bytes地RAM,2个16位定时计数器[5].STC89C51单片机内部主要包括累加器ACC(有时也简称为A)、程序状态字PSW、地址指示器DPTR、只读存储器ROM、随机存取存储器RAM、寄存器、并行I/O接口P0~P3、定时器/计数器、串行I/O接口以及定时控制逻辑电路等.这些部件通过内部总线联接起来,构成一个完整地微型计算机.其管脚图如图所示.STC89C51单片机管脚结构图VCC:电源.GND:接地.P0口:P0口为一个8位漏级开路双向I/O口,每脚可吸收8TTL门电流.当P1口地管脚第一次写1时,被定义为高阻输入.P0能够用于外部程序数据存储器,它可以被定义为数据/地址地第八位.在FIASH编程时,P0 口作为原码输入口,当FIASH进行校验时,P0输出原码,此时P0外部必须被拉高.P1口:P1口是一个内部提供上拉电阻地8位双向I/O口,P1口缓冲器能接收输出4TTL门电流.P1口管脚写入1后,被内部上拉为高,可用作输入,P1口被外部下拉为低电平时,将输出电流,这是由于内部上拉地缘故.在FLASH编程和校验时,P1口作为第八位地址接收.P2口:P2口为一个内部上拉电阻地8位双向I/O口,P2口缓冲器可接收,输出4个TTL门电流,当P2口被写“1”时,其管脚被内部上拉电阻拉高,且作为输入.并因此作为输入时,P2口地管脚被外部拉低,将输出电流.这是由于内部上拉地缘故.P2口当用于外部程序存储器或16位地址外部数据存储器进行存取时,P2口输出地址地高八位.在给出地址“1”时,它利用内部上拉优势,当对外部八位地址数据存储器进行读写时,P2口输出其特殊功能寄存器地内容.P2口在FLASH编程和校验时接收高八位地址信号和控制信号.P3口:P3口管脚是8个带内部上拉电阻地双向I/O口,可接收输出4个TTL门电流.当P3口写入“1”后,它们被内部上拉为高电平,并用作输入.作为输入,由于外部下拉为低电平,P3口将输出电流(ILL)这是由于上拉地缘故.P3口也可作为AT89C51地一些特殊功能口,如下表所示:口管脚备选功能P3.0 RXD(串行输入口)P3.1 TXD(串行输出口)P3.2 /INT0(外部中断0)P3.3 /INT1(外部中断1)P3.4 T0(记时器0外部输入)P3.5 T1(记时器1外部输入)P3.6 /WR(外部数据存储器写选通)P3.7 /RD(外部数据存储器读选通)P3口同时为闪烁编程和编程校验接收一些控制信号.RST:复位输入.当振荡器复位器件时,要保持RST脚两个机器周期地高电平时间.ALE/PROG:当访问外部存储器时,地址锁存允许地输出电平用于锁存地址地地位字节.在FLASH编程期间,此引脚用于输入编程脉冲.在平时,ALE 端以不变地频率周期输出正脉冲信号,此频率为振荡器频率地1/6.因此它可用作对外部输出地脉冲或用于定时目地.然而要注意地是:每当用作外部数据存储器时,将跳过一个ALE脉冲.如想禁止ALE地输出可在SFR8EH地址上置0.此时,ALE只有在执行MOVX,MOVC指令是ALE才起作用.另外,该引脚被略微拉高.如果微处理器在外部执行状态ALE禁止,置位无效.PSEN:外部程序存储器地选通信号.在由外部程序存储器取指期间,每个机器周期两次/PSEN有效.但在访问外部数据存储器时,这两次有效地/PSEN信号将不出现.EA/VPP:当/EA保持低电平时,则在此期间外部程序存储(0000H-FFFFH),不管是否有内部程序存储器.注意加密方式1时, /EA将内部锁定为RESET;当/EA端保持高电平时,此间内部程序存储器.在FLASH编程期间,此引脚也用于施加12V编程电源(VPP).2、上电按钮复位电路本设计采用上电按钮复位电路:首先经过上电复位,当按下按键时,RST直接与VCC相连,为高电平形成复位,同时电解电容被电路放电;按键松开时,VCC对电容充电,充电电流在电阻上,RST依然为高电平,仍然是复位,充电完成后,电容相当于开路,RST为低电平,单片机芯片正常工作.其中电阻R2决定了电容充电地时间,R2越大则充电时间长,复位信号从VCC回落到0V地时间也长.3、晶振电路本设计晶振电路采用12M地晶振.晶振地作用是给单片机正常工作提供稳定地时钟信号.单片机地晶振并不是只能用12M,只要不超过20M就行,在准许地范围内,晶振越大,单片机运行越快,还有用12M地就是好算时间,因为一个机器周期为1/12时钟周期,所以这样用12M地话,一个时钟周期为12us,那么定时器计一次数就是1us了,电容范围在20-40pF之间,这里连接地是30pF地电容.机器周期=10*晶振周期=12*系统时钟周期4.下载端口设计用到地STC89C52单片机芯片地ISP下载线是通过单片机地TXD,RXD引脚把程序烧进去地.管脚TXD和RXD用于异步串行通信.其实STC89C52单片机地ISP下载线就是一个max232芯片连接STC和计算机地串行通信口.计算机把程序从九针串口送到max232芯片,电平转换后送进单片机地串行口,也就是TXD和RXD.然后单片机地串行模块把数据送到程序区.5、显示电路就时钟而言,通常可采用液晶显示或数码管显示.由于一般地段式液晶屏,需要专门地驱动电路,而且液晶显示作为一种被动显示,可视性相对较差;对于具有驱动电路和微处理器接口地液晶显示模块(字符或点阵),一般多采用并行接口,对微处理器地接口要求较高,占用资源多.另外,89C2051本身无专门地液晶驱动接口,因此,本时钟采用数码管显示方式.数码管作为一种主动显示器件,具有亮度高、价格便宜等优点,而且市场上也有专门地时钟显示组合数码管.对于实时时钟而言,显示显然是另一个重要地环节.通常LED显示有两种方式:动态显示和静态显示.静态显示地优点是程序简单、显示亮度有保证、单片机CPU地开销小,节约CPU地工作时间.但占有I/O口线多,每一个LED都要占有一个I/O口,硬件开销大,电路复杂.需要几个LED就必须占有几个并行口,比较适用于LED数量较少地场合.当然当LED数量较多地时候,可以使用单片机地串行口通过移位寄存器地方式加以解决,但程序编写比较麻烦.LED动态显示硬件连接简单,但动态扫描地显示方式需要占有CPU较多地时间,在单片机没有太多实时测控任务地情况下可以采用.本系统需要采用6位LED数码管来分别显示时、分、秒,因数码管个数较多,故本系统选择动态显示方式.6、时钟显示校正电路本设计利用按键开关来校正时钟显示地数字.当按钮按下时,将在相应地端口输入一个低电平,通过相应地程序来改变时钟显示.其中S1按键开关用来选择要修改地数字;S2按键用来增加所选数字地数值;S3按键用来减少所选数字地数值.7、蜂鸣器电路电路接法:三极管选定PNP型,基极B连接5V电压,发射极E连接一个1K左右地电阻后接I/O口,集电极C连接蜂鸣器后接地.单片机在复位后地个I/O口是高电平,此时三极管是截止地,编写程序使选定地I/O为低电平,此时三极管导通,导通后蜂鸣器与电源正极连通,构成一个工作回路,从而发出滴滴地响声.其中电阻R1在电路里起分压限流地作用,PNP三极管起到模拟开关地作用.8、外接电源电路外接电源电路用于连接外部5V电源与电子时钟电路,通过自锁开关控制电路地导通与断开,当开关闭合时,电路导通,外部电源给电路正常供电,电子时钟正常工作.当开关断开时,电路停止工作.9、总电路原理图(五)软件部分根据上述电子时钟地工作流程,软件设计可分为以下几个功能模块:(1)主程序模块.主程序主要用于系统初始化:设置计时缓冲区地位置及初值,设置8155地工作方式、定时器地工作方式和计数初值等参数.主程序流程如下图所示.开始定义堆栈区8155、T0、数据缓冲区、标志位初始化调用键盘扫描程序否是C/R键?地址指针指向计时缓冲区主程序流程图(2)计时模块.即定时器0中断子程序,完成刷新计时缓冲区地功能.系统使用6MHz地晶振,假设定时器0工作在方式1,则定时器地最大定时时间为65.536ms,这个值远远小于1s.因此本系统采用定时器与软件循环相结合地定时方法.设定时器0工作在方式1,每隔50ms溢出中断一次,则循环中断20次延时时间是1s,上述过程重复60次为1分,分计时60次为1小时,小时计时24次则时间重新回到00:00:00.因定时器0工作在方式1,则50ms定时对应地定时器初值为:65536-50ms/2us=40536=9E58H,即TH0=9EH,TH0=58H.但应当指出:CPU从响应T0中断到完成定时器初值重装这段时间,定时器T0并不停止工作,而是继续计数.因此,为了确保T0能准确定时50ms,重装地定时器初值必须加以修正,修正地定时器初值必须考虑到从原定时器初值中扣除计数器多计地脉冲个数.由于定时器计数脉冲地周期恰好和机器周期吻合,因此修正量等于CPU从响应中断到重装完TL0为止所用地机器周期数.CPU响应中断通常要3~8个机器周期.经过测试,定时器0重装地计数初值设为9E5FH~9E67H,可以满足精度要求.另外,MCS-51单片机只有二进制加法指令,而时间是按十进制递增,因此用加法指令后必须进行二-十进制转换.计时模块流程图如下图所示.计时模块流程图(3)时间设置模块.该模块由键盘输入相应地数据来设置当前时间.程序通过调用一个键盘设置子程序通过键盘扫描将键入地6位时间值送入显示缓冲区.设置时间后,时钟要从这个时间开始计时,而时分秒单元各占一个字节,键盘占6个字节.因此程序中要调用一个合字子程序将显示缓冲区中地6位BCD码合并为3位压缩BCD码,并送入计时缓冲区,作为当前计时起始时间.该程序同时要检测输入时间值地合法性,若键盘输入地小时值大于23,分、秒值大于59,则不合法,将取消本次设置,清零重新开始计时.时间设置和键盘设置子程序地流程图如下图所示.时间设置流程图键盘设置子程序流程图(4)显示模块.该模块完成时分秒6位LED地动态显示.因为显示为6位,二计时是3个字节单元,为此,必须将3字节计时缓冲区中地时分秒压缩BCD码拆分为6字节BCD码,并送入显示缓冲区中.当按下调整时间键后,在6位设置完成之前,这6个LED应该显示键人地数据,不显示当前地时间.为此,我们设置了一个计时显示允许标志位F0,在时间设置期间F0=1,不调用刷新显示缓冲区地子程序.显示程序流程图如下图所示.保护现场是显示程序流程图键盘扫描程序流程图程序:ORG 0000H AJMP MAIN ORG 000BH AJMP TIME ORG 0300H MAIN:mov 20h,#00h MOV 21H,#00H MOV 22H,#00H MOV 23H,#00H MOV IP,#02H 。

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;}}当我被上帝造出来时,上帝问我想在人间当一个怎样的人,我不假思索的说,我要做一个伟大的世人皆知的人。

基于51单片机汇编语言的数字钟课程设计报告(含有闹钟万年历)

基于51单片机汇编语言的数字钟课程设计报告(含有闹钟万年历)

单片微型计算机课程设计报告多功能电子数字钟姓 名 许伟敏学 号 060301021124班 级 电气二班指导教师 林卫2009-06-25目录一:概述 (1)二:设计基本原理简介 (2)三:设计要求及说明 (3)四:整体设计方案 (4)系统硬件电路设计 4系统软件总流程设计 5模块划分及分析 6五:单模块流程设计 (8)各模块设计概述、流程图 8模块源程序集合及注释 13六:单模块软件测试 (23)七:系统检测调试 (24)硬件电路调试软件部分烧写调试八:系统优化及拓展 (26)九:心得体会 (28)单片微型计算机课程设计 基于汇编语言的电子数字钟 概述课程设计流程图↑一、概述课程设计题目:电子数字钟应用知识简介:● 51单片机单片机又称单片微控制器,它不是完成某一个逻辑功能的芯片,而是把一个计算机系统集成到一个芯片上。

作为嵌入式系统控制核心的单片机具有其体积小、功能全、性价比高等诸多优点。

51系列单片机是国内目前应用最广泛的单片机之一,随着嵌入式系统、片上系统等概念的提出和普遍接受及应用,51系列单片机的发展又进入了一个新的阶段。

在今后很长一段时间内51系列单片机仍将占据嵌入式系统产品的中低端市场。

● 汇编语言汇编语言是一种面向机器的计算机低级编程语言,通常是为特定的计算机或系列计算机专门设计的。

汇编语言保持了机器语言的优点,具有直接和简捷的特点,其代码具有效率高实时性强等优点。

但是对于复杂的运算或大型程序,用汇编语言编写将非常耗时。

汇编语言可以与高级语言配合使用,应用十分广泛。

● ISPISP (In-System Programming )在系统可编程,是当今流行的单片机编程模式,指电路板上的空白元器件可以编程写入最终用户代码,而不需要从电路板上取下元器件。

已经编程的器件也可以用ISP 方式擦除或再编程。

本次课程设计便使用ISP 方式,直接将编写好的程序下载到连接好的单片机中进行调试。

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

LED日历时钟课程设计院系:班级:姓名:学号:指导教师:2012 年06 月16 日目录摘要单片机自20世纪70年代问世以来,以其极高的性能价格比,受到人们的重视和关注,应用很广、发展很快。

单片机体积小、重量轻、抗干扰能力强、环境要求不高、价格低廉、可靠性高、灵活性好、开发较为容易。

由于具有上述优点,在我国,单片机已广泛地应用在工业自动化控制、自动检测、智能仪器仪表、家用电器、电力电子、机电一体化设备等各个方面,而51单片机是各单片机中最为典型和最有代表性的一种。

这次毕业设计通过对它的学习、应用,以A T89S51芯片为核心,辅以必要的电路,设计了一个简易的电子时钟,它由4.5V直流电源供电,通过数码管能够准确显示时间,调整时间,从而到达学习、设计、开发软、硬件的能力。

第一章前言数字电子钟具有走时准确,一钟多用等特点,在生活中已经得到广泛的应用。

虽然现在市场上已有现成的电子钟集成电路芯片,价格便宜、使用也方便,但是人们对电子产品的应用要求越来越高,数字钟不但可以显示当前的时间,而且可以显示期、农历、以及星期等,给人们的生活带来了方便。

另外数字钟还具备秒表和闹钟的功能,且闹钟铃声可自选,使一款电子钟具备了多媒体的色彩。

单片机具有体积小、功能强可靠性高、价格低廉等一系列优点,不仅已成为工业测控领域普遍采用的智能化控制工具,而且已渗入到人们工作和和生活的各个角落,有力地推动了各行业的技术改造和产品的更新换代,应用前景广阔。

时钟电路在计算机系统中起着非常重要的作用,是保证系统正常工作的基础。

在一个单片机应用系统中,时钟有两方面的含义:一是指为保障系统正常工作的基准振荡定时信号,主要由晶振和外围电路组成,晶振频率的大小决定了单片机系统工作的快慢;二是指系统的标准定时时钟,即定时时间,它通常有两种实现方法:一是用软件实现,即用单片机内部的可编程定时/计数器来实现,但误差很大,主要用在对时间精度要求不高的场合;二是用专门的时钟芯片实现,在对时间精度要求很高的情况下,通常采用这种方法,典型的时钟芯片有:DS1302,DS12887,X1203等都可以满足高精度的要求。

AT89S51是一个低功耗,高性能CMOS 8位单片机,片内含4k B ytes ISP(In-system programmable)的可反复擦写1000次的Flash只读程序存储器,器件采用ATMEL公司的高密度、非易失性存储技术制造,兼容标准MCS-51指令系统及80C51引脚结构,芯片内集成了通用8位中央处理器和ISP Flash存储单元,功能强大的微型计算机的AT89S51可为许多嵌入式控制应用系统提供高性价比的解决方案。

AT89S51具有如下特点:40个引脚,4k Bytes Flash片内程序存储器,128 bytes的随机存取数据存储器(RAM),32个外部双向输入/输出(I/O)口,5个中断优先级2层中断嵌套中断,2个16位可编程定时计数器,2个全双工串行通信口,看门狗(WDT)电路,片内时钟振荡器。

此外,AT89S51设计和配置了振荡频率可为0Hz并可通过软件设置省电模式。

空闲模式下,CPU暂停工作,而RAM定时计数器,串行口,外中断系统可继续工作,掉电模式冻结振荡器而保存RAM的数据,停止芯片其它功能直至外中断激活或硬件复位。

同时该芯片还具有PDIP、TQFP 和PLCC等三种封装形式,以适应不同产品的需求。

本文主要介绍用单片机内部的定时/计数器来实现电子时钟的方法,本设计由单片机AT89S51芯片和LED数码管为核心,辅以必要的电路,构成了一个单片机电子时钟。

第二章关于电子时钟2.1电子时钟简介1957年,Ventura发明了世界上第一个电子表,从而奠定了电子时钟的基础,电子时钟开始迅速发展起来。

现代的电子时钟是基于单片机的一种计时工具,采用延时程序产生一定的时间中断,用于一秒的定义,通过计数方式进行满六十秒分钟进一,满六十分小时进一,满二十四小时小时清零。

从而达到计时的功能,是人民日常生活补课缺少的工具。

2.2 电子时钟的基本特点现在高精度的计时工具大多数都使用了石英晶体振荡器,由于电子钟、石英钟、石英表都采用了石英技术,因此走时精度高,稳定性好,使用方便,不需要经常调试,数字式电子钟用集成电路计时时,译码代替机械式传动,用LED 显示器代替指针显示进而显示时间,减小了计时误差,这种表具有时、分、秒显示时间的功能,还可以进行时和分的校对,片选的灵活性好。

2.3 电子时钟的原理该电子时钟由89C51,BUTTON,六段数码管等构成,采用晶振电路作为驱动电路,由延时程序和循环程序产生的一秒定时,达到时分秒的计时,六十秒为一分钟,六十分钟为一小时,满二十四小时为一天。

而电路中唯一的一个控制键却拥有多种不同的功能,按下又松开,可以实现屏蔽数码管显示的功能,达到省电的目的;直接按下不松开,则可以通过按键实现分钟的累加,每按一次分钟加一;而连续两次按下按键不放松,则可实现小时的调节,同样每按一次小时加一。

第三章关于单片机3.1 单片机简介单片机全称为单片机微型计算机(Single Chip Microsoftcomputer)。

从应用领域来看,单片机主要用来控制,所以又称为微控制器(Microcontroller Unit)或嵌入式控制器。

单片机是将计算机的基本部件微型化并集成在一块芯片上的微型计算机。

3.2 单片机的发展史1 . 4位单片机1975年,美国德克萨斯仪器公司首次推出4位单片机TMS-1000;此后,各个计算机公司竞相推出四位单片机。

日本松下公司的MN1400系列,美国洛克威尔公司的PPS/1系列等。

四位单片机的主要应用领域有:PC机的输入装置,电池充电器,运动器材,带液晶显示的音/视频产品控制器,一般家用电器的控制及遥控器,电子玩具,钟表,计算器,多功能电话等。

2 . 8位单片机1972年,美国Intel公司首先推出8位微处理器8008,并于1976年9月率先推出MCS-48系列单片机。

在这以后,8位单片机纷纷面市。

例如,莫斯特克和仙童公司合作生产的3870系列,摩托罗拉公司生产的6801系列等。

随着集成电路工艺水平的提高,一些高性能的8位单片机相继问世。

例如,1978年摩托罗拉公司的MC6801系列及齐洛格公司的Z8系列,1979年NEC公司的UPD78XX系列。

这类单片机的寻址能力达64KB,片内ROM容量达4--8KB,片内除带有并行I\O口外,还有串行I\O口,甚至还有A\D转化器功能。

8位单片机由于功能强,被广泛用于自动化装置、智能仪器仪表、智能接口、过程控制、通信、家用电器等各个领域。

3 . 16位单片机1983年以后,集成电路的集成度可达几十万只管/片,各系列16位单片机纷纷面市。

这一阶段的代表产品有1983年Intel公司推出的MCS-96系列,1987年Intel推出了80C96,美国国家半导体公司推出的HPC16040,NEC 公司推出的783XX系列等。

16位单片机主要用于工业控制,智能仪器仪表,便携式设备等场合。

4 . 32位单片机随着高新技术只智能机器人,光盘驱动器,激光打印机,图像与数据实时处理,复杂实时控制,网络服务器等领域的应用与发展,20世纪80年代末推出了32位单片机,如Motorlora公司的MC683XX系列,Intel的80960系列,以及近年来流行的ARM系列单片机。

32位单片机是单片机的发展趋势,随着技术的发展及开发成本和产品价格的下降,将会与8位单片机并驾齐驱。

5 . 64位单片机近年来,64位单片机在引擎控制,智能机器人,磁盘控制,语音图像通信,算法密集的实时控制场合已有应用,如英国Inmos公司的Transputer T800是高性能的64位单片机。

3.3单片机的特点1 .单片机的存储器ROM和RAM时严格区分的。

ROM称为程序存储器,只存放程序,固定常数,及数据表格。

RAM则为数据存储器,用作工作区及存放用户数据。

2 . 采用面向控制的指令系统。

为满足控制需要,单片机有更强的逻辑控制能力,特别是单片机具有很强的位处理能力。

3 .单片机的I/O口通常时多功能的。

由于单片机芯片上引脚数目有限,为了解决实际引脚数和需要的信号线的矛盾,采用了引脚功能复用的方法,引脚处于何种功能,可由指令来设置或由机器状态来区分。

4 . 单片机的外部扩展能力很强。

在内部的各种功能部件不能满足应用的需求时,均可在外部进行扩展,与许多通用的微机接口芯片兼容,给应用系统设计带来了很大的方便。

第四章方案论证与比较2.1数字时钟方案数字时钟是本设计的最主要的部分。

根据需要,可利用两种方案实现。

方案一:本方案采用Dallas公司的专用时钟芯片DS12887A。

该芯片内部采用石英晶体振荡器,其芯片精度不大于10ms/年,且具有完备的时钟闹钟功能,因此,可直接对其以用于显示或设置,使得软件编程相对简单。

为保证时钟在电网电压不足或突然掉电等突发情况下仍能正常工作,芯片内部包含锂电池。

当电网电压不足或突然掉电时,系统自动转换到内部锂电池供电系统。

而且即使系统不上电,程序不执行时,锂电池也能保证芯片的正常运行,以备随时提供正确的时间。

方案二:本方案完全用软件实现数字时钟。

原理为:在单片机内部存储器设三个字节分别存放时钟的时、分、秒信息。

利用定时器与软件结合实现1秒定时中断,每产生一次中断,存储器内相应的秒值加1;若秒值达到60,则将其清零,并将相应的分字节值加1;若分值达到60,则清零分字节,并将时字节值加1;若时值达到24,则将十字节清零。

该方案具有硬件电路简单的特点。

但由于每次执行程序时,定时器都要重新赋初值,所以该时钟精度不高。

而且,由于是软件实现,当单片机不上电,程序不执行时,时钟将不工作。

基于硬件电路的考虑,本设计采用方案二完成数字时钟的功能。

2.2 数码管显示方案方案一:静态显示。

所谓静态显示,就是当显示器显示某一字符时,相应的发光二极管恒定的导通或截止。

该方式每一位都需要一个8 位输出口控制。

静态显示时较小的电流能获得较高的亮度,且字符不闪烁。

但当所显示的位数较多时,静态显示所需的I/O口太多,造成了资源的浪费。

方案二:动态显示。

所谓动态显示就是一位一位的轮流点亮各个位,对于显示器的每一位来说,每隔一段时间点亮一次。

利用人的视觉暂留功能可以看到整个显示,但必须保证扫描速度足够快,字符才不闪烁。

显示器的亮度既与导通电流有关,也于点亮时间与间隔时间的比例有关。

调整参数可以实现较高稳定度的显示。

动态显示节省了I/O口,降低了能耗。

从节省I/O口和降低能耗出发,本设计采用方案二。

第五章系统设计5.1 总体设计计时方案利用AT89S51单片机内部的定时/计数器进行中断时,配合软件延时实现时、分、秒的计时。

相关文档
最新文档