AVR汇编百例之四 ---- 输入输出
;时钟日历芯片62×42×读写程序,时钟日历数据读入到显示缓存区$6C--$73
;范例24 ;USE 8515!使用DSPA子程序
.EQU RTCH=$40 ;rtc地址高八位
RDATE: RCALL BSYT ;初始化,兼冻结RTC
LDI XL,$6D ;数据缓存区首地址
LDI YL,$06 ;首指日单元
RDLP: LD R16,Y+ ;$6b 6c 6d 6e 6f 70 71 72 73
ANDI R16,15 ; 2 9(D) - 1 0(M) - 0 2(Y)
CPI R16,10
BRCS RDL1
ANDI R16,$7F ;容错处理
RDL1: ST X,R16$
DEC R26
CPI R26,$6B
BRNE RDLP1
LDI XL,$70
RDLP1: CPI R26,$6E
BRNE RDLP2
LDI R16,$14 ;送‘-’到$6E单元
ST X,R16
LDI XL,$73
RDLP2: CPI R26,$71
BRNE RDLP
LDI R16,$14
ST X,R16 ;送‘-’到$71单元并结束子程序
RDINVL: RJMP WCRT
RTIME: RCALL FIL2 ;请除缓存区
RCALL BSYT
LDI XL,$73
LDI YL,$02 ;指向分单元(只读时分)
RCL: LD R16,Y+
ANDI R16,15
CPI R16,10
BRCS RCL0
ANDI R16,$7F ;容错处理
RCL0: ST X,R16
DEC R26
CPI R26,$71
BRNE RCL1
LDI R16,$14 ;写入‘-’
ST X,R16
DEC R26
RCL1: CPI R26,$6E ;$6c 6d 6e 6f 70 71 72 73
BRNE RCL ; 1 6 - 3 5
CLR R16
ST Y,R16
LDS R17,$9FFB ;时制存储单元
LDS R16,$6f
SWAP R16
LDS R15,$70
ADD R16,R15 ;合成小时
SUBI R16,$24 ;模24
RCALL SUDAA ;BCD码减法调整
BRCC RCL2 ;够减,转
SUBI R16,-36 ;否则恢复被减数
RCL2: CPI R17,2
BRNE PRTD1 ;24小时制,转
SUBI R16,$12
RCALL SUDAA
BRCC PRTD1 ;12小时制处理
SUBI R16,-18
PRTD1: MOV R17,R16
SWAP R16
ANDI R16,$0F
ANDI R17,$0F
STS $6F,R16
STS $70,R17 ;小时数据送入显示区
RJMP WCRT
WDATE: RCALL WRTC ;将显示缓存区中日期数据写入RTC
LDI XL,$6F
LD R16,X
CPI R16,10
BRCC WDRT ;非法数据,退出
LDI YL,6
WDLP: LD R16,X
DEC R26
CPI R16,$24 ;SPC?
BRNE WD0
CLR R16 ;变为0
WD0: ST Y+,R16
CPI R26,$6D
BRNE WD1 ;$6d 6e 6f 70 71 72 73
LDI XL,$71 ; 2 9(日) 1 1(月) 0 2 (年)
RJMP WDLP
WD1: CPI R26,$6f
BRNE WD2
LDI R26,$73
WD2: CPI R26,$71
BRNE WDLP
LWDRT: RJMP WCRT
WTIME: RCALL WRTC ;将显示缓存区中时间数据写入RTC
LDI R26,$73
LD R16,X
CPI R16,10
BRCC WCRT ;非法数据,退出
LDI YL,2
WLOP: LD R16,X
CPI R16,$24
BRNE WT1
CLR R16 ;容错处理
WT1: ST Y+,R16
DEC R26
WLP: CPI R26,$6F
BRNE WLOP ;$6E 6f 70 71 72 73
WCRT: CLR R16 ; 1 5 3 8
LDI YL,$0D
ST Y,R16 ;解除对RTC之冻结
IN R16,MCUCR
CBR R16,$C0
OUT MCUCR,R16 ;禁止读写外部RAM
RET
;对rtc初始化/冻结时钟
BSYT: LDI YH,RTCH ;rtc地址高八位
LDI YL,$0D ;指向D寄存器
IN R16,MCUCR
SBR r16,$C0 ;允许读写外部RAM并选一个时钟周期等待时间
OUT MCUCR,R16
LDI R16,5 ;设置冻结位和中断申请位
ST Y,R16
CLR XH
BSRT: RET
;写RTC初始化子程序
WRTC: RCALL BSYT
LDI YL,$0E ;指向寄存器E
LDI R16,6
ST Y+,R16 ;指向寄存器F
LDI R16,1 ;设置时制位
ST Y,R16
LDI R16,4 ;选24小时制
ST Y,R16
CLR R16 ;请除时制位
ST Y,R16
RJMP BSYT
;范例25 ;显示保护子程序/晶振4MHZ
DSPRV: LDI R16,HIGH(ramend)
OUT SPH,R16
LDI R16,LOW(ramend)
OUT SPL,R16
CLR R2 ;调DSPY次数寄存器清除
WDR
LDI R16,$0D ;启动看门狗,溢出时间为0.49s
OUT WDTCR,R16 ;写入看门狗控制寄存器
CLR XH
LDI XL,$6C
DSPVL: ST X+,XH ;清显示缓存区($6c-$73)
CPI XL,$74
BRNE DSPVL
DSPV0: LDI R16,$66
MOV R9,R16
LDI R16,$82 ;$6582=25986,高位字节增1为$66
MOV R10,R16 ;调25986次DSPA耗时120s
DSNEX: LDI XL,$74 ;将显示区十进制数据增1以演示数据变化
DSLOP: LD R16,-X ;实用时可以采样数据更新显示(参考范例96)
INC R16
ST X,R16
CPI R16,$0A
BRNE DSPRV1
CLR R16
ST X,R16
CPI R26,$6C
BRNE DSLOP ;增1后如有进位则调整
DSPRV1: DEC R10
BRNE DSPGN
DEC R9
BRNE DSPGN ;2分钟定时到?
DSCLOS: RCALL FIL2 ;将显示缓存区充入空白($24)
RCALL DSPA ;其效果相当于关显
SBRC R16,7
RJMP DSCLOS
RJMP DLFUNC ;有键按下,转出;否则继续关显
DSPGN: RCALL DSPA ;未到,显示数据
SBRC R16,7
RJMP DSNEX ;无键按下,继续显示
DLFUNC: CPI R16,12 ;关显键键值为12
BEEQ DSCLOS ;关显键按下,转关闭显示
;.
;.
;.
;.
;(其他键值处理,参考范例26 DEALKY程序)
RJMP DSPV0 ;执行功能后转入二分钟定时
;范例26 ;键值处理程序
DEALKY: LDI R16,HIGH(ramend)
OUT SPH,R16
LDI R16,LOW(ramend)
OUT SPL,R16
CLR R2 ;调DSPY次数寄存器清除
WDR
LDI R16,$0D ;启动看门狗,溢出时间为0.49”
OUT WDTCR,R16 ;写入看门狗控制寄存器
DEALK0: RCALL DSPA
SBRC R16,7
RJMP DEALK0 ;无键按下,反复查询
CPI R16,10
BRCC FNCKY ;功能键按下,跳转
RCALL FIL2 ;键值<10为数字键 ,先清除显示缓存区
NUMKY: RCALL LSDD8 ;8位数字左移,新键值加入序列尾
DSLP: RCALL DSPA
SBRC R16,7
RJMP DSLP ;无键按下,继续显示
CPI R16,11
BRCS NUMKY ;键入数字形成左移序列/按清除键则清除所有键入数据
BRNE DSLP ;键值大于11无效
;11为回车键,对键入数字进行处理(如将其两两合并为BCD
;码,再转为二进制数等)
RJMP DEALK0 ;转回
FNCKY: SUBI R16,10 ;功能键散转处理,先计算键值偏移量
LDI R31,HIGH(FKYTB)
LDI R30,LOW(FKYTB);散转表表首
ADD R30,R16
CLR R16
ADC R31,R16 ;偏移量加入指针
IJMP ;散转
FKYTB: RJMP CLTTL ;10:清除累加和
RJMP DSTTL ;11:显示累加和
RJMP DSCLS ;12:关显示
RJMP SLFTS ;13:自检
RJMP FDPAP ;14:打印机走纸
RJMP PRSMP ;15:打印采样
RJMP PRTTL ;16:打印累加和
RJMP DSCLK ;17:显示系统时钟
;............. ;.........
;............. ;.........
CLTTL: ;............. ;程序内容略
;.............
RJMP DEALK0 ;程序执行完毕,转回
DSTTL: RCALL BRTTL ;分解累加和送显示缓存区
RCALL DSPA ;显示累加和
SBRC R16,7
RJMP DSTTL ;任一键按下,结束显示累加和
RJMP DEALK0 ;程序执行完毕,转回
DSCLS: RJMP DSCLOS ;转去关显示
SLFTS: ;.............
;.............
RJMP DEALK0 ; 自检程序执行完毕,转回
FDPAP: ;.............
;.............
RJMP DEALK0 ; 走纸程序执行完毕,转回
PRSMP: ;.............
;.............
RJMP DEALK0 ; 打印采样程序执行完毕,转回
PRTTL: ;.............
;.............
RJMP DEALK0 ;打印累加和程序执行完毕,转回
DSCLK: RCALL BRCLK ;分解系统时钟送入显示缓存区
RCALL DL1S ;延时1秒
RCALL DSPA ;显示时钟
SBRC R16,7 ;任一键按下,结束显示时钟
RJMP DSCLK
RJMP DEALK0 ;程序执行完毕,转回
;.............
;............. ;其他功能键处理略
;.............
;范例27 ;主显子程序
DSPA: SBRC R16,7 ;USE R0,R2,R11,R12,r13,r14,r15,r16,r17&Z,X POINTERS
RJMP DSA2 ;无键按下,跳转
DSA0: CLR R12
INC R12 ;有键按下,将计数器置1
DSA1: RCALL DSPY
DEC R12
BRNE DSA1 ;等待键释放
DSA2: RCALL DSPY
LDS R16,$A3
SBRS R16,7 ;有进入功能表程序标志?
RET ;没有返回
SBI PORTA,0 ;
SBIS PINA,0 ;退出功能表程序吗?
RET
CBR R16,$80 ;是,清除进入功能表程序标志($A3,7)
STS $A3,R16
RCALL FIL2
LDI R16,$0F ;'F'
STS $6C,R16
LDI R16,$0E ;'E'
STS $6E,R16
LDI R16,$17 ;'n'
STS $6F,R16
LDI R16,$0D ;'d'
STS $70,R16 ;显示‘F End'
RCALL DL2S ;2秒后
RJMP DIPA1 ;转到主程序(包括对堆栈)初始化
DL2S: RCALL DL1S ;延时2秒子程序
DL1S: LDI R16,217 ;延时1秒子程序/4MHz clk
MOV R11,R16 ;4.618×217=1000ms
DLCOM: RCALL DSPA
DEC R11
BRNE DLCOM
RET
;范例28 ;基显子程序,显示缓存区:$6C--$73,执行时间4.618ms/晶振4MHZ
;主程序应对看门狗初始化,设置溢出时间为0.49秒!
DSPY: LDI R17,$0F ;使用R0,R2,R12,R13,R14,R15,R16&R17/z&x pointer!
OUT DDRA,R15 ;PA7--PA4为键列值输入
CLR R15
COM R15
OUT DDRB,R15
OUT DDRC,R15 ;口B:段选输出,口C:位选输出
OUT PORTC,R15 ;关显
DPY1: LDI R26,$6C ;指向显示缓存区首址:$6C
CLR R27
LDI R17,$7F
MOV R13,R17 ;位选初始化(首显最高位)
L0D: LD R17,X+
LDI R31,HIGH(table*2)
LDI R30,LOW(table*2)
ADD R30,R17
ADC R31,R27
L0C: LPM ;取段选码
OUT PORTB,R0 ;送段选口
OUT PORTC,R13 ;位选口
SEC ;
ROR R13 ;指下一位位选
LDI R17,3 ;4MHz(6 if 8MHz)
CLR R14
DLOP: DEC R14
BRNE DLOP
DEC R17
BRNE DLOP ;延时0.5762毫秒
IN R16,PORTA
ORI R16,$F0 ;保护PA3--PA0输出
OUT PORTA,R16 ;提拉PA7-PA4
IN R14,PINA ;读入列值
NEX: ROL R14 ;use high 4bits!
BRCC L1 ;有键按下,跳转
NEX1: INC R17 ;指向下一列
CPI R17,4
BRNE NEX ;各列都查完?
NEX2: SER R17
OUT PORTC,R17 ;将$FF写入位选口(关显)
CPI R26,$74
BRNE L0D ;每位LED都显示一遍??
MOV R16,R15 ;YES
INC R2 ;增一调DSPY次数寄存器
MOV R17,R2
CPI R17,100 ;到100次?
BRNE NEX3
CLR R2 ;清除看门狗定时器时间到计数器/4.618ms×100=0.462s(<0.49s)
WDR ;看门狗定时器复位
NEX3: RET
L1: LDS R16,$73 ;计算键值代码/查键值
SUB R16,R26 ;$73-(r26)-->r16
LSL R16
LSL R16 ;行值*4
ADD R16,R17 ;键值代码=行值*4+列值
LDI R30,LOW(TABL0*2)
ADD R30,R16
LDI R31,HIGH(TABL0*2)
ADC R31,R27
LA00: LPM ;查出键值
MOV R15,R0 ;放在R15
LA10: INC R12 ;计数器增1以备判断键释放
RJMP NEX1 ;转回查下一列
TABL0: .DB 10,0,11,20,1,2,3,16,4,5,6,22,7,8,9,18,12,15,19,23,14,17,21,13
TABLE: .DB $3F,$06,$5B,$4F,$66,$6D,$7D,$07,$7F,$67,$77,$7C,$39 ;0--C
.DB $5E,$79,$71,$6F,$74,$04,$1F,$40,$38,$37,$54,$5C ;'d'---'o'
.DB $73,$67,$50,$6D,$78,$1C,$3E,$7E,$F8,$6E,$49,$00
.DB $48,$52,$D3,$76 ;$25(=),$26(/)$27(?) END AT $28(H)
.DB $BF,$86,$DB,$CF,$E6,$ED,$FD,$87,$FF,$E7;THE 0.($29)--9.($32)
.DB $D7,$C9,$80 ;THE 'X.' 'Z.' &'.'($33--$35)
.DB $DE,$EF,$B8,$F3,$E7,$D0,$DC,$ED,$86,$F9,$B9H,$F7,$F1,$B7,$D4
;the d.,g.,L.,p.,q.,r.,o.,s.,l.,E.,C.,A.,F.,M.,n.(36--44h)
;范例29 ;键入数字序列左移处理子程序
LSDD8: LDI R26,$6C ;8bcd码($6C--$73H)
LDS R27,$A3
CBR R27,8 ;清$A3,3
STS $A3,R27
CLR R27
CPI R16,10 ;10为清除键
BRNE DDL
RCALL FIL2 ;清除显示缓存区($6c-$73)!
LDS R16,$A3
SBR R16,8
STS $A3,R16 ;建清除显示缓存区标志$A3,3=1
RET
DDL: INC R26 ;数字键按下,序列左移
LD R16,X ;
SUBI R16,$29 ;数字带小数点?
BRCC DD4 ;若带则将其复原(参考DSPY子程序段码表)
SUBI R16,$D7 ;恢复
DD4: ST -X,R16 ;移入左邻单元
DD5: INC R26
CPI R26,$73
BRNE DDL ;各数字都左移了一位?
ST X,R15 ;新键入数字进入数字序列末位
LDI R26,$6C
DEL: LD R16,X
CPI R16,10 ;是BCD码?
BRCS DEL2
CPI R16,$29
BRCC DELRT ;大于$29为错误!
DELA: INC R26 ;0--9/$24/$14为有效!
CPI R26,$73
BRNE DEL ;缓存区检查完毕?
RJMP DELRT
DEL2: CPI R16,0
BRNE DELRT
LDI R16,$24 ;0改为空白
ST X,R16
RJMP DELA ;
DELRT: LDS R16,$A0 ;小数点位置单元
TST R16
BREQ DDRET ;($a0)=0,无小数点
NEG R16
ADD R16,$73
MOV R26,R16 ;找到缓存区内带小数点的数据位
LD R16,X
SUBI R16,$D7 ;加上小数点
ST X,R16
CPI R16,$4D ;在空白码加了小数点($24(空白)+$29=$4d)?
BRNE STLR1
LDI R16,$29
ST X,R16 ;是,将其改为'0.'
STLR1: CPI R26,$73
BREQ DDRET ;并将其后所有空白都改为0
INC R26
LD R16,X
CPI R16,$24
BRNE DDRET
CLR R16
ST X,R16
RJMP STLR1
DDRET: RET
FIL2: LDI R26,8 ;在显示缓存区内填充空白
MOV R14,R26
FIL2A: LDI R26,$6C
FIL: CLR R27
LDI R16,$24
FILP: ST X+,R16
DEC R14
BRNE FILP
RET
;范例30 ;双键输入检查数据子程序,Ky1数据键/Ky2回车键
KYIN2: LDI R26,$60 ;寄存器地址:portb:$18/ddrb:$17/pinb:$16
CLR R27 ;指向数据区首地址
CBI DDRB,7
CBI DDRB,6 ;pb7和pb6皆为输入口
SER R17
OUT DDRC,R17 ;c口为数据显示口
LA0: LD R17,X ;取数据
CPI R17,$0A
BRCS LA1
CLR R17
LA1: LDI R31,HIGH(table*2)
LDI R30,LOW(table*2);DSPY段选码表
ADD R30,R17
ADC R31,R27
LPM
COM R0 ;段选码取出并取反
OUT PORTC,R0 ;送C口
SBI PORTB,7
SBIC $16,7
RJMP NXA1 ;数字键未按下,转
RCALL DL50 ;否则延时
XA2: SBI PORTB,6
SBIC $16,6
RJMP XA0 ;只有数字键按下,转
XA20: RCALL DL50 ;两键都按下,先延时50mS
SBI PORTB,6
SBIS $16,6
RJMP XA20
SBI PORTB,7
SBIS $16,7
RJMP XA20 ;等两键都释放
RCALL DL50
XA21: SBI PORTB,6
SBIS $16,6
RJMP XA21 ;等待释放
SBI PORTB,7
SBIS $16,7
RJMP XA21 ;再次等待释放
RJMP NXA6 ;先按数字键,再按回车键,待2都键释放后退出子程序
XA0: SBI PORTB,7
SBIS $16,7
RJMP XA2 ;等待数字键释放
XA1: RCALL DL50 ;延时
SBI PORTB,7
SBIS $16,7
RJMP XA1 ;再次等待释放
INC R17 ;数字增1
CPI R17,10
BRCS NXA1
CLR R17 ;超过10,将键值归为0
NXA1: SBI PORTB,6
SBIC $16,6
RJMP LA1 ;回车键也未按下,重新查键
RCALL DL50 ;延时
NXA3: SBI PORTB,6
SBIS $16,6
RJMP NXA3 ;再次等待回车键释放
RCALL DL50
SBI PORTB,6
SBIS $16,6
RJMP NXA3
ST X+,R17 ;数字转入缓存区
SER R17
OUT PORTB,R17 ;关显
RCALL DL50 ;
CPI R26,$70 ;到规定数字个数?
BRNE LA0 ;
LDI R17,$86 ;显示'E'nd
OUT PORTC,R17 ;
NXA4: SBI PORTB,6
SBIS $16,6
RJMP NXA5 ;回车键按下,转
SBI PORTB,7
SBIC $16,7 ;数字键按下,转
RJMP NXA4 ;否则反复查键
NXA40: RCALL DL50
SBI PORTB,7
SBIS $16,7
RJMP NXA40
SBI PORTB,7
SBIS $16,7
RJMP NXA40 ;等待键释放
RJMP KYIN2 ;转检查键入数据
NXA5: RCALL DL50
SBI PORTB,6
SBIS $16,6
RJMP NXA5
SBI PORTB,6
SBIS $16,6
RJMP NXA5 ;等回车键释放
NXA6: SER R17
OUT PORTB,R17 ;关显,结束子程序
RET
DL50: ;RCALL DL25 ;延时50毫秒子程序/8Mhz(去掉指令前“;”号)
DL25: CLR R14 ;延时50毫秒子程序/4Mhz
CLR R15
DL50L: DEC R15
NOP
BRNE DL50L
DEC R14
BRNE DL50L
RET
;范例31
LPRNT: SER R17 ;宽行打印机检测及控打程序
OUT DDRC,R17 ;C口为打印机输出口!
SBI DDRD,7
CBI DDRD,3 ;pd7为选通输出口,pd3(INT1)查忙输入口
SBI PORTD,3
SBIC PIND,3 ;查打印机忙信号
RJMP ERR5 ;打印机尚未工作忙信号即已为高,打印机不能打印
LDI R17,$0D ;写回车命令给打印机
OUT PORTC,R17
CBI PORTD,7 ;发出选通信号
NOP
NOP
NOP
SBI PORTD,7 ;strobe
LDI R16,50
TSPRT: SBI PORTD,3
SBIc PIND,3
RJMP LPRT2 ;50次内忙信号高起来为正常
DEC R16 ;否则为非正常状态
BRNE TSPRT
ERR5: LDI R16,5
RCALL ERRX ;显示5号错误
RJMP DIPA1 ;转主程序初始化
LPRT2: LDI R25,1
CLR R24 ;point to $100
LDI R17,$80
OUT GIMSK,R17 ;允许int1中断
LDI R17,$0A
OUT MCUCR,R17 ;INT1下降沿中断
SEI ;general interrupt enable
RET
EX_INT1:PUSH R26
PUSH R27
IN R27,SREG
PUSH R27
PUSH R17 ;保护现场
MOV R27,R25 ;取数据指针
MOV R26,R24
LD R17,X+ ;
MOV R25,R27
MOV R24,R26 ;增1后将指针送回
CPI R17,3 ;是停止符?
BRNE INT1SD
CLR R17
OUT GIMSK,R17 ;禁止INT1中断
RJMP INT1ED
INT1SD: OUT PORTC,R17 ;打印数据输出到打印口
CBI PORTD,7 ;clr ($12,7)
NOP
NOP
NOP
SBI PORTD,7 ;向打印机发出选通
INT1ED: POP R17
POP R27
OUT SREG,R27
POP R27
POP R26 ;恢复现场
RETI |