电子万年历设计与调试.docx
《电子万年历设计与调试.docx》由会员分享,可在线阅读,更多相关《电子万年历设计与调试.docx(36页珍藏版)》请在冰豆网上搜索。
电子万年历设计与调试
第1章方案论证与比较
以单片机为控制器设计的电子万年历单片机最小系统、利用温度传感器采集外界温度,利用时钟控制芯片进行时间控制,利用输入器件进行参数调整,并通过显示设备进行参数显示。
1.1控制器选择
方案一:
AT89S52(图1-1)是ATMEL公司一款高性能8位单片机,兼容标准的MCS51指令系统级80C51引脚结构,片内含8K的可反复擦写的Flash只读存储器,256B的内部数据存储器,具有4个并行I/O口,1个全双工串行口,3个16位的定时/计数器,6个中断源,2个中断优先级,广泛应用于各种控制系统中。
图1-1
方案二:
STC89C52RC(图1-2)是宏晶科技公司的一款高性能低功耗8位单片机,兼容标准的8051内核,片内含8K的可反复擦写的Flash只读存储器,256B的内部数据存储器,具有4个并行I/O口,1个全双工串行口,3个16位的定时/计数器,6个中断源,2个中断优先级,广泛应用于各种控制系统中。
图1-2
方案选择:
二者在结构和功能上基本一样,与AT89S52相比,STC89C52RC具有更好的性价比,实用性好,因此选择STC89C52RC为控制器。
1.2显示设备选择
方案1:
LED数码管(图1-3)是由LED发光二极管组合显示字符的显示器件。
它使用了8个LED发光二极管,其中7个用于显示字符,1个用于显示小数点,故通常称为7段发光二极管。
数码管静态显示特点是数码管恒定亮,亮度较高,显示某个数值,直到显示字符的编码改变为止。
这种显示方式由于太占据I/O线,所以用于1个或较少数码管显示的场合。
数码管动态显示特点是数码管轮流点亮,显示亮度不够,所以通常加驱动电路,由于此中显示方式可以节省I/O口,所以用于多个数码管显示的场合。
图1-3
方案2:
LCD液晶屏(如图1-4)是一种专门用于显示字母、数字、符号等ASCII码的显示器件。
LCD1602是一种常用的字符型液晶显示器,控制器大部分为HD44780,接口标准为SIP16引脚,分电源、通讯数据和控制3部分。
LCD1602芯片和背光电路工作电压与单片机兼容,可以很方便的与单片机连接。
图1-4
方案选择:
LED数码管占I/O线较多设计不方便,LCD1602可以显示跟多内容节省I/O口可以很方便的与单片机连接故选LCD1602液晶屏。
1.3输入器件选择
方案1:
独立按键(如图1-5)的使用较简单,其特点是每个按键单独占用一根I/O口线,每个按键不会影响其它I/O口线的状态。
方案2:
矩阵按键(如图1-6)采用行列式结构并按照矩阵形式排列,可以节省I/O口。
图1-5图1-6
按键选择:
由于电路需要按键功能较多所以选择独立按键更加方便。
1.4温度传感器
方案1:
数字温度传感器(DS18B20)(如图1-7)是DALLAS公司生产的1-Wire,即单总线器件,具有线路简单、体积小的特点。
因此用它来组成一个测温系统,具有线路简单,在一根通信线可以接多个相同数字温度计的优点,十分方便。
方案2:
DS1621是DALLAS(如图1-8)公司生产的一种功能较强的数字式温度传感器和恒温控制器。
与同系列的DS1620相比控制更为简单,接口与12C总线兼容,且可以使用一片控制器控制多达8片的DS1621,其数字温度输出达9位,精度为0.5℃。
通过读取内部的计数值和用于温度补偿的每摄氏度计数值,利用公式计算还可提高温度值的精度。
DS1621可工作在最低2.7V电压下,适用于低功耗应用系统。
利用DS1621和一片51单片机即可构成一个简洁但功能强大的低电压温度测量控制系统
图1-7图1-8
1.5时间控制芯片
方案1时钟芯片DS12887是一个内嵌锂电池的并行通讯芯片,该器件提供完整的实时时钟/日历、定时闹钟,还包含三个可屏蔽中断(共用一个中断输出)以及可编程方波输出。
DS12887内部还提供114字节静态RAM,这些存储器是内部锂电池供电的,因此数据不会丢失。
DS12C887对于少于31天的月份,其日期能够在月末自动调整,带有闰年的月份可以自动补偿。
该器件可配置为24小时或12小时格式。
精确的温度补偿电路用于监视的VCC状态。
一旦检测到主电源失效,器件可自动切换到备用电源。
支持Intel和Motorola模式。
主要特点是:
∙ RTC计算秒、分、时、星期、日、月、年信息,具有润年补偿,有效期至2099年;
∙用二进制或BCD表示时间;
∙具有AM、PM标示的12小时模式或24小时模式;
∙可选择Intel或Motorola总线时序;
∙内部包含128字节存储单元,其中114字节供用户自由使用;
∙三路中断可分别通过软件屏蔽与检测;
∙闹钟可设置为每秒一次至每星期一次;
∙可编程的方波输出信号;
∙自动电源失效检测和切换电路。
方案2DS1302是一种可编程的串行实时时钟芯片,内部具有实时时钟、日历和用户可用RAM,可计算2100年之前的秒、分、时、日、月、周、年,且对月末日期、闰年天数可自动调整,RAM容量为31×8bit,以SPI串行总线方式向单片机传送单字节或多字节的实时时间数据,当主电源断电时备用电源可继续保持时钟连续运行。
方案选择:
第2章仿真电路设计
2.1控制系统框图
根据控制系统要求设计的电子万年历控制系统由单片机STC89S52RC构成的最小系统,由独立按键构成的按键扫描电路、由LCD1602构成的显示电路,由DS1302构成的时间控制电路以及由DS18B20构成的温度采集电路等,控制系统框图如图2-1所示。
图2-1控制系统框图
2.2仿真电路设计
设计的电子万年历仿真图如图2-2所示,其中单片机最小系统由单片机、时钟电路、复位电路和电源组成,按键扫描电路由选择、调整和确定三个独立按键构成,温度采集电路由单总线温度传感器DS18B20和上拉电阻组成,时钟控制电路由时间I²C总线协议的时钟芯片DS1302和晶振构成,液晶显示电路由LCD1602液晶和排阻以并行连接方式与单片机相连,滑动变阻器用来调节液晶显示亮度。
图2-2电子万年历仿真图
2.3主要元器件清单
电子万年历元器件清单如表2-1所示:
表2-1电子万年历元器件清单
序号
元器件名称
规格型号
数量
标号
备注
1
单片机
STC89S52RC
1
U1
DIP封装
2
液晶
LM016L
1
LCD1
并行接口
3
按键
四脚
4
功能控制
4
晶振
12MHz
1
X1
时钟电路
5
32768Hz
1
X2
时钟控制
6
电容
30pF
2
C1C2
瓷片,时钟电路
10uf
1
C3
电解,复位电路
7
电阻
10k
1
R1
复位
4.7k
1
R2
上拉
8
温度传感器
DS18B20
1
U2
温度采集
9
时钟控制芯片
DS1302
1
U3
时间控制
10
排阻
1K
1
RP1
上拉电阻
第3章软件程序设计
电子万年历程序采用自下而上的模块化编程方式,根据控制任务要求,将程序划分为主程序、液晶显示模块、温度采集模块、时间控制模块和按键扫描模块5个模块,其结构如图3-1所示:
图3-1程序结构图
3.1液晶显示模块
液晶显示模块完成日期、时间和温度显示,主要有初始化函数、写命令函数、写数据函数和液晶显示函数4部分组成。
(1)液晶写命令函数
液晶写命令操作时序图如图3-2所示,由此设计的流程图如图3-3所示:
图3-2液晶写命令操作时序图
(2)液晶写数据函数
液晶写数据操作时序图如图3-4所示,由此设计的流程图如图3-5所示:
图3-4液晶写数据操作时序图
图3-3写命令流程图图3-5写数据流程图
(3)液晶初始化函数
液晶初始化函数流程图如图3-6所示:
:
图3-6
液晶显示函数流程图如图3-7所示:
图3-7
液晶显示模块程序清单如下:
/********头文件及宏定义*******/
#include
#defineucharunsignedchar
/********变量声明及定义*******/
sbitRS=P2^2;
sbitRW=P2^3;
sbitE=P2^4;
ucharlcd1[]={"D:
--W:
"};
ucharlcd2[]={"T:
:
:
T:
"};
/***********延时函数**********/
voiddelay()
{
ucharx;
for(x=100;x>0;x--);
}
/******液晶写命令控制函数*****/
voidlcd_com(ucharcom)
{
RS=0;//命令
RW=0;//写操作
E=1;//使能有效
P0=com;//送命令
E=0;//使能无效
delay();//延时
RW=1;//复位
RS=1;
}
/******液晶写数据控制函数*****/
voidlcd_dat(uchardat)
{
RS=1;//数据
RW=0;//写操作
E=1;//使能有效
P0=dat;//送数据
E=0;//使能无效
delay();//延时
RW=1;//复位
RS=1;
}
/******液晶初始化控制函数*****/
voidlcd_init()
{
lcd_com(0x38);//模式设置
lcd_com(0x0c);//显示设置
lcd_com(0x01);//清屏
lcd_com(0x06);//输入模式
}
/*******液晶显示控制函数******/
voiddisp_lcd()
{
uchari;
lcd_com(0x80);//第一行地址
for(i=0;i<16;i++)
lcd_dat(lcd1[i]);
lcd_com(0xc0);//第二行地址
for(i=0;i<16;i++)
lcd_dat(lcd2[i]);
}
3.2温度控制模块
温度控制模块包括DS18B20初始化函数、写字节函数、读字节函数、温度控制函数4个部分。
(1)初始化函数
DS18B20初始化时序图如图3-8所示,流程图如图3-9所示。
图3-8
图3-9初始化流程图
(2)写字节函数
DS18B20写字节函数时序图如图3-10所示,流程图如图3-11所示。
图3-10写字节时序图
图3-11写字节流程图
(2)读字节函数
DS18B20读字节函数时序图如图3-12所示,流程图如图3-13所示。
图3-12写数据时序图
图3-13写数据流程图
(4)温度控制函数
温度控制函数流程图如图3-14所示。
图3-13写数据流程图
温度控制程序头文件如下:
#ifndef_DS18B20_H_
#define_DS18B20_H_
voidtemperate();
#endif
温度控制程序清单如下:
/******头文件及宏定义******/
#include
#defineucharunsignedchar
/******变量声明及定义*******/
uchart,value[]={0x00,0x00};
bits;
sbitDQ=P1^7;
externucharlcd2[];
/******延时控制函数*****/
voiddel(uchart)//7us
{
uchari;
for(i=t;i>0;i--);
}
/****18B20初始化控制函数***/
ucharinit_18b20()
{
ucharstatus;
DQ=1;
DQ=0;
del(100);//700us
DQ=1;
del(5);//35us
status=DQ;
del(25);//175us
DQ=1;
del(30);//210us
returnstatus;
}
/******读18B20控制函数*****/
ucharrd_18b20()
{
uchari,dat=0;
for(i=0;i<8;i++)
{
DQ=1;
DQ=0;
dat>>=1;
DQ=1;
if(DQ==1)
dat|=0x80;
del(5);//35us
DQ=1;
}
returndat;
}
/******写18B20控制函数*****/
voidwr_18b20(uchardat)
{
uchari;
DQ=1;
for(i=0;i<8;i++)
{
DQ=0;
del
(1);//7us
DQ=dat&0x01;
del(5);//35us
DQ=1;
dat>>=1;
}
}
/********温度控制函数*******/
voidtemperate()
{
init_18b20();
wr_18b20(0xcc);
wr_18b20(0x44);
init_18b20();
wr_18b20(0xcc);
wr_18b20(0xbe);
value[0]=rd_18b20();
value[1]=rd_18b20();
if((value[1]&0xf8)==0xf8)
{
s=1;
value[0]=~value[0]+1;
if(value[0]==0x00)
value[1]=~value[1]+1;
else
value[1]=~value[1];
}
else
s=0;
t=(value[0]>>4)|(value[1]<<4);
if(s==1)
lcd2[13]='-';
else
lcd2[13]=t/100+'0';
lcd2[14]=t%100/10+'0';
lcd2[15]=t%10+'0';
}
3.3时间控制模块
时间控制模块包括读字节函数、写字节函数、读数据函数、写数据函数和初始化函数5部分组成。
(1)读字节函数
读字节操作时序图如图3-14所示,读字节函数流程图如图3-15所示:
图3-14读字节操作时序图
图3-15读字节函数流程图
(2)写字节函数
写字节操作时序图如图3-16所示,读字节函数流程图如图3-17所示:
图3-16写字节操作时序图
(3)读数据函数
读数据函数流程图如图3-18所示:
(4)写数据函数
写数据函数流程图如图3-19所示:
图1-7图1-8图1-9
(5)初始化函数
初始化函数流程图如图3-20所示:
时间控制模块头文件如下:
#ifndef_1302_H_
#define_1302_H_
#defineucharunsignedchar
voidset_1302(ucharwei,ucharbeet);
voidtime();
#endif
时间控制模块程序清单如下:
/********头文件及宏定义*******/
#include
#defineucharunsignedchar
#defineuintunsignedint
/********变量声明及定义*******/
sbitCLK=P1^0;
sbitSDA=P1^1;
sbitRST=P1^2;
uchar*week[]={"***","SUN","MON",
"TUS","WEN","THU","FRI","SAT"};
uchardatetime[7];
externbitflag;
externucharlcd1[],lcd2[];
/******1302写数据控制函数*****/
voidwr_1302(uchardat)
{
uchari;
for(i=0;i<8;i++)
{
SDA=dat&0X01;
CLK=1;
CLK=0;
dat>>=1;
}
}
/******1302读数据控制函数*****/
ucharrd_1302()
{
uchari,b,t;
for(i=0;i<8;i++)
{
b>>=1;
t=SDA;
b|=t<<7;
CLK=1;
CLK=0;
}
returnb/16*10+b%16;
}
/******读数据控制函数*****/
ucharrd_dat(ucharaddr)
{
uchardat;
RST=0;
CLK=0;
RST=1;
wr_1302(addr);
dat=rd_1302();
CLK=1;
RST=0;
returndat;
}
/******写数据控制函数*****/
voidwr_dat(ucharadd,uchardat)
{
RST=0;
CLK=0;
RST=1;
wr_1302(add);
CLK=0;
wr_1302(dat);
CLK=0;
RST=0;
}
/******时间数据写入控制函数*****/
voidset_1302(ucharwei,ucharbeet)
{
wr_dat(0x8e,0x00);
wr_dat(wei,beet);
wr_dat(0x8e,0x80);
}
/********时间控制函数*******/
voidtime()
{
uchari;
if(flag==0)
{
for(i=0;i<7;i++)
{
datetime[i]=rd_dat(0x81+2*i);
}
lcd1[13]=*(week[datetime[5]]);
lcd1[14]=*(week[datetime[5]]+1);
lcd1[15]=*(week[datetime[5]]+2);
lcd1[8]=datetime[3]/10+'0';
lcd1[9]=datetime[3]%10+'0';
lcd1[5]=datetime[4]/10+'0';
lcd1[6]=datetime[4]%10+'0';
lcd1[2]=datetime[6]/10+'0';
lcd1[3]=datetime[6]%10+'0';
lcd2[8]=datetime[0]/10+'0';
lcd2[9]=datetime[0]%10+'0';
lcd2[5]=datetime[1]/10+'0';
lcd2[6]=datetime[1]%10+'0';
lcd2[2]=datetime[2]/10+'0';
lcd2[3]=datetime[2]%10+'0';
}
}
3.4按键扫描模块
按键扫描模块包含延时消抖函数、按键处理函数、选择按键函数、调节按键函数和确定按键函数5个部分。
(1)按键处理函数
按键处理函数程序流程图如图3-22所示:
图3-22按键处理函数程序流程图
(2)选择按键函数
选择按键函数程序流程图如图3-23所示:
(3)确定按键函数
确定按键函数程序流程图如图3-24所示:
图3-23图3-24
(4)调节按键函数
调节按键函数程序流程图如图3-25所示:
图3-25
按键处理模块头文件如下:
#ifndef_KEY_H_
#define_KEY_H_
voidkey();
#endif
按键处理模块程序清单如下:
/********头文件及宏定义*******/
#include
#include"1302.h"
/********变量声明及定义*******/
#defineucharunsignedchar
uchark,set,shi,fen,miao,day,month,w,year;
bitflag;
externucharlcd1[],lcd2[],*week[];
/***********按键消抖函数**********/
voiddel()
{
uchari,j;
for(i=0;i<10;i++)
for(j=0;j<250;j++);
}
/*********选择按键控制函数********/
voidkey_xuan()
{
flag=1;
set++;
if(set==7)
set=0;
}
/*********调节按键控制函数********/
voidkey_tiao()
{
if(set==0)
{
year++;
if(year==100)
year=0;
lcd1[2]=year/10+'0';
lcd1[3]=year%10+'0';
}
if(set==1)
{
month++;
if(month==13)
month=1;
lcd1[5]=month/10+'0';
lcd1[6]=month%10+'0';
}
if(set==2)
{
day++;
if(((month==0)||(month==2)||(month==4)||(month==6)
||(month==7)||(month==9)||(month==11))&&(day==32))
day=1;
if(((month==3)||(month==5)||(month==8)||(month==10))&&(day==31))
day=1;
if(((year%4==0)&&(month==2))&&(day==30))
day=1;
if(((year%4!
=0)&&(month==2))&&(day==29))
day=1;
lcd1[8]=day/10+'0';
lcd1[9]=day%10+'0';
}
if(set==3)
{
w++;
if(w==8)
w=1;
lcd1[13]=*(week[w]);
lcd1[14]=*(week[w]+1);
lcd1[15]=*(week[w]+2);
}
if(set==4)
{
shi++;
if(sh