一.设计目的:
1、进一步掌握8255电路的编程方法。
2、进一步掌握定时器的使用和编程方法。
二.设计内容:
利用MPLAB微机实验系统上提供的8255,键盘电路,数码显示电路,设计一个电子时钟,要求按24小时制显示,能够修改初始时间值。
三.设备及连线:
本实验使用MPLAB微机试验系统
四.程序说明:
本程序采用模块化编程,能够实现输入时间数据检测,当输入错误格式及时间数据时,自动清空时间为初始0值。能够自由启动,停止和重设时间初值。秒针进位由定时器控制。定时器工作方式设为1。
电子时钟格式及功能如下:
XX XX XX 由左向右以此显示:时,分,秒
1、C键:清除,显示时间00 00 00
2、B键:启动电子时钟
3、F键:停止电子时钟,并可设置时间
当输入时间数据错误,立即清零,显示00 00 00
例如,当输入 27 34 23 ―― 小时数据错误!
13 78 43 ―― 分钟数据错误!
03 23 a4 ―― 秒数据错误!
五.程序框图:
六.程序代码:
comport equ 9003h ;8255命令字地址9003h
aport equ 9000h ;8255 PA口输出显示字符段码地址
bport equ 9001h ;8255 PB口输出显示字符位码地址
cport equ 9002h ;8255 PC口输入读取键盘数据
databuf equ 50h ;设置存放时间数据首地址
mov r6,#5
mov r5,#8 ;定时器循环次数
mov tmod,#10h ;设置定时器1 方式1
mov th1,#3ch ;设置定时器初值高位
mov tl1,#0b0h ;设置定时器初值低位
start:
mov sp,#30h ;设置SP值为30h
mov dptr,#comport
mov a,#10001000b
movx @dptr,a ;初始化8255
mov r0,#databuf
mov r1,#6
clr a
initloop: ;清空时间数据为0(循环6次)
mov @r0,a
inc r0
djnz r1,initloop
hf: mov r4,#50h ;备份存放时间数据首地址
;初始化完毕
mainloop: ;主程序运行
call scankey ;调用键盘扫描子程序
jc ccc ;判断进位标志是否为1(即有无按键输入)
sjmp qwe ;不为1(有按键输入),跳转键值输入程序段
ccc: ljmp time ;为1(无按键输入),跳转到定时程序
qwe: push acc ;数据压栈,保存按键值
mov a,r4 ;取出当前时间数据存放位置
mov r0,a
pop acc ;数据出栈,按键值保存在a中
cjne a,#0ch,nor ;判断按键是否为c键,否则跳转继续判断
ajmp start ;按键值是C键(清零功能),跳转程序开始处
nor: cjne a,#0bh,nor2 ;判断按键是否为b键,否则跳转继续判断
setb tr1 ;按键值是b键(启动时钟功能),启动定时器
mov r0,#databuf ;取出第一个时间数据
mov a,@r0 ;赋值给a
jmp nor3 ;跳转到赋值时间数据程序段
nor2: cjne a,#0fh,nor3 ;判断按键是否为F键,否则跳转到赋值时间程序段
clr tr1 ;按键值是F键(设置时间功能),停止定时器
jmp dspbuf ;跳转到时间显示子程序
nor3:
mov @r0,a ;给当前数据存放地址内赋时间数据
call vali ;调用数据合法性判断子程序
inc r4 ;r4值+1,即当前存放数据地址后移一位
mov a,r4
subb a,#56h ;判断r4是否为55h,即数据存放地址是否为最后一位
jz hf ;是转初始化r4程序段,即改变当前数据存放地址为第一位
time: ;定时器子程序
jbc tf1,agai ;tf1是否溢出,是转
jmp dspbuf ;否转显示子程序
agai: djnz r5,time ;判断定时器是否循环8次(1秒时间)
mov r5,#8 ;是恢复定时器初始值为8
jmp count ;跳转至秒针进位程序
dspbuf: ;调用显示子程序
call dspled
jmp mainloop ;回转到主程序开始处
scankey: ;扫描键盘子程序
mov dptr,#cport
clr a
movx @dptr,a
movx a,@dptr
orl a,#0fh
inc a
jnz skloop
call dspled
ljmp exit
skloop: ;查键闭合否
call dspled
mov dptr,#cport
clr a
movx @dptr,a
movx a,@dptr
orl a,#0fh
inc a
jz exit
mov r0,#0
mov r1,#4
mov r2,#0feh
skloop1: ;软消除按键抖动
mov a,r2
movx @dptr,a
rl a
mov r2,a
movx a,@dptr
orl a,#0fh
cjne a,#0ffh,keyval
mov a,#4
add a,r0
mov r0,a
djnz r1,skloop1
sjmp exit
keyval:
swap a
mov r1,#4
skloop2:
rrc a
jnc readval ;有键按下,跳转读键值程序段
inc r0
skloop3:djnz r1,skloop2
exit: setb c ;无键按下,退出
sjmp quit
readval: ;读键值
mov dptr,#tab
mov a,r0
movc a,@a+dptr ;查表获取相应按键值
push acc ;键值压栈
wait: call dspled
mov dptr,#cport
clr a
movx @dptr,a
movx a,@dptr
orl a,#0fh
inc a
jnz wait
clr c ;清空进位标志,初始化8255输入端
pop acc ;键值出栈
quit: ret
tab: db 0,1,2,3,4,5,6,7,8,9,0ah,0bh,0ch,0dh,0eh,0fh
count: ;秒针进位子程序
mov th1,#3ch
mov tl1,#0b0h
mov r0,#databuf+5 ;取个位秒数值
mov a,@r0
cjne a,#09h,mc ;判断个位秒值是否为9,否转
clr a ;是,个位秒值清零
mov @r0,a
jmp jwm ;转判断十位秒值
mc: inc a ;个秒值+1
mov @r0,a
jmp dspbuf ;显示数值
jwm: mov r0,#databuf+4
mov a,@r0
cjne a,#05h,mmc ;判断十秒位是否为5,否则转
clr a
mov @r0,a ;是,十秒位清零
jmp jwf ;转判断个位分值
mmc: inc a
mov @r0,a ;否,十秒位数值+1
jmp dspbuf ;显示数值
jwf: mov r0,#databuf+3 ;判断个位分值
mov a,@r0
cjne a,#09h,fc ;判断个位分值是否为9,否则转
clr a
mov @r0,a ;是,个位分值清零
jmp jwsf ;转判断十位分值
fc: inc a
mov @r0,a ;否,个位分值+1
jmp dspbuf ;显示数值
jwsf: mov r0,#databuf+2 ;判断十位分值
mov a,@r0
cjne a,#05h,fcc ;判断十位分值是否为5,否则转
clr a
mov @r0,a ;是,十位分值清零
jmp jws ;转判断个位小时
fcc: inc a
mov @r0,a ;否,十位分值+1
jmp dspbuf ;显示数值
jws: ;判断个位小时数值
mov r0,#databuf
mov a,@r0 ;先取十位小时数值
cjne a,#02h,sss ;判断十位小时数值是否为2,否则转
mov r0,#databuf+1 ;是,取个位小时数值
mov a,@r0
cjne a,#03h,xxs ;判断个位小时数值是否为3,否则转
clr a
mov @r0,a ;是,个位小时数值清零
jmp jwxs ;判断十位小时数值
xxs: inc a
mov @r0,a ;否,个位小时数值+1
jmp dspbuf ;显示数值
sss: mov r0,#databuf+1 ;取个位小时数值
mov a,@r0
cjne a,#09h,xss ;判断个位小时数值是否为9,否则转
clr a
mov @r0,a ;是,个位小时清零
jmp jwxxs ;转十位小时+1
xss: inc a
mov @r0,a ;否,各位小时数值+1
jmp dspbuf ;显示数值
jwxxs:mov r0,#databuf ;十位小时直接+1
mov a,@r0
inc a
mov @r0,a
jmp dspbuf ;显示数值
jwxs: mov r0,#databuf ;十位小时直接清零
mov a,@r0
clr a
mov @r0,a
jmp dspbuf ;显示数值
dspled: ;时间显示子程序
mov r0,#databuf ;赋r0为存放第一个显示数值的地址
mov r1,#6 ;赋r1为显示次数
mov r7,#20h ;赋显示位码给r7(20h为6位数码管左边第一位)
dsploop:
mov a,@r0 ;取第一个显示数据(即十位小时数值)
mov dptr,#ledcode
movc a,@a+dptr ;查表得显示数据得相应段码
mov dptr,#aport
movx @dptr,a ;赋段码值给8255 PA端口
mov a,r7
mov dptr,#bport
movx @dptr,a ;赋位码值给8255PB端口
mov b,#1
call delay ;调用显示延迟子程序
inc r0 ;指向存放当前显示数值得地址后一位
djnz r1,shift ;依次循环显示存放的时间数据(共6次)
ret
shift: mov a,r7
rr a ;右移当前段码值,即当前显示数码管右移一位
mov r7,a
sjmp dsploop ;继续显示数值
delay: mov r2,#3
mov r3,#0
dloop: djnz r3,dloop
djnz r2,dloop
djnz b,dloop
ret
ledcode:
db 3fh,06h,5bh,4fh,66h,6dh,7dh,07h,7fh,6fh,77h,7ch,39h,5eh,79h,71h
vali: ;判断数据合法性子程序
mov r0,#databuf
mov a,@r0 ;取十位小时数值
cjne a,#0,aa ;判断十位小时数值是否为0,否转继续判断
jmp aga2 ;是,转十位分数值合法性判断
aa: cjne a,#1,bb ;十位小时数值是否为1,否转继续判断
jmp aga2 ;是,转十位分数值合法性判断
bb: cjne a,#2,wrong ;十位小时数值是否为2,否转出错程序段
jmp aga ;是,转个位小时数值合法性判断
wrong: mov r4,#4fh ;出错程序段
mov r0,#databuf
mov r1,#6
clr a
initloop3: ;初始化显示数值全部为0
mov @r0,a
inc r0
djnz r1,initloop3
ok: ret
aga: mov r0,#databuf+1 ;取个位小时数值
mov a,@r0
cjne a,#0,cc ;个位小时数值是否为0,否转继续判断
jmp ag ;是,转十位分数值判断
cc: cjne a,#1,dd ;个位小时数值是否为1
jmp ag
dd: cjne a,#2,ee ;个位小时数值是否为2
jmp ag
ee: cjne a,#3,wrong ;个位小时数值是否为3,否转出错
jmp ag ;是,转十位分数值判断
ag: mov r0,#databuf+2 ;先取十位分数值进行合法性判断
twice: mov a,@r0
cjne a,r6,taga ;依次判断十位分数值是否为5,4,3,2,1
pd: cjne r0,#54h,addd ;当前判断位是否为十位秒?无继续进行判断
jmp ok
addd: inc r0
inc r0 ;地址后移,取十位秒数值进行合法性判断
mov r6,#5
jmp twice
taga: djnz r6,twice
cjne a,r6,wrong ;数值是否为0,否则出错
jmp pd
[hide]需要回复才[/hide]