基于AT89C51单片机的电子时钟设计_毕业设计
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
基于AT89C51单片机的电子时钟设计
摘要:本文介绍了AT89C51单片机控制162液晶显示屏的工作原理以及设计方法,利用ds1302芯片和162液晶屏以51单片机为主控芯片设计一个时钟电路,分为硬件设计与软件设计两个部分。
硬件设计主要是单片机、液晶和ds1302的接口设计;软件设计的主要部分是:单片机的端口初始化以及ds1302初始化,液晶显示屏的初始化,单片机驱动液晶屏的显示。
关键词:AT89C51单片机;162液晶显示屏;ds1302;LCD
1 引言
液晶显示器以其微功耗、体积小、显示内容丰富、超薄轻巧等许多优点,在袖珍式仪表和低功耗应用系统中得到越来越广泛的应用。
本文中详细介绍了基于AT89C51单片机控制下的162液晶屏显示设计,此设计基于da1302的时钟电路方便实用,电路设计简单。
2 硬件介绍
2.1、AT89C51简介
AT89C51是一种带4K字节FLASH存储器(FPEROM—Flash Programmable and Erasable Read Only Memory)的低电压、高性能CMOS 8位微处理器,俗称单片机。
AT89C2051是一种带2K字节闪存可编程可擦除只读存储器的单片机。
单片机的可擦除只读存储器可以反复擦除1000次。
该器件采用ATMEL高密度非易失存储器制造技术制造,与工业标准的MCS-51指令集和输出管脚相兼容。
由于将多功能8位CPU和闪烁存储器组合在单个芯片中,ATMEL的AT89C51是一种高效微控制器,AT89C2051是它的一种精简版本。
AT89C单片机为很多嵌入式控制系统提供了一种灵活性高且价廉的方案。
AT89C51 提供以下标准功能:4k 字节Flash 闪速存储器,128字节内
部RAM,32 个I/O 口线,两个16位定时/计数器,一个5向量两级中断
结构,一个全双工串行通信口,片内振荡器及时钟电路。
同时,AT89C51可降至0Hz的静态逻辑操作,并支持两种软件可选的节电工作模式。
空闲方式停止CPU的工作,但允许RAM,定时/计数器,串行通信口及中断系统继续工作。
掉电方式保存RAM中的内容,但振荡器停止工作并禁止其它所有部件工作直到下一个硬件复位。
·与MCS-51 兼容
·4K字节可编程闪烁存储器
寿命:1000写/擦循环
数据保留时间:10年
·全静态工作:0Hz-24Hz
·三级程序存储器锁定
·128*8位内部RAM
·32可编程I/O线
·两个16位定时器/计数器
·5个中断源
·可编程串行通道
·低功耗的闲置和掉电模式
·片内振荡器和时钟电路
2.2 162液晶显示屏介绍
HS162-4液晶模块是一种用5x7点阵图形来显示字符的液晶显示器,根据显示的容量可以分为1行16个字、2行16个字等。
2.2.1 162液晶屏显示屏的引脚定义
首先,我们来看162的引脚定义,162的引脚是很整齐的SIP单列直插封装。
表1.2.1是液晶屏的引脚定义。
表2.2.1 接口信号说明表
HS162-4采用标准的16脚接口,我们只需要关注一下几个管脚:
3脚:VO,液晶屏显示偏压信号,用于调整液晶屏的显示对比度,一般会外界电位器用以调整偏压信号,接正电源时对比度最弱,接地电源时对比度最高,对比度过高时会产生“阴影”,使用时可以通过一个10K的电位器调整对比度。
4脚:RS,数据/命令选择端,即对寄存器进行选择,高电平时选择数据寄存器、低电平时选择指令寄存器。
5脚:R/W,读写选择端,高电平时进行读操作,低电平时进行写操作。
6脚:E,使能信号,其实时162的逐句控制时钟信号,利用该信号的上升沿实现对液晶屏的数据传输。
7~14脚:8位双向数据线。
2.2.2 162液晶显示屏的指令说明
162液晶模块的读写操作、屏幕和光标的操作都是通过指令编程来实现的。
(说明:1为高电平、0为低电平)。
162液晶屏内部模块共有11条控制指令,如表2.2.2所示。
指令1:清显示,指令码01H,光标复位到地址00H位置
指令2:光标复位,光标返回到地址00H
指令3:光标和显示模式设置
I/D:光标移动方向,高电平右移,低电平左移
S: 屏幕上所有文字是否左移或者右移。
高电平表示有效,低电平则无效
指令4:显示开关控制。
D:控制整体显示的开与关,高电平表示开显示,低电平表示关显示
C:控制光标的开与关,高电平表示有光标,低电平表示无光标
B:控制光标是否闪烁,高电平闪烁,低电平不闪烁
指令5:光标或显示移位 S/C:高电平时移动显示的文字,低电平时移动光标
指令6:功能设置命令
DL:高电平时为4位总线,低电平时为8位总线
N:低电平时为单行显示,高电平时双行显示
F: 低电平时显示5x7的点阵字符,高电平时显示5x10的点阵字符
指令7:字符发生器RAM地址设置
指令8:DDRAM地址设置
指令9:读忙信号和光标地址 BF:忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙。
指令10:写数据
指令11:读数据
2.2.3 162液晶显示屏的时序
操作液晶屏,我们得对它的工作时序图熟悉,这里我们介绍的是162液晶显示屏的两个写时序:写指令和写入数据。
写指令,即设置162液晶显示屏的工作方式:需要把RS置为低电平,RW置为低电平,然后将数据送到数据口D0~D7,最后E引脚一个高脉冲将数据写入。
写数据,即在液晶屏上实现显示时:需要把RS置为低电平,RW置为低电平,然后将数据送到D0~D7,最后E引脚一个高脉冲将数据写入。
RS DA TA 数据准备好
RW RS
CMD 命令准备好RW
EN EN
(1)写命令时序图 (2)写数据时序图
图1-2-3 162液晶显示屏时序图
值得注意的是,162液晶显示模块是一个慢显示器件,所以在执行每条指令之前一定要确认模块的忙标志为低电平,表示不忙,否则此指令失效。
当然,162
提供了读忙信号的方法:当RS和RW共同为低电平时可以写入指令或者显示地址,当RS为低电平RW为高电平时可以读忙信号。
2.2.4 162液晶屏的RAM地址映射及标准字库表
HS162-4液晶模块内部的字符发生存储器(CGROM)已经存储了128个不同的点阵字符图形,这些字符有:阿拉伯数字、英文字母的大小写和常用的符号等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是01000001B (41H),显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到字母“A” 。
要显示字符时要先输入显示字符地址,也就是告诉模块在哪里显示字符。
液晶屏第一行的首地址是80H,第二行的首地址是C0H。
表1.2.4是液晶屏的GROM 中的字符代码与图形对应关系。
1101 - = M ] m }
1110 . > N ^ n →
1111 / ? O _ o ←
2.3、ds1302芯片介绍
DS1302是美国DALLAS公司推出的一种高性能、低功耗的实时时钟芯片,附加31字节静态RAM,采用SPI 三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号和RAM数据。
实时时钟可提供秒、分、时、日、星期、月和年,一个月小与31天时可以自动调整,且具有闰年补偿功能。
工作电压宽达2.5~5.5V 。
采用双电源供电(主电源和备用电源),可设置备用电源充电方式,提供了对后背电源进行涓细电流充电的能力。
DS1302的外部引脚分配如图1 所示及内部结构如图2 所示。
DS1302用于数据记录,特别是对某些具有特殊意义的数据点的记录上,能实现数据与出现该数据的时间同时记录,因此广泛应用于测量系统中。
各引脚的功能为:
Vcc1 :主电源;Vcc2:备份电源。
当Vcc2>Vcc1+0.2V时,由Vcc2向DS1302供电,当Vcc2< Vcc1时,由Vcc1向DS1302供电。
SCLK:串行时钟,输入,控制数据的输入与输出;
I/O :三线接口时的双向数据线;
CE :输入信号,在读、写数据期间,必须为高。
该引脚有两个功能:第一,CE开始控制字访问移位寄存器的控制逻辑;其次,CE提供结束单字节或多字节数据传输的方法。
DS1302有下列几组寄存器:
①DS1302有关日历、时间的寄存器共有12个,其中有7 个寄存器(读时81h ~
8Dh ,写时80h ~8Ch ),存放的数据格式为BCD码形式,如图3 所示。
小时寄存器(85h 、84h )的位7 用于定义DS1302是运行于12小时模式还是24小时模式。
当为高时,选择12小时模式。
在12小时模式时,位5 是,当为 1 时,表示 PM。
在 24小时模式时,位5 是第二个10小时位。
秒寄存器(81h 、80h )的位 7 定义为时钟暂停标志(CH)。
当该位置为1 时,时钟振荡器停止,DS1302处于低功耗状态;当该位置为0 时,时钟开始运行。
控制寄存器(8Fh 、8Eh )的位7 是写保护位(WP),其它 7 位均置为0 。
在任何的对时钟和RAM的写操作之前,WP位必须为0 。
当WP位为1 时,写保护位防止对任一寄存器的写操作。
② DS1302有关RAM的地址
DS1302 中附加31字节静态RAM的地址如图4 所示。
③DS1302的工作模式寄存器
所谓突发模式是指一次传送多个字节的时钟信号和RAM数据。
突发模式寄存器如图5 所示。
④此外,DS1302还有充电寄存器等。
2 读写时序说明
DS1302是SPI 总线驱动方式。
它不仅要向寄存器写入控制字,还需要读取相应寄存器的数据。
要想与DS1302通信,首先要先了解DS1302的控制字。
DS1302的控制字如图6 。
控制字的最高有效位(位7 )必须是逻辑 1 ,如果它为 0 ,则不能把数据写入到DS1302中。
位6 :如果为 0 ,则表示存取日历时钟数据,为1 表示存取RAM数据;位5 至位1 (A4~A0):指示操作单元的地址;位0 (最低有效位):如为0 ,表示要进行写操作,为1 表示进行读操作。
控制字总是从最低位开始输出。
在控制字指令输入后的下一个SCLK 时钟的上升沿时,数据被写入DS1302,数据输入从最低位(0位)开始。
同样,在紧跟8 位的控制字指令后的下一个SCLK 脉冲的下降沿,读出DS1302的数据,读出的数据也是从最低位到最高位。
数据读写时序如图7 。
3 硬件设计
硬件电路设计主要是AT89C51单片机、ds1302时钟芯片与162液晶显示屏的接口设计。
硬件电路如图所示,单片机的p2.0、p2.1、p2.2分别连接液晶的寄存器选择、读写选择、使能端这三个端口;单片机的p0口的8位分别连接液晶的8个数据端口;单片机的p1端口作为输入端,ds1302芯片,整个系统采用5V的电
源。
4 软件设计
在前面几节中,我们了解了AT89C51单片机、162液晶显示屏与ds1302的接口设计以及液晶屏的时序,那么这部分阐述的是单片机对液晶屏显示和ds1302的驱动控制。
软件工作流程如下:
液晶屏的初始化根据它的时序来及表2.2.2的控制命令表对其进行初始化。
Ds1302初始化是根据图3、4、5、6中对相应的寄存器操作来进行的初始化。
5 结束语
晶液显示器作为输出器件有以下几个优点:
1.显示质量高:由于液晶显示器每一个点在收到信号后就一直保持那种色彩和亮度,恒定发光,而不像阴极射线管显示器(CRT)那样需要不断刷新新亮点。
因此,液晶显示器画质高且不会闪烁。
2. 数字式接口:液晶显示器都是数字式的,和单片机系统的接口更加简单可靠,操作更加方便。
3.体积小、重量轻:液晶显示器通过显示屏上的电极控制液晶分子状态来达到显示的目的,在重量上比相同显示面积的传统显示器要轻得多。
4.功耗低:相对而言,液晶显示器的功耗主要消耗在其内部的电极和驱动IC上,因而耗电量比其它显示器要少得多。
DS1302 高性能,低功耗带RAM实时时钟芯片简介:
1.可对秒、分、时、日、周、月以及带润年补偿的年进行计数,有效至2100年。
2.用于高速数据暂存31字节非易失性RAM.
3.宽工作电源电压范围:2.0V~5.5V。
4.用于(时鈡)或RAM数据读/写的单字节或多字节数据传送方式。
5.简单的3线接口与单片机通信。
6.TTL兼容(VCC=5V)
7.可选的工业温度范围:-40C。
~+85C。
参考文献:
[1] HS162-4液晶显示使用说明资料.
[2] DS1302使用说明资料.
[3] 贺敬凯,刘德新,管明祥.单片机系统设计、仿真与应用。
西安电子科技大学出版社,2011.
附件:
#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
uchar count_10ms; //定义10ms计数器
sbit reset = P1^5;
sbit sclk = P1^6;
sbit io = P1^7;
sbit LCD_RS=P2^0;
sbit LCD_RW=P2^1;
sbit LCD_EN=P2^2;
uchar code line1_data[] = {"Date: 1"}; //定义第1行显示的字符
uchar code line2_data[] = {"Time: "}; //定义第2行显示的字符
uchar disp_buf[8] ={0x00};
uchar disp_buf1[8]={0x00}; //定义显示缓冲区
uchar time_buf[7] ={0,0,0x12,0,0,0,0}; //DS1302时间缓冲区,存放秒、分、时、日、月、星期、年
/********以下是函数声明********/
void Delay_ms(uint xms) ;
bit lcd_busy();
void lcd_wcmd(uchar cmd);
void lcd_wdat(uchar dat) ;
void lcd_clr() ;
void lcd_init() ;
void write_byte(uchar inbyte); //写一字节数据函数声明
uchar read_byte(); //读一字节数据函数声明
void write_ds1302(uchar cmd,uchar indata); //写DS1302函数声明
uchar read_ds1302(uchar addr); //读DS1302函数声明
void set_ds1302(uchar addr,uchar *p,uchar n); //设置DS1302初始时间函数声明void get_ds1302(uchar addr,uchar *p,uchar n); //读当前时间函数声明
void init_ds1302(); //DS1302初始化函数声明
/********以下是延时函数********/
void Delay_ms(uint xms)
{
uint i,j;
for(i=xms;i>0;i--) //i=xms即延时约xms毫秒
for(j=110;j>0;j--);
}
/********以下是LCD忙碌检查函数********/
bit lcd_busy()
bit result; LCD_RS = 0; LCD_RW = 1; LCD_EN = 1; _nop_(); _nop_(); _nop_(); _nop_(); // result = (bit)(P0&0x80); LCD_EN = 0; return result; }
/********以下是写指令寄存器IR函数********/
void lcd_wcmd(uchar cmd) { while(lcd_busy()); LCD_RS = 0; LCD_RW = 0; LCD_EN = 0; _nop_(); _nop_(); P0 = cmd; _nop_(); _nop_(); _nop_(); _nop_(); LCD_EN = 1; _nop_(); _nop_(); _nop_(); _nop_(); LCD_EN = 0; }
/********以下是写寄存器DR函数********/
void lcd_wdat(uchar dat) { while(lcd_busy()); LCD_RS = 1; LCD_RW = 0; LCD_EN = 0; P0 = dat; _nop_(); _nop_();
_nop_();
LCD_EN = 1;
_nop_();
_nop_();
_nop_();
_nop_();
LCD_EN = 0;
}
/********以下是LCD清屏函数********/
void lcd_clr() {
lcd_wcmd(0x01); //清除LCD的显示内容
Delay_ms(5);
}
/********以下是LCD初始化函数********/
void lcd_init() {
Delay_ms(15); //等待LCD电源稳定
lcd_wcmd(0x38); //16*2显示,5*7点阵,8位数据
Delay_ms(5); lcd_wcmd(0x38);
Delay_ms(5); lcd_wcmd(0x38);
Delay_ms(5);
lcd_wcmd(0x0c); //显示开,关光标
Delay_ms(5); lcd_wcmd(0x06); //移动光标
Delay_ms(5); lcd_wcmd(0x01); //清除LCD的显示内容
Delay_ms(5); }
/********以下是写一字节数据函数********/
void write_byte(uchar inbyte)
{
uchar i;
for(i=0;i<8;i++)
{
sclk=0; //写时低电平改变数据
if(inbyte&0x01)
io=1;
else
io=0;
sclk=1; //高电平把数据写入DS1302
_nop_();
inbyte=inbyte>>1;
}
}
/********以下是读一字节数据函数********/
uchar read_byte()
{
uchar i,temp=0;
io=1;
for(i=0;i<7;i++)
{
sclk=0;
if(io==1)
temp=temp|0x80;
else
temp=temp&0x7f;
sclk=1; //产生下跳沿
temp=temp>>1;
}
return (temp);
}
/********写DS1302函数, 往DS1302的某个地址写入数据 ********/ void write_ds1302(uchar cmd,uchar indata)
{
sclk=0;
reset=1;
write_byte(cmd);
write_byte(indata);
sclk=0;
reset=0;
}
/********读DS1302函数,读DS1302某地址的的数据********/
uchar read_ds1302(uchar addr)
{
uchar backdata;
sclk=0;
reset=1;
write_byte(addr); //先写地址
backdata=read_byte(); //然后读数据
sclk=0;
reset=0;
return (backdata);
}
/********初始化DS1302函数********/
void init_ds1302()
{
reset=0;
sclk=0;
write_ds1302(0x80,0x00); //写秒寄存器
write_ds1302(0x90,0xab); //写充电器
write_ds1302(0x8e,0x80); //写保护控制字,禁止写
}
/********以下是转换函数,负责将走时数据转换为适合LCD显示的数据********/
void LCD_conv (uchar ina,inb,inc,in1,in2,in3 ) //形参in1、in2、in3接收实参time_buf[2]、time_buf[1]、time_buf[0]传来的小时、分钟、秒数据
{
disp_buf[0]=in1/10+0x30; //小时十位数据
disp_buf[1]=in1%10+0x30; //小时个位数据
disp_buf[2]=in2/10+0x30; //分钟十位数据
disp_buf[3]=in2%10+0x30; //分钟个位数据
disp_buf[4]=in3/10+0x30; //秒十位数据
disp_buf[5]=in3%10+0x30; //秒个位数据
disp_buf1[0]=ina/10+0x30; //年十位数据
disp_buf1[1]=ina%10+0x30; // 年个位数据
disp_buf1[2]=inb/10+0x30; //月十位数据
disp_buf1[3]=inb%10+0x30; //月个位数据
disp_buf1[4]=inc/10+0x30; //日十位数据
disp_buf1[5]=inc%10+0x30; // 日个位数据
}
/********以下是LCD显示函数,负责将函数LCD_conv转换后的数据显示在LCD上********/
void LCD_disp ()
{ lcd_wcmd(0x07 | 0x80); //从第一行第五列开始显示
lcd_wdat(disp_buf1[0]); //显示年十位
lcd_wdat(disp_buf1[1]); // 显示年个位
lcd_wdat(0x2d); //显示“—”
lcd_wdat(disp_buf1[2]); // 显示月十位
lcd_wdat(disp_buf1[3]); // 显示月个位
lcd_wdat(0x2d); // 显示“-”
lcd_wdat(disp_buf1[4]); // 显示日十位
lcd_wdat(disp_buf1[5]); //显示日个位
lcd_wcmd(0x47 | 0x80); //从第2行第5列开始显示
lcd_wdat(disp_buf[0]); //显示小时十位
lcd_wdat(disp_buf[1]); //显示小时个位
lcd_wdat(0x3a); //显示':'
lcd_wdat(disp_buf[2]); //显示分钟十位
lcd_wdat(disp_buf[3]); //显示分钟个位
lcd_wdat(0x3a); //显示':'
lcd_wdat(disp_buf[4]); //显示秒十位
lcd_wdat(disp_buf[5]); //显示秒个位
}
/********以下是读取时间函数,负责读取当前的时间,并将读取到的时间转换为10进制数********/
void get_time()
{
uchar sec,min,hour,date,month,year; //定义秒、分、小时、日、月、年变量
write_ds1302(0x8e,0x00); //控制命令,WP=0,允许写操作
write_ds1302(0x90,0xab); //涓流充电控制
sec=read_ds1302(0x81); //读取秒
min=read_ds1302(0x83); //读取分
hour=read_ds1302(0x85); //读取时
date=read_ds1302(0x87); //读取日
month=read_ds1302(0x89); //读取月
year=read_ds1302(0x8d); //读取年
time_buf[0]=sec/16*10+sec%16; //将读取到的16进制数转化为10进制 time_buf[1]=min/16*10+min%16; //将读取到的16进制数转化为10进制 time_buf[2]=hour/16*10+hour%16; //将读取到的16进制数转化为10进制 time_buf[3]=date/16*10+date%16; //将读取到的16进制数转化为10进制
time_buf[4]=month/16*10+month%16; //将读取到的16进制数转化为10进制 time_buf[5]=year/16*10+year%16; //将读取到的16进制数转化为10进制
}
/********以下是主函数********/
void main(void)
{
uchar i;
P0 = 0xff;
P2 = 0xff;
lcd_init(); //LCD初始化函数(在LCD驱动程序软件包中)
lcd_clr(); //清屏函数(在LCD驱动程序软件包中)
lcd_wcmd(0x00|0x80); //设置显示位置为第1行第0列
i = 0;
while(line1_data[i] != '\0')
{
lcd_wdat(line1_data[i]); //显示第1行字符
i++; //指向下一字符
}
lcd_wcmd(0x40|0x80); //设置显示位置为第2行第0列
i = 0;
while(line2_data[i] != '\0')
{ lcd_wdat(line2_data[i]); //显示第2行字符
i++; //指向下一字符
}
init_ds1302(); //DS1302初始化
while(1)
{
get_time(); //读取当前时间
LCD_conv(time_buf[5],time_buf[4],time_buf[3],time_buf[2],time_buf[1],time_b uf[0]); //将DS1302的小时/分/秒传送到转换函数
LCD_disp(); //调LCD显示函数,显示年、月、日、小时、分和秒
}
}
毕业设计(论文)原创性声明和使用授权说明
原创性声明
本人郑重承诺:所呈交的毕业设计(论文),是我个人在指导教师的指导下进行的研究工作及取得的成果。
尽我所知,除文中特别加以标注和致谢的地方外,不包含其他人或组织已经发表或公布过的研究成果,也不包含我为获得及其它教育机构的学位或学历而使用过的材料。
对本研究提供过帮助和做出过贡献的个人或集体,均已在文中作了明确的说明并表示了谢意。
作者签名:日期:
指导教师签名:日期:
使用授权说明
本人完全了解大学关于收集、保存、使用毕业设计(论文)的规定,即:按照学校要求提交毕业设计(论文)的印刷本和电子版本;学校有权保存毕业设计(论文)的印刷本和电子版,并提供目录检索与阅览服务;学校可以采用影印、缩印、数字化或其它复制手段保存论文;在不以赢利为目的前提下,学校可以公布论文的部分或全部内容。
作者签名:日期:
学位论文原创性声明
本人郑重声明:所呈交的论文是本人在导师的指导下独立进行研究所取得的研究成果。
除了文中特别加以标注引用的内容外,本论文不包含任何其他个人或集体已经发表或撰写的成果作品。
对本文的研究做出重要贡献的个人和集体,均已在文中以明确方式标明。
本人完全意识到本声明的法律后果由本人承担。
作者签名:日期:年月日
学位论文版权使用授权书
本学位论文作者完全了解学校有关保留、使用学位论文的规定,同意学校保留并向国家有关部门或机构送交论文的复印件和电子版,允许论文被查阅和借阅。
本人授权大学可以将本学位论文的全部或部分内容编入有关数据库进行检索,可以采用影印、缩印或扫描等复制手段保存和汇编本学位论文。
涉密论文按学校规定处理。
作者签名:日期:年月日
导师签名:日期:年月日
指导教师评阅书
评阅教师评阅书
教研室(或答辩小组)及教学系意见。