基于52单片机电子时钟的设计
摘要
本次设计的多功能时钟系统采用STC89C52单片机为核心器件,利用其定时器/计数器定时和记数的原理,结合液晶显示电路、时钟芯片DS1302电路、电源电路以及按键电路来设计计时器。将软硬件有机地结合起来,使得系统能够实现液晶显示,显示有年、月、日、时、分、秒以及星期,还可以设置闹钟和整点报时。其中软件系统采用单片机汇编语言编写程序,包括显示程序、闹钟程序、中断、延时程序,按键消抖程序等,并在keil中调试运行,硬件系统利用PROTEUS强大的功能来实现,简单且易于观察,在仿真中就可以观察到实际的工作状态。
1 设计任务及要求分析
1.1 设计任务:基于单片机的电子时钟设计
1.2 要求:
1.2.1 用LCD液晶作为显示设备
1.2.2 可以分别设定小时、分钟和秒,复位后时间为 00 00 00
1.2.3 能实现日期的设置年、月、日
1.3 扩展要求:如闹钟功能、显示星期、整点音乐报时等
2 系统方案
2.1 系统整体方案的论证
电路原理设计是基于小系统板包括电源电路、复位电路、按键电路、DS1302时钟电路、液晶显示驱动电路、输出控制电路。电源部分是用电池来提供的3v-5v,晶体振荡器采用的是12MHz的石英晶体振荡器。
整个系统用单片机为中央控制器,由单片机执行采集时钟芯片的时间信号并通过显示模块来输出信号及相关的控制功能。时钟芯片产生时钟信号,利用单片机的I/O口传给单片机;并通过I/O口实现LCD的显示。系统设有4个独立式按键可以对时间年、月、日和星期进行调整,还可以设置闹钟。具体如图2.1所示:
图2.1 系统整体框图
3 硬件设计与实现
3.1单片机最小系统
STC89C52是一款非常适合单片机初学者学习的单片机,它完全兼容传统的8051,8031的指令系统,他的运行速度要比8051快最高支持达33MHz的晶体震荡器,在此系统中使用12MHz的晶振。
AT89S52是一种低功耗、高性能CMOS8位微控制器,具有8K在系统可编程Flash存储器。使用Atmel公司高密度非易失性存储器技术制造,与工业80C51 产品指令和引脚完全兼容。片上Flash允许程序存储器在系统可编程,亦适于常规编程器。在单芯片上,拥有灵巧的8 位CPU 和在系统可编程Flash,使得STC89C52为众多嵌入式控制应用系统提供高灵活、超有效的解决方案。STC89C52具有以下标准功能:8k字节Flash,256字节RAM,32 位I/O 口线,看门狗定时器,2 个数据指针,三个16位定时器/计数器。一个6向量2级中断结构,全双工串行口及时钟电路。另外,STC89C52 可降至0Hz 静态逻辑操作,支持2种软件可选择节电模式。空闲模式下,CPU停止工作,允许RAM、定时器/计数器、串口、中断继续工作。掉电保护方式下,RAM内容被保存,振荡器被冻结,单片机一切工作停止,直到下一个中断或硬件复位为止。
3.2振荡电路的工作原理
STC89C52单片机内部有一个高增益反相放大器,用于构成振荡器,但要形成时钟,外部还需附加电路。XTAL1引脚为反相放大器和时钟发生电路的输入端,XTAL2引脚为反相放大器的输出端。振荡电路如图3.1所示:
图3.1 振荡电路图
3.2时钟电路的工作原理
片内时钟发生器实质是个2分频的触发其输入来自振荡器的fosc,输出为2相时钟信号,即节拍信号P1、P2,器频率为fosc\2。2个节拍为1个状态时钟S。状态时钟再3分频后为ALE信号,其频率为fosc\6,状态时钟6分频后为机器周期信号,器频率为fosc\12。特殊功能寄存器PCON的PD位可以控制振荡器的工作,当PD=0时,振荡器停止工作,单片机进入低功耗工作状态,复位后,PD=0,振荡器正常工作。时钟电路如图3.2所示:
图3.2时钟电路图
3.3单片机最小系统电路图
图3.3单片机最小系统电路图
3.4 时钟芯片
(1)DS1302是一种可编程的实时时钟芯片,具有计算2100年前的时间的能力,包括时钟/日历寄存器和31字节(8位)的数据暂存寄存器,数据通信权通过一条串行输出口。时钟/日历提供包括秒、分、时、日期、月份和年份信息。闰年可自行调整,以串行方式向单片机传送单字节或多字节的秒、分、时、日、月、年等实时时间数据;只通过三根线进行数据的控制和传递:RST、I/O、SCLK;其在电路的功能是还具有在出现主电源断电时备用电源可继续保持时钟的连续运行。时钟引脚图如图3.4所示:
如果单片机要对DS1302内部寄存器进行读写操作,必须先将与寄存器对应的位操作地址传送给DS1302,然后再进行读写数据的操作。控制寄存器是用来决定能否对DS1302进行读写操作,当控制字的最高位WP=0时,允许进行读写操作;当WP=1时,禁止读写操作。所以单片机对DS1302进行读写操作时,必须先将控制字00H写入到DS1302的控制寄存器中。
3.5 液晶显示电路
LCD显示器能显示数码管不能显示的其他字符、文字和图形,是十分重要的显示终端,LCD1602是字符点阵液晶显示模块。利用LCD1602,所用的时间年、月、日、星期可同时可见,一目了然,采用双行显示,让电子钟能够更直观的显示。其实图如图3.5、显示电路图如图3.6、引脚功能如表3-2所示:
图3.5 液晶显示器实图
3.6 输出控制电路
在P2.0端口接一个蜂鸣器,用于整点报时和响闹铃。具体如图3.7所示:
图3.7输出控制电路图
3.7按键电路
本次设计采用按键电平复位,按键电平复位相当于按复位键后,复位端通过电阻与Vcc电源接通,按键电路图如图3.8所示:
图3.8按键电路图
4 软件设计与实现
4.1软件总体设计方案
4.1.1 软件设计目标
软件部分总体上是模块化的设计思想,通过子程序调用设计方式 ,将所有的模块综合到一起,使程序可读性较高。
4.1.2 总体架构说明
该时钟程序设计思路如下:
(1)在程序头将设计中的一些固定空间进行分配并注释。
(2)初始化程序,如设定时钟初始显示“2016年6月30日,星期四,00:00”以便一开始就能进入整点报时状态,显示该功能;设定使用定时器1;将一些未到时钟设计功能的功能端口关闭等。
(3)开始主程序进行程序扫描,先扫描拆字子程序,将分配好的时分秒等高地位的数字调入到显示子程序中。→显示子程序通过分配的空间对应口将拆字子程序的内容在液晶显示器上显示相应的时分秒,再调用走时程序使时钟进行读秒等工作。→进入按键扫描,判断按键是否有变动,若有就根据设计程序对相应的按键按入次数而进行实现相应的功能。如进入时间调整、闹钟设置、闹钟开启与否等。→进入闹钟的判断,在时分上与设置的闹铃时间吻合的话就做相对应的判断,再依据是否有开启闹钟而进行响铃与否,如果有响铃则设置其一直响铃知道有人为按取消按键取消闹铃。→进入整点报时扫描,判断是否在时分上都进入了整点,如果是就报时,然后就退出整点报时,等到下一个整点的到来。→最后返回主程序头重新依次扫描。显示过程设有消隐,按键设有去抖。
(4)子程序部分。在主程序的调用下依据不同的子程序工能而编写子程序,有多级嵌套。这些子程序包括拆字子程序、延时子程序、走时间子程序、整点报时子程序、按键处理子程序、调时间子程序、闹钟设置子程序、闹钟子程序、闹钟开启子程序
4.2按键模块设计
设计系统中的按键模块仅占用四个I/O口,从89s52芯片p1.0、p1.1、p1.2、p1.3四个引脚接入进行控制。当没有按键按下时,均为高电平,有按键按下时相应I/O口为低电平,但并没有立即执行相应的程序,延时5ms后若再为低电平,等I/O口恢复高电平,即按键松开时,才执行相应的程序,此时按键才起作用。这样该按键模块具有去抖动,且按键按下一次仅作用一次,起到精确判断的作用。
4.2.1 按键1的说明
按键1有四种功能,分别为下面4个子程序:
(1)子程序0的功能为:进入设置当前时间状态,且令keycode=2;
(2)子程序1的功能为:进入设置闹钟时间状态,且令keycode=3;
(3)子程序2的功能为:把所设置的时间作为当前时间,且令keycode=0;
(4)子程序3的功能为:把所设置的时间作为闹钟时间,且令keycode=0;
每次按下按键1,按键1程序根据的KeyCode内容转入各对应的子程序中(因为当KeyCode值不同时,经过计算得到dptr的值不同,然后经过jmp @a+dptr指令就可跳转到不同的子程序中,具体程序说明),从而实现不同的功能。
从各按键的功能可知,每次按下按键1,都会改变KeyCode内容,使按键1的功能发生改变。
4.2.2 按键2的说明
按键2有两种不同的功能:对应于设置状态为加1;对应于非设置状态为切换屏幕。所以按键2程序开头就先判断闹钟是否处于设置状态。
当闹钟处于非设置状态时,keycode等于0或1;处于设置状态时,keycode等于2或3;所以可用如下语段判断闹钟是否处于设置状态:
当闹钟处于设置状态,keycode值大于2,c等于0
当闹钟处于非设置状态,keycode值小于2,c等于1
4.2.3 其他按键的说明
剩下3、4按键都于按键2类似,先判断是否处于设置状态,然后转入不同的语句,不再说明。
4.2.4 报时功能的说明:
当报时功能开启,即bs=0时,LCD上会出现相应的标示符号,此时主程序将扫描zhengshi子程序。
zhengshi子程序能判断当前时间是否为整点,若为整点将使cxbs=0,且把hour由BCD码化为二进制存储在字节shengshu(为报时声数,将在baoshi子程序中使用)中,之后主程序将扫描baoshi子程序,即开始报时。
chuzhi=0, 由baoshi子程序可知,闹钟从0秒开始报时,当报时完毕将自动令cxbs=1。
4.2.5 闹钟功能的说明:
当闹钟功能开启,即bj=0时,LCD上会出现相应的标示符号此时,主程序将扫描zhengshi子程序。zhengshi子程序对当前时间和闹钟时间进行比较,当它们的分、时全相等时开启中断sub1,否则关闭中断sub1。这样就可实现闹钟闹铃一分钟后自动停止鸣叫的要求。
4.2.6 加1、移位功能的说明:
将年份前两位与年(year)、月(month)、星期(week)、日(day)、时(hour)、分(min)、秒(sec)拆字后分别存储在DspBuf-2、DspBuf-1、DspBuf+0、DspBuf+1、DspBuf+2、DspBuf+3等13个字节中。而把它们的每一为在LCD上的显示位置地址放在如下表中:
tab4:db 80h,81h,82h,83h,85h,86h,88h,89h,8eh,0c2h,0c3h,0c5h,0c6h,0c8h,0c9h;
当前时间各编辑位在LCD上的位置表。然后执行mov r1,#DspBuf+12; inc @r1就可实现对秒个位加1。执行:dec r1和子程序www就可实现移位功能.
4.3 时钟模块设计
单片机要先从DS1302芯片中读取时钟数据,然后通过LCD显示出来。在读取DS1302的时间和日期之前,先要对DS1302进行赋初始时间并开启时钟。时钟被启动后若未接收到新的赋时间指令,其内部的时钟将一直不停的运行,以保证时间的实时性和准确性;期间单片机可随时读取DS1302内部时间和日期寄存器中的数值。
4.4 液晶显示模块设计
本设计液晶时钟显示系统设计上由液晶显示器显示、时钟芯片DS1302提供时间,可为使用者提供完整的时间信息。由于LED数码管只能显示数字而无法显示其他中英文字符,并对成本及功能考虑,因此从设计的成本及功能的角度考虑,采用LCD一1602显示模块,它可以显示年、月、日、星期等中文字目。LCD一1602驱动电路简单,可以由单片机直接输出命令驱动。
5.4仿真结果图如下所示
图5.4 K4仿真结果图
6 不足与展望
6.1 设计不足之处
没有停止闹钟的硬件功能
没有实现按键减1,只能加1调节时钟
没有实现音乐整点报时
没有安装三极管,蜂鸣器声音很小
6.2 设计的展望
可以增加一个温度传感器以测量和显示温度
(2)实现阴历和阳历的转化
7设计心得
本文的电子钟系统是以单片机(STC89C52)为核心,时钟芯片DS1302、LED1602显示等部分组成。具体应用Keil2软件调试程序以及Proteus软件进行基于单片机的电子钟设计与仿真。实现了硬件软化的目的。
经过一段时间的课程设计,我们发现对于书上很多知识还不能灵活运用,有很多知识还要我们去学习。此次电子时钟的设计给我们奠定了一个实践的基础,很是受益匪浅。让我们认识到学习不但要立足于书本,而且要注重实践,要以解决理论和实际教学中的实际问题为目的。通过自己的手来解决问题比用脑子解决问题更加深刻。学习就应该采取理论与实践结合的方式,这种做法既有助于完成理论知识的巩固,而且可以加强我们的动手和解决实际问题的能力。
单片机源程序如下:
;初始化
P_Lcd equ P0 ;液晶lcd数据总线
pq equ p1 ;按键接口
pf bit p2.0 ;蜂鸣器接口
led bit p2.1 ;led灯指示接口
lcdrs bit p2.5 ;lcdrs=1选择数据寄存器,lcdrs=0选择指令寄存器
lcdrw bit p2.6 ;lcdrw=1进行读操作,lcdrw=0进行写操作
lcde bit p2.7 ;lcdep由1-->0 时,液晶模块执行命令
sclk bit p3.5 ;时钟芯片时钟线引脚
io bit p3.6 ;时钟芯片数据传输线引脚
rst bit p3.7 ;时钟芯片复位线引脚
IsSheZhi bit 30h ;设置状态标示位
BJ bit 31h ;比较标示位
QH bit 32h ;切换标示位
bs bit 33h ;报时功能标示位
cxbs bit 34h ;执行报时标志位
sec equ 50h
min equ 51h
hour equ 52h
day equ 53h
week equ 54h
month equ 55h
year equ 56h
KeyCode equ 57h ;按键1功能子程序序号存储地址
jiepai equ 58h ;存放报时声音的节拍常数
chuzhi equ 59h ;报时开始秒时间常数
shengshu equ 5ah ;存放报时声数
DspBuf equ 60h ;当前时间拆字后存储首地址
dspba equ 70h ;闹钟时间首地址
org 0h
ljmp main
org 00bh
ljmp sub1
org 01bh
ljmp sub2
org 30h
;主程序
main:
clr IsSheZhi
clr QH
setb BJ
setb bs
setb cxbs
mov KeyCode,#00h
mov sp ,#30h
mov year,#16h ;为当前时间赋初值
mov month,#06h
mov week,#4h
mov day,#30h
mov hour,#00h
mov min,#00h
mov sec,#00h
mov DspBuf-1,#0h
mov DspBuf-2,#02h
mov jiepai,#80h ;设置节拍常数
mov chuzhi,#00h ;设置1秒时开始报时
mov dspba+0,#00h ;为闹钟时间赋初值
mov dspba+1,#09h
mov dspba+2,#0h
mov dspba+3,#0h
mov TH0,#0ffh
mov TL0,#0ffh
mov TH1,#0ffh
mov TL1,#0ffh
mov IE,#8aH
mov TMOD,#11h
setb pf
acall lcd_init ;调LCM的初始化程序
lcall word ;把自创字符写入CGRAM的子程序
lcall set1302 ;DS1302初始化
mainloop:
jb IsSheZhi, SheZhi ;判断是否处于设置状态,处于设置状态则跳转
lcall get1302 ;调读时间子程序
lcall chaizi
lcall display ;调显示子程序,显示当前时间与温度
SheZhi:
jb BJ,xq ;判断闹钟功能是否开启,未开启则跳转
lcall bijiao ;调比较子程序,比较当前时间与闹钟时间
xq:
lcall anjian ;按键扫描
jb bs,bs_1
lcall zhengshi ;判断当前时间是否是整时,即能否报时
bs_1:
jb cxbs,cx_1
lcall baoshi ;执行报时功能
cx_1:
sjmp mainloop
;液晶显示初始化设定
lcd_init:
mov a,#01h ;清除LCD的显示内容(清屏)
acall LcdWrCmd
mov a,#10 ;10ms延时
acall delay
mov a,#38h ;显示模式设置(使用8位数据,显示两行,使用5*7的字型)
acall LcdWrCmd
mov a,#10
acall delay
mov a,#0ch ;显示开及光标设置(显示器开,光标关,字符不闪烁)
acall LcdWrCmd
mov a,#10
acall delay
mov a,#06h ;显示光标移动设置(字符不动,光标自动右移)
acall LcdWrCmd
mov a,#10
acall delay
ret
;LCM命令嵌入
LcdWrCmd:
clr LCDRW
clr LCDRS
mov P_Lcd, A
mov a,#6
acall delay
setb LcdE
clr LcdE
ret
;LCM数据输入
LcdWrDat:
setb LCDRS
clr LCDRW
mov P_Lcd, A
mov a,#6
acall delay
setb LcdE
clr LcdE
ret
;延时子程序
delay:
mov r7,a ;设置a为自定义变量,可省去其他延时程序的编写
d2: mov r6,#250 ;设置1ms延时
d1:
nop
nop
djnz r6,d1
djnz r7,d2
ret
;ds1302初始化程序set1302
set1302:
mov a,#8eh ;写ds1302控制寄存器地址
mov b,#00h ;允许写操作,将WP位设置为低电平
lcall clockwr
mov a,#8ch ;写年初值
mov b,year
lcall clockwr
mov a,#88h ;写月初值
mov b,month
lcall clockwr
mov a,#8ah ;写星期初值
mov b,week
lcall clockwr
mov a,#86h ;写日期初值
mov b,day
lcall clockwr
mov a,#84h ;写时初值
mov b,hour
lcall clockwr
mov a,#82h ;写分初值
mov b,min
lcall clockwr
mov a,#80h ;写秒初值
mov b,sec
lcall clockwr
ret
;读时间子程序get1302
get1302:mov a,#81h ;读秒
lcall clockrd
mov sec,a
mov a,#83h ;读分
lcall clockrd
mov min,a
mov a,#85h ;读时
lcall clockrd
mov hour,a
mov a,#87h ;读日
lcall clockrd
mov day,a
mov a,#8bh ;读星期
lcall clockrd
mov week,a
mov a,#89h ;读月
lcall clockrd
mov month,a
mov a,#8dh ;读年
lcall clockrd
mov year,a
ret
;ds1302读子程序
clockrd:clr rst ;rst先设置低电平,再设置高电平,起到去乱码作用
clr sclk ;sclk置为低电平
setb rst ;rst置为高电平,选通DS1302
mov r7,#8 ;串行移位传送次数
rds1:
rrc a
mov io,c ;输出一位寄存器读地址
setb sclk ;发串行脉冲
nop
nop
clr sclk ;sclk置为低电平
djnz r7,rds1
nop ;延时,防后面串行读数据丢失
nop
setb io ;8位地址输出完毕,IO设置为输入端口
mov r7,#8
rds2:
mov c,io ;读入一位数据
rrc a
setb sclk ;发串行脉冲
nop
nop
clr sclk
djnz r7,rds2
clr rst
setb sclk
ret
;ds1302写数据子程序
clockwr:
push acc ;设置堆栈,入栈
push b
clr rst
clr sclk
setb rst ;选通DS1302
mov r7,#8
wrs1:
rrc a
mov io,c ;输出一位寄存器写地址
clr sclk ;发串行输出脉冲
setb sclk
djnz r7,wrs1
nop
mov a,b ;将待写入数据送A
mov r7,#8
wrs2:
rrc a
mov io,c ;经IO输出一位数据
clr sclk
setb sclk
djnz r7,wrs2
pop b ;出栈
pop acc
ret
;显示设置—— 分配时间显示空间
chaizi:
mov a,year ;拆年
mov r0,#60h
acall hex2bcd
mov a,month ;拆月
mov r0,#62h
acall hex2bcd
mov a,day ;拆日期
mov r0,#64h
lcall hex2bcd
mov a,week;
mov 66h,a
mov a,hour ;拆时
mov r0,#67h
lcall hex2bcd
mov a,min
mov r0,#69h ;拆分
lcall hex2bcd
mov a,sec
mov r0,#6bh ;拆秒
acall hex2bcd
ret
;显示设置—— 采用除法指令实现的拆字子程序
hex2bcd:
mov b,a
anl a,#0f0h
swap a
mov @r0,a
mov a,b
anl a,#0fh
inc r0
mov @r0,a
ret
;显示设置——连续显示相邻的两字节
LcdDspBuf:
mov A, @R0
orl a,#30h
acall LcdWrDat
inc R0
djnz R2, LcdDspBuf
ret
;显示设置——自创字符写入CGRAM的子程序
word:
mov a,#40h
lcall LcdWrCmd
mov r5,#40
mov dptr,#tab1
mov r4,#0
nextt:
mov a,r4
movc a,@a+dptr
lcall LcdWrDat
inc r4
djnz r5,nextt
ret
tab1:
db 08h,0fh,12h,0fh,0ah,1fh,02h,00h;年
db 0fh,09h,0fh,09h,0fh,09h,13h,00h;月
db 0fh,09h,09h,0fh,09h,09h,0fh,00h;日
db 06h,0fh,1fh,0fh,07h,1bh,19h,00h;显示闹钟功能开启标示符号
db 15h,15h,04h,11h,1bh,1fh,0eh,00h;显示报时功能开启标示符号
;进入闹钟功能设置显示
display_nz:
mov a,#0c2h
acall LcdWrCmd ;确定闹钟时间的首地址
mov R0, #dspba+0
mov R2, #2
acall LcdDspBuf ;显示时
mov a,#3ah ;显示分隔符号
acall LcdWrDat
mov R0, #dspba+2
mov R2, #2
acall LcdDspBuf ;显示时
jb BJ,XT ;判断闹钟功能是否开启
mov a,#0c0h
acall LcdWrCmd
mov a,#03h ;显示闹钟功能开启标示符号
acall LcdWrDat
XT: ret
;正常显示设置
display:
mov a,#80h
acall LcdWrCmd ;指明显示的首地址
mov R0, #DspBuf-2
mov R2, #2
acall LcdDspBuf ;显示年份前两位
mov R0, #DspBuf+0
mov R2, #2
acall LcdDspBuf ;显示年后两位
mov a,#00h ;显示汉字年
acall LcdWrDat
mov R0, #DspBuf+2
mov R2, #2
acall LcdDspBuf ;显示月份
mov a,#01h ;显示汉月字年
acall LcdWrDat
mov R0, #DspBuf+4
mov R2, #2
acall LcdDspBuf ;显示日期
mov a,#02h ;显示汉日字年
acall LcdWrDat
mov a,#8ch ;w指明星期的首地址
acall LcdWrCmd
mov a,#57h
acall LcdWrDat ;显示w
mov a,#3ah ;显示分隔符号
acall LcdWrDat
mov a,66h ;显示星期值
orl a,#30h
acall LcdWrDat
jb bs,XtT ;判断报时功能是否开启
mov a,#04h ;显示报时功能开启标示符号
acall LcdWrDat
XtT:
mov a,#0c2h
acall LcdWrCmd ;确定地址
mov R0, #DspBuf+7
mov R2, #2
acall LcdDspBuf ;显示时
mov a,#3ah ;显示分隔符号
acall LcdWrDat
mov R0, #DspBuf+9
mov R2, #2
……………………