基于STC89C82的电子万年历

更新时间:2023-05-30 06:05:01 阅读量: 实用文档 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

可显示日期时间与星期,可以调整。

单片机课程设计总结报告

系别:物理与信息工程学院 专业:10电子信息科学与技术 班级:2班

学生:蔡育霞 学号:100303078 指导老师:蔡植善 日期:2013年5月

一、设计题目

电子万年历

二、设计功能要求

项目的功能要求:

1、显示年,月,日,时,分,秒以及星期;

2、可以调整日期,时间;

3、可以显示温湿度测量; 项目的主要技术指标 1.STC89C52

的工作电压范围为3.3~5.5V,工作频率范围为0~40MHZ,工作温度环境为

-40~+85℃

2.DS1302芯片的工作电压范围为2.0~5.5V,工作温度环境与单片机兼容,精确度日期可 精确到日,时间可精确到秒。 3.LCD1602显示屏显示容量为16*2个字符,芯片工作电压4.5~5.5V,工作电流为2.0mA (5.0V),字符尺寸为2.95*4.35mm,工作温度-20~70℃,与单片机相符。 4.DHT11芯片工作电压范围为3~5.5V,温度测量范围0~50℃,湿度测量范围20~90%

可显示日期时间与星期,可以调整。

(环境温度为25℃时),20~80%(环境温度为50℃)

准确度:在显示屏上显示的时间是符合现实当中的,秒的跳跃是正常时间的基度。 失真度:LCD显示屏的7至14脚每个引脚各接了一个10K电阻,防止显示出现鬼影。 灵敏度:在按键按下作调整的时候,显示屏上能准确快速地随着按键功能做不同的改 变,可见该系统的灵敏度颇高。

三、设计方案

一个完整的万年历要显示时间日期就必须有LCD显示模块,时钟电路模块以及提供时钟信号的晶振电路模块,要实现时间日期调整功能,则需要按键扫描模块,复位电路模块,还有温湿度测量的显示需用到温湿度芯片,在加上控制所有模块的主控模块,和提供基本运行基础的电源电路模块。我们的电路主控模块采用STC89C52单片机,按键模块用四个键来实现调整时间日期的功能,按键功能分别为:选择,加,减,确定。显示模块采用LCD1602显示屏,时钟模块采用DS1302时钟芯片实现对时间,日期的操作,温湿度的测量采用简单的DTH11芯片。

系统方框图:

电子万年历系统方框图

四、主要元器件介绍

主控制模块:

这个系统的主要控制我们选用了STC89C52单片机作为中心控制,引脚图如下图所示,STC89C52是一种带8K字节闪烁可编程可檫除只读存储器的低电压,高性能的微处理器。它不仅拥有MCS51单片机的优点而且拥有低功耗的空闲和省电模式,可以降低我们电路的功耗,内部包含了定时器,程序存储器,数据存储器等硬件,符合我们电路的

可显示日期时间与星期,可以调整。

硬件要求,方便的构成一个最小系统,且价格合理,便宜程序编写。

2.DS1302时钟电路

我们的时钟电路是用时钟芯片DS1302,备用电池,晶振三部分构成,引脚图如下图所示,DS1302是用3线的串行接口,内部集成了可编程日历时钟,通过单片机的控制来设置芯片,Vcc1和Vcc2是双电源,外部电源和备用电源,现如今的DS1302芯片本身带有备用电池,备用电池可以是时钟在主电源中断的情况下继续运行工作。

DS1302引脚图: DS1302时钟模块:

3.LCD显示

显示模块我们选用LCD1602液晶显示,它是专门用来显示字母,数字,符号的点阵型液晶,它有几个5x7或是5X11点阵字符组成,每一个点阵字符位都袔显示一个字符,LCD显示如图所示:

可显示日期时间与星期,可以调整。

4.DHT11温湿度

DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。它应用专用的数字模块采集技术和温湿度传感技术,确保极高的可靠性与长期稳定性。传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。因此DHT11具有超快响应、抗干扰能力强、性价比极高等优点。

五、系统电路 程序流程图

主程序首先初始化定时器、LCD1602及DS1302,然后就开始查询按键,有键按下则开始调整时间和日期,若没有按下,则执行下面的时间、日期的显示,最后依次循环这些相同的操作,相应流程图如图所示:

可显示日期时间与星期,可以调整。

图(12)程序流程图

按键的检测是通过中断的办法来实现,利用按键进行间调整。 K1按下则开始设置时间及日期,同时在第一行最右端显示被选择的对象,第一次按下K1时,设置年份,若按下K3,则是减1操作,按下K2是加1操作,设置好年后,第二次按下K1时,则是设置月份,按K3减,按K2则加1,依次循环下去,则可以将时间和日期设置完毕,K4是确定键,设置好按下即可保存设置了。 1.硬件设计:

系统总电路图:

第一个:显示模块

可显示日期时间与星期,可以调整。

工作原理: 芯片的1,2脚是电源与地,3脚是用来调节显示屛的背光,4,5,6是LCD1602的控制入口,用于控制芯片的读写指令,7至14脚是LCD1602的数据口。当程序写入单片机的时候,通过控制口读取单片机中的指令,相当于写指令,然后将数据通过数据口进入LCD芯片中,再通过读指令,在显示屏上显示程序中的指令,如日期,时间,温湿度等。 第二个:DS1302时钟模块

工作原理:3脚为CLK串行时钟的输入口,4脚DAT为I/O口,是数据输入输出口,5脚RST是复位脚。给复位脚RST高电平,当CLK产生一个脉冲时,处于上升沿时,通过串行口向单片机读取程序,相当于写指令,在处于下降沿时,仍然通过串行口输出数据,相当于读指令,之后在显示屏上显示相对应的时间日期。 第三个:时钟振荡

可显示日期时间与星期,可以调整。

工作原理:电路由两个30PF的瓷片电容和一个12MHZ的晶振组成,并接入单片机的XTAL1和XTAL2引脚,让单片机处于内部振荡模式。在加电后延迟大概10ms振荡器振荡,在XTAL2引脚产生3V左右的正弦波时钟信号。两个电容的作用是为了提高电路的运行速度。

第四个: 按键电路模块

工作原理:四个按键通过一个TTL逻辑与门将其与单片机的中断入口相连,使单片机能全面的控制这四个按键的工作,在将四个按键分别与单片机的不同引脚相接,使四个按键分工合作工作,在程序中嵌入按键中断程序,每个按键各自有中断的功能,K1中断功能为选择,K2的中断功能为加,K3的中断功能为减,K4的中断功能为确定。 第五个:温湿度测量模块

工作原理:DHT11芯片内部本身含有一个电阻式感湿元件和NTC测温元件,它们与一个高性能的8位单片机相连接。此芯片温湿度测量元件共用引脚2与单片机P2.3相连。

2.软件设计

软件总设计:主程序首先对系统环境初始化,设置定时器T0工作模式为16位定时/计数器模式,置位总中断允许位EA,并对键盘端口置位,再对LCD1602初始化,DS1302初始化。接着扫描键盘,在键盘程序里面是对时间、日期及闹钟的调整,最下面是时间的显示。

软件程序编写:软件程序编写的好坏直接影响着系统运行情况的良好。因本程序涉及的模块较多,所以程序编写也采用模块化设计,C语言具有编写灵活、移植方便、便于模块化设计的特点,所以本系统的软件采用C51编写。

可显示日期时间与星期,可以调整。

六、调试及性能分析

硬件调试:

1.硬件调试问题:

1)第一次焊完PCB板后接上电源,发现显示屛不亮 2)显示屏幕可显示,但是亮度不够 2.问题分析:

1)可能是电路虚焊,或是某些电线未焊

2)可能是电路虚焊,或是某些电阻过大导致电流小 3)没调节滑阻 3.问题解决:

1)用万用表全面检查每一条导线的焊接,发现有一条外接导线漏焊,补焊后,显示 屏显示正常。

2)通过调节滑阻,使屏幕显示更加清晰

软件调试:

在经过硬件调试之后,进入了软件调试模块,由于我们系统涉及到了多个模块,故而在程序的编写上花费的时间较长,多个芯片的编程,需要调用多个子程序,因此发现的问题也较多,在此次的软件编程上出现的问题有:

1. 调试问题:

1) 初次软件调试时,在确保程序没有错误的情况下,将程序写入单片机,但是 在做时间与日期的调整是发现按键操作出现功能不稳定,灵敏度不高,不能 立马做出相对应的改变

2)LCD显示屏出现闪烁 问题分析:

1)按键存在抖动,是不是在程序中加上延时能改善这个问题 2)LCD屏幕闪烁,有可能是在执行了清屏程序时序太长 问题解决:

1)在程序中添加去抖动延时,基本解决了问题。 2)将不需要的清屏程序去掉,就可解决这个问题。

2.在软件调试过程中,当调节时间和日期后,单片机上电后更新的是PC 的时间,后来查找资料发现,是设置ds1302的问题,

性能分析:通过完成电子万年历这一作品之后发现,STC89C52单片机的程序编

写较为简便快捷,之前所使用的AT89C52需要专门的程序编写适配器,故而用STC89C52 代替。蓝屏背光的LCD1602显示正常,在各方面此显示屏的使用率较高。温湿度测量模块所采用的芯片DHT11相对于温度与湿度分别测量最为简单方便,且次芯片本身具有超快响

可显示日期时间与星期,可以调整。

应,抗干扰能力强,低功耗等优势。

设计总结:通过这次的课程设计,让我收益颇多,以往自己疏于加强的发面在

这段实验中都有很大的提高,比如知识的巩固,软件的运用,心态的调整,以及团体的集体荣誉感,虽然这次的课程设计结果有点差强人意,但是我学会了如何自主求知,如何遇事时沉稳淡定,学会了关键时候还是要靠自己的,感谢这段时间老师以及同学的帮助,让我能够发现自己的缺点,改善自己。也感谢自己的队友们,不嫌弃我的无知,给予我最大的帮助,让我体会到这个团体共同努力时所迸发的力量有多绚丽。

七、完整的源程序

#include <reg51.h> #include <intrins.h> #include <string.h> #define uint unsigned int #define uchar unsigned char

sbit IO= P1^0; //DS1302数据线 sbit SCLK = P1^1; //DS130时钟线 sbit RST = P1^2; //DS1302复位线

sbit RS = P2^0; sbit RW = P2^1; sbit EN = P2^2; sbit K1=P3^4; sbit K2=P3^5; sbit K3=P3^6;

//LCD数据/命令选择端 //LCD读/写控制 //LCD使能端

//选择 //加 //减

sbit K4=P3^7; //确定

uchar tCount=0;

uchar MonthsDays[]={0,31,0,31,30,31,30,31,31,30,31,30,31}; 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]; //所读取的日期时间

char Adjust_Index=-1; //当前调节的时间对象:,,分,是,日,月,年

(1,2,3,4,6)

uchar Change_Flag[]= "-MHDM-Y";

周)

/*---------延时程序------------------*/ void DelayMS(uint ms) {

uchar i;

while(ms--){for(i=0;i<120;i++);} }

//-----------向DS1302写入一字节------------------// void Write_A_Byte_TO_DS1302(uchar x) { uchar i;

for(i=0;i<8;i++){

IO=x&0x01; //每一位与1与存入IO中 } }

//-----------从DS1302读取一字节------------------// uchar Get_A_Byte_FROM_DS1302() { uchar i,b=0x00; for(i=0;i<8;i++){

b |= _crol_((uchar)IO,i); }

return b/16*10+b%16; //返回BCD码

SCLK=1;SCLK=0;

//每一个高脉冲读取一位数据

SCLK=1;SCLK=0; //一个高脉冲将数据送入液晶控制器 x>>=1; // 右移

//(分,时,日,月,年)(不调节秒与

可显示日期时间与星期,可以调整。

//-----------从DS1302指定位置读数据------------------// uchar Read_Data(uchar addr) {

uchar dat;

RST = 0;SCLK=0;RST=1; //RST高电平时读/写

Write_A_Byte_TO_DS1302(addr); //先写入地址

dat = Get_A_Byte_FROM_DS1302();

SCLK=1;RST=0;

return dat; }

//---------向DS1302某地址写入数据--------------------// void Write_DS1302(uchar addr,uchar dat) { SCLK=0;RST=1;

Write_A_Byte_TO_DS1302(addr); Write_A_Byte_TO_DS1302(dat); SCLK=0;RST=0; }

//--------------设置时间----------------// void SET_DS1302() { uchar i;

//写控制字,取消写保护 Write_DS1302(0x8E,0x00); //分时日月年依次写入 for(i=1;i<7;i++)

{ //分的起始地址10000010(0x82),后面依次是时,日,月,周,年,写入

地址每次递增2

}

Write_DS1302(0x8E,0x80); //加保护

Write_DS1302(0x80+2*i,(DateTime[i]/10<<4)|(DateTime[i]%10));

//高脉冲写入数据

可显示日期时间与星期,可以调整。

//----------读取当前日期时间------------// void GetTime() {uchar i;

for(i=0;i<7;i++){ DateTime[i]=Read_Data(0X81+2*i);} }

//-----------读LCD状态------------------// uchar Read_LCD_State() { uchar state;

RS=0;RW=1;EN=1; //输出:D0~D7=状态字 DelayMS(1); state=P0;

//从P0口读LCD状态

EN = 0;DelayMS(1); return state; }

//-----------忙等待------------------// void LCD_Busy_Wait() {

while((Read_LCD_State()&0x80)==0x80); DelayMS(5); }

//-----------向LCD写数据------------------// void Write_LCD_Data(uchar dat) {

LCD_Busy_Wait(); RS=1;EN=0;RW=0;

//写数据,EN为高脉冲,

P0=dat;EN=1;DelayMS(1);EN=0; }

//-------------写LCD指令-------------------// void Write_LCD_Command(uchar cmd)

可显示日期时间与星期,可以调整。

LCD_Busy_Wait();

RS=0;EN=0; RW=0; //写指令,EN高脉冲,输出:D0~D7=数据 P0=cmd;EN=1;DelayMS(1);EN=0; }

//-------------LCD初始化-------------------// void Init_LCD() {

Write_LCD_Command(0x38); //设置16*2显示,5*7点阵,8位数据接口 DelayMS(1);

Write_LCD_Command(0x01); //显示清零,数据指针清零 DelayMS(1);

Write_LCD_Command(0x06); //写一个字符后地址指针自动加1 DelayMS(1);

Write_LCD_Command(0x0c); //设置开显示,不显示光标 DelayMS(1); }

//------------------------------------------ //设置液晶显示位置

//------------------------------------------ void Set_LCD_POS(uchar p){

Write_LCD_Command(p|0x80);//相当于在0x80基础上加入位置量 }

//----在LCD上显示字符串---------// void Display_LCD_String(uchar p,uchar *s) {

uchar i;

Set_LCD_POS(p); for(i=0;i<16;i++) {

可显示日期时间与星期,可以调整。

} }

DelayMS(1);

//---------日期与时间值转换为数字字符----------------// void Format_DateTime(uchar d,uchar *a) {

a[0]=d/10+'0'; a[1]=d%10+'0'; }

//判断是否为闰年 uchar isLeapYear(uint y)

{ return (y%4==0&&y%100!=0)||(y%400==0);} //求自2000.1.1开始的任何一天是星期几 //函数没有通过,求出总天数后再求星期几 //因为求总天数可能会超出uint的范围 void RefreshWeekDay()

{ uint i,d,w=5; //已知1999.12.31是周五 for(i=2000;i<2000+DateTime[6];i++) { } d=0;

for(i=1;i<DateTime[4];i++) { d+=MonthsDays[i]; } d+=DateTime[3];

//保存星期,0~6表示星期日,星期一,二,...,六,为了与DS1302的星期

格式匹配,返回值需要加1

DateTime[5]=(w+d)%7+1;

d=isLeapYear(i)?366:365; w=(w+d)%7;

可显示日期时间与星期,可以调整。

//*****年月日时分++/--********// void DateTime_Adjust(char x) { {

断二月 天数

DateTime[3]++;

switch(Adjust_Index)

case 6: //年00-99 if(x==1&&DateTime[6]<99) DateTime[6]++; if(x==-1&&DateTime[6]>0) DateTime[6]--; //获取2月天数

MonthsDays[2]=isLeapYear(2000+DateTime[6])?29:28; //如果年份变化后当前月份的天数大于上限则设为上限 if(DateTime[3]>MonthsDays[DateTime[4]]) { DateTime[3]=MonthsDays[DateTime[4]];} RefreshWeekDay(); //刷新星期

break;

case 4: //月01-12 if(x==1&&DateTime[4]<12) DateTime[4]++; if(x==-1&&DateTime[4]>1) DateTime[4]--;

MonthsDays[2]=isLeapYear(2000+DateTime[6])?29:28; if(DateTime[3]>MonthsDays[DateTime[4]]) { DateTime[3]=MonthsDays[DateTime[4]];} RefreshWeekDay();

break;

case 3: //日00-28、29、30、31,调节之前首先根据年份得出该年中

MonthsDays[2]=isLeapYear(2000+DateTime[6])?29:28; //根据当前月份决定调节日期的上限

if(x==1&&DateTime[3]<MonthsDays[DateTime[4]])

if(x==-1&&DateTime[3]>0) DateTime[3]--;

可显示日期时间与星期,可以调整。

} }

break;

case 2: //时

if(x==1&&DateTime[2]<23) DateTime[2]++; if(x==-1&&DateTime[2]>0) DateTime[2]--; break;

//分

case 1:

if(x==1&&DateTime[1]<59) DateTime[1]++; if(x==-1&&DateTime[1]>0) DateTime[1]--; break;

//---定时器0每秒刷新LCD显示----// void T0_INT() interrupt 1 {

TH0=-50000/256; TL0=-50000%256; if(++tCount !=2) tCount=0;

//按指定格式生成待显示的日期时间串

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]-1]); //时分秒

Format_DateTime(DateTime[2],LCD_DSY_BUFFER2+5); Format_DateTime(DateTime[1],LCD_DSY_BUFFER2+8); Format_DateTime(DateTime[0],LCD_DSY_BUFFER2+11); //显示年月日,星期,时分秒

return;

可显示日期时间与星期,可以调整。

Display_LCD_String(0x00,LCD_DSY_BUFFER1); Display_LCD_String(0x40,LCD_DSY_BUFFER2); }

//----------键盘中断(INT0)-------------// void EX_INT0() interrupt 0 {

if(K1==0) //选择调整对象(Y M D H M) {

DelayMS(10); if(K1==0){ //while(K1==0);

if(Adjust_Index==-1||Adjust_Index==1) { }

Adjust_Index--;

if(Adjust_Index==5) Adjust_Index=4; LCD_DSY_BUFFER2[13]='[';

Adjust_Index=7;

LCD_DSY_BUFFER2[14]=Change_Flag[Adjust_Index]; //显示调节对象 }

else if(K2==0) { //while(K2==0);

DelayMS(10); if(K2==0)

//加

LCD_DSY_BUFFER2[15]=']'; }

DateTime_Adjust(1); }

else if(K3==0) {

//减

可显示日期时间与星期,可以调整。

}

if(K3==0)

DateTime_Adjust(-1);

else if(K4==0) { } }

void main() { Init_LCD(); IE=0x83; IP=0x01;

//while(K4==0); DelayMS(10); if(K4==0){

//确定

SET_DS1302(); //将调整后的时间写入DS1302

LCD_DSY_BUFFER2[13]=' '; LCD_DSY_BUFFER2[14]=' '; LCD_DSY_BUFFER2[15]=' '; Adjust_Index=-1; }

//液晶初始化

//允许INT0,T0中断,EA=1,,ET0=1,EX0=1 //设置外部中断0为高级中断

IT0=0x01; //外部中断0为电平触发,低电平有效 TMOD=0x01; //设置定时器T0工作方式为方式1, TH0=-50000/256; TL0=-50000%256; TR0=1; while(1) {

//如果未执行调整操作则正常读取当前时间

if(Adjust_Index==-1)

GetTime();

//启动定时器

//装入初始值,定时1秒

可显示日期时间与星期,可以调整。

}

八、参考书目:

1. 张毅刚,,彭喜元,单片机原理与应用设计 电 子工业出版社

2.郭天祥 51单片机C语言教程-入门,提高,开发, 拓展全攻略, 电子工业出版社

3.张毅坤 陈善久, 单片微型计算机原理及应用 西 安电子科技大学出版社

本文来源:https://www.bwwdw.com/article/n574.html

Top