;初始化
P_Lcd equ P0 ;液晶lcd数据总线
pq equ p3 ;按键接口
pf bit p2.1 ;蜂鸣器接口
led bit p2.0 ;led灯指示接口
lcdrs bit p2.6 ;lcdrs=1选择数据寄存器,lcdrs=0选择指令寄存器
lcdrw bit p2.5 ;lcdrw=1进行读操作,lcdrw=0进行写操作
lcde bit p2.7 ;lcdep由1-->0 时,液晶模块执行命令
sclk bit p3.6 ;时钟芯片时钟线引脚
io bit p3.4 ;时钟芯片数据传输线引脚
rst bit p3.5 ;时钟芯片复位线引脚
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
acall LcdDspBuf ;显示分
mov a,#3ah ;显示分隔符号
acall LcdWrDat
mov R0, #DspBuf+11
mov R2, #2
acall LcdDspBuf ;显示秒
jb BJ,xyz ;判断闹钟功能是否开启
mov a,#0c0h
acall LcdWrCmd
mov a,#03h ;显示闹钟功能开启标示符号
acall LcdWrDat
xyz: ret
ret
;按键处理
anjian:
mov a,pq
anl a,#0fh
cjne a,#0fh,kp1
ret
kp1:
mov a,#5 ;设置5ms延时,起到去抖扫描
acall delay
mov a,pq
anl a,#0fh
cjne a,#0fh,kp2
ret
kp2:
JB pq.0,KK1
jnb pq.0,$
lcall anjian1
ret
KK1:
JB pq.1,KK2
jnb pq.1,$
lcall anjian2
ret
KK2:
JB pq.2,KK3
jnb pq.2,$
lcall anjian3
ret
KK3:
JB pq.3,KK4
jnb pq.3,$
lcall anjian4
KK4: ret
;该子程序根据的KeyCode内容转入各对应的操作程序中
anjian1:
mov a,KeyCode
mov dptr,#tab5
add a,KeyCode
jnc nadd
inc dph ;KeyCode乘2进位加到DPH中
nadd:
mov r3,a ;暂存
movc a,@a+dptr ;取地址高八位
xch a,r3 ;保存转移地址高8位
inc a
movc a,@a+dptr ;取地址低八位
mov dpl,a ;置转移地址低8位
mov dph,r3
clr a
jmp @a+dptr
ret
tab5: dw opr00,opr01,opr02 ,opr03 ;16位转移地址表的首地址
;进入时间调整设置状态
opr00:
setb IsSheZhi
mov r1,#DspBuf+12 ;编辑时间从秒个位开始
mov a,#0fh
acall LcdWrCmd
mov a,#0c9h
acall LcdWrCmd
mov KeyCode,#02h
ret
;进入设置闹钟时间状态
opr01:
setb IsSheZhi
mov r1,#dspba+3 ;编辑时间从分个位开始
mov a,#0fh
acall LcdWrCmd
mov a,#0c6h
acall LcdWrCmd
mov KeyCode,#03h
ret
;把所设置的时间作为当前时间
opr02:
mov a,DspBuf+11
swap a
mov b,DspBuf+12
orl a,b
mov sec,a ;存秒
mov a,DspBuf+9
swap a
mov b,DspBuf+10
orl a,b
mov min,a ;存分
mov a,DspBuf+7
swap a
mov b,DspBuf+8
orl a,b
mov hour,a ;存时
mov a,DspBuf+4
swap a
mov b,DspBuf+5
orl a,b
mov day,a ;存日期
mov week,DspBuf+4; ;存星期值
mov a,DspBuf+2
swap a
mov b,DspBuf+3
orl a,b
mov month,a ;存月
mov a,DspBuf+0
swap a
mov b,DspBuf+1
orl a,b
mov year,a ;存年
lcall set1302 ;为当前时间
cpl IsSheZhi ;退出设置状态
mov a,#0ch ;开启 闪动
acall LcdWrCmd
mov KeyCode,#00h
ret
;把所设置的时间作为闹钟时间
opr03:
mov a,#0c0h
acall LcdWrCmd
mov a,#03h ;显示闹钟功能开启标示符号
acall LcdWrDat
mov a,#0ch ;撤销闪动
acall LcdWrCmd
clr IsSheZhi ;退出设置状态
mov KeyCode,#00h
clr QH
clr BJ ;开启闹钟功能
ret
anjian2:
mov a, KeyCode
clr c
subb a,#02h
jc ppr1 ;判断钟是否处于设置状态,不是则跳
jb QH, opr1a
mov a,r1
clr c
subb a,#5eh
mov dptr,#taba4
movc a,@a+dptr
mov b,a
inc @r1
mov a,@r1
cjne a, b,ppra1
mov @r1,#0
ppra1:
lcall www ;扫描当前时间编辑位
ret
taba4: db 0ah,0ah,0ah,0ah,02h,0ah,04h,0ah,08h,03h,0ah,06h,0ah,06h,0ah;当前时间各编辑位极大值表
opr1a:
mov a,r1
clr c
subb a,#70h
mov dptr,#taba6
movc a,@a+dptr
mov b,a
inc @r1
mov a,@r1
cjne a,b,ppra1k
mov @r1,#0
ppra1k:
lcall wwwa ;扫描闹钟时间编辑位
ret
taba6 : db 03h,0ah,06h,0ah ;闹钟时间各编辑位极大值表
ppr1: cpl IsSheZhi
cpl QH ;切换屏幕
jnb QH,TY
mov a,#01h ;清屏幕
acall LcdWrCmd
mov KeyCode,#01h ;指明按键1下次执行的功能子程序
acall display_nz ;显示闹钟时间
ret
TY: mov KeyCode,#00h ;指明按键1下次执行的功能子程序
ret
;按键3处理设计
anjian3:
mov a, KeyCode
clr c
subb a,#02h
jc ajppr2 ;判断钟是否处于设置状态,不是跳
jb QH, opr2b ;判断钟是否处于编辑闹钟时间状态
dec r1 ;移位
cjne r1,#DspBuf-3,ppr2a
mov r1,#DspBuf+12
ppr2a:
lcall www ;扫描当前时间编辑位
ret
opr2b:
dec r1 ;移位
cjne r1,#dspba-1,ppr2ak
mov r1,#dspba+3
ppr2ak:
lcall wwwa ;扫描闹钟时间编辑位
ret
ajppr2:
mov a,#01h ;清除屏幕
acall LcdWrCmd
cpl BJ
JB BJ,TY_1
ret
TY_1:
clr tr0
setb pf
ret
;按键4处理设计
anjian4:
mov a, KeyCode
clr c
subb a,#02h
jc anjian4_1 ;判断钟是否处于设置状态,否则跳
clr IsSheZhi
mov KeyCode,#00h
mov a,#0ch ;取消闪动
acall LcdWrCmd
ret
anjian4_1:
mov a,#01h ;清除屏幕
acall LcdWrCmd
cpl bs ;控制报时功能
JB bs,TY_2
ret
TY_2:
clr tr1
setb pf
ret
;扫描当前时间编辑位
www:
mov a,r1
clr c
subb a,#5eh
mov dptr,#tab4
movc a,@a+dptr
mov b,a ;暂存 闪动位置
acall LcdWrCmd ;写入编辑位的位置
mov a,#10 ;设置10ms延时
acall delay
mov a,@r1
orl a,#30h
acall LcdWrDat ;写入数据
mov a,b ;确定闪动位置
acall LcdWrCmd
ret
;扫描闹钟时间编辑位
wwwa:
mov a,r1
clr c
subb a,#70h
mov dptr,#tab6
movc a,@a+dptr
mov b,a ;暂存 闪动位置
acall LcdWrCmd ;写入编辑位的位置
mov a,#10 ;设置10ms延时
acall delay
mov a,@r1
orl a,#30h
acall LcdWrDat ;写入数据
mov a,b ;确定闪动位置
acall LcdWrCmd
ret
tab4:db 80h,81h,82h,83h,85h,86h,88h,89h,8eh,0c2h,0c3h,0c5h,0c6h,0c8h,0c9h
;当前时间各编辑位在LCD上的位置表
tab6:db 0c2h,0c3h,0c5h,0c6h ;闹钟时间各编辑位在LCD上的位置表
;比较子程序
bijiao:
mov a, dspba+0
cjne a,DspBuf+7,bijiao_1 ;比较当前时间与闹钟时间的时十位
mov a, dspba+1
cjne a,DspBuf+8,bijiao_1 ;比较当前时间与闹钟时间的时个位
mov a, dspba+2
cjne a,DspBuf+9,bijiao_1 ;比较当前时间与闹钟时间的分钟十位
mov a, dspba+3
cjne a,DspBuf+10,bijiao_1;比较当前时间与闹钟时间的分钟个位
setb TR0
ret
bijiao_1:
clr TR0
setb pf
clr led
ret
; 整点报时子程序
zhengshi:
mov a,sec ;判断当前时间是否是整时,即能否报时
jnz js ;判断是否位0秒
mov a,min
jnz js ;判断是否位0分
mov a,DspBuf+7
mov b,#10
mul ab
add a,DspBuf+8 ;;BCD码转化位二进制
cjne a,#13,$+3 ;判断时是否超过12小时
jc ss
clr c
subb a,#12
ss:
mov shengshu,a
cpl bs ;暂时关闭判断整时
clr cxbs ;开始报时
js: ret
;执行报时baoshi
baoshi: ;执行报时功能
mov a,chuzhi
cjne a,sec,ltt
setb tr1
mov a,chuzhi
add a,#01h
da a
mov chuzhi,a
djnz shengshu,ltt
cpl bs
setb cxbs
mov chuzhi,#00h
ltt: ret
;蜂鸣器响功能设置
sub1:
cpl pf
reti
sub2:
mov th1,#0f8h ;设置报时声的音色
cpl pf
djnz jiepai,sub2_1
mov jiepai,#80h ;设置节拍常数
clr tr1
sub2_1: reti
end
|