数字时钟课程设计Word文件下载.docx
《数字时钟课程设计Word文件下载.docx》由会员分享,可在线阅读,更多相关《数字时钟课程设计Word文件下载.docx(27页珍藏版)》请在冰点文库上搜索。
![数字时钟课程设计Word文件下载.docx](https://file1.bingdoc.com/fileroot1/2023-5/2/8eb0d1b7-01c9-486e-9963-12f6e875fa8e/8eb0d1b7-01c9-486e-9963-12f6e875fa8e1.gif)
该数码管组合的功能管脚是八个位选择连接芯片的p2引脚,八个显示管位并联再接入到芯片p0引脚。
从而在功能上区分开,实现数码管的显示功能。
(3)用一个led灯和电阻组成的简易电路结合设计来实现正点报时的功能,当时钟走到正点时,该led灯便能够闪烁五秒刚好是五下,之后进入暗的状态,等到下一个整点到来。
(4)用一个喇叭和三极管等配件组成一个闹钟电路,再与芯片的p1.0引脚连接。
当时钟到设定的报时点时便会发出“嘟嘟嘟嘟….‘的声音来实现闹钟功能。
(5)用一个按键和其他部件组成的复位电路与芯片连接来实现整个程序及硬件的重新复位功能。
三、硬件原理分析
电路设计分析
电路原理设计是基于小系统包括电源电路、复位电路、按键电路、时钟电路、数码管显示驱动电路、输出控制电路。
电源部分是用电池来提供的3v-5v,晶体振荡器采用的是12MHz的石英晶体振荡器。
总体硬件设计框图如下:
1.1复位电路
本次设计采用按键电平复位,按键电平复位相当于按复位键后,复位端通过电阻与Vcc电源接通;
1.2振荡器和时钟电路设计
1.21振荡器和时钟电路工作原理
80C51系列单片机内部有一个高增益反相放大器,用于构成振荡器,但要形成时钟,外部还需附加电路。
XTAL1引脚为反相放大器和时钟发生电路的输入端,XTAL2引脚为反相放大器的输出端。
片内时钟发生器实质是个2分频的触发其输入来自振荡器的fosc,输出为2相时钟信号,即节拍信号P1、P2,器频率为fosc\2。
2个节拍为1个状态时钟S。
状态时钟再3分频后为ALE信号,其频率为fosc\6,状态时钟6分频后为机器周期信号,器频率为fosc\12。
特殊功能寄存器PCON的PD位可以控制振荡器的工作,当PD=0时,振荡器停止工作,单片机进入低功耗工作状态,复位后,PD=0,振荡器正常工作。
1.22本次设计采用常用的内部时钟方式接法:
通过在引脚XTAL1和XTAL2两端跨接晶体或陶瓷谐振器,再利用芯片内部的振荡电路,就构成了稳定的自激振荡器,其发出的脉冲直接送入内部时钟电路,如图所示,外接晶振时,C5和C6的值通常选择为20-30pf。
C5、C6对频率有微调作用,影响振荡的稳定性和起振速度。
所采用的晶体或陶瓷谐振器得频率选择0-24\33MHz。
为了减小寄生电容,更好的保证振荡器稳定、可靠的工作,谐振器和电容赢尽可能与单片机芯片靠近安装。
1.3电源
因为该电路所需电压为3-5v,可直接用电池供应或也可以用直流电源供应,但需经过变压才行。
1.4数码管显示电路
采用LED共阳极数码管的发光二极管接到高电平(电压为5V),用LED动态扫描显示方式,在单片机电路里,芯片的驱动电流很小,一般为微安级别的,要通过三极管(可驱动电流为毫安级别,甚至更大)来驱动LED(正常工作电流为几十毫安)发光,本设计由P2端口扫描数码管的选通,P0口送数据显示。
1.5按键电路
S1按键接在P3.0口,用于切换正常走时、调时间、设定闹钟;
S2按键接在P3.1口,用于调整时钟分加一和调闹钟时间分加一的功能;
S3按键接在P3.2口,用于调整时钟时加一和调闹钟时加一的功能;
S4按键接在P3.3口,用于设定是否开启闹钟。
1.6输出控制电路
在P1.1和P1.0端口分别接一个发光二极管,用于整点报时,和一个蜂鸣器,用于响闹铃。
1.7整体布局图
四、软件设计分析
1、地址空间及端口分配
30h—37h地址空间分别分配给led1、led2、led3、led7、led4、led8、led5、led6.用于数码管显示。
38h地址空间分配给gn,定义38h空间为按键次数读取的缓存空间。
3bh地址空间分配给nk1,定义3bh空间是闹钟开启开关按键次数读取缓存空间。
39h地址空间分配给nao1f,用于存储调整闹钟一分加一按键次数读取缓存。
3ah地址空间分配给nao1s,用于存储调整闹钟一时加一按键次数读取缓存。
3dh地址空间分配给nao2f,用于存储调整闹钟二分加一按键次数读取缓存。
3eh地址空间分配给nao2s,用于存储调整闹钟二时加一按键次数读取缓存。
50h地址空间用于存放50ms中断寄存。
51h地址空间用与存放秒的十位和个位。
52h地址空间用与存放分的十位和个位。
53h地址空间用与存放时的十位和个位。
p1.1端口分配给zdled,定义灯接到p1.1.利用setb和clrzdled控制灯的亮暗起到整点报时显示作用。
p1.0端口分配给nb,定义蜂鸣器接到p1.0利来实现闹肿
p0端口分配给数码管显示控制
p2端口分配给数码管选择显示控制。
2、总体架构说明
该时钟程序设计思路如下:
(1)、在程序头将设计中的一些固定空间进行分配并注释。
(2)、初始化程序,如设定时钟初始显示00—59—56以便一开始就能进入整点报时状态,显示该功能;
设定使用定时器1;
将一些未到时钟设计功能的功能端口关闭等。
(3)开始主程序进行程序扫描,先扫描拆字子程序,将分配好的时分秒等高地位的数字调入到显示子程序中。
——>
显示子程序通过分配的空间对应口将拆字子程序的内容在七段数码管上显示相应的时分秒,再调用走时程序使时钟进行读秒等工作。
进入按键扫描,判断按键是否有变动,若有就根据设计程序对相应的按键按入次数而进行实现相应的功能。
如进入时间调整、闹钟一设置、闹钟开启与否等。
进入闹钟一、二的判断,在时分上与设置的闹铃时间吻合的话就做相对应的判断,再依据是否有开启闹钟而进行响铃与否,如果有响铃则设置其一直响铃知道有人为按取消按键取消闹铃。
进入整点报时扫描,判断是否在时分上都进入了整点,如果是就报时显示灯闪烁五下(5s),然后就退出整点报时,等到下一个整点的到来。
最后返回主程序头重新依次扫描。
显示过程设有消隐,按键设有去斗。
(4)、子程序部分。
在主程序的调用下依据不同的子程序工能而编写子程序,有多级嵌套。
这些子程序包括显示子程序、拆字子程序、延时子程序、走时间子程序、整点报时子程序、按键处理子程序、调时间子程序、闹钟设置子程序、闹钟子程序、闹钟开启子程序。
3、各子程序功能及出入口地址
(1)各子程序功能:
显示子程序:
将拆分好的高低位时分秒拆分码放入相对应的数码管,调用tab选通相应的七段数码显示时分秒当前数字。
拆字子程序:
将空间51h、52h、53h内的秒时分拆成高低字节分配到,30h、31h、33h、34h、36h、37h实现时分秒的显示。
延时子程序:
该子程序是为了实现八个七段数码管显示的顺序显示选通时间,2ms的显示时间频率是的显示效果稳定,同时作为按键开关扫描判断去抖
走时间子程序:
该程序功能是使得秒程序走动,走到59后进位分,后变00从新开始计时,分走到59后进位时,分从新开始00计时,时走到23,分走到59,秒走到59后进入从新日期周期计时。
整点报时子程序:
在达到整点时该程序的功能实现报时,报时以led灯闪烁显示为报时信号。
按键处理子程序:
该程序进行按键处理的功能判断分别是有调试按键处理,闹钟设置按键处理,闹钟开启与否按键处理。
调时间子程序:
该程序功能实现时间的调整。
调闹钟子程序:
该程序闹钟程序设计与按键结合实现闹钟设置调整的功能。
闹钟开启子程序:
该功能实现闹钟开启与否而达到闹钟响铃功能。
4、程序流程图
五、程序清单
;
初始化;
led1equ30h;
定义30h=第8个数码管(最右边第1个数码管)的显示内容=LED1=秒的个位
led2equ31h;
定义31h=第7个数码管显示内容=LED2=秒的十位
led3equ32h;
定义32h=第6个数码管显示内容=LED3=时分秒中间的一个横杆
led7equ33h;
定义33h=第5个数码管显示内容=LED7=分的个位
led4equ34h;
定义34h=第4个数码管显示内容=LED4=分的十位
led8equ35h;
定义35h=第3个数码管显示内容=LED8=时分秒中间的一个横杆
led5equ36h;
定义36h=第2个数码管显示内容=LED5=时的个位
led6equ37h;
定义37h=第1个数码管显示内容=LED6=时的十位
gnequ38h;
定义38h空间为按键次数读取的缓存空间
bssjequ3fh;
zdledbitp1.1;
定义灯接到p1.1.利用setb和clrzdled控制灯的亮暗
nbbitp1.0;
定义蜂鸣器接到p1.0利来实现闹铃响
nk1equ3bh
nao1fequ39h
nao1sequ3ah
nao2fequ3dh
nao2sequ3eh
org00h;
这句话把下面那条指令定位到(烧写到)00h这个地址去
sjmpmain;
这里是单片机复位后运行的第一条指令,这句话使单片机跳到main那里继续执行程序
org001bh;
这句话把下面那条指令定位到(烧写到)001b这个地址去.
ljmpzoushijian;
这句话是定时器50毫秒定时到之后,TH0,TL0记数到FFFFH时单片机自动跳到这里运行,我们再把它跳到zoushijian继续执行,因为这个时候主程序已经暂停运行,我们称主程序发生了中断,而zuoshijian就是中断服务主程序.
org40h;
把主程序main定位到40h这个地址
main:
movsp,#5FH;
设置堆栈指针,存放进入50ms中断时的PC值
mov50h,#01;
50h存放定时器中断的次数,现在定时器每50ms中断一次,所以
;
赋初值20,利用djnz减,减到0时自然就是1秒到了
mov51h,#55;
51h存放秒的十位和个位,现在给32h等于十进制的50,相当于一开始让
第7个,第8个数码管显示50秒,尽快到达整点,利于调试整点报时.
mov52h,#59;
52h存放分的十位和个位,现在给3bh等于十进制的59,相当于一开始让
;
第4个,第5个数码管显示59分,尽快到达整点,利于调试整点报时.
mov53h,#00;
53h存放小时的十位和个位,现在给00h等于十进制的00,相当于一开始让
第1个,第2个数码管显示00小时,
movtmod,#10h;
使定时器1工作在工作模式1,即16位定时器工作模式
movth1,#3ch;
65536us-50000us=15536微秒,刚好是3cb0h,这样定时器1每50ms进入中断一次
movtl1,#0afh
setbzdled;
还没到整点,先让灯暗
mova,#0
movr1,a
movbssj,#10
clrrs0
clrrs1
clrgn
clrnao1f
clrnao1s
clrnk1
setbnb
setbtr1;
开启定时器1,使TH1,TL1不断加1
setbet1;
开启定时器1中断,使TH1,TL1加到FFFF时让单片机自动跳到001bh去执行,如果不开启这个中断标志,那么即使单片机TH1,TL1记数到FFFF,单片机也不会跳到001bh去的.
setbea;
开启总中断
主程序;
l5:
nop
lcallchaizi;
把当前的时分秒的值(即53h~51h的内容)按照十位,个位拆到35h~30h中
lcalldisplay;
把拆好的时分秒的十位,个位分别显示到相应的数码管上面.
lcallanjian;
理按键
lcallxiang1;
判断闹钟
lcallxiang2
lcallnk;
设置闹钟是否开
lcallzdbs;
整点报时
sjmpl5;
主循环结束,又跳到主循环开始处
显示子程序,把拆好的时分秒的十位,个位分别显示到相应的数码管上面;
入口地址:
r2、r3
出口地址:
p0、p2
display:
movr0,#led1;
从LED1开始显示,即从第8个数码管秒的个位开始
movdptr,#tab
movr2,#08;
8个数码管同时显示
movr3,#0feh;
选通第8个数码管,关闭其他的数码管
disp_1:
mova,@r0;
把当前要显示的数放到A里面
movca,@a+dptr;
得到当前要显示数的7段码
movp2,#0ffh;
关掉所有数码管显示,消隐,把残留在数码管上面的乱码消去
movp0,a;
显示当前的数,运行到这里,人的眼睛应该看到显示内容
mova,r3;
位选给A
movp2,a;
选通相应的数码管
rla;
得到新的位选码
incr0;
指针指向下一个要显示的内容
movr3,a;
保存下一个位选码,以便选通下一个数码管.
lcalldelay;
延时4毫秒显示当前的数码管
djnzr2,disp_1;
跳回去,进入下一个数码管的显示
ret
tab:
db0c0h,0f9h,0a4h,0b0h,99h,92h,82h,0f8h,80h,90h,0bfh,0ffh,8ch,3fh,7fh
采用除法指令实现的拆字程序;
38h、
30h—38h、3bh
chaizi:
mova,gn;
显示闹钟二
cjnea,#3,chaizi2
mova,nao2f
movb,#10
divab
movled2,a
movled1,b
mova,nao2s
movled4,a
movled7,b
movled5,#02h
movled6,#0ch
chaizi2:
mova,gn;
显示闹钟一
cjnea,#2,chaizi1
mova,nao1f
mova,nao1s
movled5,#01h
lcallbcd
chaizi1:
mova,51h;
把51h这个秒的数值拆成个位和十位
movled2,a;
秒的十位进入LED2保存
movled1,b;
秒的个位进入LED1保存
mova,52h;
把52h这个分的数值拆成个位和十位
movled4,a;
分的十位进入LED4保存
movled7,b;
分的个位进入LED7保存
mova,53h;
把53h这个时的数值拆成个位和十位
movled6,a;
时的十位进入LED6保存
movled5,b;
时的个位进入LED5保存
lcallbcd1
lcallbcd2;
处理第3个和第6个数码管的显示
bcd1:
mova,gn
cjnea,#0,l3
cjner1,#0,l3
mova,50h;
读取50ms中断的次数,看看经过了几次50ms的中断
cjnea,#09,l1
l1:
jcl3
mova,nk1
cjnea,#1,k_1
movled3,#0dh
k_1:
movled3,#0bh;
没到0.5秒,显示横杆
ret;
是否经过了0.5秒(即是否经过了10次的50ms中断)
l3:
cjnea,#1,k_2
movled3,#0eh
k_2:
movled3,#0ah;
已经到了0.5秒,让两个横杆消失,这样造成两个横杆一闪一闪效果
bcd2:
cjnea,#0,l13
cjner1,#0,l13
cjnea,#09,l11
l11:
jcl13
cjnea,#1,k_11
movled8,#0dh
k_11:
movled8,#0bh;
是否经过了0.5秒(即是否过了10次50ms中断)
l13:
cjnea,#1,k_21
movled8,#0eh
k_21:
movled8,#0ah;
延时程序;
;
r6、r7
r6
delay:
movr6,#5;
这是一个((1+1+2)*100+2+1)*5=2015微秒=2毫秒的延时程序
dl2:
movr7,#100;
1微秒
dl1:
nop;
1微秒
djnzr7,dl1;
2微秒
djnzr6,dl2;
走时间;
acc、psw
acc
zoushijian:
PUSHacc;
0E0H就是A,见课本44页,因为这个时候SP=5fh,故把A的值保存在5fh里面去
PUSHpsw;
因为0D0H就是PSW(见课本44页),此时SP=60H,所以这句话是把PSW的值保存到60h中去
重新给定时器赋初值,让它再定时50ms
djnz50h,l2;
判断是否到了1秒没有,50h减到0表示已经进行了20次的50ms,刚好1秒
mov50h,#20;
已经到1秒,重新赋次数,再定时记数一秒
inc51h
mova,51h;
从51h读取秒的值(包含十位,个位)
cjnea,#60,l2;
判断是否到60秒,没到60秒,中断返回退到主程序
mov51h,#0;
到60秒,重新从0秒加起,分钟加1
inc52h
mova,52h;
读取分钟
判断是否到了60分钟,没到60分钟,中断返回退到主程序
mov52h,#0;
到60分钟,重新从0分钟加,小时加1
inc53h
mova,53h;
读取小时值
cjnea,#24,l2;
判断是否到了24小时,没到24小时街卸戏祷赝说街鞒绦?
mov53h,#0;
到了24小时,重新清零小时,从00小时又开始新一天定时
l2:
POPpsw;
把放在60h的东西放回到PSW里面,因为这个时候SP=60h,0D0H就是PSW
POPacc;
把放在60h的东西放回到PSW里面,因为这个