定点运算和定点数制转换
;范例1
LSDAA: ADC R16,R16 ;十进制数(在R16中)左移调整子程序
ADDAA: IN R6,SREG ;bcd码相加调整子程序,先保存相加后的
LDI R17,$66 ;状态the old status
ADD R16,R17 ;再将和预加立即数$66
IN R17,SREG ;输入相加后新状态(the new status)
OR R6,R17 ;新旧状态相或
SBRS R6,0 ;相或后进位置位则跳行
SUBI R16,$60 ;否则减去$60(十位bcd不满足调整条件)
SBRS R6,5 ;半进位置位则跳行
SUBI R16,6 ;否则减去$06(个位bcd不满足调整条件)
ROR R6 ;向高位字节BCD返还进位位!
RET
;范例2
SUDAA: BRCC SBD1 ;bcd码减法调整子程序,差在R16中
BRHC SBD3
SUBI R16,$66 ;进位半进位都置位,将差减去立即数$66
SEC ;并恢复借位C
RET ;ret. with seC
SBD1: BRHC SBD2 ;进位半进位都清位,返回
SUBI R16,6 ;进位清除而半进位置位,将差减去6
SBD2: RET ;ret. with clC
SBD3: SUBI R16,$60 ;进位置位而半进位清除,将差减去$60
SEC ;并恢复借位C
RET ;ret. with seC
;范例3
RSDAA: SBRC R16,7 ;bcd码(在R16中)右移调整子程序
SUBI R16,$30 ;十位BCD最高位为1(代表8),将其变为5(否则跳行)
SBRC R16,3
SUBI R16,3 ;个位BCD最高位为1(代表8),将其变为5(否则跳行)
RET
;范例4
ADBCD4: MOV R16,R15 ;4字节压缩bcd码相加子程序
ADD R16,R11 ;R12,R13,R14,R15内为被加数,R8,R9,R10,R11内为加数
RCALL ADDAA ;相加后调整
MOV R15,R16 ;并返还调整后结果
MOV R16,R14
ADC R16,R10
RCALL ADDAA
MOV R14,R16
MOV R16,R13
ADC R16,R9
RCALL ADDAA
MOV R13,R16
MOV R16,R12
ADC R16,R8
RCALL ADDAA
MOV R12,R16
RET
;范例5
ADBCD: LDI R16,4 ;多字节压缩bcd码相加子程序
MOV R7,R16 ;(r7):字节数
CLC
ADLOP: LD R16,-X ;X-1指向被加数;
LD R6,-Y ;Y-1指向加数
ADC R16,R6
RCALL ADDAA ;相加后调整
ST X,R16 ;返还调整后结果
DEC R7
BRNE ADLOP
RET
;范例6
SUBCD4: MOV R16,R15 ;4字节压缩bcd码减法子程序
SUB R16,R11 ;R12,R13,R14,R15内为被减数,R8,R9,R10,R11内为减数
RCALL SUDAA ;相减后调整
MOV R15,R16 ;并返还调整后结果
MOV R16,R14
SBC R16,R10
RCALL SUDAA
MOV R14,r16
MOV R16,R13
SBC R16,R9
RCALL SUDAA
MOV R13,R16
MOV R16,R12
SBC R16,R8
RCALL SUDAA
MOV R12,R16
RET
;范例7
SUBCD: LDI R16,4 ;多字节压缩bcd码相减子程序
MOV R7,R16 ;(r7):压缩bcd码字节数
CLC
SUBLP: LD R16,-X ;X-1指向被减数
LD R6,-Y ;Y-1指向减数
SBC R16,R6
RCALL SUDAA ;相减后调整
ST X,R16 ;返还调整后结果
DEC R7
BRNE SUBLP
RET
;范例8 ;16位被乘数*16位乘数-->32位积
MUL16: LDI R16,17 ;(r10r11)*(r14r15)-->r12r13r14r15
ClR R12
ClR R13 ;积的高位字预清除
CLC ;第1次只右移,不相加
MLOOP: BRCC MUL1 ;
ADD R13,R11 ;乘数右移移出位为1,将被乘数加入部分积
ADC R12,R10
MUL1: ROR R12
ROR R13
ROR R14
ROR R15 ;部分积连同乘数整体右移1位
DEC R16
BRNE MLOOP ;17次右移后结束
RET
;范例9 ;16位整数被乘数*16位小数乘数-->16位整数积,精确到0.5
MUL165: RCALL MUL16 ;先得到32位积
SBRS R14,7 ;积小数部分最高位为1,将整数部分加1
RET ;否则返回
LDI R17,255
SUB R13,R17
SBC R12,R17 ;以减去-1($FFFF)替代加1
RET
;范例10 ;32位被除数/16位除数-->16位商,精确到1
DIV16: LDI R16,16 ;(r12r13r14r15)/(r10r11)-->r14r15
DLOOP: LSL R15
ROL R14
ROL R13
ROL R12 ;被除数左移1位
BRCS DI1
SUB R13,R11
SBC R12,R10 ;移出位为0,被除数高位字减去除数试商
BRCC DI2 ;够减,本位商为1
ADD R13,R11
ADC R12,R10 ;否则恢复被除数
RJMP DI3 ;本位商0
DI1: SUB R13,R11
SBC R12,R10 ;移出位为1,被除数高位字减去除数
DI2: INC R15 ;本位商1
DI3: DEC R16
BRNE DLOOP
RET
;范例11 ;32位被除数/16位除数-->16位商,精确到0.5
;可能产生溢出!例$7FFFC000/$8000=$FFFF.8->$10000!
DIV165: RCALL DIV16 ;(r12r13r14r15)/(r10r11)-->r14r15
LSL R13
ROL R12 ;余数乘2
BRCS D165 ;有进位,转5入
SUB R13,R11
SBC R12,R10 ;否则,余数乘2减去除数
BRCS D164 ;不够减,转4舍
D165: CLR R13 ;否则将商增1
SEC
ADC R15,R13
ADC R14,R13
ADC R13,R13 ;若有溢出,溢出位在R13中
RET
D164: CLR R13
RET
;范例12 ;32位整数/16位整数->16整数+16位小数->4字节浮点数
;(r12r13r14r15)/(r10r11)-->r12r13r14r15
DIV16F: RCALL DIV16 ;先做整数除法
MOV R9,r15
MOV R8,r14 ;保存整数部分
CLR R15
CLR R14
RCALL DIV16 ;除得小数部分
MOV R11,R15
MOV R15,R14
MOV R13,R8
MOV R14,R9 ;整数部分在r13r14,小数部分在r15r11
LDI R17,$90 ;预设阶码$90(整数为16位)
MOV R12,R17
LDI R17,32 ;设32次右移
DIV16L: SBRC R13,7
RJMP NMLDN ;最高位为1,已完成规格化
LSL R11 ;否则继续右移R13,R14,R15,R11
ROL R15
ROL R14
ROL R13
DEC R12 ;阶码减1
DEC R17
BRNE DIV16L
CLR R12 ;右移达32次,浮点数为零,置零阶
RET
NMLDN: SBRS R11,7
RJMP DIVRT ;欲舍去部分(R11)最高位为0,转4舍
RCALL INC3 ;否则尾数部分增1
BRNE DIVRT
INC R12 ;尾数增1后变为0,改为0.5,并将阶码增1
DIVRT: LDI R17,$7F ;将尾数最高位清除,表示正数(负数不要清除)
AND R13,R17 ;规格化浮点数在R12(阶码)R13R14R15(尾数)中
RET
;范例13 ;(R16,R12,R13,R14,R15)/(R10,R11)-->R13,R14,R15
DIV24: CLR R16 ;32位整数/16位整数->24位整数,要求(R10)不为0;否则
;要求(R12)<(R11)
DIV40: LDI 17,24 ;40位整数/16位整数->24位整数 要求(R16,R12)
LXP: LSL R15 ; <(R10,R11)
ROL R14
ROL R13
ROL R12
ROL R16
BRCC LXP1
SUB R12,R11 ;右移后C=1 够减
SBC R16,R10 ;被除数减去除数
RJMP DIV0 ;本位商为1
LXP1: SUB R12,R11 ;C=0
SBC R16,R10 ;被除数减去除数试商
BRCC DIV0 ;C=0 够减,本位商1
ADD R12,R11
ADC R16,R10 ;否则恢复被除数,本位商0
RJMP DIV1
DIV0: INC R15 ;记本位商1
DIV1: DEC R17
BRNE LXP
LSL R12
ROL R16
BRCS GINC ;C=1,5入
SUB R12,R11
SBC R16,R10
BRCS RET3 ;不够减,舍掉
GINC: RCALL INC3 ;将商增1
RET3: RET
;范例14 ;定点整数(最大$FFFFFFFF)开平方子程序
INTSQR: LDI R16,17 ;SQR(R12,R13,R14,R15)-->(r15r8r9)
CLR R8 ;R8,R9存储平方根
CLR R9 ;r10,r11,r12,r13,r14,r15
CLR R10 ; r8, r9(根) r16 (counter)
CLR R11 ;r10,r11:被开平方数扩展字节
LDI R17,$40
SQR0: SUB R12,R17
SBC R11,R9
SBC R10,R8
BRCS SQR1
SEC ;试根够减,本位根1
RJMP SQR2
SQR1: ADD R12,R17
ADC R11,R9
ADC R10,R8
CLC ;否则恢复被开平方数,本位根0
SQR2: DEC R16
BRNE SQR3 ;when the No.17bit of root be getting
SQR20: ADC R9,R15 ;R15 HAVE BEEN CLEARED!
ADC R8,R15
ADC R15,R15 ;将开出之根4舍5入,使根最大可达65536(=$10000)!
RET ;for example:sqr.($ffff0001)≈$10000
SQR3: ROL R9
ROL R8 ;记本位根
LSL R15
ROL R14
ROL R13
ROL R12
ROL R11
ROL R10 ;被开平方数连同其扩展字节左移一位
LSL R15
ROL R14
ROL R13
ROL R12
ROL R11
ROL R10 ;被开平方数连同其扩展字节再次左移一位/左移2位开出1位根
BRCS SQR20 ;被开平方数左移2位后,若进位置位,则仅表明第17位根
;已被提前开出且该位根=1,将平方根增1,开平方结束。
RJMP SQR0 ;否则转试下一位根
;范例15 ;定点整数二翻十
CONV1: LDI R17,24 ;r12r13r14r15<--(r9r10r11)左移24次
MOV R7,R17 ;例:16777215<--$FFFFFF
CLR R12
CLR R13 ;68719476735<--$FFFFFFFFF
CLR R14 ;1099511627775<--$FFFFFFFFFF
CLR R15 ;十进制数存储区予清除
CV1: LSL R11
ROL R10
ROL R9 ;二进制数整体左移一位
MOV R16,R15
RCALL LSDAA
MOV R15,R16
MOV R16,R14
RCALL LSDAA
MOV R14,R16
MOV R16,R13
RCALL LSDAA
MOV R13,R16
MOV R16,R12
RCALL LSDAA ;十进制数左移并调整
MOV R12,R16
DEC R7
BRNE CV1
RET
;范例16 ;定点整数十翻二
CONV2: LDI R17,24 ;(r9r10r11)-->r13r14r15,右移24次
CLR R31 ;例:999999-->$0F423F
MOV R7,R17 ; 99999999-->$05F5E0FF
CV2: LSR R9
ROR R10
ROR R11
ROR R13
ROR R14
ROR R15 ;十进制数连同二进制数右移一位
LDI R30,12 ;数据指针
CV2L: LD R16,-Z
RCALL RSDAA ;十进制数右移调整
ST Z,R16
CPI R30,9 ;十进制数各字节调整完毕?
BRNE CV2L
DEC R7 ;右移次数(24次)完成?
BRNE CV2
RET
;范例17 ;定点小数二翻十
CONV3: LDI R17,24 ;(r13r14r15)--->r9r10r11r12右移24次
CONV31: MOV R7,R17
CLR R9
CLR R10 ;例:$0.FFFFFF-->0.99999994
CLR R11 ;$0.FFFFFFFF-->0.999999999767
CLR R12 ;$0.FFFFFFFFF->0.999999999985448
CLR R31
CV3: LSR R13
ROR R14
ROR R15
ROR R9
ROR R10
ROR R11
ROR R12 ;二进制数连同十进制数右移一位
LDI R30,9
CV3L: LD R16,Z
RCALL RSDAA ;十进制数右移调整
ST Z+,r16
CPI R30,13
BRNE CV3L ;十进制数各字节调整完毕?
DEC R7
BRNE CV3 ;右移次数(24次)完成?
RET
;范例18 ;定点小数十翻二
CONV4: LDI R17,32 ;r12r13r14r15<--r8r9r10r11<--(r12r13r14r15)
MOV R7,R17 ;左移32次
CV4: CLC ;例:$0.FFFFFFD5<--0.99999999
MOV R16,R15 ;$0.FFFFFFFF92<--0.9999999999
RCALL LSDAA
MOV R15,R16
MOV R16,R14
RCALL LSDAA
MOV R14,R16
MOV R16,R13
RCALL LSDAA
MOV R13,R16
MOV R16,R12
RCALL LSDAA
MOV R12,R16 ;定点十进制小数左移并调整
ROL R11
ROL R10
ROL R9
ROL R8 ;定点二进制小数带进位位左移一位
DEC R7
BRNE CV4
MOV R12,R8 ;最终结果转入R12--R15
MOV R13,R9
MOV R14,R10
MOV R15,R11
RET
AVR实用程序
;范例19 ;等步距线性内插计算子程序
.EQU TBLGTH=10
CHETA: LDI R16,TBLGTH-1 ;r16<--表长(即字数)-1
LDI R31,HIGH(chtbl*2);y0(函数初值)在r14r15,STEP(步长)在r10r11,自变量X在r12r13
LDI R30,LOW(chtbl*2+1);查表指针,首指数据表第1字之高位字节!
RCALL CPMR1 ;X与表中第一个字型数据(X0)比较
BRCC CHRET ;X<X0 查表结束,Y=Y0
CHET1: RCALL CMPR1 ;X与表中下一个数据比较
BRCC NX33 ;X<X(i+1) 找到插值区间
ADD R15,R11 ;否则Y0中加入一个STEP:Yk=Y0+k*step(步距为负时则
;减去|STEP|)
ADC R14,R10
DEC R16
BRNE CHET1 ;未查到表格终值,循环;否则结束,Y取得最大值Yn
CHRET: RET
NX33: SBIW R30,5 ;指针退回(-5),指向Xi
MOV R8,R14
MOV R9,R15 ;保存Y0+i*STEP
RCALL SUBS ;(X-Xi)-->r16r17
MOV R15,R17
MOV R14,R16 ;转入r14r15
RCALL MUL16 ;(X-Xi)*STEP-->r12r13r14r15
MOV R10,R12
MOV R11,R13 ;保存乘积高位字
LPM ;X(i+1)低位字节
MOV R13,R0
ADIW R30,1
LPM ;X(i+1)高位字节
MOV R12,R0
SBIW R30,3 ;指针指向Xi
RCALL SUBS ;X(i+1)-Xi-->r16r17
MOV R12,R10
MOV R13,R11 ;取回乘积高位字
MOV R10,R16
MOV R11,R17 ;X(i+1)-Xi-->r10r11
RCALL DIV165 ;(X-Xi)*STEP/[X(i+1)-Xi]-->r14r15
ADD R15,R9
ADC R14,R8 ;Y0+i*STEP+(X-Xi)*STEP/[X(i+1)-Xi]-->r14r15
RET ;若STEP为负值则改为计算(r8r9)减去(r14r15)之值
CMPR1: LPM ;取数据高位字节
ADIW R30,2 ;指向下一数据的高位字节
CP R0,R12 ;与X高位字节相比较
BRNE CPRT1 ;不相等即转出
SBIW R30,3 ;否则调整指针
LPM ;取数据低位字节
ADIW R30,3 ;指向下一数据的高位字节
CP R0,R13 ;与X低位字节相比较
CPRT1: RET ;以进位C带回比较结果
SUBS: LPM ;计算(X-Xi)或[X(i+1)-Xi]并送入r16r17
MOV R5,R0 ;取Xi低位字节
ADIW R30,1
LPM ;取Xi高位字节
SBIW R30,1 ;仍指向Xi低位字节
SUB R13,R5
MOV R17,R13
SBC R12,R0
MOV R16,R12 ;计算差并将其转入R16R17
RET
;自变量x表长为12字
CHTBL:DW 19214,23404,27600,32799,37009,40211,45414,48618,51821,55029,57787,60070
;步距表长为11字
STEPT: DW 356,366,379,395,415,440,471,509,555,603,657
;不等步距线性内插计算子程序,步距表首址在R6R7中
;自变量X在R12R13之中, 函数初值Y0在R14R15中
;范例20 ;表长(字个数)-1在R16中
CHTSTP: LDI R31,HIGH(chtbl*2)
LDI R30,LOW(chtbl*2+1);查表指针
LDI R16,LOW(stept*2)
MOV R7,R16
LDI R16,HIGH(stept*2)
MOV R6,R16 ;步距表指针
LDI R16,TBLGTH-1 ;r16<--表长(字个数)-1
RCALL CMPR1 ;X与表首数据比较
BRCC CHSTPT ;X<X0 查表结束,有Y=Y0
CHSTP1: RCALL CMPR1 ;否则与表中下一数据比较
BRCC CHSTP3 ;X<X(i+1),找到插值区间!
RCALL GTSTP ;查表取STEP字型变量
ADD R15,R11 ;Y0<--Y0+STEPk
ADC R14,R10
DEC R16
BRNE CHSTP1 ;未查到表格终值循环;否则结束,Y取得最大值Yn
CHSTPT: RET
CHSTP3: SBIW R30,5 ;指针退回,指向Xi低位字节
MOV R8,R14
MOV R9,R15 ;Y0+∑STEPk送入r14 r15
RCALL SUBS ;(X-Xi)->r16r17
MOV R15,R17
MOV R14,R16 ;(X-Xi)转入R14R15
RCALL GTSTP ;查表取STEPi-->R10R11
RCALL MUL16 ;(X-Xi)*STEPi-->R12R13R14R15
MOV R10,R12
MOV R11,R13 ;保存积高位字
LPM
MOV R13,R0
ADIW R30,1
LPM
MOV R12,R0
SBIW R30,3
RCALL SUBS ;(X(i+1)-Xi)-->r16 r17
MOV R12,R10
MOV R13,R11
MOV R10,R16
MOV R11,R17 ;取回积高位字 &(X(i+1)-Xi)-->r10r11
RCALL DIV165 ;(X-Xi)*STEPi/[X(i+1)-Xi]-->r14r15
ADD R15,R9 ;
ADC R14,R8 ;Y0+∑STEPk+(X-Xi)*STEPi/[X(i+1)-Xi]-->r14r15
RET
GTSTP: MOV R5,R6 ;查取STEP字型变量/POINTER in r6r7!
MOV R6,R30
MOV R30,R5
MOV R5,R7
MOV R7,R31
MOV R31,R5 ;(r6r7)<-->Z
LPM
MOV R11,R0
ADIW R30,1
LPM
MOV R10,R0 ;STEPk取到r10r11
ADIW R30,1
MOV R5,R6
MOV R6,R30
MOV R30,R5
MOV R5,R7
MOV R7,R31
MOV R31,R5 ;指针增2后送回r6r7
RET
;范例21 ;功能表程序
FUNC2: LDS R16,$A3 ;use r0,r8,r9,r10,r11,r16&r17/& subprogram dspa
SBR R16,$80 ;功能表程序标志
STS $A3,R16
LDI YH,2
LDI YL,0 ;功能内容表SRAM地址
RCALL FLFUNC ;CLR r27!
LDI R16,2
ST X,R16 ;显示'FUNC.2'
RCALL DL2S
CLR R9 ;功能内容寻址偏移量R9!
CLR R8 ;功能名称寻址偏移量(R8)=(r9)*3
FFUNC0: RCALL DSF_ ;显示'F- '
FF0: RCALL DSPA ;in subprogram dspy clr. r27!
CPI R16,11 ;回车键按下?
BRNE FF2P
FF0C: RCALL COMBNO ;合成功能名称送入r16
CPI R16,20 ;是最后一个功能名称?
BRNE FF1
CLR R9 ;是,两偏移量初始化!
CLR R8
FF1: LDI ZH,HIGH(FTABL*2)
LDI ZL,LOW(FTABL*2);功能名称表指针
ADD ZL,R8
ADC ZH,R27 ;(r27)=0 ALWAYS
LPM
MOV R16,R0
RCALL BRA3A ;分解新功能名称到$6E/$6F
FF0G: LDI R28,0
ADD R28,R9 ;功能内容指针加偏移量
LD R16,Y
LDI R26,$72
RCALL BRAX ;将新功能内容分解到$72/$73
FF0A: RCALL DSPA ;显示新功能名称/内容
CPI R16,11
BRNE FF0B ;回车键按下?
INC R8
INC R8
INC R8 ;是,功能名称寻址偏移量加3
INC R9 ;功能内容寻址偏移量加1
RJMP FF0C ;转回
FF2P: RJMP FF2
FF0B: CPI R16,10
BRNE FF0D
RCALL DSF_ ;清除键按下,清除显示区后,显示‘F-’
FF1B: RCALL DSPA
CPI R16,11
BREQ FF1 ;转恢复当前显示
CPI R16,10
BRCC FF1B
RJMP FF2D ;只有数字键按下才转出去处理
FF0D: CPI R16,10
BRCC FF0A
FF1D: LDI R17,$24 ;
STS $73,R17 ;数字键处理,先在缓存区内放一空白
FF0E: LDS R17,$73
STS $72,R17 ;键入数字左移
STS $73,R16 ;存入新数字
FF0F: RCALL DSPA
CPI R16,10
BREQ FF0G ;清除键按下,恢复显示旧功能内容
BRCS FF0E ;键入数字左移更新
CPI R16,11
BRNE FF0F
LDS R26,$72 ;回车键按下
RCALL COMBA ;合成新功能内容(combin $72&$73 into binary(r16))
MOV R17,R8
INC R17
LDI ZH,HIGH(FTABL*2)
LDI ZL,LOW(FTABL*2)
ADD ZL,R17 ;取当前功能内容下限
ADC ZH,R27
FF1F: LPM
CP R16,R0
BRCS DSER2 ;新功能内容小于下限,错误
INC R17
LDI ZH,HIGH(FTABL*2)
LDI ZL,LOW(FTABL*2)
ADD ZL,R17 ;取当前功能内容上限
ADC ZH,R27
LPM
CP R0,R16
BRCS DSER3 ;新功能内容大于上限,错误
FF7: LDI R28,0
ADD R28,R9 ;功能内容表首地址为$200!
ST Y,R16 ;合法的新功能内容进入功能内容表
INC R9
INC R8
INC R8
INC R8 ;调整偏移量,进入下一个功能显示
RJMP FF0C
FF1P: RJMP FF1
DSER2: RCALL FERR2 ;显示'F Err.2'2秒
RCALL EXCH0
RJMP FF0G ;恢复原数据显示
DSER3: RCALL FERR3 ;显示'F Err.3'2秒
RCALL EXCH0
RJMP FF0G ;恢复原数据显示
FF2: CPI R16,10
BRCS FF2D ;功能键按下,转初始
RJMP FF0
FF2D: LDI R17,$24 ;数字键按下,在显示缓存区内左移
STS $6F,R17 ;
FF3: LDS R17,$6F
STS $6E,R17
STS $6F,R16
FF4: RCALL DSPA
CPI R16,10
BRNE FF41
RCALL DSF_ ;清除数字,显示‘F-’
FF40: RCALL DSPA
CPI R16,11
BREQ FF1P ;转回显示当前功能名称及内容
CPI R16,10
BRCC FF40 ;无效键按下,转回
RJMP FF2D ;否则转数字处理
FF41: BRCS FF3
CPI R16,11
BRNE FF4
RCALL COMBNO ;合成新功能名称
CLR R10 ;功能名称偏移量计数器清除
CLR R11 ;功能内容偏移量计数器清除
SFFLP: LDI ZH,HIGH(FTABL*2)
LDI ZL,LOW(FTABL*2)
ADD ZL,R10
ADC ZH,R27
LPM
CP R0,R16 ;
BREQ SFFND ;在功能名称表中找到新名称
INC R11 ;
INC R10
INC R10
INC R10 ;调整偏移量
LDI R17,60
CP R10,R17 ;功能名称指针偏移量超过59?
BRCS SFFLP ;否,继续查功能名称表
RCALL FERR1 ;查完功能名称表未查到键入功能名称!
RJMP FFUNC0 ;转回恢复原显示
SFFND: MOV R9,R11 ;得到功能内容指针偏移量
MOV R8,R10 ;得到功能名称指针偏移量
RJMP FF0G ;转显示新功能名称及内容
FTABL: .DB 1,0,1,2,1,8,3,0,2,4,0,1 5,1,2,6,0,4,7,1,4,8,1,2,9,2,7,10,1,5,11,1
.DB 5,12,0,5,13,1,2,14,1,7,15,1,10,16,1,4,17,2,4,18,2,5,19,1,2,20,1,3
COMBNO: LDI XL,$6E ;取$6E$6F中的BCD码,合成新功能名称子程序
COMBA: LD R16,X+
CPI R16,$24
BRNE CMBA
CLR R16
CMBA: MOV R0,R16
LSL R16
LSL R16
ADD R16,R0
LSL R16 ;高位BCD乘10
LD R0,X
ADD R16,R0 ;加低位BCD
RET
DSF_: RCALL FIL8 ;准备显示'F- '
LDI R16,$0F
STS $6C,R16
LDI R16,$14
STS $6D,R16
RET
BRA3A: LDI XL,$6E ;二进制数转换为两位BCD码并显示
BRAX: LDI R17,$24 ;十位为0时显示空白
ST X,R17
BRHOUR: CLR R0 ;
BRX0: SUBI R16,10 ;减10
BRCS BRX2
INC R0
RJMP BRX0
BRX2: SUBI R16,-10 ;不够减恢复出十位BCD
TST R0
BREQ BRX1
ST X,R0 ;放入显示区
BRX1: INC R26
ST X,R16
BRART: RET
FERR1: LDI XL,$71 ;显示'F Err.1'
LDI R16,1
ST X,R16
RJMP FER123
FERR2: RCALL MOVE1 ;显示'F Err.2'
LDI R16,2
STS $71,R16
RJMP FER123
FERR3: RCALL MOVE1 ;显示'F Err.3'
LDI R16,3
STS $71,R16
FER123: LDI XL,$6C
LDI R16,$0F
ST X+,R16
LDI R16,$24
ST X+,R16
LDI R16,$0E
ST X+,R16
LDI R16,$1B
ST X+,R16
LDI R16,$3B
ST X+,R16 ;显示'F Err.1/2/3'
LDI R16,$24 ;2秒
STS $72,R16
STS $73,R16
RCALL DL2S
RET
FIL8: LDI R26,8 ;将显示缓存区充空白
MOV R10,R26
LDI R26,$6C
CLR R27
LDI R16,$24
FILP: ST X+,R16
DEC R10
BRNE FILP
RET
FLFUNC: RCALL FIL8 ;准备显示'Func.'
LDS R26,$6C
LDI R16,$0F ;'F'
ST X+,R16
LDI R16,$1E ;'u'
ST X+,R16
LDI R16,$17 ;'n'
ST X+,R16
LDI R16,$40 ;'c.'
ST X+,R16
RET
EXCH0: LDI ZL,$14 ;将显示缓存区内容转移$6C-$73<-->$214-$21B
LDI ZH,2
LDI XL,$6C
EXL: LD R16,X
LD R17,Z
ST X+,R17
ST Z+,R16
CPI R26,$74
BRNE EXL
RET
MOVE1: LDI ZL,$14 ;将显示缓存区内容传送到$214-$21B
LDI ZH,2
LDI XL,$6C
MV1: LD R16,X+
ST Z+,R16
CPI R26,$74
BRNE MV1
RET
;EEPROM 读写程序
;范例22 ;读出EEPROM子程序
REEP: LDI YH,1
LDI YL 0 ;EEPROM 读出首地址:$100
LDI XL,$60 ;读出数据存放首地址:$60
CLR XH
REEP1: SBIC $1C,1 ;查EEWE位,EEWE=1为当前尚有写入操作未结束
RJMP REEP1 ;等待EEWE=0
OUT $1F,YH
OUT $1E,YL ;读出地址写入EEPRO地址寄存器
SBI $1C,0 ;设置读出使能位(EERE)
IN R16,$1D ;从EEPROM数据寄存器中读出数据
ST X+R16 ;存入缓存区
INC YL
BRNE REEP1 ;
INC YH
CPI YH,2 ;EEPROM最末数据(地址为$1FF)读完?
BRNE REEP1
RET
;范例23 ;写入EEPROM子程序
WEEP: LDI YH,1
LDI YL 0 ;EEPROM 写入之首地址:$100
LDI XL,$60 ;写入数据存储区首地址:$60
CLR XH
WEEP1: SBIC $1C,1 ;查EEWE位,EEWE=1为当前尚有写入操作未结束
RJMP WEEP1 ;等待EEWE=0
OUT $1F,YH
OUT $1E,YL ;送写入地址到EEPRO地址寄存器
LD R16,X+ ;取写入数据并调整数据指针
OUT $1D,R16 ;送到EEPROM数据寄存器
SBI $1C,2 ;设置EEPROM写入总使能位EEMWE
SBI $1C,1 ;设置EEPROM写入使能位EEWE
INC YL
BRNE WEEP1
INC YH
CPI YH,2 ;EEPROM最末写入单元地址为$1FF
BRNE WEEP1
RET
;时钟日历芯片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
;范例32 ;步进电机控制程序
.ORG 0
STRT10: RJMP RST10 ;8535/8515/晶振4MHZ
.ORG $011
RST10: LDI R16,HIGH(ramend)
OUT SPH,R16
LDI R16,LOW(ramend)
OUT SPL,R16
SER R16
OUT DDRB,R16 ;B口为输出
LDI R17,8
OUT PORTB,R16 ;接通总开关
LDI R16,50 ;50次基本运作
RCALL DELAY5 ;延时5毫秒
LOOPX: LDI R17,$68 ;step1时序脉冲控制
OUT PORTB,R17
RCALL DELAY2 ;延时2毫秒
LDI R17,$38 ;step2时序脉冲控制
OUT PORTB,R17
RCALL DELAY2 ;延时2毫秒
LDI R17,$98 ;step3时序脉冲控制
OUT PORTB,R17
RCALL DELAY2 ;延时2毫秒
LDI R17,$C8 ;step4时序脉冲控制
OUT PORTB,R17
RCALL DELAY2 ;延时2毫秒
DEC R16
BRNE LOOPX ;到50次?
LDI R17,8
OUT PORTB,r17 ;关闭各相位开关
RCALL DELAY5
RCALL DELAY5 ;延时10毫秒
CLR R17
OUT PORTB,R17 ;关闭所有相位开关和总开关
HH0: RJMP HH0 ;踏步
DELAY1: LDI R17,$06 ;延时1毫秒
MOV R15,R17 ;1000/0.75=1333=$535,外層计数器装入$06
LDI R17,$35 ;DEC+BRNE=0.75微秒
RJMP DLCOM
DELAY2: LDI R17,$0B ;延时2毫秒
MOV R15,R17 ;2000/0.75=2666=$0A6A,外層计数器装入$0B
LDI R17,$6A
DLCOM: DEC R17
BRNE DLCOM
DEC R15
BRNE DLCOM
RET
DELAY5: LDI R17,$1B ;延时5毫秒
MOV R15,R17 ;5000/0.75=6666=$1A0A,外層计数器装入$1B
LDI R17,$0A
RJMP DLCOM
;范例33
.ORG 0 ;8515采用定时器中断输出时序脉冲方式控制电机转动
STRT11: RJMP RST11 ;晶振4MHZ
.ORG $007
RJMP T0_OVF ;中断服务程序与STRT12共用
.ORG $00D
RST11: LDI R17,HIGH(ramend)
OUT SPH,R17
LDI R17,LOW(ramend)
OUT SPL,R17
LDI R17,$68
MOV R7,R17 ;初始脉冲为0B01101000
SER R17
OUT DDRB R17 ;B口为输出
LDI R17,N ;运作次数N(N>0)
RCALL STPDRV ;初始化子程序
HH20: RJMP HH20 ;实用时改为具体的背景程序!
STPDRV: TST R17
BRNE STPDR1
INC R17 ;N=0时,将其改为1
STPDR1: MOV R6,R17
INC R6 ;N+1-->r6(max.is 256;“植树问题”,N必需增1!
LDI R17,$A4
CBR R17,$20
STS $A4,R17 ;清除连续转动电机标志
LDI R17,$08
OUT PORTB,R17 ;接通总开关
LDI R17,4 ;0B00000100/ 256分频(4兆/256=1兆/64)
OUT TCCR0,R17
LDI R17,178 ;78*64=4.992ms
OUT TCNT0,R17 ;时间常数,首定时为5毫秒
LDI R17,$02
OUT TIMSK,R17 ;允许T/C0溢出中断
SEI
HH21: SJMP HH21
;范例34
.ORG $000 ;步进电机手动控制程序(8515)晶振4MHZ
STRT12: RJMP RST12
.ORG $007
RJMP T0SEV
.ORG $00D
RST12: LDI R17,HIGH(ramend)
OUT SPH,R17
LDI R17,LOW(ramend)
OUT SPL,r17
LDI R17,$68
MOV R7,R17 ;第一个时序脉冲
LDI R17,$F8
OUT DDRB,R17 ;PB7-PB3输出,PB2-PB0输入
CLR R17
OUT PORTB,R17 ;输出为低电平
LDS R17,$A4
SBR R17,$20 ;设置连续转动标志
CBR R17,$40 ;设置电机正转标志
TSTLP1: SBI PORTB,1 ;PB1接地,正转
SBIS PINB,1
RJMP TSTL11 ;
TSTL10: SBI PORTB,2
SBIC PINB,2 ;PB2接地,反转
RJMP TSTLP1 ;PB1,PB2都未接地,反复查询
SBR R17,$40 ;设置电机反转
TSTL11: STS $A4,R17 ;保存标志
CLR R6
INC R6 ;R6中装入1,减一次即为0!
LDI R17,$08
OUT PORTB,R17 ;接通总开关
LDI R17,4 ;0B00000100/256分频(256/4=64微秒)!
OUT TCCR0,R17
LDI R17,178 ;178之补为78,78*64=4.992ms
OUT TCNT0,R17 ;
LDI R17,$02
OUT TIMSK,R17 ;允许T/C0中断(toie1=$39,7 toie0=$39,1)
;8535,toie1:$39,2 toie0:$39,0
SEI
TSTLP2: SBI PORTB,1
SBI PORTB,2
IN R17,PINB
ANDI R17,6
CPI R17,6
BRNE TSTLP2 ;两开关未全部打开,查询等待
LDS R17,$A4
CBR R17,$20 ;清除连续转动标志
STS $A4,R17 ;
TSTLP3: IN R17,TIMSK
SBRC R17,1 ;已禁止8515中断?(8535:timsk,0)
RJMP TSTLP3 ;未,查询等待
RJMP RST12
T0_OVF: PUSH R17 ;电机控制中断服务子程序
IN R17,SREG
PUSH R17
LDS R17,$A4
SBRC R17,7
RJMP T0SV2 ;$A4,7:关电机前10毫秒延时标志
MOV R17,R7
CPI R17,$68
BRNE T0SV0
LDS R17,$A4
SBRC R17,5
RJMP T0SV0 ;电机连续转动,不减R6
DEC R6 ;R6减为0,将停止电机
BREQ T0SV1 ;
T0SV0: LDI R17,225 ;每步进延时(256-225)*64=1.984MS err.<0.8%
OUT TCNT0,R17 ;
OUT PORTB,R7 ;步进控制脉冲输出
LDS R17,$A4
SBRC R17,6
RJMP T0SVA ;$A4,6=1 为连续反转
CLC
SBRC R7,4 ;组织下一步控制脉冲
SEC
ROR R7
LDI R17,$08 ;正转
OR R7,R17 ;01101***->00111***->10011***->11001***->01101***.......
RJMP T0RET
T0SVA: MOV R17,R7 ;
SBR R17,$04
ROL R17 ;组织下一步控制脉冲(反转)
BRCS T0SVB
CBR R17,$10 ;01101***->11001***->10011***->00111***->01101***.......!
T0SVB: MOV R7,R17
RJMP T0RET
T0SV1: LDS R17,$A4
SBR R17,$80
STS $A4,R17 ;总开关关断前10毫秒延时标志
LDI R17,$08
OUT PORTB,R17 ;关断4个相位开关
LDI R17,100 ;156(256-100)*64=9.984ms
OUT TCNT0,R17 ;
RJMP T0RET
T0SV2: LDI R17,$07
OUT PORTB,R17 ;关闭所有开关
CLR R17
OUT TCCR0,R17 ;关T/C0中断
OUT TIMSK,R17
LDS R17,$A4
CBR R17,$C0
STS $A4,R17 ;清除10毫秒延时和反向转动标志
T0RET: POP R17
OUT SREG,R17
POP R17
RETI
;精确定时及时钟日历走时子程序
;范例35
.EQU DTPNT=$75 ;年年月日时分秒(from $7B to $75)
.ORG $000
STRT20: RJMP RST20 ;晶体实测频率4.000119MHZ
.ORG $006 ;8515 t1 overflow INT.vector
RJMP T1_OVF
.ORG $00D
RST20: LDI R16,HIGH(ramend)
OUT SPH,R16
LDI R16,LOW(ramend)
OUT SPL,R16
LDI R16,2 ;8分频,4000119/8=500015
OUT TCCR1B,R16
LDI R16,$5E ;500015=65536*8-24273=8*$10000-$5ed1/TCC=$5Ed1
OUT TCNT1H,R16 ;
LDI R16,$D1 ;
OUT TCNT1L,R16 ;将TCC写入TCNT1
LDI R16,$80
OUT TIMSK,R16 ;允许T/C1溢出中断
LDI R16,8 ;8次中断出秒号
MOV R6,R16
SEI
HH10: RJMP HH10 ;可改为具体的实用程序
T1_OVF: PUSH R16
PUSH R17
IN R7,SREG
DEC R6 ;到8次中断?
BRNE GOON1
IN R17,TCNT1L ;*
IN R16,TCNT1H ;*读回TCNT1自然计数值
SUBI R17,$2F ;*$5ED1之补为$A12F,以减法替代加法修正TCC
SBCI R16,$A1 ;*减去$A12E可不做下面的加1修正
SUBI R17,$FF ;*8条修正指令占用一个计数单位时间
SBCI R16,$FF ;*修正后TCC=$5ED1+(TCNT1)+1
OUT TCNT1H,R16 ;*
OUT TCNT1L,R17 ;*将修整后TCC写入TCNT1
LDI R16,8
MOV R6,R16 ;重装中断次数8
;.
;.
RCALL ACLK ;时钟走时
GOON1: POP R17
POP R16
OUT SREG,R7
RETI
;范例36
.EQU DTPNT=$75 ;yyyy mm dd hh mm ss(from $7B--$75)
.ORG $000 ;晶体实测频率8.000267MHZ,8分频
;INT(8000267/8)=1000033
STRT21: RJMP STRT21
.ORG $006 ;8515 t1 overflow INT. vector
RJMP T1_OVF
.ORG $00D
STRT21: LDI R16,HIGH(ramend)
OUT SPH,R16
LDI R16,LOW(ramend)
OUT SPL,R16
LDI R16,2
OUT TCCR1B,R16 ;8分频
LDI R16,1 ;1000033=62332*15+65053
;=($10000-$0C84)*15-$10000-$1E3
OUT TCNT1H,R16 ;主常数62332(补码为$0C84) 补尝常数TCC=$01E3
LDI R16,$E3 ;$FE1D=65053\65053+62332*15=1000033
OUT TCNT1L,R16
CLR R16
OUT TCCR1A,R16 ;DISABLE CMPA/CMPB/PWM!
LDI R16,$80 ;8515
OUT TIMSK,R16 ;允许T/C1溢出中断
LDI R16,16 ;16次中断
MOV R6,R16
SEI
HH11: RJMP HH11 ;
T1_OVF: PUSH R17
PUSH R16
IN R7,SREG
DEC R6 ;中断次数到?未到转装入主常数
BRNE COMP ;否则重装入TCC
IN R17,TCNT1L ;*
IN R16,TCNT1H ;*读回自然计数值
SUBI R17,$1D ;*
SBCI R16,$FE ;*减去TCC之补码
SUBI R17,255 ;*再加1
SBCI R16,255 ;*修正后TCC=$01E3+(TCNT1)+1
OUT TCNT1H,R16 ;*
OUT TCNT1L,R17 ;*
LDI R16,16
MOV R6,R16 ;重写中断次数
;.
;.
RCALL ACLK ;时钟走时
RJMP GOON2
COMP: IN R17,TCNT1L ;*
IN R16,TCNTIH ;*读回TCNT1自然计数值
SUBI R17,$7C ;*先减去$0C84$'补码$F37C
SBCI R16,$F3 ;*再作加1补偿
SUBI R17,$FF ;*
SBCI R16,$FF ;*修整后重装值=[$0C84+(TCNT1)+1]
OUT TCNT1H,R16 ;*
OUT TCNT1L,R17 ;*
GOON2: POP R16
POP R17
OUT SREG,R7
RETI
;范例37 ;8515使用T/C0定时,64分频,晶振频率4000131HZ
.ORG $000
.EQU DTPNT=$75
STRT22: RJMP RST22
.ORG $007
RJMP T0_OVF ;INT(4000131/64)=62502=245*256-218
.ORG $00D
RST22: LDI R16,245 ;245次中断
MOV R6,R16
LDI R16,3
OUT TCCR0,R16 ;主频FCK(4000131HZ)64分频
LDI R16,$02
OUT TIMSK,R16 ;允许T/C0溢出中断
LDI R16,218
OUT TCNT0,R16 ;TCC=218
SEI
HH12: RJMP HH12 ;
T0_OVF: IN R7,SREG
DEC R6
BRNE DECL1 ;
IN R16,TCNT0 ;1秒时间到!
SUBI R16,38 ;218之补
OUT TCNT0,R16 ;
LDI R16,245
MOV R6,R16 ;重装中断次数
RCALL ACLK ;时钟走时
DECL1; OUT SREG,R7
RETI
;范例38 ;8535异步时钟定时程序
.ORG $000 ;时钟频率32768HZ
.EQU DTPNT=$75
STRT23: RJMP RST23
.ORG $004
RJMP T2_OVF
.ORG $011
RST23: LDI R16,8
OUT ASSR,R16 ;选异步时钟
LDI R16,5
OUT TCCR2,R16 ;128分频
CLR R16
OUT TCNT2,R16 ;时间常数256($00)
LDI R16,$40
OUT TIMSK,R16 ;允许T/C2溢出中断
;............
SEI
HH13: LDI R16,$70 ;掉电休眠模式
OUT MCUCR,R16
SLEEP ;进入休眠
RJMP HH13 ;
T2_OVF IN R7,SREG ;
RCALL ACLK ;时钟走时
;...........
OUT SREG,R7
RETI
;范例39
ACLK: PUSH R16
PUSH R27
PUSH R26
PUSH R7
LDI R26,LOW(dtpnt);
LDI R27,HIGH(dtpnt);时钟日历单元指针
RCALL DHM3 ;秒单元加1调整
CPI R16,$60 ;
BRNE COM0 ;未到60秒返回
RCALL DHM ;分单元加1调整
CPI R16,$60
BRNE COM0 ;未到60分返回
RCALL DHM ;时单元加1调整
CPI R16,$24
BRNE COM0 ;未到24时返回
RCALL DHM ;日单元加1调整
SUBI R16,$29
BRCS COM0 ;小于29返回
BRNE T30 ;转继续测试30/31/32日
ADIW R26,1 ;29,指向月
LD R16,X
CPI R16,2
BRNE COM0 ;非二月返回
ADIW R26,1 ;指向年
LD R16,X ;取年十个位
TST R16
BRNE TYLB
ADIW R26,1
LD R16,X ;年十个位为0,取年千百位
TYLB: SWAP R16
ANDI R16,15
MOV R7,R16
LSL R7
LSL R7 ;高位BCD乘4
ADD R16,R7 ;乘5
LSL R16 ;乘10
LD R7,X ;加个位BCD
ADD R16,R7 ;年十个位(千百位)转成二进制数
ANDI R16,3 ;该二进制数末两位皆为0,为闰年
BREQ COM0 ;返回(二月有29日)
RJMP DAY1 ;否则为3月1日
T30: SUBI R16,7 ;减7调整
BRNE T31 ;$30-$29-7=0
ADIW R26,1 ;指向月
LD R16,X
CPI R16,2
BRNE COM0 ;非2月返回
RJMP DAY1 ;闰年的2月30日为3月1日
T31: DEC R16 ;$31-$29-7=1&$32-$29-7=2
BRNE DAY1 ;日为32 ,为下月1日
ADIW R26,1 ;日为31 ,指向月
LD R16,X
SUBI R16,8 ;月份减去8
BRCC SCHY
INC R16 ;月份小于8,差增1,奇数变偶数
SCHY: SBRS R16,0
RJMP COM0 ;1-7月奇数月为大月/8-12月偶数月为大月;有31日,返回
DAY1: LDI R26,LOW(dtpnt+3)
LDI R27,HIGH(dtpnt+3);指向日
LDI R16,1 ;
RCALL DHM1 ;日置为1,月加1
CPI R16,$13
BRNE COM0
LDI R16,1 ;月变为13,改为1
RCALL DHM1 ;年十个位加1调整,可能有$99+1=$A0
CPI R16,$A0
BRNE COM0 ;
RCALL DHM ;年千百位加1调整
COM0: POP R7
POP R26
POP R27
POP R16
RET
DHM: CLR R16 ;秒,分,时单元清除,高位加1
DHM1: ST X+,R16
DHM3: LD R16,X
INC R16 ;
CPI R16,$0A ;若个位BCD码未变成$0A
BRHS DHM2 ;例如$58+1=$59,不须调整;
SUBI R16,$FA ;否则做减$FA调整:例如$49+1-$FA=$50
DHM2: ST X,R16 ;并将调整结果送回
RET
;范例40
.ORG 0 ;8535UART串行通讯程序,晶振4MHZ
.EQU DTPINT=$180 ;UBRR=12 波特率19200(REL.ERR.=0.16%)
.EQU DRPINT=$1D0
STRT30: RJMP RST30
.ORG $00B
RJMP U_RXC ;UART接收完成中断
.ORG $00C
RJMP U_TXC ;UART发送寄存器空中断
.ORG $011
RST30: LDS R16,$A3 ;
CBR R16,3
STS $A3,R16 ;清完整ASCII数据块接收到标志($A3,1),错误标志(FE/OR)($A3,0)
LDI R16,12
OUT UBRR,R16 ;BAUD RATE=FCP/16(UBRR+1)=19200
LDI R27,HIGH(DIPINT)
MOV R6,R27
LDI R26,LOW(DTPINT)
MOV R7,R26 ;发送数据指针在r6r7(dtpint)
CLR R11
INC R11
LDI R16,$30 ;发送数据块长度为$30
MOV R12,R16
RCALL CRC0 ;得到CRC检测之余式(冲掉$0D&$0A)
INC XL
INC XL
LDI R16,$0D
ST X+,R16
LDI R16,$0A
ST X,R16 ;在数据块末尾加$0D&$0A,实际发送数据块长度为$32
LDI R16,$B8 ;允许UART发送和接收,接收中断,发送寄存器空中断,8位数据
OUT UCR,R16
LDI R16,HIGH(DRPINT)
MOV R8,R16
LDI R16,LOW(DRPINT)
MOV R9,R16 ;r8,r9:接收缓存区指针(FIRST POINT TO $1D0)
CLR R10 ;接收数据块长预先清除
SEI ;
HH30: LDS R16,$A3
SBRC R16,0 ;错误接收?
RJMP RCVER ;错误处理
SBRS R16,1 ;接收数据完成?
RJMP HH30 ;否,转再查询
RCVEF: CLR R11 ;块长予处理
INC R11
DEC R10
DEC R10 ;$0D&$0A不算块长度之内(故将块长减2)
MOV R12,R10 ;(R11,R12):块长
LDI XH,HIGH(DRPINT)
MOV R8,XH
LDI XL,LOW(DRPINT)
MOV R9,XL
RCALL CRC0 ;恢复出CRC余式
LDI R16,$0D
CP R16,R14
BRNE CRCER
LDI R16,$0A
CP R16,R15 ;恢复出$0D$0A为正确接收
BREQ HH30
CRCER: ;. ;循环冗余检测错误处理
;.
;.
RJMP STRT30
RCVER: CBI UCR,RXCIE
;. ;接收错误(FE/OR)处理
;. ;(过程略)
;.
RJMP STRT30
:UART接收数据块程序
U_RXC: PUSH R16
IN R16,SREG
PUSH R16
PUSH R26
PUSH R27
RSC1: IN R16,USR ;UART状态寄存器
ANDI R16,$18 ;FE/OR ERROR?
BRNE RVERR ;错误转
INC R10 ;块长加1
MOV XH,R8
MOV XL,R9 ;r8r9:接收数据指针,首指$1D0
IN R16,UDR
ST X+,r16 ;
MOV R8,XH
MOV R9,XL
CPI R16,$0A ;收到最末字符(回车命令LF)?
BRNE RSCOM
LDS R16,$A3
SBR R16,2 ;建立数据块接收完毕标志
STS $A3,R16
CBI UCR,RXCIE ;禁止接收中断
RJMP RSCOM
RVERR: LDS R16,$A3
SBR R16,1
STS $A3,R16 ;$A3,0:FE/OR错误接收标志
RSCOM: POP R27
POP R26
POP R16
OUT SREG,R16
POP R16
RETI
; UART发送数据块程序
U_TXC: PUSH R16
IN R16,SREG
PUSH R16
PUSH R26
PUSH R27
SPSV1: MOV XH,R6
MOV XL,R7 ;发送数据指针,首指$180
LD R16,X+ ;取发送数据,调指针
MOV R6,XH
MOV R7,XL
SPS11: OUT UDR,R16 ;送入数据寄存器,移入发送移位寄存器后即引起数据寄存器空中断
CPI R16,$0A
BRNE SPCOM
CBI UCR,UDRIE ;发送最末字符后禁止发送寄存器空中断
LDI R16,HIGH(DRPINT)
MOV R8,R16
LDI R16,LOW(DRPINT)
MOV R9,R16 ;接收数据指针初始化,指向$1D0
;CBI USR,6 ;
SPCOM: POP R27
POP R26
POP R16
OUT SREG,R16
POP R16
RETI
.DSEG
.ORG $180
DTPINT:.BYTE $32
;$41,$45,$65,$73,$46,$42,$40,$6F,$33,$44,$66,$8C,$4D,$4B,$2F,$67
;$42,$4F,$66,$78,$47,$45,$44,$63,$32,$48,$60,$7C,$6D,$45,$2A,$63
;$43,$56,$55,$53,$4D,$4F,$40,$2E,$31,$42,$67,$4C,$47,$4A,$38,$39
;$0D,$0A
.EQU DRPINT=$1D0
.ORG $1D0
DRPINT: .BYTE $34 ;(内容略)
;范例41 ;外部中断int0接收ASCII码数据块
.ORG 0 ;8515/8535/晶振4MHZ
STRT31: RJMP RST31
RJMP EX_INT0
.ORG $00D ;8535外部中断0
RST31: LDI R17,HIGH(ramend)
OUT SPH,R17
LDI R17,LOW(ramend)
OUT SPL R17
LDI R17,2
OUT TCCR1B,R17 ;4mhz/8分频,计数单位为2微秒,TCCR1B:$2e
LDI R17,$40
OUT GIMSK,R17 ;gimsk,6(允许int0中断)
LDI R17,2
OUT MCUCR,R17 ;设INT0为下降沿中断(mcucr'b1&b0=10)
CBI DDRD,2 ;int0 为输入
;.
;. ;其他初始化略
SEI ;
CLRBUF: LDI R27,1
CLR R26 ;接收数据缓存区首址$100
LDI R17,$40
OUT GIMSK,R17 ;gimsk,6
CLR R17
CLRLOP: ST X+,R17
CPI R26,$48
BRNE CLRLOP ;清接收缓存区($100--$147)
LDS R16,$A3
CBR R16,$60
STS $A3,R16 ;接收错误($A3,6)和接收完成($A3,5)标志清除
CLR5: ;.
;. ;背景程序略
RJMP CLR5 ;
RCVST: CBI DDRD,2 ;int0 为输入
SER R16 ;接收开始
OUT PORTC,R16 ;关显
LDI R27,1
CLR R26 ;接收数据指针,首指$100
LDI R17,18 ;接收18个字符,其末尾为$0D$0A
MOV R14,R17
RCALL RVBYT1 ;接收第一个字符
RJMP RVBYT
RVBLOP: RCALL RVBYT2 ;接收第二个字符及其后字符
RVBYT: LDS R17,$A3
SBRC R17,6
RJMP CLRBUF ;接收出错,转去清除$100--$14F
SBRC R17,5
RJMP DTCOM ;接收完整数据块,转去处理
ST X+,R16
DEC R14
BRNE RVBLOP ;未收完18个字符,继续
CPI R26,$42 ;指针达到$142?
BREQ DTCOM ;接收完整数据块,转去处理
DEC R26
DEC R26 ;$0D$0A(CR&LF)丢掉
RCVLP: LDI R17,18
MOV R14,R17
RJMP RVBLOP
DTCOM: LDI R27,1
CLR R26 ;接收数据首地址:$100
DLLOP: CLR R29
LDI R28,$90 ;处理ASCII码程序acum要求将数据放在$90--$9f
LD R16,X
CPI R16,$50 ;第一个字符约定为‘P’才有效
BRNE RVCOM1 ;也是判断处理结束符
DLLOP1: LD R16,X+
ST Y+,R16
CPI R28,$A0
BRNE DLLOP1 ;传16个字符
PUSH R26
PUSH R27
RCALL ACUM ;ASCII变BCD再变为二进制数,累加
POP R27
POP R26
BRTS RVCOM1 ;ASCII码无效,转出!
RJMP DLLOP
RVCOM1:
CLT
RJMP CLRBUF ;转去清缓存区,重新接收
;晶振采用4MHZ,指令(DEC+BRNE)耗时0.75微秒)!
EX_INT0:POP R16 ;int0中断服务子程序
POP R16 ;废弃返回地址
LDI R16,HIGH(RCVST)
PUSH R16
LDI R16,LOW(RCVST)
PUSH R16 ;设置返回地址
IN R16,GIMSK ;禁止int0中断
CBR R16,$40
OUT GIMSK,R16
RETI
RVBYT1: LDI R17,2 ;查到0接收时,再做一次接收
MOV R15,R17
LDI R17,50 ;第一个起始位半位延时(50*0.75=38微秒)
MOV R12,R17
RJMP RVBCM
RVBYT2: LDI R17,2
MOV R15,R17
RVBY2: LDI R17,147 ;110微秒>1位宽/9600baud,110/0.75=147
MOV R12,R17
TEST3: SBI PORTD,2
SBIS PIND,2 ;停止位超宽测试
RJMP RVST
DEC R12
BRNE TEST3
LDS R16,$A3 ;110微秒内查到低电平为起始位
ORI R16,$20
STS $A3,R16 ;否则为接收结束,令$A3,5=1
RET
RVST: LDI R17,60 ;60*0.75=45微秒(半位延时)
MOV R12,R17
RVBCM: DEC R12
BRNE RVBCM
LDI R17,9 ;1位起始+8位数据
MOV R13,R17
SBI PORTD,2
SBIC PIND,2
RJMP RVER1 ;无效起始位(半位测试)
RVLOP: LDI R17,130 ;may be 128-132/位延时常数
MOV R12,R17
RVLP1: DEC R12 ;0.25微秒
BRNE RVLP1 ;0.5微秒/if condition is true
SEC
SBI PORTD,2
SBIS PIND,2
CLC
DEC R13
BRNE OVRRC ;不是停止位,转数据位接收
BRCC RVER1 ;无效停止位,出错
TST R16 ;
BRNE RBYRT ;不为0,收到一个有效字符
DEC R15
BRNE RVBY2 ;2次接收到$00,出错
RVER1: LDS R16,$A3
ORI R16,$40 ;接收出错标志
CBR R16,$20
STS $A3,R16
RBYRT: RET
OVRRC: ROR R16 ;组织数据
RJMP RVLOP ;100.7微秒/程序实设位宽
;范例42 ;8535'T0中断发送ASCII码程序,晶振4MHZ
.EQU DATA2=$150
.ORG $000
STRT32: RJMP RST32
.ORG 009
RJMP T0_OVF
.ORG $011
RST32: SER R17
OUT DDRB,R17 ;B口为输出
OUT PORTB,R17 ;输出高电平
LDI R16,2 ;0B00000010/8 DIVIDED(4fc/8:2微秒)
OUT $33,R17 ;写入tccr0
LDI R16,204 ;(256-204)*2=104微秒/9600baud 104微秒/位!
OUT TCNT0,R17 ;
LDI R17,HIGH(ramend)
OUT SPH,R17
LDI R17,LOW(ramend)
OUT SPL,R17
LDI R25,HIGH(DATA2)
LDI R24,LOW(DATA2);发送数据指针
LDS R17,$A3
CBR R17,$14 ;发送出错标志($A3,4)/发送完毕标志位($A3,2)清除!
STS $A3,R17
SEI
LDI R17,1
OUT TIMSK,R17 ;允许T/C0溢出中断
CLR R17 ;位计数器请除
HH32: LDS R16,$A3
SBRC R16,4
RJMP HHER32 ;出错
SBRS R16,2 ;
RJMP HH32 ;查询等待数据块发送完成
;. ;其他程序略
;. ;可安排接收对方发来数据程序,见STRT33
RJMP RST32
HHER32:;.
;. ;错误处理略
RJMP RST32
T0_OVF: PUSH R16
IN R16,SREG
PUSH R16
PUSH R26
PUSH R27
IN R16,TCNT0
INC R16
SUBI R16,52 ;重写入一位定时常数(带修正)
OUT TCNT0,R16
MOV R26,R24 ;数据指针
MOV R27,R25
CPI R17,10
BREQ SND10
TST R17
BRNE SND9
SND0: CBI PORTB,0 ;发起始位(0)
RJMP SVCOM
SND9: CPI R17,9
BRNE SND18 ;1-8为数据位
SBI PORTB,0 ;9为停止位(1)
CLR R17 ;停止位发完后,位计数器清除
ADIW R24,1 ;指针增1,指下一位数据
LD R16,X
CPI R16,$0A ;本次发送的是$0A?
BRNE SVCOM1
LDI R17,10 ;停止位标志
RJMP SVCOM1
SND10: LDS R16,$A3
SBR R16,4 ;发送完成标志
STS $A3,R16 ;
SND11: CLR R16
OUT TCCR0,R16 ;关闭T/C0
CLR R17 ;清位计数器
LDI R24,LOW(DATA2);发送指针初始化
LDI R25,HIGH(DATA2)
RJMP SVCOM1
SENDER: LDS R16,$A3
SBR R16,$10
STS $A3,R16 ;建出错标志
RJMP SND11
SND18: BRCC SENDER ;大于10为错误
LD R16,X
ROR R16 ;发送位传到进位C
BRCC S182
SBI PORTB,0 ;C(=1)-->PB0($18,0)
BRCS S183
S182: CBI PORTB,0 ;C(=0)-->PB0($18,0)
S183: LD R16,X
ROR R16 ;
ST X,R16 ;保存剩余位
MOV R24,R26 ;存数据指针
MOV R25,R27
SVCOM: INC R17 ;位计数器增1
SVCOM1: POP R27
POP R26
POP R16
OUT SREG,R16
POP R16 ;恢复现场
RETI
;范例43 ;8515/8535/晶振4MHZ RECEIVING ASCII CHAR. BY TCNT0&PB0
.EQU DATA3=$100 ;UES R11 SAVE SREG, R12 R13:数据指针DATA3
;R14: 块长(BLOCK LENGTH) ,R15:接收字符暂存寄存器
.ORG 0 ;R16:(THE BIT SEQUENCE COUNTER)位序列计数器
;R17:WORKING REG.R18:FLAG UNIT, BAUD RATE:9600
STRT33: RJMP RST33 ;X&Y:POINTER/接收数据缓存区首地址:$100
.ORG $009 ;$007(8515)
RJMP T0_OVF1
.ORG $011 ;$00D(8515)
RST33: LDI R17,HIGH(ramend)
OUT SPH,R17
LDI R17,LOW(ramend)
OUT SPL,R17
LDI R17,HIGH(DATA3)
MOV R12,R17
LDI R17,LOW(DATA3)
MOV R13,R17 ;R12R13:接收数据指针
CLRBF1: CLR R16
CLRLP: ST X+,R16
CPI R26,$48
BRNE CLRLP ;接收数据缓存区请除
CLR R18 ;标志寄存器请除/R18,2:完整数据块收到,R18,1
;第一字符(块长)收到:R18,0:出错
LDI R17,$02 ;8535:$01
OUT TIMSK,R17 ;允许T/C0溢出中断
LDI R17,6 ;外部脉冲下降沿计数
OUT TCCR0,R17
CBI DDRB,0 ;PB0为输入
LDI R17,$FF
OUT TCNT0,R17 ;计一个数即中断
;
SEI ;
TEST1: RCALL DSPLY3 ;调串行移位显示子程序
SBRC R18,0 ;
RJMP DLERR ;出错,转错误处理
SBRS R18,2 ;数据块接收完成?
RJMP TEST1
LDI R16,128
DECLP: DEC R16
BRNE DECLP
RJMP DTCOM0 ;先延时,再转处理数据块
DLERR: ;. ;出错处理
;.
;.
RCALL DL50 ;延时50毫秒后
RJMP RST33 ;重新接收
DTCOM0: LDI R27,1
CLR R26 ;数据存储区首地址$100
DLLOP0: CLR R29
LDI R28,$90 ;ASCII码处理区为$90--$9f
LD R16,X
CPI R16,$50 ;字母P打头才有效
BRNE RVCOM0 ;否则为无效字串或ASCII码处理结束
DLLO1: LD R16,X+
ST Y+,R16
CPI R28,$A0
BRNE DLLO1 ;传送16个字符
PUSH R26
PUSH R27
RCALL ACUM ;处理一组ASCII码数据
POP R27
POP R26
BRTC DLLOP0 ;T=1,ASCII码数据无效
CLT
;. ;错误处理
RJMP STRT33
RVCOM0:;. ;错误处理
;.
RJMP STRT33
T0_OVF1:IN R11,SREG ;T/C0中断服务
PUSH R17
CPI R16,0 ;起始位下降沿中断?
BRNE T0SV10
LDI R17,2 ;YES
OUT TCCR0,R17 ;改为内定时(4MHZ/8分频)
LDI R17,232 ;半位时间常数24 定48微秒(<52)
OUT TCNT0,R17
RJMP T0SV6
T0SV10: CPI R16,1 ;1,半位定时到
BRNE T0SV2
SBI PORTB,0
SBIC PINB,0
RJMP T0ERR ;高电平,错误
RJMP T0SV60 ;低电平,有效起始位
T0SV2: CPI R16,10 ;
BRNE T0SV3
SBI PORTB0 ;10,接收停止位
SBIS PINB,0
RJMP T0ERR ;低电平,错误
LDI R17,6
OUT TCCR0,R17 ;改为外部脉冲下降沿计数,为接受下一位字符准备
LDI R17,$FF ;计一个数即中断
OUT TCNT0,R17
CLR R16 ;位计数器请除
SBRC R18,1 ;是第一个字符(r18,1=0)?
RJMP T0SV21 ;否,为块内数据
MOV R14,R15 ;块长转入r14
SBR R18,2 ;块长已收到
RJMP T0SV61
T0SV21: PUSH XL
PUSH XH
MOV XH,R12
MOV XL,R13 ;取缓存区指针
ST X+,R15 ;字符送入缓存区
MOV R12,XH
MOV R13,XL
POP XH
POP XL
DEC R14
BRNE T0SV61
SBR R18,4 ;块长减为0,完整数据块收到
CLR R16
OUT TCCR0,R16 ;停止TCNT0
RJMP T0SV61
T0SV3: BRCC T0ERR ;出错(大于10)
CLC ;2--9:数据位
SBI PORTB,0 ;接收一位数据
SBIC PINB,0
SEC
ROR R15 ;数据组织到R15
T0SV60: IN R17,TCNT0 ;读TCNT0计数值
INC R17 ;
SUBI R17,52
OUT TCNT0,R17 ;写入补偿后的时间常数
T0SV6: INC R16 ;位序列计数器增1
T0SV61: POP R17
OUT SREG,R11
RETI
T0ERR: CLR R16
T0ERL: SBR R18,1 ;错误接收标志
OUT TCCR0,R16 ;停止TCNT0
RJMP T0SV61
;范例44
.ORG 0 ;8535多机通讯主机程序/振4MHZ
.EQU DTPINT=$180 ;UBRR=12,波特率19200(REL.ERR.=0.16%)
.EQU DRPINT=$1C0 ;主机发往#1,#2,#3,#分机数据在
;$180-18F,$190-19F,$1A0-1AF和$1B0-1BF
STRT34: RJMP RST34 ;主机接收#1,#2,#3,#4分机之数据块分别在
;$1C0-1CF,$1D0-1DF,$1E0-1EF和$1F0-1FF
.ORG $00B
RJMP U_RXC ;UART接收完成中断
.ORG $00C
RJMP U_TXC ;UART 发送完成中断
.ORG $011
RST34: LDI R16,12
OUT UBRR,R16 ;BAUD RATE=FCP/16(UBRR+1)=4000000/(16*13)=19200
CLR R15 ;分机号初始化
LDI R27,HIGH(DTPINT)
LDI R26,LOW(DTPINT);发送数据指针,首指$180
LDI R29,HIGH(DRPINT)
LDI R28,LOW(DRPINT);接收数据指针(POINT TO $1C0)
NEXTNO: LDI R16,$18
OUT UCR,R16 ;允许UART接收和发送,8位数据模式
INC R15 ;指向分机
OUTLP: OUT UDR,R15 ;呼分机号
TSLOP: IN R16,USR
SBRS R16,7
RJMP TSLOP ;分机返回机号?
IN R16,UDR
CP R16,R15 ;与发送分机号符合?
BRNE OUTLP ;不符再发
TXLOP: LD R16,X+
OUT UDR,R16 ;向分机发送数据块
TESTL: IN R17,USR
SBRS R17,5 ;发送寄存器空?
RJMP TESTL
CPI R16,$0A
BRNE TXLOP ;发完整个数据块?
RXTST: IN R17,USR
SBRS R17,7 ;RXC=1 分机发来数据
RJMP RXTST
IN R16,UDR
ST Y+,R16 ;接收数据转入内存
CPI R16,$0A
BRNE RXTST ;接收完整数据块后
MOV R16,R15
CPI R16,4 ;转与下一分机通讯(只有4台分机)
BRNE NEXTNO ;直到轮询完毕
HH34: RJMP HH34 ;可改为处理分机发来数据,再转入下一周轮询
.DSEG
.ORG $180
DTPINT:.BYTE $40
$41 $45 $65 $73 $46 $42 $40 $6F $33 $44 $66 $5C $4D $4B $0D $0A
$42 $4F $66 $78 $47 $45 $44 $63 $32 $48 $60 $7C $6D $45 $0D $0A
$43 $56 $55 $53 $4D $4F $40 $2E $31 $42 $67 $4C $47 $4A $0D $0A
$45 $54 $59 $63 $3D $4B $48 $2F $35 $48 $69 $3C $77 $43 $0D $0A
.ORG $1C0
DRPINT: .BYTE $40
;范例45
.ORG 0 ;8535多机通讯1#分机程序,晶振4MHZ
.EQU DTPIT1=$180 ;UBRR=12 波特率19200(REL.ERR.=0.16%)
.EQU DRPNT1=$1C0
STRT35: RJMP RST35
.ORG $00B
RJMP UARXC ;UART接收完成中断
.ORG $00C
RJMP UATXC ;UART发送寄存器空中断
.ORG $011
RST35: CLR R18 ;请除主机发来完整数据块标志(R18,7)/主机呼号选中分机
;标志(R18,6)
LDI R16,12
OUT UBRR,R16 ;[BAUD RATE=FCP/16(UBRR+1)]
LDI R16,HIGH(DRPNT1)
MOV R8,R16
LDI R16,LOW(DRPNT1)
mov R9,R16 ;r8,r9:接收数据指针(FIRST POINT TO $1C0)
LDI R16,$98 ;允许UART发送,接收,接收完成中断
OUT UCR,R16
SEI
CLR R15
INC R15 ;1#分机设为1/2#分机设为2/3#分机设为3/4#分机设为4
RXDTS: SBRS R18,6 ;收到主机发来呼号?
RJMP RXDTS
OUT UDR,R15 ;将分机号反还主机
TXDON: IN R16,USR
SBRS R16,5
RJMP TXDON ;发送寄存器空?
RCVBLK: SBRS R18,7
RJMP RCVBLK ;等待接收主机发来数据块
LDI R16,HIGH(DTPIT1)
MOV R6,R16
LDI R16,LOW(DTPIT1)
MOV R7,R16 ;设置发送数据指针r6r7,首指$180
SBI UCR,5 ;UDRIE=1 ,引起发送寄存器空中断
TXDN: SBIC UCR,5
RJMP TXDN
RJMP RST35 ;等待UDRIE=0 ,向主机发送数据块完毕后,转下一轮通讯
:UART中断接收程序
UARXC: IN R14,SREG
TST R18
BREQ NUMB ;无主机呼号选中标志,查机号
PUSH R26
PUSH R27
IN R17,UDR ;读入接收数据
MOV XH,R8
MOV XL,R9 ;r8r9:接收数据缓存区指针,首指$1C0
ST X+,R17
MOV R8,XH
MOV R9,XL
CPI R17,$0A ;收到换行符?
BRNE RSCOM1
SBR R18,$80 ;建立数据块接收完毕标志
RSCOM1: POP R27
POP R26
DRETI: OUT SREG,R14
RETI
NUMB: IN R17,UDR
CP R17,R15 ;主机呼号与本分机号符合?
BRNE DRETI ;不符,转
SBR R18,$40 ;建选中标志
RJMP DRETI
; UART中断发送数据程序
UATXC: IN R16,SREG ;r6 r7:the sendDATA pointer(FIRST POINT TO $180)
PUSH R16
PUSH R26
PUSH R27
MOV XH,R6
MOV XL,R7 ;发送数据指针
LD R16,X+
MOV R6,XH
MOV R7,XL
OUT UDR,R16 ;发送数据写入数据寄存器
CPI R16,$0A ;发送LF?
BRNE SDCOM
CBI UCR,5 ;禁止数据寄存器空中断(清UDRIE)
LDI R16,HIGH(DRPINT)
MOV R8,R16
LDI R16,LOW(DRPINT)
MOV R9,R16 ;为接收作准备(FIRST POINT TO $1C0)
SDCOM: POP R27
POP R26
POP R16
OUT SREG,R16
POP R16
RETI
.DSEG
.ORG $180
DTPIT1: .BYTE $10
;$41 $45 $65 $73 $46 $42 $40 $6F $33 $44 $66 $5C $4D $4B $0D $0A
.ORG $1C0
DRPNT1: .BYTE $10
;$41 $45 $65 $73 $46 $42 $40 $6F $33 $44 $66 $5C $4D $4B $0D $0A
;范例46
.ORG $000 ;RS232<->RS485通讯标准转换/晶振4MHZ
STRT36: RJMP RST485 ;使用8515!
.ORG $009
RJMP U_RXC ;UART 接收中断
.ORG $00D
RST485: LDI R16,2
OUT SPH,R16
LDI R16,$5f ;
OUT SPL,R16
LDI R16,$98 ;允许UART接收和发送,允许接收中断
OUT UCR,R16
LDI R16,12
OUT UBRR,R16 ;波特率19200
SBI DDRB,7
SBI DDRB,6 ;PB7,PB6为输出
CBI PORTB,7
CBI PORTB,6 ;PB7控制485发送(高有效)PB6控制485接收(低有效)
SEI
HERE0: CPI R16,3 ;收到停止符?
BRNE HERE0 ;未收到循环等待
HERE1: SBIS USR,6 ;
RJMP HERE1 ;等待停止符发送完毕
CBI PORTB,7 ;禁止485发送
CBI PORTB,6 ;允许485接收
SBI USR,6 ;写‘1’清除发送完成标志!
CLR R16
RJMP HERE0 ;转等待下一轮中转
U_RXC: SBI PORTB,7 ;允许485发送
SBI PORTB,6 ;禁止485接收,
IN R16,UDR ;读出接收数据,同时清除接收中断标志
TSAGN: SBIS USR,6 ;上一数据发送完毕?
RJMP TSAGN
SBI USR,6 ;清除发送完成标志
OUT UDR,R16 ;转发本次接收数据
RETI
;范例47
.EQU DATA4=$220
.ORG $000 ;同步串口通讯主机程序,晶振4MHZ
STRT37: RJMP RST37
.ORG $00A ;8535 SPI中断矢量(8515为$008)
RJMP SPINT
.ORG $011 ;$00D(8515)
RST37: LDI R16,2
OUT SPH,R16
LDI R16,$5f
OUT SPL,R16 ;堆栈指针初始化
LDI R16,$A0
OUT DDRB,R16 ;SCK,MOSI为输出
LDI R16,$DC
OUT SPCR,R16 ;允许SPI中断,先发送高位,主控方式,时钟为主频4分
;频,后沿有效
LDI XH,HIGH(DATA4)
LDI XL,LOW(DATA4);数据指针
LDI R16,$30
MOV R15,R16 ;数据块长
LDI R16,12 ;0.25微秒
SPI0: DEC R16 ;0.25微秒
BRNE SPI0 ;0.5微秒 总延时9微秒
LD R16,X
OUT SPDR,R16 ;写发送数据寄存器,启动发送
SEI
HH37: RJMP HH37 ;背景程序略
SPINT: IN R14,SREG
IN R16,SPDR ;读出接收数据
ST X+,R16
DEC R15
BRNE SPI1 ;数据收发完毕?
OUT SPCR,R15 ;是,停止收发
OUT SREG,R14
RETI
SPI1: LDI R16,6 ;0.25微秒
SPI1A: DEC R16 ;0.25微秒
BRNE SPI1A ;0.5微秒 总共4.5微秒
LD R16,X
OUT SPDR,R16 ;发下一个数据
OUT SREG,R14
RETI
;范例48
.ORG $000
STRT37S:RJMP RST37S ;同步串口通讯从机程序(8515) 晶振4MHZ
.ORG $008 ;$00A(8535)
RJMP SPINTS ;同步串口中断矢量
.ORG $00D ;$011(8535)
RST37S: LDI R16,2
OUT SPH,R16
LDI R16,$5f
OUT SPL,R16
LDI R16,$40
OUT DDRB,R16 ;MISO为输出
LDI R16,$CC
OUT SPCR,R16 ;允许SPI中断,先发送高位,从控方式,时钟为主频4分频,后沿有效
LDI YH,HIGH(DATA4)
LDI YL,LOW(DATA4);数据指针
LDI R16,$30 ;数据长度
LD R15,Y
OUT SPDR,R15 ;写入数据寄存器
SEI
HH37S: RJMP HH37S ;背景程序从略
SPINTS: IN R14,SREG
IN R15,SPDR ;读接收数据
ST Y+,R15
DEC R16
BRNE SPI2 ;数据块收发完毕
OUT SPCR,R16 ;停止中断收发
RJMP SPI3
SPI2: LD R15,Y
OUT SPDR,R15 ;发下一数据
SPI3: OUT SREG,R14
RETI
;范例49 以模拟串口与串行移位寄存器74165通讯,以74165驱动LED显示子程序
DSPLY3: SBI DDRC,1 ;PC1,串行数据输出
SBI DDRC,0 ;PC0,移位时钟
CBI PORTC,0 ;
LDI R17,8 ;8字节显示缓存区$60(高)--$67(低))
MOV R8,R17
CLR XH
LDI XL,$60 ;指针,首指最高位($60)
SRDLOP: LDI R17,8 ;8位/字节
MOV R9,R17
LD R10,X+
LDI ZH,HIGH(TABLE*2)
LDI ZL,LOW(TABLE*2);使用DSPY子程序段选表
ADD ZL,R10 ;加代码寻址
BRCC DSPL1
INC ZH
DSPL1: LPM ;取段选码
COM R0 ;取为反码
SENDLP: ROR R0 ;段选码右移一位 C<--R0最低位
CBI PORTC,1
BRCC SNDL1 ;进位C传给PC1
SBI PORTC,1
SNDL1: SBI PORTC,0 ;移位时钟,上升沿有效
CBI PORTC,0 ;移位时钟变低
DEC R9
BRNE SENDLP ;8位段选码循环右移
DEC R8
BRNE SRDLOP ;8位LED显示数据都更新一遍?
RET ;是,结束
;脉宽调制(PWM)输出程序
;范例50 ;以定时器定时产生精确半秒信号,以PD5输出精确秒号
.ORG $000 ;晶体实测频率为8000367HZ
STRT40: RJMP RST40 ;USE 8535
.ORG $008 ;t/C1 overflow vector
RJMP T1_OVF
.ORG $011
RST40: LDI R16,HIGH(ramend)
OUT SPH,R16
LDI R16,LOW(ramend)
OUT SPL,R16
SBI DDRD,5 ;PD5(OC1A)为输出
CBI PORTD,5 ;初始输出为低
LDI R16,2 ;8分频 INT(8000367/8)=1000046) 折半500023定半秒
OUT TCCR1B,R16 ;T/C1控制寄存器(I/O ADDR:$2E)
LDI R16,$5E ;500023=65536*8-24265=$10000*8-$5EC9
OUT TCNT1H,R16 ;TCC=$5EC9 先写高位字节
LDI R16,$C9
OUT TCNTIL,R16
LDI R16,$04
OUT TIMSK,R16 ;允许T/C1溢出中断/8535C/t1:timsk,2&t0:timsk,0
LDI R17,8 ;8次中断定半秒
CLR R16
OUT TIFR,R16 ;清除定时/计数器中断标志
SEI ;
HH40: RJMP HH40 ;背景程序略
T1_OVF: IN R5,SREG ;保存状态寄存器
DEC R17
BRNE COMP1 ;定时时间到?
IN R16,PORTD ;读入PD5当前状态
LDI R17,$20
EOR R16,R17 ;求反PD5(OC1A)输出
OUT PORTD,R16
IN R17,TCNT1L ;*
IN R16,TCNT1H ;*读回TCNT1计数值
SUBI R17,$37 ;*
SBCI R16,$A1 ;*减去$5EC9之补码$A137
SUBI R17,$FF ;*补偿指令8条占一个计数单位
SBCI R16,$FF ;*补偿后TCC=$5EC9+(TCNT1)+1
OUT TCNT1H,R16 ;*
OUT TCNT1L,R17 ;*写入TCNT1
LDI R17,8 ;重新写入中断次数
COMP1: OUT SREG,R5
RETI
;范例51 ;以比较匹配A达到时交替输出高低电平及写入其维持
;时间常数之方法实现脉宽调制输出
.ORG $000
STRT41: RJMP RST41 ;5.008MS(高):10.000MS(低) 晶振4MHZ
.ORG $006
RJMP T1_CMPA ;USE 8535
.ORG $011
RST41: LDI R16,HIGH(RAMEND)
OUT SPH,R16
LDI R16,LOW(RAMEND)
OUT SPL,R16
LDI R16,$80 ;T/C1比较匹配A达到时,清除输出脚oc1a
OUT TCCR1A,R16
LDI R16,$0B ;64分频 ctc1=1 比较匹配达到清tcnt1
OUT TCCR1B,R16
SBI DDRD,5
SBI PORTD,5 ;pd5(oc1a)初始化输出为高
CLR R16
OUT TCNT1H,R16 ;予清除tcnt1
OUT TCNT1L,R16
LDI R16,1
OUT OCR1AH,R16
LDI R16,$39 ;写比较匹配寄存器(313*0.25*64=5.008MS)
OUT OCR1AL,R16
LDI R16,$10
OUT TIMSK,R16 ;允许比较匹配A中断
SEI
HH41: RJMP HH41 ;背景程序略
T1_CMPA:IN R5,SREG
IN R16,TCCR1A
SBRS R16,6
RJMP OUTLOW ;当前输出低电平,转
LDI R16,1
OUT OCR1AH,R16
LDI R16,$39 ;写入高电平维持时间313
OUT OCR1AL,R16
LDI R16,$80 ;比较匹配A达到时,OC1A输出为低
OUT TCCR1A,R16
OUT SREG,R5
RETI
OUTLOW: LDI R16,2
OUT OCR1AH,R16
LDI R16,$71 ;写入低电平维持时间625(=$271) (625*0.25*64=10.000MS)
OUT OCR1AL,R16
LDI R16,$C0 ;比较匹配A达到时,OC1A输出为高
OUT TCCR1A,R16
OUT SREG,R5
RETI
;范例52 ;以比较匹配达到时求反输出并按高低电平写入
.ORG $000 ;维持时间之方法实现脉宽调制输出
STRT42: RJMP RST42 ;5.008MS(高):10.000MS(低) 晶振4MHZ
.ORG $006
RJMP T1_CMPA
.ORG $011
RST42: LDI R16,HIGH(ramend)
OUT SPH,R16
LDI R16,LOW(RAMEND)
OUT SPL,R16
LDI R16,$40 ;比较匹配A达到时,对OC1A输出求反
OUT TCCR1A,R16
LDI R16,$0C ;256分频 ctc1=1 比较匹配达到时 清除cnt1
OUT TCCR1B,R16
SBI DDRD,5 ;PD5(oc1a)为输出
SBI PORTD,5 ;初始输出为高
CLR R16
OUT TCNT1H,R16 ;清除tcnt1
OUT TCNT1L,R16
OUT OCR1AH,R16
LDI R16,78 ;高电平时间常数78
OUT OCR1AL,R16
LDI R16,$10
OUT TIMSK,R16 ;允许比较匹配A中断
SEI
HH42: RJMP HH42 ;背景程序略
T1_CMPA:IN R5,SREG ;
IN R16,PORTD
SBRC R16,5
RJMP T1CM1 ;当前oc1a为高,转
LDI R16,0
OUT OCR1AH,R16
LDI R16,156 ;低电平时间常数156
OUT OCR1AL,R16
OUT SREG,R5
RETI
T1CM1: LDI R16,0
OUT OCR1AH,R16
LDI R16,78 ;高电平时间常数78
OUT OCR1AL,R16
OUT SREG,R5
RETI
;模/数转换和数/模转换及脉宽调制输出应用
;范例53 ;模拟量采集和3路脉宽调制输出(OCR1A/OCR1B&OCR2)综合程
;序/晶振4MHZ
.ORG $000
STRT50: RJMP RST50 ;avr is AT90S8535
.ORG $00E
RJMP ADCOM ;模数转换完成中断
.ORG $011
RST50: LDI R16,HIGH(ramend)
OUT SPH,R16
LDI R16,LOW(ramend)
OUT SPL,R16 ;堆栈指针初始化
CLR R11 ;通道号初始化
CLR R12
CLR R13 ;累加和予清除
OUT $07,R11 ;ADC通道初始化,指向0#通道
LDI R16,$6C ;T/C2为自运行pwm输出,加法计数匹配清除OC2,减法计
;数匹配置位OC2(正向PWM);对晶振64分频
OUT TCCR2,R16 ;tccr2' ADDR.:$25
LDI R16,$ED ;使能,启动ADC/自由运行/转换完成中断/对晶振32分频
OUT ADCSR,R16 ;ADDR:$06 adc控制状态寄存器
IN R16,ASSR
CBR R16,8
OUT ASSR,R16 ;TCNT2 用主时钟!
INC R11
OUT $07,R11 ;予切换到1号ADC通道
SBI DDRD,4
SBI PORTB,4 ;pd4:oc1b
SBI DDRD,5 ;pd5:oc1a pd4,pd5 皆为输出 oc1b初始输出为高
SBI DDRD,7 ;oc2 输出
LDI R16,$E3 ;0B11100011,自运行PWM,COM1A1/0=11,COM1B1/0=10
OUT TCCR1A,R16 ;减法计数匹配清除OC1A,加法计数匹配置位OC1A(反向PWM);加法计
;数匹配清除OC1B,减法计数匹配置位OC1B(正向PWM)
LDI R16,2
OUT TCCR1B,R16 ;tcnt1 8分频
LDI R16,0
OUT TCNT1H,R16 ;wr.high B at first
OUT TCNT1L,R16 ;清除TCNT1
OUT TCNT2,R16 ;清除TCNT2
OUT DDRA,R16 ;A口输入
OUT PORTA,R16 ;输入为高阻态
SEI
COMLP: CPI R11,1
BREQ COMLP ;通道号初始为1,等待切换过去
COML0: CPI R11,1
BRNE COML0 ;通道号再次为1时,0#通道正在转换,7#通道已转换完毕,
;已得到8个A/D采样累加和
ASR R12
ROR R13
ASR R12
ROR R13
ASR R12
ROR R13 ;累加和除以8
BRCC COML1
CLR R16
ADC R13,R16
ADC R12,R16 ;四舍五入
COML1: OUT OCR1AH,R12
OUT OCR1AL,R13
OUT OCR1BH,R12
OUT OCR1BL,R13 ;10位数据写入比较匹配寄存器
ASR R12
ROR R13
ASR R12
ROR R13
BRCC COML2
INC R13
BRNE COML2
DEC R13
COML2: OUT OCR2,R13 ;8位数据写入比较匹配寄存器
CLR R12
CLR R13 ;累加和清除
RJMP COMLP
ADCOM: IN R15,ADCL ;ADC完成中断
IN R14,ADCH
ADD R13,R15 ;模拟数值加入累加和
ADC R12,R14
INC R11
SBRC R11,3
CLR R11 ;total 8 chanales!&8 CHANGED TO 0
OUT $07,R11 ;$07:admux'address REGISTER
RETI
;范例54 ;以R-2R电阻网络和C口配合组成DAC与输入模拟量比较实现模数转换
.ORG $000 ;电阻网络DAC最大输出(AIN0)只能达到3.32V(PCi输出只能达到5V)
STRT51: RJMP RST51 ;输入模拟量最大为4.98V,故应将DAC输出放大1.5倍再与前者比较
.ORG $011 ;也可将输入模拟量衰减为2/3再与DAC输出比较
RST51: LDI R16,2 ;但应将转换结果乘以1.5以使其复原,程序取后者
OUT SPH,R16 ;堆栈指针初始化
LDI R16,$5F
OUT SPL,R16
SER R16
OUT DDRC,R16 ;C口全部为输出,DAC输出为AIN0输入
CLR R16
OUT DDRB,R16 ;B口为输入
LDI R16,$F3
OUT PORTB,R16 ;PB2(AIN0),PB3(AIN1)输入为高阻状态
CLR R15 ;模数转换结果予清除
LDI R16,$80 ;逼近增量初始值
CMPLP: ADD R15,R16 ;模数转换阶段值加逼近增量
OUT PORTC,R15 ;转成模拟量
NOP
NOP
NOP ;4MHZ/等待1微秒
SBIC ACSR,ACO ;输入模拟量大于DAC模拟量,清除ACO
SUB R15,R16 ;否则去掉逼近增量
LSR R16 ;逼近增量折半
BRNE CMPLP ;逼近增量变为0?
MOV R16,R15 ;*是,转换结束
LSR R15 ;*
ADC R15,R16 ;*将转换结果乘以1.5
HH50: RJMP HH50 ;背景程序略
;范例55 ;40点平均在r18r19,累加和在r5r6r7;20点平均在R14R15,累加和在R1R3R4
SLPAV: PUSH R26 ;采样在R8R9,采样数据存储区$150--$19F/工作寄存器r1--r19&r26 r27
PUSH R27
LDI R27,1
LDS R26,$14F ;数据存储区首地址$14F
ADD R7,R9
ADC R6,R8 ;采样加入40点平均累加和
BRCC SLP1
INC R5 ;有进位,高位字节增1
SLP1: ADD R4,R9
ADC R3,R8 ;采样加入20点平均累加和
BRCC SLP2
INC R1 ;有进位,高位字节增1
SLP2: LD R16,X
ST X+,R9
MOV R9,R16 ;置换出最旧采样低位字节
LD R16,X
ST X+,R8
MOV R8,R16 ;置换出最旧采样高位字节
CPI R26,$A0
BRNE SLPA1
LDI R26,$50 ;采样放满存储区后,指针初始化($1A0=$150)
STS $14F,R26
LDS R16,$A4
SBRC R16,4
RJMP SLPA2 ;40点平均时间达到,转
SBR R16,$10 ;设置40点平均时间达到标志
STS $A4,R16
RJMP SLDIV ;转去计算40点平均
SLPA1: STS $14F,R26 ;暂存指针
LDS R16,$A4
SBRS R16,4
RJMP SLPB0 ;还未到40点平均,转
SLPA2: SUB R7,R9
SBC R6,R8 ;到40点平均后除加上新采样外,还要减去最旧采样
BRCC SLDIV
DEC R5 ;不够减,高位字节减1
SLDIV: CLR R12
LDI R16,40
MOV R11,R16
CLR R10
MOV R13,R5
MOV R14,R6
MOV R15,R7
RCALL DIV165 ;计算40点平均
MOV R18,R14
MOV R19,R15 ;存入r18r19
SLPB0: CPI R26,$78
BRNE SLPB1
LDS R16,$A4
SBRC R16,3
RJMP SLPB2
SBR R16,8 ;建20点平均时间到标志
STS $A4,R16
RJMP SLPDV ;
SLPB1: LDS R16,$A4
SBRS R16,3
RJMP SLRET ;20点平均时间未到
SLPB2: SUBI R26,42 ;指针退回42字节,指向20点平均最旧数据
CPI R26,$50 ;不小于80,未超出采样数据存储区
BRCC SLPB20
SUBI R26,-80 ;否则加80调整回$150-$19F
SLPB20: LD R11,X+ ;
LD R10,X
SUB R4,R11
SBC R3,R10 ;找到20点平均最旧采样,并将其从累加和中减去!
BRCC SLPDV
DEC R1
SLPDV: LDI R16,20
MOV R11,R16
CLR R10
CLR R12
MOV R13,R1
MOV R14,R3
MOV R15,R4
RCALL DIV165 ;20点平均在r14r15中
SLRET: POP R27
POP R26
RET
;范例56 ;断电保护芯片MAX704,/RESET脚接8515同名脚
;/PFO接INT0,由VOUT脚给UT6264(或UT62256)/62x42x供电,
;本程序不涉及休眠!
.ORG $000 ;AT90S8515/时钟4MHZ
STRT60: RJMP RST60
RJMP EX_INT0 ;外部中断0
RJMP EX_INT1 :外部中断1
.ORG $009 ;uart_rxc interrupt
RJMP RCVSV
.ORG $010
RST60: LDI R16,2
OUT SPH,R16
LDI R16,$5f
OUT SPL,R16 ;堆栈指针初始化,指向$25f
CLR XH
LDI XL,$60
CLR R16
CLRX: ST X+,R16
CPI XL,$5E
BRNE CLRX
CPI XH,2
BRNE CLRX ;清除$60--$25d
LDI R16,$F0
OUT DDRB,R16 ;PB3-PB0输入 PB7-PB4输出
OUT PORTB,R16 ;上拉PB7-PB4
SBI PORTB,0
SBIS PINB,0
RJMP BG1A ;若将PB0接地,不做断电启动
LDI R16,70
CLR R12
CLR R11
DLOPX: DEC R11
BRNE DLOPX
DEC R12
BRNE DLOPX
DEC R16
BRNE DLOPX ;延时3.4秒(clk 4mhz)
CLR R27
LDI R26,$60
CLR R16
LOPX1: ST X+,R16
CPI R26,$5E
BRNE LOPX1
CPI R27,2 ;清除$60--$25d
BRNE LOPX1
CLI
LDI R16,$80
OUT GIMSK,R16 ;int1中断使能
LDI R16,$DA ;激活外部RAM,加1等待周期,不休眠,int0/int1下降沿有效
OUT MCUCR,R16
;.
;.
;. ;
LDS R16,$9FFE ;片外sram $8000-$9fff)
CPI R16,$55
BRNE BG1A ;查断电标志
LDS R16,$9FFF
CPI R16,$AA
BREQ BG2B ;查到
BG1A: LDI R27,$80
LDI R26,0
CLR R16
CLOPX: ST X+,R16
CPI R27,$A0
BRNE CLOPX ;清除$8000--$9FFF
LDI R16,$AA
ST -X,R16 ;$AA-->($9fff)
COM R16
ST -X,R16 ;$55-->($9ffe)
BG1A0: IN R16,GIMSK
SBR R16,$40
OUT GIMSK,R16 ;允许int0中断
RJMP NRMST
BG2B: LDS R16,$9FFD ;$9FFD:最高位为生产标志
SBRS R16,7
RJMP NRMST ;无生产标志转平常启动
BG5C: CBI PORTB,7 ;指示断电启动
LDI R27,$80
LDI R26,2 ;SRAM 8002-825F传回片内
LDI R29,0
LDI R28,2
CLR R0 ;检查和清除
APX0: LD R1,X+
ST Y+,R1 ;传送数据块
ADD R0,R1
CPI R28,26 ;指向r26?
BRNE APX0
LD R1,X+ ;取r26
ADD R0,R1
LD R1,X+ ;取r27
ADD R0,R1
LD R1,X+ ;取r28
ADD R0,R1
LD R1,X+ ;取r29/ r26--r29为数据指针,不能当作数据传送
ADD R0,R1
LDI R28,30
APX2: LD R1,X+
ADD R0,R1
ST Y+,R1
CPI R28,$5F
BRNE APX2
INC XL
INC YL ;SREG不断变化,不能加入累加和!
APX3: LD R1,X+
ADD R0,R1
ST Y+,R1
CPI R28,$60
BRNE APX3
CPI R29,2
BRNE APX3 ;到$25f?
LDS R1,$9FFC ;取检查和
ADD R0,R1 ;检查和(CHECKSUM)正确?
BREQ BG5D
RJMP BG1A ;错,转总清
BG5D: WDR
LDI R16,$0D ;看门狗初始化,溢出时间0.49"
OUT WDTCR,R16
CLR R2 ;调DSPA次数计数器清除
IN R16,GIMSK
SBR R16,$40
OUT GIMSK,R16 ;允许int0中断
LDS R26,$235
OUT SPH,R26
LDS R26,$234
OUT SPL,R26
POP R26
POP R27
POP R28
POP R29 ;数据指针出栈
POP R1
OUT SREG,R1 ;
POP R1
POP R0
RETI ;弹出断点,开放中断
NRMST: WDR
LDI R16,$0D ;看门狗初始化,溢出时间0.49"
OUT WDTCR,R16
CLR R2
;.......
SEI
;(略)
RCVSV: ;.
;.
;.
EX_INT0:PUSH R0 ;断电中断服务 I BE CLEARED!
PUSH R1
IN R1,SREG
PUSH R1
PUSH R29
PUSH R28
PUSH R27
PUSH R26 ;保护X,Y指针
LDI R26,$1D
OUT WDTCR,R26
LDI R26,$15
OUT WDTCR,R26 ;禁止看门狗
IN R26,SPL
STS $234,R26
IN R26,SPH
STS $235,R26 ;保护堆栈指针
LDI R27,0
LDI R26,2
LDI R29,$80
LDI R28,2 ;SRAM $002-25F 转片外$8002-$825f
CLR R0 ;检查和予清除
ALPX1: LD R1,X+
ST Y+,R1
ADD R0,R1 ;加入累加和
CPI R26,26 ;
BRNE ALPX1 ;
POP R1 ;R26~R29从堆栈中取!
ADD R0,R1
ST Y+,R1
POP R1 ;取R27
ADD R0,R1
ST Y+,R1
POP R1 ;取R28
ADD R0,R1
ST Y+,R1
POP R1 ;取R29
ADD R0,R1
ST Y+,R1
IN R26,SPL
SUBI R26,4 ;恢复堆栈指针,抵消4个POP
OUT SPL,R26
LDI R26,30 ;越过R26-R29,指向R30
APX10: LD R1,X+
ST Y+,R1
ADD R0,R1
CPI R26,$5F
BRNE APX10
INC XL ;SREG 越过!
INC YL
APX20: LD R1,X+
ST Y+,R1
ADD R0,R1
CPI R26,$60
BRNE APX20
CPI R27,2
BRNE APX20 ;完成到$8002-825F之转移
NEG R0
STS $9FFC,R0 ;SAVE THE CHECKSUM TO $9FFC
LDI R26,62
CLR R27
CLR R28
DLPX5: DEC R28
BRNE DLPX5
DEC R27
BRNE DLPX5
DEC R26
BRNE DLPX5 ;延时3秒(49.16ms*62=3")
LDI R27,$80
LDI R26,2 ;$8002-$825F
LDI R29,0
LDI R28,2 ;$002-25F
CLR R0
APX1A: LD R1,X+
ST Y+,R1 ;将片外SRAM数据传回片内
ADD R0,R1
CPI R28,26
BRNE APX1A
LD R1,X+ ;R26
ADD R0,R1
LD R1,X+ ;R27
ADD R0,R1
LD R1,X+ ;R28
ADD R0,R1
LD R1,X+ ;R29
ADD R0,R1
LDI R28,30
APX1B: LD R1,X+
ST Y+,R1
ADD R0,R1
CPI R26,$5F
BRNE APX1B
INC XL ;越过SREG!
INC YL
APX2A: LD R1,X+
ADD R0,R1
ST Y+,R1
CPI R28,$60
BRNE APX2A
CPI R29,2
BRNE APX2A ;到$25f?
LDS R1,$9FFC
ADD R0,R1
BRNE ERRDL
RJMP BG5D ;检查和正确
ERRDL: (略) ;错误处理
;范例57
;使用干电池便携系统断电保护程序 MAX704 RESET引脚接8535同名脚
;/PFO接8535INT0 断电时由电池给AT90LS8535供电
;晶振4MHZ
.ORG $000 ;AT90LS8535只使用片内sram;在片内RAM中保护数据
STRT61: RJMP RST61
RJMP EX_INT0
RJMP EX_INT1
.ORG $00B
RJMP RVCMPLT ;串行数据接收完成
.ORG $011
RST61: LDI R16,$00
OUT DDRA,R16 ;PA7-PA0为输入
LDI R16,21
CLR R12
CLR R13
DLPX: DEC R13
BRNE DLOPX
DEC R12
BRNE DLPX
DEC R16
BRNE DLOPX ;延时1秒(clk 4mhz)
LDI R16,2
OUT SPH,R16
LDI R16,$5f
OUT SPL,R16 ;堆栈指针$25f
CLR R2 ;调DSPB次数预清除
WDR
LDI R16,$0D ;设置看门狗溢出时间0.49"
OUT WDTCR,R16
LDI R16,$0F
OUT PORTA,R16
IN R16,PINA
CBR R16,$F0 ;清除无用的高4位
CPI R16,15
BRNE BG3A ;K0-K3有键按下,转
LDS R16,$23E ;
CPI R16,$55
BRNE BG3A
LDS R16,$23F
CPI R16,$AA
BRNE BG3A ;无断电标志,转
CLR R16
STS $23E,R16 ;清除断电标志
CLI
LDI R16,$C0
OUT GIMSK,R16 ;
LDI R16,$60 ;掉电休眠,
OUT MCUCR,R16 ;int0 INT0 电平中断
;.
;. ;其他初始化程序略
;. ;
RJMP REST2 ;转断电启动!
RVCMPLT:;(MISSING)
BG3A: CLR R27
LDI R26,$60
CLR R16
LOPX1: ST X+,R16
CPI R26,$60
BRNE LOPX1
CPI R27,2
BRNE LOPX1 ;清除$60--$25f
LDI R16,2
OUT SPH,R16
LDI R16,$5FH
OUT SPL,R16
CLI
LDI R16,$C0
OUT GIMSK,R16 ;允许int0/int1中断
LDI R16,$60 ;掉电休眠
OUT MCUCR,R16 ;INT0/INT1 电平中断
;.
;. ;其他初始化程序略
;.
SEI
HH61: RCALL DSPB ;液晶显示子程序略
LDI R16,$0F ;激活上拉电阻
OUT PORTA,R16 ;
IN R16,PINA ;读入键状态
CBR R16,$F0
CPI R16,$0F ;有键按下?
BRNE HH61 ;等待释放
IN R16,TIMSK
SBR R16,$C0
OUT TIMSK,R16 ;重新允许INT1中断
SLEEP ;进入掉电休眠
RJMP HH61 ;唤醒后显示新采集的数据
EX_INT1:SEI ;允许INT0中断
PUSH R16 ;K0/K1/K2/K3有按下者,产生电平中断唤醒MCU,采集数据
IN R16,SREG
PUSH R16
SBI PORTA,3
SBIS PINA,3
RJMP DLK63 ;K3按下采集数据
SBI PORTA,2
SBIS PINA,2
RJMP DLK62 ;K2按下采集数据
SBI PORTA,1
SBIS PINA,1
RJMP DLK61 ;K1按下采集数据
RJMP DLK60 ;K0按下采集数据
DLKRT: IN R16,TIMSK
CBR R16,$80
OUT TIMSK,R16 ;禁止INT1中断(键未释放或抖动时不引起中断)
POP R16
OUT SREG,R16
POP R16
RETI
DLK60: ;. ;采集、处理数据,数据处理后送入显示缓存区
;.
;.
RJMP DLKRT
DLK61: ;. ;采集、处理数据,数据处理后送入显示缓存区,
;.
;.
RJMP DLKRT
DLK62: ;. ;采集、处理数据,数据处理后送入显示缓存区
;.
;.
RJMP DLKRT
DLK63: ;. ;采集、处理数据,数据处理后送入显示缓存区
;.
;.
RJMP DLKRT
EX_INT0:PUSH R0 ;掉电中断服务子程序
PUSH R2
PUSH R12
PUSH R13 ;CLI ALREADY!
PUSH R14
PUSH R15
PUSH R16
PUSH R17
PUSH R26
PUSH R27
PUSH R30
PUSH R31
IN R16,SREG
PUSH R16 ;保护状态寄存器
LDI R16,$1D
OUT WDTCR,R16
LDI R16,$15
OUT WDTCR,R16 ;停止看门狗
IN R16,SPL
STS $23C,R16
IN R16,SPH
STS $23D,R16 ;保护堆栈指针
LDI R16,$55
STS $23E,R16
COM R16
STS $23F,R16 ;写断电标志
SER R16
OUT PORTC,R16 ;关显示
CLR R16
OUT GIMSK,R16 ;禁止外部中断(INT0&INT1)
SLEEP ;进入掉电休眠
REST2: LDS R16,$23D
OUT SPH,R16
LDS R16,$23C
OUT SPL,R16 ;取出堆栈指针
POP R16
OUT SREG,R16 ;恢复状态寄存器
POP R31
POP R30
POP R27
POP R26
POP R17
POP R16
POP R15
POP R14
POP R13
POP R12
POP R2
POP R0 ;恢复工作寄存器,主程序初始化时只能使用这些寄存器!
RETI ;弹出断点,开放中断
;范例58
.EQU DPOINT=$100 ;DATA BLOCK from $100 to $22b
CRCST: LDI R16,2 ;最末2字节在发送方已清为零(或仍为$0D$0A)
MOV R11,R16 ;在接收方则为对方计算出的CRC校验码(余式)
LDI R16,$2C
MOV R12,R16 ;(r11r12)内装入$22C,块长为$12C
CRCST1: LDI R26,HIGH(DPOINT)
LDI R27,LOW(DPOINT);数据指针
CRC0: CLR R14
CLR R15
LDI R17,$80 ; 16 15 2
LDI R18,$05 ;P(X)=X +X +X +1=$18005
CRC1: LDI R16,8
MOV R13,R16 ;8位/字节
LD R16,X+
CRC2: LSL R16
ROL R15
ROL R14
BRCC CRC3
EOR R14,R17
EOR R15,R18 ;移出位为1时,将寄存器r14r15内容异或立即数$8005
CRC3: DEC R13 ;位数减1
BRNE CRC2
DEC R12 ;字节数减1
BRNE CRC1
DEC R11
BRNE CRC1
ST -X,R15
ST -X,R14 ;除得余数放在数据块尾部(或将原始数据恢复)!
RET
;范例58A ;DS18B20读出温度数据CRC检测子程序,生成多项式为P(X)=X8+X4+X3+1
CRCSTA:LDI XL,$70 ;温度数据指针
CLR XH
LDI R16,9 ;温度数据,上、下限......CRC校验码等共9字节
CLR R15 ;异或除法工作单元
LDI R18,$8C
CRC1A: LD R14,X+
LDI R17,8
CRC2A: LSR R14
ROR R15 ;位序列右移
BRCC CRC3A
EOR R15,R18 ;移出位为1时,位序列异或立即数$8C
CRC3A: DEC R17
BRNE CRC2A ;右移次数减1
DEC R16
BRNE CRC1A ;块长减1
RET ;(R15)=0 接收正确!
;范例59
DEMCRC: LDI R27,1 ;CRC演示程序(校验码16位)
CLR R26 ;数据块首地址为$100
DEMLP: ST X+,R26 ;
CPI R26,$2A ;在$100-$229中充入数据
BRNE DEMLP
CPI R27,2
BRNE DEMLP ;$100--$229中充入$00--$FF和$00-$29
CLR R16
ST X+,R16
ST X,R16 ;$22A,$22B两单元请除,将计算出余式(即CRC校验码)放在其中
RCALL CRCST ;在发送方计算出CRC校验码
RETEST: RCALL CRCST ;在接收方做CRC检测(余式在r14r15)
OR R15,R14 ;r14r15恢复为$0000(或恢复出原数据为正确接收)
BRNE ERCRC
HCRC: RJMP HCRC
ERCRC: ;. ;出错处理,要求对方重发
;.
RJMP RETEST ;重新CRC检测
.DSEG
.ORG $100
DPOINT: .BYTE $12C
; $00 $01 $02 $03 $04 $05 $06 $07 $08 $09 $0a $0b $0c $0d $0e $0f
; $10 $11 $12 $13 $14 $15 $16 $17 $18 $19 $1a $1b $1c $1d $1e $1f
; $20 $21 $22 $23 $24 $25 $26 $27 $28 $29 $2a $2b $2c $2d $2e $2f
; $30 $31 $32 $33 $34 $35 $36 $37 $38 $39 $3a $3b $3c $3d $3e $3f
; $40 $41 $42 $43 $44 $45 $46 $47 $48 $49 $4a $4b $4c $4d $4e $4f
; $50 $51 $52 $53 $54 $55 $56 $57 $58 $59 $5a $5b $5c $5d $5e $5f
; $60 $61 $62 $63 $64 $65 $66 $67 $68 $69 $6a $6b $6c $6d $6e $6f
; $70 $71 $72 $73 $74 $75 $76 $77 $78 $79 $7a $7b $7c $7d $7e $7f
; $80 $81 $82 $83 $84 $85 $86 $87 $88 $89 $8a $8b $8c $8d $8e $8f
; $90 $91 $92 $93 $94 $95 $96 $97 $98 $99 $9a $9b $9c $9d $9e $9f
; $a0 $a1 $a2 $a3 $a4 $a5 $a6 $a7 $a8 $a9 $aa $ab $ac $ad $ae $af
; $b0 $b1 $b2 $b3 $b4 $b5 $b6 $b7 $b8 $b9 $ba $bb $bc $bd $be $bf
; $c0 $c1 $c2 $c3 $c4 $c5 $c6 $c7 $c8 $c9 $ca $cb $cc $cd $ce $cf
; $d0 $d1 $d2 $d3 $d4 $d5 $d6 $d7 $d8 $d9 $da $db $dc $dd $de $df
; $e0 $e1 $e2 $e3 $e4 $e5 $e6 $e7 $e8 $e9 $ea $eb $ec $ed $ee $ef
; $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $fa $fb $fc $fd $fe $ff
; $00 $01 $02 $03 $04 $05 $06 $07 $08 $09 $0a $0b $0c $0d $0e $0f
; $10 $11 $12 $13 $14 $15 $16 $17 $18 $19 $1a $1b $1c $1d $1e $1f
; $20 $21 $22 $23 $24 $25 $26 $27 $28 $29 $00 $00
;码制转换
;范例60
;地址 $90 1 2 3 4 5 6 7 8 9 a b c d e f $a0
;ascii码数据 P i , A S , +/- x x x x . x x k g
.EQU DPNT=$90 ;the first ascii character addr.
;DataPoint(.'sit):$a0/weighing unit:$a1,$a2
;P1-P4'no.:$a6$a7--$ac$ad/max.no.:$ae$af
.EQU TPTR=$b0 ;the first total(total1($b0-$b3)) addr.
.EQU CPTR=$C0 ;print char. buffer addr.
.EQU SREG=$3F
.EQU SPH=$3E
.EQU SPL=$3D
ACUM: CLR R29
CLR R27 ;ASCII码存放区为$90-9F
LDI R26,$90
LD R16,X
CPI R16,$50 ;P打头方为有效
BRNE ACRT
ADIW R26,2 ;指向$92
LD R16,X
CPI R16,$2C ;是','?
BREQ DOP0
ACRT: SET ;非法数据!
RET
DOP0: LDI R17,4
LDI R26,$99 ;设指针,寻找小数点
DOP1: LD R16,X+
CPI R16,$2E
BREQ DOP3 ;找到'.'
DOP2: DEC R17
BRNE DOP1
DOP3: LDI R28,$A0 ;小数点放入$A0,1,2,3,4表示小数点后有1,2,3,4位数据
ST Y+,r17 ;0表示无小数点
LDI R26,$9E ;指向质量单位
LD R17,X+
ST Y+,R17
LD R17,X+
ST Y,R17 ;质量单位(kg/ t)-->$a1,$a2
LDI R28,11
CLR R9
CLR R10
CLR R11 ;予请除,存放BCD码
LDI R26,$9E
F1: LD R16,-X ;减1后指向$9d!
CPI R16,$2E ;从低位到高位顺序将ASCII转为BCD,两两合成1字节压缩BCD码
BREQ F1 ;遇到小数点跳过
F2: BRCS FEND ;遇空格/+/-等结束
SUBI R16,$30 ;十进制数ascii变bcd
MOV R12,R16
ST Y,R16
F3: LD R16,-X
CPI R16,$2E
BREQ F3
F4: BRCS FEND ;小于$2E转换结束
SUBI R16,$30
SWAP R16
ADD R16,R12
ST Y,R16
DEC R28
CPI R28,8
BRNE F1
FEND: MOV R17,R9
OR R17,R10
OR R17,R11
BREQ ACRT ;0数据转出
RCALL CONV2 ;整数二翻十(r9r10r11-->r13r14r15)
MOV R5,R13
MOV R6,R14
MOV R7,R15
CLR R12
LDS R16,$96 ;取数据符号
CPI R16,$2d ;'-'ASCII码
BRNE F09
LDI R26,16
RCALL NEG4 ;负数取补
F09: LDI R26,$91 ;指向数据序号ASCII码
LD R16,X+
SUBI R16,$31 ;将ASCII码序号$31--$34变为0--3,
CPI R16,4
BRCC FRET ;大于3为无效
MOV R9,R16 ;暂存
LSL R16
LSL R16 ;乘4
LDI R26,$B0 ;$B0为第一个累加和首地址(TPTR)
ADD R26,R16 ;得到实际首地址
LDI R16,4
LDI R28,16 ;数据指针
CLC
LACM: LD R17,X ;取累加和一字节数据
LD R10,-Y
ADC R17,R10
ST X+,R17
DEC R16
BRNE LACM ;r12,13,14,15 加入累加和
LSL R9 ;序号乘2
LDI R26,$AE ;指向最大累加次数
LDI R28,$A6 ;指向第一个累加次数
ADD R28,R9 ;指向实际累加次数
LD R11,X+
LD R10,X ;取最大累加次数(2字节)
LD R13,Y
INC R13 ;实际累加次数增1
ST Y+,R13 ;低位字节送回
LD R12,Y
TST R13
BRNE F10
INC R12 ;低位字节增1后为0,高位字节增1
ST Y,R12
F10: SUB R11,R13
SBC R10,R12 ;与最大累加次数相比较
BRCC F12
ST X,R12
ST -X,R13 ;存最大累加次数
F12: MOV r15,r7
MOV r14,r6
MOV r13,r5
LDI R17,$98 ;予设阶码(假定为24位整数)
MOV R12,R17
F120: SBRC R13,7
RJMP F13
LSL R15
ROL R14
ROL R13
DEC R12
RJMP F120
F13: LDS R0,$A0 ;取小数点位数(0,1,2,3,4)
TST R0
BREQ F14 ;整数转
F130: RCALL G01 ;取浮点数0.1(范例70)
RCALL FPMU ;(范例65)
DEC R0
BRNE F130 ;小数点位置决定乘几个0.1
F14: LDS R16,$96
CPI R16,$2B ;负数?
BRNE F9
LDI R16,$7F
AND R13,R16 ;正数清除数符位
F9: CLT ;合法数据出口(T=0)
RET
FRET: SET ;非法数据出口(T=1)
RET
NEG4: LDI R16,4 ;4字节二进制数据求补
CLC
NG4L: CLR R17
LD R11,-X ;X-1指向最低位字节
SBC R17,R11
ST X,R11
DEC R16
BRNE NG4L
RET
FLSPC: LDI R26,$C0 ;准备一行空格字符,为打印一行空格做准备
CLR R31
LDI R16,$20 ;SPC
FSLOP: ST X+,R16
CPI r30,$d0
BRNE FSLOP
LDI R16,$0D ;$0D-->($D0)
ST X+,R16
LDI R16,$0A ;$0A-->($D1)
ST X+,R16
RET
BRDT: RCALL CONV1A ;二翻十并将压缩BCD码转换为ASCII码
RCALL FLSPC
LDI R28,$A3 ;$A1,$A2 is the weighing unit
CLR R29 ;取质量单位到打印数据存储区
LDI R26,$D0
LD R16,-Y
ST -X,R16 ;'g'-->($D0-1)
LD R16,-Y
ST -X,R16 ;取质量单位:($A1)-->$ce &($A2)-->$CF
LD R10,-Y ;取小数点位置:($A0)->R10
LP59: LDI R28,15
LP60: LD R16,Y
RCALL BTOA ;低位BCD变为ASCII码
LD R16,Y
RCALL BTOA0 ;高位BCD变为ASCII码
DEC R28
CPI R28,10 ;r11,12,13,14,15 都分解完毕?
BRNE LP60
DL30H: LDI R26,$C5
BRTC DL300 ;数据为负?
LDI R16,$2D
ST X,R16 ;负数加'-',送入$C5
CLT ;并清除负数标志
DL300: INC R26
LD R16,X
CPI R16,$30
BRCS DL300 ;去掉数据头无效的零ASCII码$30
DL301: CPI R16,$30
BRNE DLRT ;非零结束
INC R26
LD R16,X
CPI R16,$30
BRCS DLRT ;小于$30结束(质量单位 t)
CPI R16,$3A
BRCS DL302 ;大于$3A结束(质量单位kg)
DLRT: RET
DL302: DEC R26
LDI R16,$20 ;无效零充以空格
ST X+,R16
LD R16,X
RJMP DL301
BTOA0: SWAP R16
BTOA: ANDI R16,15
SUBI R16,$D0 ;加$30变为ASCII码
ST X,R16
DEC R26
DEC R10
BRNE BART
LDI R16,$2E ;加入小数点ASCII码
ST X,R16
DEC R26
BART: RET
PRAV: LDI R17,4 ;打印4组平均数据
MOV R0,R17
DEC R0
PRV: MOV R17,R0
LSL R17
LSL R17 ;组别序号之偏移量
LDI R26,$B0 ;TOTAL1首趾
ADD R26,R17 ;得到实际组别之首地址
LDI R28,16 ;将TOTAL取入 R12R13R14&R15
CLR R10
BRV: LD R16,X+
ST -Y,R16
OR R10,R16
NOC: CPI R28,12
BRNE BRV
TST R10
BREQ NBR ;TOTAL为零不打印!
BRV1: BST R12,7 ;数符位送入T
BRTC BRV2
LDI R26,16
RCALL NEG4 ;负数求补
BRV2: MOV R26,R0
LSL R26
SUBI R26,-$A6 ;取本组累加和之累加次数(第一组从$A6开始)
LD R11,X+
LD R10,X+
RCALL DIV24 ;计算平均值(在r13r14r15中)
CLR R7
MOV R8,R13
MOV R9,R14
MOV R10,R15 ;r11r12r13r14r15<--r7r8r9r10
RCALL BRDT ;二翻十,再将BCD码转为ASCII码,如为负数将'-'装入$c5!
LDI R26,$C5
LDI R16,$56 ;'V'
ST -X,R16 ;start from $c4!
LDI R16,$41 ;'A'
ST -X,R16
LDI R16,$2C ;','
ST -X,R16
MOV R16,R0 ;i(=1/2/3/4)
SUBI R16,$CF ;加上$31
ST -X,R16
LDI R16,$50
ST -X,R16 ;'P'
RCALL PR1 ;打印一行
NBR: DEC R0
BRNE PRV
RET
PRNO: RCALL FLSPC ;打印最大累加次数(整数),不加小数点
LDI R26,$CD ;存放ASCII码指针
LDI R28,$AE ;指向最大累加次数
LD R10,Y+
LD R9,Y ;最大累加次数取到R9R10
CLR R8
CLR R7
RCALL CONV1A ;二进制数变为BCD码
BRN: CLR R10 ;不加 '.'
RCALL LP59 ;转为ASCII码
LDI R26,$C4
LDI R16,$2E ;'.'
ST -X,R16
LDI R16,$4F ;'O'
ST -X,R16
LDI R16,$4E
ST X,R16 ;'N',加上‘NO.’后
RJMP PR1 ;打印
PRTL: LDI R17,4
MOV R0,r17 ;取序号之偏移量
DEC R0
PRL: MOV R17,R0
LSL R17
LSL R17 ;乘4:累加和为4字节
CLR R27
LDI R26,$B0 ;第一个累加和TOTAL1之首地址
ADD R26,R17 ;累加和之实际地址
CLR R15
LDI R28,11
BRL: LD R16,X+
ST -Y,R16
OR R15,R16
CPI R28,7
BRNE BRL ;累加和取到r7r8r9r10
NINC: TST R15
BREQ NBL ;累加和为零,不打印
BST R7,7
BRTC BRTL1
LDI R26,11
RCALL NEG4 ;累加和为负数,取补
BRTL1: RCALL BRDT ;BCD转为ASCII
LDI R26,$C5
LDI R16,$4C ;加'L'
ST -X,R16
LDI R16,$54 ;加'T'
ST -X,R16
LDI R16,$2C
ST -X,R16 ;加','
MOV R16,R0
SUBI R16,$CF ;i(=1/2/3/4)/加上$30变为ASCII码
ST -X,R16
LDI R16,$50
ST -X,R16 ;加'P'
RCALL PR1 ;打印一行累加和数据(一个TOTAL)
NBL: DEC R0
BRNE PRL ;共打印4行
RET
PR1: LDI R26,$C0 ;打印区首地址
CLR R27
LDI R16,$28 ;允许UART发送,允许发送寄存器空中断,8位数据
OUT UCR,R16
SEI ;使能总中断
RET
CONV1A: LDI R17,32 ;整数二翻十(最大$FFFFFFFF=4294967295)
MOV R0,R17
CLR R11
CLR R12 ;r11r12r13r14r15(BCD)<--(r7r8r9r10二进制)
CLR R13
CLR R14
CLR R15 ;十进制数存储区清除
CV1A: LSL R10
ROL R9
ROL R8
ROL R7 ;二进制数左移一位
MOV R16,R15
RCALL LSDAA
MOV R15,R16
MOV R16,R14
RCALL LSDAA
MOV R14,R16
MOV R16,R13
RCALL LSDAA
MOV R13,R16 ;十进制数带进位左移并调整
MOV R16,R12
RCALL LSDAA
MOV R12,R16
MOV R16,R11
RCALL LSDAA
MOV R11,R16
DEC R0
BRNE CV1A
RET
;范例61 ;格雷码与二进制数相互转换
GTB8: LDI R16,7 ;8格雷码(在R17中)翻为二进制数
CLR R15
LSL R17
ADC R17,R15 ;将左移移出位加到末位上
GB1: SBRC R17,0
SUBI R17,$80 ;Bi⊕G(i+1)-->B(i+1)
GB2: LSL R17
ADC R17,R15 ;将左移移出位加到末位上
DEC R16
BRNE BG1 ;循环7次,结束
RET ;二进制数在r17中
GTB9: LDI R16,8 ;9位格雷码(最高位在进位C,低8位在R17中)翻为二进制数
CLR R15
INC R15 ;1-->r15
ROL R17 ;9位格雷码带进位循环左移一位
GB90: ROL R17 ;the ORIGINAL highest bit->r17,1 AT THE FIRST!
SBRC R17,1
EOR R17,R15 ;Bi⊕G(i+1)-->B(i+1)
DEC R16
BRNE GB90
RET ;结果仍在进位C和r17中
BTG8: LDI R16,7 ;8位二进制数翻为格雷码
CLR R15
INC R15 ;1-->r15
CLC
ROL R17 ;0-->r17,0&B1-->C
BRCC BGLOP
INC R17 ;B1-->r17.0
BGLOP: ROL R17
BRCC BG4
EOR R17,R15 ;Bi⊕B(i+1)-->G(i+1)/FOR EXAMPLE:(1110-->1001)
BG4: DEC R16
BRNE BGLOP
RET ;结果在R17
AVR浮点程序库
;范例62
.ORG $A00
EXCH: MOV R5,R8 ;两浮点数交换子程序
MOV R8,R12
MOV R12,R5
EXCH1: MOV R5,R9 ;尾数交换
MOV R9,R13
MOV R13,R5
MOV R5,R10 ;双字节交换
MOV R10,R14
MOV R14,R5
MOV R5,R11
MOV R11,R15
MOV R15,R5
RET
DP: ANDI R16,$7F ;处理积/商数符,计算积/商阶码子程序
SBRC R9,7
SUBI R16,$80
SBRC R13,7
SUBI R16,$80 ;积/商符号放在r16,7
ADD R12,R8 ;移码相加(除数阶码已求补)
LDI R17,$80
BRCC DP1
ADD R12,R17 ;移码求和有进位,将和再加上$80,再有进位为溢出
RET
DP1: SUB R12,R17 ;移码求和无进位,将和减去$80,有借位
RET ;或差为0也为溢出
NEG3: COM R15 ;3字节数据求补
COM R14 ;先求反后加1
COM R13
INC3: LDI R17,255
SUB R15,R17 ;以减去-1代替加1
SBC R14,R17
SBC R13,R17
RET
;范例63 ;浮点数比较大小子程序 X1为被减数 X2为减数
FPCP: SBRC R9,7 ;X1为正,跳行
RJMP CP1
SBRC R13,7 ;X2为正,跳行
RJMP CP2 ;X1,X2异号
FPCP1: CP R11,R15 ;X1,X2皆为正,以尾数低位字节,中位字节,高位字节和
CPC R10,R14 ;阶码的顺序(按无符号数)进行比较
CPC R9,R13 ;不等,阶码大者浮点数值也大;只有阶码和尾数对应相等,
CPC R8,R12 ;两浮点数才相等
RET ;比较结果:Z=1时X1=X2,否则C=0时X1>X2,C=1时X1<X2
CP1: SBRC R13,7
RJMP CP3 ;两负数比较,转
CP2: CP R13,R9 ;正数与负数比较,只比较尾数高位字节即可
RET
CP3: CP R15,R11 ;X1,X2皆为负,以尾数低位字节,中位字节,高位字节和
CPC R14,R10 ;阶码的顺序(按无符号数)进行比较
CPC R13,R9 ;但要将X1、X2交换位置后按正数比较过程进行
CPC R12,R8
CP4: RET ;比较结果:Z=1时X1=X2,否则C=0时X1>X2,C=1时X1<X2
;范例64
FPSU: LDI R17,$80 ;浮点减法子程序
SUB R13,R17 ;减数数符求反后作为加数
FPAD: TST R8 ;浮点加法子程序
BREQ DON1 ;被加数为0,加数为和
TST R12
BRNE FPLAD ;加数为0,取被加数为和
SAV0: MOV R12,R8 ;传送被加数取代加数
MOV R13,R9
MOV R14,R10
MOV R15,R11
DON1: RET
FPLAD: ANDI R16,$3f ;清除被加数,加数数符
SBRC R9,7
ORI R16,$80 ;被加数数符取到(R16,7)
SBRC R13,7
ORI R16,$40 ;加数数符取到(R16,6)
LDI R17,$80
OR R9,R17
OR R13,R17 ;恢复尾数最高位
MOV R17,R12
SUB R17,R8 ;计算阶差
BREQ GOON ;两阶相等,转
BRCC NX3
NEG R17 ;不够减求补
CPI R17,24
BRCC EXAD ;|阶差|>24,取被加数为和
NX2A: LSR R13
ROR R14
ROR R15
DEC R17
BRNE NX2A ;加数阶小,右移加数对阶
MOV R12,R8 ;取被加数阶为和之阶
BRCC GOON
RCALL INC3 ;舍入移出位
RJMP GOON
NX3: CPI R17,24
BRCC COM1 ;阶差>24,取加数为和
LOOP: LSR R9
ROR R10
ROR R11
DEC R17
BRNE LOOP ;加数阶大,右移被加数对阶
BRCC GOON
RCALL INC3A ;舍入移出位
GOON: SBRC R16,6
SUBI R16,$80
SBRS R16,7 ;判别两数是否同号
RJMP SAMS ;同号转
SUB R15,R11 ;异号,执行减法,加数为被减数
SBC R14,R10
SBC R13,R9
BRCC NOM ;够减转
SUBI R16,$40 ;否则被减数数符求反为和之数符
RCALL NEG3 ;并将差求补
NOM: MOV R17,R13
OR R17,R14
OR R17,R15
BREQ DON0 ;差为0转
NMLOP: SBRC R13,7
RJMP COM1
LSL R15
ROL R14
ROL R13
DEC R12
BRNE NMLOP ;规格化
OV1: SEV ;阶码变为0,下溢(可取为0,不算溢出)
RET
SAMS: ADD R15,R11
ADC R14,R10
ADC R13,R9 ;两数同号,执行加法
BRCC COM1
ROR R13
ROR R14
ROR R15
INC R12 ;有进位时右规1次($7F+1=$80溢出)
BREQ OV1 ;阶码增1后变为0为上溢
BRNC COM1
RCALL INC3
COM1: CLV
SBRC R16,6
RET
COMA: LDI R17,$7F
AND R13,R17 ;正数数符为0
DON: RET
EXAD: RCALL SAV0 ;取被加数为和
SBRS R16,7
RJMP COMA ;配置数符
RET
DON0: CLR R12 ;浮点数为0
RET
;范例65 ;浮点乘法子程序
FPMU: TST R8
BREQ M0 ;被乘数为0,积为0
TST R12
BRNE M1 ;乘数为0,积也为0
M0: RJMP G0
M1: RCALL DP ;处理积符号,计算积之阶码
BRCS OV2
BREQ OV2 ;判断溢出
LDI R17,$80
OR R9,R17
OR R13,R17 ;恢复尾数最高位
MOV R5,R13
MOV R6,R14
MOV R7,R15 ;乘数转入R5,R6,R7
LDI R17,25 ;设右移部分积次数
CLR R13
CLR R14
CLR R15 ;r13r14r15清除,存放积
CLC
LOOP1: BRCC M2
ADD R15,R11
ADC R14,R10
ADC R13,R9 ;乘数右移移出位为1,被乘数加入部分积1次
M2: ROR R13
ROR R14
ROR R15
ROR R5
ROR R6
ROR R7 ;部分积连同乘数右移1位
DEC R17
BRNE LOOP1 ;尾数相乘计算完成?
SBRC R13,7
RJMP M3 ;乘积最高位为1 转
ROL R5
ROL R15
ROL R14
ROL R13 ;乘积最高位为0,高4位字节左移1位
SBRS R5,7
RJMP M5
RCALL INC3 ;末位字节舍入
BRNE M5
SEC ;舍入后R13变为0
ROR R13 ;将其改为$80(即0.5)
RJMP COM2
M5: DEC R12 ;舍入后R13不为0
BRNE COM2 ;阶码减1
OV2: SEV ;变为0为溢出
RET
M3: SBRC R5,7
RCALL INC3 ;乘积低3位字节舍入
COM2: LDI R17,$7F
SBRS R16,7
AND R13,R17 ;正数将符号位请除
DON2: CLV
RET
;范例66
FPDI: TST R12 ;浮点除法子程序
BREQ OV3 ;除数为0,溢出
TST R8
BRNE D1
RJMP G0 ;被除数为0,商为0
D1: NEG R12 ;除数阶码求补,以加补码代替减原码
RCALL DP ;处理商符号,计算商之阶码
BRCS OV3
BREQ OV3 ;判断溢出
LDI R17,$80
OR R9,R17
OR R13,R17 ;恢复尾数最高位
FPD3: LDI R17,25 ;左移相减试商25次,最后1次舍入
SUB R11,R15
SBC R10,R14
SBC R9,R13
BRCS D2 ;第一次尾数相减试商
INC R12 ;够减,商阶增1
SEC
BRNE D3 ;商阶增1后不为0,转计商;否则为溢出
OV3: SEV
RET
D2: ADD R11,R15
ADC R10,R14
ADC R9,R13 ;不够减则恢复被除数
LOOP2: LSL R11
ROL R10
ROL R9 ;被除数算术左移
BRCS D4 ;进位位为1,够减,本位商1
SUB R11,R15
SBC R10,R14
SBC R9,R13 ;否则相减试商
BRCS D2A
SEC
RJMP D3 ;够减,本位商1
D2A: ADD R11,R15 ;不够减,恢复被除数
ADC R10,R14
ADC R9,R13
CLC ;本位商0
RJMP D3
D4: SUB R11,R15
SBC R10,R14
SBC R9,R13 ;被除数减去除数
D3: DEC R17
BRNE D5 ;除法未完成,循环(1-1=0,不溢出)
MOV R13,R5
MOV R14,R6
MOV R15,R7 ;取回商
BRCC COM3
RCALL INC3 ;第25位商舍入($800000-$FFFFFF不溢出,故INC3不会溢出!)
COM3: LDI R17,$7F
SBRS R16,7
AND R13,R17 ;配置商数符
DON3: RET
D5: ROL R7 ;在R5,R6,R7中记商(不必预先清除)
ROL R6
ROL R5 ;商数左移1位并记商
RJMP LOOP2
;范例67
FPSQ: ANDI R16,$7F ;模拟手算开平方子程序
SBRC R13,7
ORI R16,$80 ;负数 建虚根标志
FPS0: TST R12
BREQ DON4 ;0的平方根为0
LDI R17,$80
OR R13,R17 ;恢复尾数最高位
LSR R12 ;阶码算术右移1位
BRCC FSQ2
INC R12 ;移出位舍入
RCALL INC3 ;先将位数增1(提前舍入)
BRCS FSQ1 ;C=1,不够减
SEC
ROR R13 ;若尾数变为0将其改为0.5($80-->r13)
RJMP FSQ2
FSQ1: LSR R13
ROR R14
ROR R15 ;否则将为数算术右移
FSQ2: LDI R17,25 ;开出25位根,末位舍入
MOV R8,R17
LDI R17,$40
ADD R12,R17 ;根恢复为移码
CLR R5
CLR R6
CLR R7 ;根扩展区清除
CLR R9
CLR R10
CLR R11 ;根存储区清除
FSQ3: SUB R13,R17
SBC R7,R11
SBC R6,R10
SBC R5,R9 ;试根
BRCS FSQ3A
SEC
RJMP FSQ4 ;够减,本位根1
FSQ3A: ADD R13,R17
ADC R7,R11
ADC R6,R10
ADC R5,R9 ;否则恢复开平方数之尾数
CLC ;本位商0
FSQ4: DEC R8
BRNE FSQ5 ;开出第25位根?
FQDON: MOV R13,R9
MOV R14,R10
MOV R15,R11 ;回送根尾数
BRCC COM4
RCALL INC3 ;第25位根舍入
COM4: LDI R17,$7F
AND R13,R17 ;根尾数为正数
DON4: RET
FSQ5: ROL R11
ROL R10
ROL R9 ;根尾数带进位左移,记根
LSL R15
ROL R14
ROL R13
ROL R7
ROL R6
ROL R5
LSL R15
ROL R14
ROL R13
ROL R7
ROL R6
ROL R5 ;开平方数之尾数连同扩展区左移2位
BRCC FSQ3 ;未产生进位,循环
RJMP FQDON ;否则进位为第25位根(不须试,并结束子程序)!
;范例68 ;牛顿迭代开平方子程序
FSQR: TST R12
BREQ SQRT ;0的平方根为0
ANDI R16,$7E
SBRC R13,7
ORI R16,$80 ;虚根标志
SBRC R12,0
INC R16 ;阶码为奇数
LDI R17,$7F
AND R13,R17 ;尾数变为正数
LSR R12
LDI R17,$40
ADC R12,R17 ;得到根之移码
PUSH R12 ;暂存
LDI R17,$80
MOV R12,R17
SBRC R16,0
INC R12 ;得到X1的阶码(0.5≤X1<2)
RCALL LD1 ;存 X1
LSR R13
ROR R14
ROR R15
LDI R17,$40
SBRS R16,0 ;阶码为奇数时算术右移尾数即得到X1之尾数;否则将其最
;高位字节加上$40
OR R13,R17 ;得到首次根r0=(1+x1)/2
LDI R17,3
MOV R0,R17 ;迭代3次
FSQLP: RCALL LD2
RCALL GET1
RCALL FPDI
RCALL GET2
RCALL FPAD
DEC R12 ;计算r(i+1)=(x1/ri+ri)/2
DEC R0
BRNE FSQLP ;r3的尾数为根之尾数
POP R12 ;取回根之阶码
SQRT: RET ;r16,7=1 为虚数根
;范例69 ;基本运算程序的演示程序
DMST1: .EQU SPL=$3D
.EQU SPH=$3E
LDI R16,2 ;high(ramend)
OUT SPH,R16
LDI R16,$5F ;low(ramend)
OUT SPL,R16
LDS R11,$60 ;r11,7:数符 r11,6 :阶符 r11,5--0:阶(最大为38)
LDS R12,$61 ;r12-r15:尾数
LDS R13,$62
LDS R14,$63
LDS R15,$64 ;尾数共8位BCD码
RCALL DTOB ;转为二进制浮点数
RCALL LD2 ;暂存
LDS R11,$65 ;r11,7:数符 r11,阶符 r11,5--0:阶(最大为38)
LDS R12,$66 ;r12-r15:尾数
LDS R13,$67
LDS R14,$68
LDS R15,$69
RCALL DTOB ;转为二进制浮点数
RCALL GET2 ;取第一操作数
RCALL FPAD ;调基本运算子程序之一(FPSU/FPMU/FPDI)
RCALL BTOD ;转回十进制浮点数
DMRET: RJMP DMRET
;范例70 ;辅助子程序
KP2: MOV R8,R12 ;复制第二操作数
MOV R9,R13
MOV R10,R14
MOV R11,R15
RET
LD1: STS $70,R12 ;存浮点数
STS $71,R13
STS $72,R14
SYS $73,R15
RET
LD2: STS $74,R12 ;存浮点数
STS $75,R13
STS $76,R14
STS $77,R15
RET
LD3: STS $78,R12 ;存浮点数
STS $79,R13
STS $7A,R14
STS $7B,R15
RET
GET1: LDS R8,$70 ;取浮点数
LDS R9,$71
LDS R10,$72
LDS R11,$73
RET
GET2: LDS R8,$74 ;取浮点数
LDS R9,$75
LDS R10,$76
LDS R11,$77
RET
GET3: LDS R8,$78 ;取浮点数
LDS R9,$79
LDS R10,$7A
LDS R11,$7B
RET
INVPI: LDI R17,$86 ;取浮点数180/л
MOV R8,R17
LDI R17,$65
MOV R9,R17
LDI R17,$2E
MOV R10,R17
LDI R17,$E1
MOV R11,R17
RET
G90: LDI R17,$87 ;取浮点数90
MOV R8,R17
LDI R17,$34
MOV R9,R17
CLR R10
CLR R11
RET
DTOR: RCALL PI18 ;角度化为弧度
RJMP FPMU
RTOD: RCALL INVPI ;弧度化为角度
RJMP FPMU
GHPI: LDI R17,$81 ;取浮点数л/2
MOV R8,R17
LDI R17,$49
MOV R9,R17
LDI R17,$0f
MOV R10,R17
LDI R17,$DB
MOV R11,R17
RET
G01: LDI R17,$7D ;取浮点数0.1
MOV R8,R17
LDI R17,$4C
MOV R9,R17
LDI R17,$CC
MOV R10,R17
LDI R17,$CD
MOV R11,R17
RET
G1: LDI R17,$81 ;取浮点数1
MOV R8,R17
CLR R9
CLR R10
CLR R11
RET
PI18: LDI R17,$7B ;取浮点数л/180
MOV R8,R17
LDI R17,$0E
MOV R9,R17
LDI R17,$FA
MOV R10,R17
LDI R17,$35
MOV R11,R17
RET
GINT: LDI R17,R12 ;浮点数取整
CPI R17,$81
BRCC GINT1
RCALL G0 ;阶码<$81,结果为0
RJMP KP2
GINT1: ANDI R16,$DD
SBRC R13,7
ORI R16,2 ;记数符
CPI R17,$98
BRCC GOVER ;阶码>$97,溢出
RCALL BRK ;分解出整数部分(在R9 R10 R11)
SBRS R16,1
RET ;正数返回
NEG3A: COM R11 ;负数求(r9 r10 r11)之补
COM R10
COM R9
INC3A: LDI R17,255
SUBI R11,R17
SBCI R10,R17
SBCI R9,R17 ;求反后加1
RET
GOVER: ORI R16,$20 ;设整数部分超过23位标志
RET
BRK: ANDI R16,$DF ;将正浮点数分解为整数/小数两部分
LDI R17,$80
OR R13,R17 ;恢复尾数最高位
CLR R9
CLR R10
CLR R11
MOV R17,R12
SUBI R17,$80
BREQ BRKRT
BRCS LOOPT
CPI R17,$19 ;整数部分超过24位
BRCC GOVER ;为溢出
LOOP4: LSL R15
ROL R14
ROL R13
ROL R11
ROL R10
ROL R9
DEC R17
BRNE LOOPT ;左移位数为阶码-$80,整数部分进入r9-r11中
BRKRT: RET
LOOPT: LSR R13 ;只有小数部分右移尾数($80-阶码)位
ROR R14
ROR R15
INC R17
BRNE LOOPT
RET
NRML: ANDI R16,$BF ;1字节正整数(在R13中)规格化为浮点数
CLR R14
CLR R15
LDI R12,$88 ;设阶码
RJMP NMLOP
G10: LDI R17,$84 ;取浮点数10
MOV R8,R17
LDI R17,$20
MOV R9,R17
CLR R10
CLR R11
RET
GLN2: LDI R17,$80 ;取浮点数ln2(=0.6931471806)
MOV R8,R17
LDI R17,$31
MOV R9,R17
LDI R17,$72
MOV R10,R17
LDI R17,$18
MOV R11,R17
RET
GLN10: LDI R17,$82 ;取浮点数ln10(=2.302585093)
MOV R8,R17
LDI R17,$13
MOV R9,R17
LDI R17,$5D
MOV R10,R17
LDI R17,$8E
MOV R11,R17
RET
INVX: TST R12 ;计算1/X, X=0时溢出
BRNE INV
OV4: SEV
RET
INV: RCALL G1 ;取1
RJMP FPDI
;范例71 ;用荷纳法计算多项式值子程序
FPLN1: ORI R16,$10 ;设计算奇函数(lnx,sinx,arcsinx 等)标志
RCALL LD3 ;存X
RCALL KP2
RCALL FPMU ;计算X2
RJMP FLN0 ;
FPLN2: ANDI R16,$EF ;设计算偶函数(EXP,COSX等)标志
FLN0: RCALL LD1 ;存T,T=X 或T=X2
POP R30
POP R31 ;系数表数据地址进入Z
LSL R30
ROL R31 ;由按字取数变为按字节取数
LPM ;r0<--(z)取阶码
MOV R8,R0
ADIW R30,1 ;指针增1
LPM ;取尾数高位字节
MOV R9,R0
ADIW R30,1 ;z+1
LPM ;取尾数中位字节
MOV R10,R0
ADIW R30,1 ;z+1
LPM ;取尾数低位字节
MOV R11,R0 ;取浮点数到r8 r9 r10&r11
ADIW R30,1 ;z+1
PLN: RCALL M1 ;计算(....((An*T+A(n-1))*T+A(n-2))*T+....+Ai)*T
LPM
MOV R8,R0
ADIW R30,1
LPM
MOV R9,R0
ADIW R30,1
LPM
MOV R10,R0
ADIW R30,1
LPM
MOV R11,R0 ;取A(i-1)
ADIW R30,1
RCALL FPLAD ;计算(....((An*T+A(n-1))*T+A(n-2))*T+....+Ai)*T+A(i-1)
LPM
RCALL GET1
DEC R0
BRNE PLN ;1为停止符号;否则继续计算
PEND: SBRS R16,4
RJMP REND
RCALL GET3 ;奇函数 取出自变量
RCALL M1 ;自变量乘以计算结果才是函数值
REND: LSR R31
ROR R30 ;Z指针折半后
ADIW R30,1 ;增1为后继指令地址
IJMP ;转到该地址去执行
;范例72
LNX: TST R12 ;对数函数子程序
BREQ OV5
SBRS R13,7
RJMP LN1
OV5: SEV ;求负数或0的对数为错误
RET
LN1: ANDI R16,$7E ;R16,7:(T-1)/(T+1)或(2T-1)/(2T+1)之符号 R16,0:p之符号
; m
MOV R0,R12 ;设X=2 *T, 则LnX=m*Ln2+LnT,存入p=m
LDI R17,$F3
CP R15,R17
LDI R17,$04
CPC R14,R17
LDI R17,$35
CPC R13,R17 ; _
BRCC LN5 ;T>√2/2时跳转
DEC R0 ;取p=m-1 LnX=(m-1)*Ln2+LN(2T)
MOV R17,R15
OR R17,R14
OR R17,R13
MOV R12,R17
BREQ LN5A ;2T-1=0 只须计算(m-1)Ln2
RCALL KP2 ;R12 NOUSED!
LSL R9
ROL R10
ROL R11 ;(2T-1)
LSR R13
ROR R14
ROR R15
LDI R17,$80
OR R13,R17 ;2T+1
LDI R17,$7E
MOV R12,R17 ;取1/(2T+1)的阶码
RJMP LNTLP
LN5: ORI R16,$80 ;(T-1)为负,数符位改为1
RCALL KP2
RCALL NEG3A
LDI R17,$80
ADD R9,R17 ;计算(T-1)
LSR R13
ROR R14
ROR R15
LDI R17,$C0
OR R13,R17
LDI R17,$7F
MOV R12,R17 ;取1/(T+1)的阶码
LNTLP: LSL R11
ROL R10
ROL R9 ;(2T-1)或(T-1)规格化
DEC R12 ;调整(2T-1)/(2T+1))或(T-1)/(T+1)的阶码
SBRS R9,7
RJMP LNTLP
RCALL FPD3 ;计算(2T-1)/(2T+1)或(T-1)/(T+1) 位r16,7为商之数符
PUSH R0
RCALL FPLN1 ;计算LnT或Ln(2T)
.DB $7E,$12,$49,$25 ;0.14285714 ;er.total<0.000000029!
.DB $7E,$4C,$CC,$CD ;0.2
.DB $7F,$2A,$AA,$AB ;0.33333333
.DB $81,$00,$00,$00 ;1
.DB $01,$00 ;结束符
INC R12
POP R0
LN5A: LDI R17,$80
ADD R0,R17
BREQ LN53 ;p=$80结束
BRCS LN51
NEG R0
INC R16 ;p为负数
LN51: RCALL LD1 ;存LnT或Ln(2T)
MOV R13,R0
RCALL NRML ;|P|规格化
RCALL GLN2 ;取ln2
RCALL FPMU ;计算|p|*ln2
RCALL GET1 ;取LnT或Ln(2T)
SBRS R16,0
RJMP LN52
RCALL FPSU ;p<0 计算lnT-|p|*ln2或Ln(2T)-|p|*ln2
RET
LN52: RCALL FPAD ;p>0 计算lnT+|p|*ln2或Ln(2T)+|p|*ln2
LN53: RET
;范例73 ;对数衍生函数子程序
LGX: RCALL LNX ;计算lnx
RCALL GLN10 ;取ln10
RCALL EXCH
RJMP FPDI ;转计算lgx=lnx/ln10
LGAX: RCALL LD2 ;存a
RCALL EXCH
RCALL LNX ;计算lnx
RCALL GET2 ;取a
RCALL LD2 ;存lnx
RCALL EXCH
RCALL LNX ;计算lna
RCALL GET2 ;转计算logax=lnx/lna
RJMP FPDI
;范例74
EXP: MOV R17,R12 ;指数函数子程序
CPI R17,$68 ;X之阶<$68
E1: BRCC E2
RCALL G0
ROR R12 ;(R12)=$80
INC R12 ;取exp=1
RET
E2: ANDI R16,$3F ;r16,6:数符
SBRC R13,7
ORI R16,$40 ;负数
LDI R17,$7F
AND R13,R17 ;取正(取|X|)
LDI R17,$33
CP R15,R17
LDI R17,$0F
CPC R14,R17
LDI R17,$30
CPC R13,R17
LDI R17,$87
CPC R12,R17 ;|X|与88.02969 比较
BRCS E3 ;|X|<88.02969 转
SBRS R16,6
RJMP OV6
G0: CLR R12 ;若x<-88.02969
CLR R13
CLR R14 ;Exp=0
CLR R15
RET
OV6: SEV ;x>88.02969,Exp溢出
RET
E3: CLR R0 ;X整数部分予清除
LDI R17,$81
MOV R8,R17
LDI R17,$38
MOV R9,R17
LDI R17,$AA
MOV R10,R17
LDI R17,$3B
MOV R11,R17 ;取log2e(=1/ln2)
RCALL FPMU ;计算X/ln2
LDI R17,$80
SBRC R16,6
OR R13,R17
MOV R17,R12
CPI R17,$81
BRCS E6 ;X/ln2整数部分为0 转
RCALL BRK ;否则分解该数为整数I(在R11),小数F两部分
LDI R17,$80
MOV R12,R17
RCALL NOM ;小数部分规格化为浮点数
SBRC R16,6
NEG R11 ;整数部分求补
MOV R0,R11 ;
E6: PUSH R0
RCALL FPLN2 ;计算EXP(F*ln2)
.DB $69,$5A,$92,$9F ;0.10178086 E-6 ;er.total<0.000000024
.DB $6D,$31,$60,$11 ;0.13215487 E-5
.DB $70,$7F,$E5,$FE ;0.15252734 E-4
.DB $74,$21,$84,$89 ;0.15403530 E-3
.DB $77,$2E,$C3,$FF ;0.13333558 E-2
.DB $7A,$1D,$95,$5B ;0.96181291 E-2
.DB $7C,$63,$58,$47 ;0.55504109 E-1
.DB $7E,$75,$FD,$F0 ;0.24022651
.DB $80,$31,$72,$18 ;0.69314718
.DB $81,$00,$00,$00 ;1
.DB $01,$00 ;结束符
POP R0
ADD R12,R0 ;整数部分I 加入阶码中
RET
;范例75 ;指数衍生函数子程序
DXP: RCALL GLN10 ;取ln10
RJMP EXP0 ;转计算EXP(X*ln10)
AXP: RCALL LD2 ;存X
RCALL EXCH
RCALL LNX ;计算lna
RCALL GET2 ;取出x
EXP0: RCALL FPMU
RJMP EXP ;转计算EXP(X*lna)
;范例76 ;双曲函数和反双曲函数子程序
SHX: RCALL SUB11 ;计算双曲正弦
RCALL FPSU
BRNE NX48
RET
CHX: RCALL SUB11 ;计算双曲余弦
RCALL FPAD
NX48: DEC R12
RET
SUB11: RCALL EXP
RCALL LD2
RCALL INVX
RJMP GET2
ASHX: RCALL SUB2 ;计算反双曲正弦
RCALL FPAD
ASH: RCALL FPSQ
RCALL GET2
RCALL FPAD
RJMP LNX
ACHX: RCALL SUB2 ;计算反双曲余弦
RCALL EXCH
RCALL FPSU
RJMP ASH
SUB2: RCALL LD2 ;存X
RCALL KP2
RCALL FPMU ;得到X2
RJMP G1 ;取浮点数1
; 范例77 ;正弦函数子程序
SINX: RCALL RTOD ;弧度化为角度
SINX1: CLR R16 ;X1为角度
SBRC R13,7
INC R16 ;存数符
LDI R17,$7F ;X1-->|X1|
AND R13,R17
NX30: RCALL G90
INC R8
INC R8 ;取360°
RCALL FPCP1 ;|X1|与360°比较
BREQ GE0 ;相等,转出
BRCC NX31 ;|X1|<360° 转出
RCALL EXCH
RCALL FPSU ;否则|X1|-360°-->|X1|
RJMP NX30 ;循环
NX31: DEC R8
RCALL FPCP1 ;|X1|与180°比较
BREQ GE0 ;相等,转出
BRCC NX32 ;|X1|<180°,转
RCALL EXCH
RCALL FPSU ;否则|X1|-180°-->|X1|
INC R16 ;将数符求反
NX32: RCALL G90
RCALL FPCP1 ;|X1|与90°比较
BRCC NX36
INC R8
RCALL FPSU ;|X1|>90°,取180°-|x1|-->|x1|
RJMP NX36
GE0: RJMP G0 ;|X1|=0 则sinX=0
NX36: RCALL DTOR ;变回弧度X
MOV R17,R12
CPI R17,$79 ;阶码<$79,sinX=X
BRCS PP2
RCALL FPLN1 ;计算sin|X|
.DB $60,$30,$92,$32 ; 0.16059044 E-9 er.total<0.0000000071
.DB $67,$D7,$32,$2A ;-0.25052108 E-7
.DB $6E,$38,$EF,$1C ; 0.27557319 E-5
.DB $74,$D0,$0D,$01 ;-0.19841270 E-3
.DB $7A,$08,$88,$88 ; 0.83333333 E-2
.DB $7E,$AA,$AA,$AA ;-0.16666667
.DB $81,$00,$00,$00 ;1
.DB $01,$00 ;结束符
PP2: LDI R17,$80
SBRC R16,0
PP3: OR R13,R17 ;配置数符
DON6: RET
;范例78 ;衍生三角函数子程序
CTNX: RCALL RTOD ;弧度化为角度
CTNX1: RCALL TANX1 ;计算tgX
RJMP INVX ;取倒数为ctgX
TANX: RCALL RTOD ;弧度化为角度
TANX1: RCALL LD2 ;存X
RCALL SINX1 ;计算sinX
RCALL GET2 ;取X
RCALL LD2 ;存sinX
RCALL EXCH
RCALL COSX1 ;计算cosX
BRNE NX39
OV7: SEV
RET ;cosX=0,溢出
NX39: RCALL GET2 ;取sinX
RJMP FPDI ;tgX=sinX/cosX
COSX: RCALL RTOD ;弧度化为角度
COSX1: RCALL G90 ;取浮点数90°
RCALL FPSU
RJMP SINX1 ;cosX=sin(90-X)
;范例79 ;反正弦函数子程序
ASINX: MOV R17,R12
CPI R17,$78
BRCS DON6 ;X阶码<$78,acrsinX=X
ANDI R16,8 ;清除数符和|X|>0.5标志,保留计算acosx标志(R16,3)
SBRC R13,7
INC R16 ;记数符
LDI R17,$7F
AND R13,R17 ;取绝对值 X-->|X|
RCALL G1
RCALL FPCP1
BREQ AA
BRCC AA1
OV8: SEV ;|X>1,溢出
RET
AA: RCALL GHPI
RCALL EXCH
RJMP PP2 ;|X|=1,arcsinX=±л/2
AA1: MOV R17,R12
CPI R17,$80
BRNE AS1 ;|X|<0.5,y=|x|
MOV R17,R13
OR R17,R14
OR R17,R15
BREQ AS1 ;X=0.5,y=|x|
ORI R16,$20 ;X>0.5,建标
RCALL NEG3
LDI R17,$80
ADD R13,R17
LDI R17,$7F
MOV R12,R17 ;((1-|x|)/2)方根之阶最大为$7F
NRMLP: LSL R15
ROL R14
ROL R13
DEC R12
SBRS R13,7
RJMP NRMLP ; __________
RCALL FPS0 ;√(1-|X|)/2-->y
AS1: RCALL FPLN1 ;计算arcsiny
.DB $7A,$3D,$43,$C4 ;0.11551801 E-1 er. total<0.0000000245
.DB $7A,$64,$CC,$CD ;0.13964844 E-1
.DB $7B,$0E,$27,$62 ;0.17352764 E-1
.DB $7B,$37,$45,$D1 ;0.22372159 E-1
.DB $7B,$78,$E3,$8E ;0.30381944 E-1
.DB $7C,$36,$DB,$6E ;0.44642857 E-1
.DB $7D,$19,$99,$9A ;0.075
.DB $7E,$2A,$AA,$AA ;0.16666667
.DB $81,$00,$00,$00 ;1
.DB $01,$00 ;结束符
SBRS R16,5
RJMP PP2 ;|x|≤0.5 转配置数符,有acsin|x|=acsiny
INC R12 ;否则取2arcsiny(=arccosx)
SBRC R16,3 ;测试计算ARCCOSX的标志
RJMP ACSRT ;有计算ARCCOSX标志,转清除该标志(其余计算在ACOSX子程序中完成)
RCALL GHPI ;否则取л/2
AS2: RCALL FPSU ;|X|>0.5时,arcsin|X|=л/2 -2arcsiny
PP20: RJMP PP2 ;转去配置数符
;范例80 ;函数值为弧度的反三角函数子程序
ACOSX: ORI R16,8 ;设计算arccosx标志
RCALL ASINX ;调反正弦函数子程序
RCALL GHPI ;取л/2
SBRC R16,3 ;计算ARCCOS|X|标志未被清除?
RJMP AS3 ;是,转计算arccosx=л/2-arcsinx
SBRS R16,0 ;x>0且x>0.5
RJMP ACSRT ;有arccosx=2arcsiny!
INC R8 ;否则取л;即当x<0且|X|>0.5时,有arccosX=л-2arcsiny
AS3: RCALL FPSU
ACSRT: ANDI R16,$F7 ;清除计算arccosx标志
RET
ATANX: MOV R17,R12 ;反正切函数子程序
CPI R17,$98
BRCS AT1
RCALL GHPI ;X阶码大于$98,取л/2
RCALL EXCH
ROL R9
BRCC AT2
LDI R17,$80
OR R13,R17 ;arctgx=л/2
AT2: RET
AT1: MOV R17,R12
CPI R17,$74 ;X阶码小于$74,arctgX=X
BRCS AT2
RCALL KP2
RCALL LD1 ;存X
RCALL FPMU
RCALL G1
RCALL FPAD ; _______
RCALL FPSQ ;计算 √(1+X2)
RCALL GET1
RCALL FPDI
RJMP ASINX ;转计算arctgx=arcsin(X/√<(1+X2)
ACTNX: RCALL ATANX ;反余切函数子程序
RCALL GHPI
RJMP FPSU ;arcctgX=л/2-arctgx
;范例81 ;函数值为角度的反三角函数子程序
ASNX: RCALL ASINX ;反正弦函数子程序,结果以角度表示
RJMP RTOD
ACSX: RCALL ACOSX ;反余弦函数子程序,结果以角度表示
RJMP RTOD
ATNX: RCALL ATANX ;反正切函数子程序,结果以角度表示
RJMP RTOD
ACNX: RCALL ACTNX ;反余切函数子程序,结果以角度表示
RJMP RTOD
;范例82 ;函数计算子程序演示程序
DMST2: LDI R16,2
OUT SPH,R16
LDI R16,$5F ;堆栈指针初始化
OUT SPL,R16
LDS R11,$65 ;取操作数(自变量X)
LDS R12,$66 ;r11,7:数符 r11,6:阶符
LDS R13,$67 ;r11,5--0:阶(最大为38)
LDS R14,$68
LDS R15,$69 ;r12-r15:十进制尾数(8位BCD码)
RCALL DTOB ;翻为二进制浮点数
RCALL LNX ;调函数子程序之一
RCALL BTOD ;将函数值转为十进制浮点数
DMHER: RJMP DMHER
;范例83 ;阶乘子程序
NP: RCALL G1 ;取浮点数1
MOV R17,R12 ;二进制整数N在R12中
CPI R17,2 ;N<2,N!=1
BRCS GG
CPI R17,34
BRCS NX59
OV9: SEV ;N>33,溢出
RET
GG: RJMP SAV0 ;取N!=1
NX59: MOV R0,R12 ;存N
DEC R0 ;N-1
LDI R17,1
PUSH R17 ;取T=1 并存入
LDI R17,$81
STS $70,R17
CLR R17
STS $71,R17
STS $72,R17
STS $73,R17 ;存储浮点数1
L43: POP R13 ;取T
INC R13 ;T+1-->T
PUSH R13 ;存T
RCALL NRML ;T规格化
RCALL GET1 ;取阶段阶乘结果
RCALL FPMU ;得到当前T!
RCALL LD1
DEC R0
BRNE L43 ;T=N时得到N!
POP R0
RET
;范例84 ;长整数(r9,r10,r11,r12)规格化为浮点数
LINOM: BST R9,7 ;数符存于T
BRTC LI10
CLR R16 ;负数求补
SUB R16,R12
MOV R12,R16
CLR R16
SBC R16,R11
MOV R11,R16
CLR R16
SBC R16,R10
MOV R10,R16
CLR R16
SUB R16,R9
MOV R9,R16
LI10: LDI R16,$A0 ;取阶32(长整数共32位)
LP10: SBRC R9,7
RJMP NX63 ;最高位为1,已规格化
LSL R12
ROL R11
ROL R10
ROL R9 ;否则左规1位
DEC R16 ;阶码减1
CPI R16,$80
BRNE LP10
RJMP G0 ;左规达32次,浮点数为0
;范例85 ;定点十进制数翻为二进制浮点数
DTOB1: RCALL LD1 ;存入十进制小数
RCALL CONV2 ;定点整数十翻二
RCALL GET1 ;取出十进制小数
RCALL LD1
RCALL SAV0
RCALL CONV4 ;定点小数十翻二
RCALL GET1 ;取出二进制定点整数
LDI R16,$98 ;予设阶码
LP11: SBRC R9,7
RJMP NX63 ;最高位为1,已规格化
LSL R15
ROL R14
ROL R13
ROL R12
ROL R11
ROL R10
ROL R9 ;整数和小数部分左移一位
DEC R16 ;阶码减1
CPI R16,$60
BRNE LP11
RET ;得到浮点数0
NX63: MOV R13,R9
MOV R14,R10
MOV R15,R11 ;尾数取到r13-r15
SBRS R12,7
RJMP PP6
RCALL INC3 ;尾数截去部分舍入
BRNE PP6
INC R16 ;尾数变为0将阶码增1
SEC
ROR R13 ;$80-->r13,即将尾数变为0.5
PP6: MOV R12,R16 ;取回阶码
BLD R13,7 ;装入数符(T-->R13,7)
RET
;范例86 ;浮点数十翻二
DTOB: ANDI R16,$FC ;r11,7:数符 r11,6:阶符 r11,5--0:阶(最大为38)
SBRC R11,6 ;R12---R15;8BCD码尾数
INC R16 ;阶符存于R16,0
SBRC R11,7
ORI R16,2 ;数符存于R16,1
MOV R17,R11
ANDI R17,$3F ;取阶
MOV R0,R17 ;存于R0
MOV R8,R12
OR R8,R13
OR R8,R14
OR R8,R15
BREQ PP8 ;十进制浮点数尾数为0,取二进制浮点数0
PUSH R16
RCALL CONV4 ;十进制浮点数尾数翻为二进制定点小数
MOV R16,R15
MOV R15,R14
MOV R14,R13
MOV R13,R12 ;二进制定点小数转入r13r14r15r16
LDI R17,$80 ;予设阶码
MOV R12,R17
LP14: SBRC R13,7
RJMP NX67
LSL R16
ROL R15
ROL R14
ROL R13
DEC R12
RJMP LP14 ;二进制定点小数规格化为浮点数
NX67: SBRS R16,7
RJMP NX66
RCALL INC3 ;调整
BRNE NX66
INC R12
SEC ;调整后结果为0将其改为0.5
ROR R13 ;即$80-->r13
NX66: LDI R17,$7F
POP R16
SBRS R16,1
AND R13,R17 ;配置数符
SBRS R16,0
RJMP DBL4 ;正阶转
DBL1: LDI R17,$10
SUB R0,R17
BRCS DBL2
RCALL INVDP ;
RCALL FPMU ;阶码减10, X*10ˉ1o -->X
RJMP DBL1
DBL2: ADD R0,R17 ;不够减则恢复阶
BREQ PP8
DBL3: RCALL G01 ;取0.1
RCALL FPMU
DEC R0 ;X*0.1-->X,阶减1
BRNE DBl3
RET
DBL4: LDI R17,$10
SUB R0,R17 ;阶减10
BRCS DBL5
RCALL DDP ;X*101o -->X
RCALL FPMU
RJMP DBL4
DBL5: ADD R0,R17 ;不够减则恢复阶
BREQ PP8
DBL6: RCALL G10
RCALL FPMU
DEC R0 ;X*10-->X,阶减1
BRNE BDL6
PP8: RET
INVDP: LDI R17,$5F ;取浮点数10ˉ1o
MOV R8,R17
LDI R17,$5B
MOV R9,R17
LDI R17,$E6
MOV R10,R17
LDI R17,$FF
MOV R11,R17
RET ;
DDP: LDI R17,$A2 ;取浮点数101o
MOV R8,R17
LDI R17,$15
MOV R9,R17
LDI R17,$02
MOV R10,R17
LDI R17,$F9
MOV R11,R17
RET
;范例87 ;浮点数二翻十
BTOD: TST R12
BREQ PP4 ;转取十进制浮点数0
ANDI R16,$FC ;予清十进制浮点数数符及阶符(r16,1&0)
CLR R0 ;予清十进制浮点数之阶
SBRC R13,7
ORI R16,2 ;取数符
LDI R17,$7F
AND R13,R17 ;取绝对值
BTA: RCALL DDP
RCALL FPCP1 ;|X|与101o 比较
BREQ BTB
BRCC BTC ;|X|<101o 转
BTB: RCALL INVDP
RCALL FPMU ;|X|*10ˉ1o-->|X|
LDI R17,$10
ADD R0,R17 ;十进制浮点数阶加10
RJMP BTA
BTC: RCALL INVDP ;
RCALL FPCP1 ;|X|与10ˉ1o 比较
BREQ BTC1 ;
BRCS BT0 ;|X|>10ˉ1o 转
BTE: RCALL DDP ;
RCALL FPMU ;|X|*101o -->|X|
LDI R17,$10
ADD R0,R17 ;十进制浮点数阶加10
ORI R16,1 ;置负阶
RJMP BTC
BTC1: LDI R17,9 ;|X|=10ˉ1o 特别处理
ADD R0,R17 ; -9
ORI R16,1 ;取0.1*10
SJMP BT4
BT0: RCALL G1
RCALL FPCP1 ;|X|与1比较
BREQ BT1
BRCC BT2 ;|X|<1转
BT1: RCALL G01
RCALL FPMU ;|X|*0.1-->|X|
INC R0 ;十进制浮点数阶加1
RJMP BT0
BT2: RCALL G01
RCALL FPCP1 ;|X|与0.1比较
BREQ BT4
BRCS BDS ;|X|≤0.1转出
BT3: RCALL G10
RCALL FPMU ;|X|*10--->|X|
INC R0 ;十进制浮点数阶加1
ORI R16,1 ;置负阶
RJMP BT2
PP4: RJMP KP2 ;十进制浮点数取为0
BT4: LDI R17,$10
MOV R9,R17
CLR R10
CLR R11
CLR R12 ;十进制浮点数尾数取为0.10000000
BT6: MOV R8,R0 ;取十进制浮点数阶
SBRS R8,3
RJMP BT7
SBRC R8,1
SUBI R8,$FA ;对产生非法BCD调整(加6)
BT7: LDI R17,$40
SBRC R16,0
OR R8,R17 ;配置阶符(r8,6)
LSL R17
SBRC R16,1
OR R8,R17 ;配置阶浮(r8,7)
RET
BDS: RCALL BT6 ;BT6将十进制浮点数阶,阶符和数符配置到R8
LDI R17,$80
OR R13,R17 ;恢复尾数最高位
LDI R17,$98
SUB R17,R12 ;右移次数为($98-阶码)
RJMP CONV31 ;调CONV31子程序完成尾数二翻十,结果在(r9r10r11r12)
;范例88 ;二进制浮点数快速翻为定点十进制数,整数在r9,r10,r11中,小数在r13,r14,r15中
FBTOD: RCALL BRK ;二进制浮点数分解为整数和小数两部分
SBRC R16,5
RET ;整数部分多于24位,溢出
MOV R0,R13
MOV R5,R14
MOV R8,R15 ;小数部分转入R0R5R8
RCALL CONV1 ;定点整数二翻十,结果在R12,R13,R14,R15
RCALL LD1 ;十进制整数-->RAM
MOV R15,R8
MOV R14,R5
MOV R13,R0 ;取回二进制小数
RCALL CONV3 ;定点小数二翻十,结果在r9,r10,r11,r12
RCALL EXCH1 ;十进制定点小数转入r13,r14,r15,r12
RCALL GET1 ;取出十进制定点整数r8,r9,r10,r11)/小数在r13,r14,r15,r12
CLR R16 ;清除无用的标志!
RET
;范例89
.ORG $E80 ;最小二乘法拟和直线子程序
.EQU NUMB=10 ;取10点,即十对浮点数,按增地址存放Y1,X1,Y2,X2,..Yn,Xn
.EQU TABLA=$9000 ;数据表,第一个浮点数为Y1
STRT: LDI R28,$70
CLR R29 ;POINT TO $0070
LP51: ST Y+,R29 ;累加和或暂存区清除(LD1,LD2,LD3,LD4和LD5子程序工作区)
CPI R28,$84
BRNE LP51
LDI R16,NUMB ;取拟合点数
MOV R0,R16
LDI R29,$90
CLR R28 ;参加拟合数据首地址$9000
IN R16,MCUCR,7
SBR R16,$C0 ;片外RAM,选一个读写等待周期
OUT MCUCR,R16
LOOP3: RCALL GETA ;取浮点数Yi 占4字节 即Yi0,Yi1,Yi2,Yi3
RCALL INVX ;计算1/Yi
RCALL LD6 ;暂存
RCALL GET1 ;取累加和 n
RCALL FPAD ;1/Yi加入累加和(∑1/Yi是 ∑1/Yi 简写形式,下同)
RCALL LD1 ; i=1
RCALL GET6 ;取1/Yi
PUSH R28
PUSH R29 ;保护堆栈指针
RCALL GETA ;取浮点数Xi(Xi0,Xi1,Xi2,Xi3)占4字节
POP R29
POP R28 ;恢复堆栈指针,仍指向Xi
RCALL FPMU ;计算Xi/Yi
RCALL LD7 ;暂存
RCALL GET2
RCALL FPAD ;Xi/Yi加入累加和∑(Xi/Yi)
RCALL LD2
RCALL GET7 ;取出Xi/Yi
RCALL SAV0 ;
RCALL FPMU ;计算(Xi/Yi)2
RCALL GET3
RCALL FPAD ;(Xi/Yi)2加入累加和∑(Xi/Yi)2
RCALL LD3
RCALL GET6 ;取1/Yi
RCALL SAV0 ;
RCALL FPMU ;计算1/Yi2
RCALL LD6 ;暂存
RCALL GET4
RCALL FPAD ;1/Yi2 加入累加和∑1/Yi2
RCALL LD4
RCALL GET6 ;取出1/Yi2
RCALL GETA ;再取Xi
RCALL FPMU ;计算Xi/Yi2
RCALL GET5
RCALL FPAD ;Xi/Yi2加入累加和∑Xi/Yi2
RCALL LD5
DEC R0 ;点数减1
BRNE LOOP3 ;未到总点数n,循环
RCALL GET4
RCALL SAV0
RCALL GET3
RCALL FPMU ;计算(∑1/Yi2)*(∑(Xi/Yi)2) 并存入
RCALL LD6
RCALL GET5 ;取出∑Xi/Yi2
RCALL SAV0
RCALL FPMU ;计算(∑Xi/Yi2)2
RCALL GET6
RCALL FPSU ;计算c=(∑1/Yi2)*(∑(Xi/Yi)2-(∑Xi/Yi2)2
RCALL LD6 ;存入
RCALL GET2
RCALL SAV0
RCALL GET4
RCALL FPMU ;计算(∑(Xi/Yi)*(∑1/Yi2)并存入
RCALL LD7
RCALL GET1
RCALL SAV0
RCALL GET5
RCALL FPMU ;计算(∑1/Yi)*(∑(Xi/Yi2) 并存入
RCALL GET7
RCALL FPSU ;计算d=(∑Xi/Yi)*(∑1/Yi2)-(∑1/Yi)*(∑Xi/Yi2))
RCALL GET6 ;取c
RCALL EXCH
RCALL FPDI ;计算b=d/c并存入
RCALL LD7
RCALL GET5 ;取 ∑Xi/Yi2
RCALL FPMU ;计算(∑Xi/Yi2)*b
RCALL GET1
RCALL FPSU ;计算(∑1/Yi)-(∑Xi/Yi2)*b
RCALL GET4 ;取 ∑1/Yi2
RCALL EXCH
RCALL FPDI ;计算a=(∑1/Yi-(∑Xi/Yi2)*b)/∑1/Yi2
RCALL LD6 ;结果a在$84-$87中,b在$88-$8b中
RER
GETA: LD R12,Y+
LD R13,Y+
LD R14,Y+
LD R15,Y+ ;从外部SRAM中取浮点数到R12-R15
RET
LD4: STS $7C,R12 ;存浮点数
STS $7D,R13
STS $7E,R14
STS $7F,R15
RET
LD5: STS $80,R12 ;计算∑Xi/Yi2的存储单元
STS $81,R13
STS $82,R14
STS $83,R15
RET
LD6: STS $84,R12 ;暂存1/Yi,1/Yi2等浮点数
STS $85,R13
STS $86,R14
STS $87,R15
RET
LD7: STS $88,R12 ;暂存Xi/Yi等浮点数
STS $89,R13
STS $8A,R14
STS $8B,R15
RET
GET4: LDS R8,$7C ;取浮点数
LDS R9,$7D
LDS R10,$7E
LDS R11,$7F
RET ;
GET5: LDS R8,$80 ;取∑Xi/Yi2或中间结果
LDS R9,$81
LDS R10,$82
LDS R11,$83
RET
GET6: LDS R8,$84 ;取浮点数1/Yi,1/Yi2等
LDS R9,$85
LDS R10,$86
LDS R11,$87
RET
GET7: LDS R8,$88 ;取浮点数Xi/Yi等
LDS R9,$89
LDS R10,$8A
LDS R11,$8B
RET
;范例90
GETAD: LDI R17,0Bxxx01110;PC0&PC4输入/PC1-PC3输出&PC3(CAL)
OUT DDRC,R17 ;
CBI PORTC,1
GAD1: SBI PORTC,4
SBIB PINC,4 ;查DRDY
RJMP GAD1 ;低为数据准备好
GAD2: SBI PORTC,4
SBIC PINC,4 ;PINC:$13/PORTB:$15
RJMP GAD2 ;DRDY低有效
CBI PORTC,2 ;置片选有效
LDI R16,16 ;16位数据
GETL0: CLC ;予清除C
SBI PORTC,0
SBIC PINC,0 ;接收一位数据
SEC
ROL R14 ;数据高位在前
ROL R13 ;在R13R14里带进位左移
SBI PORTC,1
CBI PORTC,1 ;发出时钟,下降沿读出数据
DEC R16
BRNE GETL0
SBI PORTC,2 ;置片选无效
MOV R4,R14 ;
MOV R3,R13 ;保存
GADCOM: CLR R15 ;3字节小数r13r14r15(0)规格化为浮点数
LDI R16,$80
MOV R12,R16 ;阶码为$80
GAD: SBRC R13,7
RJMP GETL2
LSL R14
ROL R13 ;尾数左移,阶码递减
DEC R12
BRNE GAD
RET ;如果(r12)=0 得到0浮点数
GETL2: LDI R16,$7F
AND R13,R16 ;正数
LDI R16,$82 ;取浮点数2.5(基准源为2.5v)
MOV R8,R16
LDI R16,$20
MOV R9,R16
CLR R10
CLR R11
RCALL FPMU ;相乘
RET ;(r12)不为0
; 以下提供几个补充参考程序,都带有详细说明和指令注释.它们是主从多机通讯程序,采
;用中断方式写入EEPROM,直接对晶振分频产生0.1秒和秒号的精确定时程序,以及RS-232/
;RS-485标准转换程序,AVR频率计程序,串行时锺日历芯片DS1302读写,共享时基的PWM输出、
;输入捕获测周期程序和定时信号获取,以及DS18B20测温等程序.多机通讯主要用8和9位数
;据模式区分被选分机(9位)和其它分机(8位),达到主机只与被选分机交换数据之目的.以中
;断方式写EEPROM的优点是可与系统运行同时进行(即在线写入),占用很少机时.
;精确定时用定时/计数器1(或0)直接对MCU主频(不设分频)设定时间常数,分频精度可达到
;1HZ.RS-232/RS-485标准转换程序中AVR不作中转,使两种器件相关脚位直接连接.以TCNT0
;定时,以T0引脚接收RS-232数据.以收到RS-232字符起始位下跳沿或结束符($03)为依据,
;控制切换RS-485的收发使能.(系统中的主AVR可兼做对通信标准之监控转换,即只是在完成
;主要工作任务的同时'附带'进行).具体过程不再细述.串行时锺日历芯片DS1302具体积小,
;可靠性高,与单片机连接方便等优点.
; 以下程序请参看有关章节或程序中的注释。
;范例91 ;多机通讯主机程序/晶振4MHZ
.ORG 0 ;以8/9位数据模式区分被选/未被选分机通讯
.EQU DTPINT=$180 ;UBRR=12 波特率19200(REL.ERR.=0.16%)
.EQU DRPINT=$1C0 ;主机对1#,2#,3#,4#分机发送数据块在$180-18F,$190-19F,$1A0-1AF)和$1B0-1BF
STRT38: RJMP RST38 ;主机从1#,2#,3#,4#分机接收数据块在$1C0-1CF,$1D0-1DF,$1E0-1EF)和$1F0-1FF
.ORG $00B ;
RJMP STRT38
.ORG $00C
RJMP STRT38 ;主机不设串口中断,只以查询接收
.ORG $011
RST38: LDI R16,12
OUT UBRR,R16 ;设波特率:[BAUD RATE=FCP/16(UBRR+1)]
CLR R15 ;初始化分机号
LDI R27,HIGH(DTPINT)
LDI R26,LOW(DTPINT);发送数据指针(首指$180)
LDI R29,HIGH(DRPINT)
LDI R28,LOW(DRPINT);接收数据指针(首指$1C0)
NEXTNO: LDI R16,$18
OUT UCR,R16 ;允许UART接收和发送,8位数据模式
INC R15 ;指向1#分机
OUTLP: OUT UDR,R15 ;呼分机号,1:1#/2:2#/03:3#/04:4#...
TSLOP: IN R16,USR
SBRS R16,7
RJMP TSLOP ;分机返回机号?
IN R16,UDR
CP R16,R15 ;分机号正确返回?
BRNE OUTLP
LDI R16,$1C ;改为9位数据模式 TXB8=0
OUT UCR,R16 ;
TXLOP: LD R16,X+
OUT UDR,R16 ;向分机发送数据块
TESTL: IN R17,USR
SBRS R17,5
RJMP TESTL ;等待发送完成
CPI R16,$0A
BRNE TXLOP ;
RXTST: IN R17,USR
SBRS R17,7 ;RXC=1 收到数据
RJMP RXTST ;等待接收分机返回数据块
IN R16,UDR
ST Y+,R16 ;存储接收数据
CPI R16,$0A ;分机数据块发完?
BRNE RXTST
MOV R16,R15
CPI R16,4 ;与分机轮询通讯完毕?
BRNE NEXTNO ;未完转对下一分机通信
HH38: RJMP HH38 ;否则踏步(可改为处理分机返回的数据,之后再进行下一个轮询)
.DSEG
.ORG $180
DTPINT:.BYTE $40
;$41 $45 $65 $73 $46 $42 $40 $6F $33 $44 $66 $5C $4D $4B $0D $0A
;$42 $4F $66 $78 $47 $45 $44 $63 $32 $48 $60 $7C $6D $45 $0D $0A
;$43 $56 $55 $53 $4D $4F $40 $2E $31 $42 $67 $4C $47 $4A $0D $0A
;$45 $54 $59 $63 $3D $4B $48 $2F $35 $48 $69 $3C $77 $43 $0D $0A
.ORG $1C0
DRPINT:.BYTE $40
;范例92
.ORG 0 ;多机通讯1#分机程序/晶振4MHZ
.EQU DTPIT1=$180 ;(UBRR)=12 波特率为19200(REL.ERR.=0.16%)
.EQU DRPNT1=$1C0
STRT39: RJMP RST39
.ORG $00B
RJMP UARXC ;8535UART接收完成中断
.ORG $00C
RJMP UATXC ;UART发送完成中断
.ORG $011
RST39: CLR R18 ;清除分机被选中(R18,6)和主机数据块接收完毕标志(R18,7)
LDI R16,12
OUT UBRR,R16 ;设波特率[BAUD RATE=4000000/16*(12+1)=19200]
LDI R16,HIGH(DRPNT1)
MOV R8,R16
LDI R16,LOW(DRPNT1)
MOV R9,R16 ;r8,r9:接收数据指针(FIRST POINT TO $1C0)
LDI R16,$98 ;允许UART中断接收,8位数据模式
OUT UCR,R16
SEI
RXDTS: SBRS R18,6 ;主机呼号已收到(若收到,在R17中)?
RJMP RXDTS
OUT UDR,R17 ;返还该机号
TXDON: IN R16,USR
SBRS R16,5
RJMP TXDON ;该机号发送完成?
LDI R16,$9C ; 允许UART中断接收,9位数据模式,TXB8=0
OUT UCR,R16
RCVBLK: SBRS R18,7
RJMP RCVBLK ;主机发来数据块已接收完毕?
LDI R16,HIGH(DTPIT1)
MOV R6,R16
LDI R16,LOW(DTPIT1)
MOV R7,R16 ;设发送数据指针r6r7,首指$180
LDI R16,$3C ;允许UART中断发送,9位数据模式,TXB8=0
OUT UCR,R16
TXDN: SBIC UCR,5
RJMP TXDN ;发送完毕?
RJMP RST39 ;
:UART中断接收程序
UARXC: SBIC USR,4
RETI ;祯错误(主机正与其它分机进行9位数据模式通信),不予接收
IN R14,SREG ;保存当前状态
TST R18
BREQ NUMB ;(R18)=0时收到数据,只可能是机号,转去核实
PUSH R16 ;否则为主机向本分机发来数据块(9位模式,机号已符合)
PUSH R26
PUSH R27
IN R17,UDR ;接收数据
MOV XH,R8
MOV XL,R9 ;取接收数据指针
ST X+,R17 ;转入RAM
MOV R8,XH
MOV R9,XL ;存数据指针
CPI R17,$0A ;是数据块结束符LF?
BRNE RSCOM1
SBR R18,$80 ;收到完整数据块标志
RSCOM1: POP R27
POP R26
POP R16
DRETI: OUT SREG,R14
RETI
NUMB: IN R17,UDR ;取出数据
CPI R17,1 ;是1#分机?2#分机与$02比较/3#分机与$03比较...
BRNE DRETI ;机号不符合,转!
SBR R18,$40 ;建机号符合标志
RJMP DRETI
; UART中断发送程序
UATXC: PUSH R16 ;r6 r7:发送数据指针,首指$180
IN R16,SREG
PUSH R16
PUSH R26
PUSH R27
MOV XH,R6
MOV XL,R7 ;取出发送指针
LD R16,X+ ;取数据,调指针
MOV R6,XH
MOV R7,XL
OUT UDR,R16 ;送入发送寄存器
CPI R16,$0A
BRNE SDCOM
CBI UCR,5 ;发送最后1个字符后,禁止发送寄存器空中断(CLR UDRIE)
LDI R16,HIGH(DRPINT)
MOV R8,R16
LDI R16,LOW(DRPINT)
MOV R9,R16 ;接收数据指针初始化(POINT TO $1C0)
SDCOM: POP R27
POP R26
POP R16
OUT SREG,R16
POP R16
RETI
.DSEG
.ORG $180
DTPIT1:.BYTE $40
.ORG $1C0
DRPNT1:.BYTE $10
;$41 $45 $65 $73 $46 $42 $40 $6F $33 $44 $66 $5C $4D $4B $0D $0A
;范例93
;以中断方式写入EEPROM(仅对8535,8515无此功能),克服查询方式占用过多机时的缺点,
;并可在线写入
;运作过程特点如下:
;(1)主程序初始化时设置EEPROM就绪(ready)中断使能位和中断总使能位
;(2)在主程序中写入第一个字节,写入完成后引起就绪中断,其他写入在中断服务中完成
;(3)本程序为一写入特例,写入地址为$100--$1FF,可作适当修改(如设块长计数器等)
;(4)为防止高优先级中断破坏写入过程,中断服务中不允许中断嵌套
;(5)本例为简化程序只以查询写入地址循环作为背景程序,实用时可改为具体的背景序
;(6)如能确信当前系统没有EEPROM正在写入,可删除对其进行查询部分.
STWEEP: LDI R16,HIGH(ramend)
OUT SPH,R16
LDI R16,LOW(ramend)
OUT SPL,R16
SBI EECR,3 ;设置EEPROM就绪(ready)中断使能位
SEI ;中断总使能
RJMP SRTW
.ORG $00F
RJMP EEPRDY ;8535 EEPROM就绪(ready)中断向量
SRTW: LDI YH,1
LDI YL 0 ;EEPROM 写入首地址:$100
LDI XL,$60 ;欲写入数据块首地址:$60
CLR XH
WEEP0: SBIC EECR,1 ;当前有EEPROM写入操作,有则等待写入完成
RJMP WEEP0
RCALL WREEP ;写入第一个字节,($60)->$100,写入完成后,EEWE=0时引发EEPROM就绪中断
INC YL ;调整写入地址指针
HHWEEP: TST YL
BRNE HHWEEP
CPI YH,2 ;写入地址达到$200后,写入完成
BRNE HHWEEP
CBI EECR,3 ;禁止EEPROM就绪(ready)中断
WDON: RJMP WDON ;踏步
EEPRDY: IN R6,SREG
PUSH R16
RCALL WREEP ;写入一个字节
INC YL
BRNE WRETI
INC YH ;EEPROM末地址为$1FF
WRETI: POP R16
OUT SREG,R6
RETI
WREEP: OUT EEARH,YH ;
OUT EEARL,YL ;写入地址送入EEAR
LD R16,X+ ;取数据,调指针
OUT EEDR,R16 ;数据写入EEPROM数据寄存器
SBI EECR,2 ;设置EEPROM写入总使能位EEMWE
SBI EECR,1 ;设置EEPROM写入使能位EEWE
RET
;范例94 ;精确定时产生0.1秒信号
;用定时/计数器1定时,不分頻定出0.1秒信号,由PC5脚输出正脉冲。
;晶体4.000119MHZ,计400012个数定出0.1秒信号
;对定时/计数器1重装常数进行加法补偿(扣除自然计数和补偿占用时间).
;加法补偿若产生进位,将中断次数减1
.ORG $000 ;精确定时产生0.1秒信号
STRT24: RJMP RST24
.ORG $006 ;8515 t1 overflow vector
RJMP T1_OVFL ;400012=65536*7-58740=7*$10000-$E574/故TCC=$E574
.ORG $00D
RST24: LDI R16,HIGH(ramend)
OUT SPH,R16
LDI R16,LOW(ramend)
OUT SPL,R16
SBI DDRC,5 ;PC5,0.1秒号输出(高有效)
CBI PORTC,5
LDI R16,1 ;不分頻
OUT TCCR1B,R16
LDI R16,$E5
OUT TCNT1H,R16
LDI R16,$74
OUT TCNT1L,R16 ;写入时间常数TCC
LDI R16,$80
OUT TIMSK,R16 ;允许定时/计数器1溢出中断
LDI R16,7 ;7次中断输出0.1秒号
MOV R6,R16
SEI ;中断总使能
HH1A: RJMP HH1A ;
T1_OVFL:PUSH R16
PUSH R17
IN R7,SREG
DEC R6 ;中断次数减一
BRNE GOON10 ;0.1秒时间到?
LDI R16,7
MOV R6,R16 ;重新装入中断次数
SBI PORTC,5 ;0.1秒号输出前沿
IN R17,TCNT1L ;*
IN R16,TCNT1H ;*读入TCNT1自然计数值
LDI R18,$7C ;*TCC=$E574
ADD R17,R18 ;*TCC+8=$E57C
LDI R18,$E5 ;*8条单周期补偿指令占用8个时钟周期
ADC R16,R18 ;*修正后TCC=$E574+(TCNT1)+8
OUT TCNT1H,R16 ;*
OUT TCNT1L,R17 ;*重新装入补偿修正后的TCC
BRCC GOON09
DEC R6 ;加法补偿若产生进位,将中断次数减1
GOON09: ;. ;数据处理略
;.
;.
;.
;.
RCALL ACLK1 ;0.1秒走时软时钟
RJMP GOON11
GOON10: CBI PORTC,5 ;输出信号后沿
GOON11: POP R17
POP R16
OUT SREG,R7
RETI
;范例95
;用定时/计数器1定时,不分頻定出1秒信号,由PC5脚输出正脉冲
;晶体4.000133MHZ,计4000133个数定出1秒信号
;对定时/计数器1重装常数进行加法补偿(扣除自然计数和补偿占用时间).
;加法补偿若产生进位,将中断次数减1
.ORG $000 ;精确定时产生秒号
STRT25: RJMP RST25
.ORG $006
RJMP T1_OVFB ;4000133=62*65536-63099=62*$10000-$F67B/故TCC=$F67B
.ORG $00D
RST25: LDI R16,HIGH(ramend)
OUT SPH,R16
LDI R16,LOW(ramend)
OUT SPL,R16
SBI DDRC,5 ;PC5输出秒信号(正脉冲)
CBI PORTC,5
LDI R16,1 ;不分頻
OUT TCCR1B,R16
LDI R16,$F6 ;
OUT TCNT1H,R16 ;写入TCC高8位
LDI R16,$7B ;
OUT TCNT1L,R16 ;写入TCC低8位
LDI R16,$80 ;
OUT TIMSK,R16 ;允许T/C1溢出中断
LDI R16,62 ;62次中断定出秒号
MOV R6,R16
SEI ;
HH1B: RJMP HH1B ;等待中断
T1_OVFB:PUSH R16
PUSH R17
IN R7,SREG
DEC R6 ;到62次中断?
BRNE GOON12
LDI R17,62
MOV R6,R17 ;重装中断次数
SBI PORTC,5 ;输出秒信号
IN R17,TCNT1L ;*
IN R16,TCNT1H ;*读入T/C1自然计数值
LDI R18,$83 ;*TCC=$F67B
ADD R17,R18 ;*TCC+8=$F683
LDI R18,$F6 ;*8条单周期补偿指令占用8个时钟周期
ADC R16,R18 ;*
OUT TCNT1H,R16 ;*
OUT TCNT1L,R17 ;*重新装入补偿修正后的TCC
BRCC GOON19
DEC R6 ;加法补偿若产生进位,将中断次数减1
GOON19: ;. ;数据处理略
;.
;.
;.
;.
RJMP GOON13
GOON12: CBI PORTC,5 ;秒号后沿
GOON13: POP R17
POP R16
OUT SREG,R7
RETI
;范例96
;AVR频率计程序
;运作特点如下:
;此程序为一完整频率测量显示程序,所测频率较高(2MHZ),使用4兆晶振
;程序兼有启动看门狗及对其管理功能
;以TCNT0精确定时输出秒号作为捕获信号,用TCNT1对被测信号频率计数
;用TCNT0直接对(8515)4兆晶振计数产生秒号,定时精度达1Hz 主常数选为256(即0)
;由PA0输出精确定时产生的秒信号(与ICP脚相连)捕获TCNT1计数值,相减计算频率
;将频率转换为十进制数,装入显示缓存区,调DSPA子程序显示之(参考范例27和图4-5)
;重装TCC时对TCC进行修正,若修正(减法)计算不产生借位,将中断次数n减1
;被测频率可近2兆,故须设1字节扩展计数器,以tcnt1溢出中断对其计数(共3字节计数器)
;在TCNT1捕获中断服务中,以3字节减法计算频率,并置位T标志;若TCNT1溢出标志置位
;必须提前增1扩展计数器,并将TCNT1溢出标志清除(不再增1扩展计数器),再计算频率.
;TCNT1溢出中断优先级高于TCNT0,故TCNT1中断服务可能影响秒号精度,导致测量误差
;可以排队法剔除坏值,即将几个连续采样按大小顺序排队,‘掐头去尾'只留中间再作平均.
;也可以监视LED显示,连续3秒稳定显示(高频测量允许有2Hz误差)即为所测频率正确值.
;若晶振采用12兆,被测信号频率(暂空比1:1或接近1:1)可接近6兆.
.ORG $000
STRT26: RJMP RST26 ;实测8515晶振频率4.000167MHZ 计4000167个数为1秒
.ORG $003
RJMP T1_CAPT ;T/C1捕获中断
.ORG $006
RJMP T1_OVRF ;T/C1溢出中断
.ORG $007
RJMP T0_OVFB ;T/C0溢出中断
.ORG $00D ;4000167=256*15626-89=256*$3D0A-89/故TCC=89 n=15626
RST26: LDI R16,HIGH(ramend)
OUT SPH,R16
LDI R16,LOW(ramend)
OUT SPL,R16
SBI DDRA,0 ;PA0输出秒定时信号,捕获频率计数值
CBI PORTA,0 ;初始为低
CLR R22
CLR R21
CLR R20 ;R20,R21,R22为频率量瞬时计数采样
CLR R2
WDR
LDI R16,$0D ;启动看门狗,溢出时间为0.49"
OUT WDTCR,R16 ;写入看门狗控制寄存器
CLR XH
LDI XL,$6C ;set the display buffer pointer
T26LP: ST X+,R2
CPI R26,$74
BRNE T26LP ;清除$6C--$73
LDI R16,$01 ;T/C0为定时器,不分频
OUT TCCR0,R16
LDI R16,89 ;
OUT TCNT0,R16 ;写TCC到TCNT0
LDI R16,$C6 ;上升沿捕获,允许噪音滤除,外部脉冲计数
OUT TCCR1B,R16
LDI R16,$8A ;允许T/C1捕获,溢出以及T/C0溢出中断
OUT TIMSK,R16 ;
LDI R16,$3E ;设15626(=$3D0A)次中断(高位字节已增1)
MOV R1,R16 ;
MOV R19,$0A ;
SEI ;
HH1C: BRTS HH2C ;已采集到频率?
RCALL DSPA ;仍显示原数据
RJMP HH1C
HH2C: CLT ;频率量已在R3,R4,R5
MOV R9,R3
MOV R10,R4
MOV R11,R5
RCALL CONV1 ;翻为十进制数(R12R13R14R15<--R9R10R11)
LDI XL,$74
CLR XH
LDI YL,15
CLR YH
HHLOP: LD R16,Y ;分解十进制数,送入LED显示区($6C--$73)
ADNI R16,$0F
ST -X,R16
LD R16,Y
SWAP R16
ANDI R16,$0F
ST -X,R16
DEC YL
CPI R26,$6C ;分解完毕?
BRNE HHLOP
RJMP HH1C ;显示新数据
T0_OVFB:SEI ;TCNT0溢出,允许中断嵌套
PUSH R16
IN R8,SREG
DEC R19
BRNE GOON13
CBI PORTA,0 ;秒信号后沿
DEC R1 ;到15626次中断?
BRNE GOON13
SBI PORTA,0 ;秒定时捕获信号前沿
IN R16,TCNT0 ;*读TCNT0自然计数值
SUBI R16,164 ;*89之补为167,考虑补偿操作本身耗时,减去164
OUT TCNT0,R16 ;*第15626次中断后,重新装入TCC=89+(TCNT0)+3到TCNT0
LDI R16,$3E
MOV R1,R16 ;重新装入中断次数
LDI R19,$0A
BRCC GOON13 ;补偿操作如有借位,将中断次数减1
DEC R19 ;->252 253 254 255 | 0 1 2 3 4 5...加法计数方向-->
GOON13: POP R16 ; | | | | | | | | | | |
OUT SREG,R8 ;<--15626次范围-->|<-15625次范围(补偿后进(借)位
;C=l)->
RETI
T1_OVRF:IN R18,SREG ;TCNT1溢出中断服务
INC R3 ;R3为TCNT1扩展字节
OUT SREG,R18
RETI
T1_CAPT:IN R6,SREG ;T/C1捕获中断
PUSH R16
IN R5,ICR1L
IN R4,ICR1H
MOV R16,R22
MOV R22,R5
SUB R5,R16
MOV R16,R21
MOV R21,R4 ;与上一次采集的频率量相减,得到频率值
SBC R4,R16
IN R16,TIFR
SBRS R16,7
RJMP T1CP1
INC R3 ;8515TCNT1溢出中断,预先对扩展字节计数
LDI R16,$80 ;并将溢出标志清除,(中断返回后不再计数)
OUT TIFR,R16 ;清除TIFR,7
T1CP1: MOV R16,R20
MOV R20,R3
SBC R3,R16 ;采集频率量在R3,R4,R5
SET ;建采集频率量标志
POP R16
OUT SREG,R6
RETI
;范例97 时基资源共享式综合测量系统
; 本时基资源共享式综合测量系统,具有精确定时PWM输出、输入捕获测外部信号
;周期、获取TCNT1溢出中断信号等多种功能。特点是TCNT1启动之后即不停运行。
; 时基资源共享式PWM的特点在于装入比较匹配寄存器之数据方式,它不是在比较
;匹配达到时清除定时/计数器,再装入高(或低)电平时间常数:而是当比较匹配
;达到时以定时/计数器当前值加上时间常数后将和装入比较匹配寄存器,二者效果
;是相同的。可称前者为静态设置,后者为动态设置。后者因不停运行定时/计数器
;,其资源可同时用于输出比较匹配A及B、输入捕获、定时信号输出等等。
; 本程序使用晶体标称值4MHZ实测为4,000,236HZ。使用定时/计数器1直接
;对主频精确定时设定PWM高低电平的维持时间。以ICP脚输入被测周期脉冲信号。
; 本程序PWM之暂空比与范例51相同,为5毫秒(高):10毫秒。故维持
;高电平的时间常数为4,000,236÷200=20,001,维持低电平的时间常数为
;4,000,236÷100=40,002。此即输出比较匹配A达到时交替写入比较匹配寄
;存器OCR1A之对TCNT1当前内容的超前值。
; 因以TCNT1直接对主频计数,频率高周期短,输入捕获的外部信号周期不能
;大于65536÷4,000,236=0.01638(秒)即16.38毫秒(但也不能太小,对频率
;较高的脉冲信号应改为测频率)。以相邻两次捕获值相减之差除以主频得到被测信
;号之周期(单位为秒)。
; 为避免小数除法运算,可将相邻两次捕获值相减之差先乘以1,000,再将乘积
;除以主频,将得到以毫秒为单位的周期值;考虑到除法子程序DIV16只实现整数
;除法,且除数不能大于65535,可将主频缩小100倍,即以40,002作除数,故
;除得之商扩大了100倍。这样将整数商二翻十后,其末两位皆为小数。本程序采用
;这种计算方法。并在主循环程序中调DSPA子程序显示所测周期值。。
; 若将以上算法中乘以1,000改为乘以10,000,并增加对商的万位转换,
;其余保留不变,则所得商数末3位皆为小数位。本算法精度高于上一种方法,如有
;提高测量精度之必要,应采用后种算法。
; 若扩大测量信号周期,应对TCNT1溢出信号计数,做3字节减法(见范例96)
;后再计算被测信号周期(除以4,000,236)。所测信号周期可达4.194秒。
; 本示例定时精度可与范例51做如下比较:本例中高低电平分别对主频计数
;20,001个和40,002个。范例51中高低电平分别对主频计数19,968个和
;40,000个。本示例定时精度明显高于范例51。
; 本示例TCNT1产生溢出中断之周期为16.38毫秒,其频率约为61HZ。在TCNT1
;溢出中断服务子程序中由PA3以正脉冲形式输出该信号。
.ORG $000 ;USE 8535
STRT43: RJMP RST43 ;5.0000MS(高):9.9999MS(低) 晶振4,OOO,236HZ
.ORG $005
RJMP T1_CP43 ;T/C1输入捕获中断
.ORG $006
RJMP T1_CA43 ;T/C1输出比较匹配A中断
.ORG $008
RJMP T1_OV43 ;TCNT1溢出中断
.ORG $011
RST43: LDI R16,HIGH(RAMEND)
OUT SPH,R16
LDI R16,LOW(RAMEND)
OUT SPL,R16
LDI R16,$80 ;T/C1比较匹配A达到时,清除输出脚OC1A
OUT TCCR1A,R16
LDI R16,$41 ;不分频,比较匹配达到不清TCNT1;上升沿捕获/禁止噪音滤除
OUT TCCR1B,R16
SBI DDRD,5
SBI PORTD,5 ;PD5(OC1A)初始化输出为高
SBI DDRA,3 ;PA3为TCNT1溢出中断信号输出
CBI PORTA,3 ;PA3输出为低
LDI R16,$4E
OUT OCR1AH,R16
LDI R16,$21 ;写比较匹配寄存器($4E21=20001脉宽5毫秒)
OUT OCR1AL,R16
LDI R16,$34 ;允许输入捕获/输出比较匹配A/TCNT1溢出中断
OUT TIMSK,R16
CLR R21
CLR R20 ;捕获值暂存单元
CLR XH
LDI XL,$6C
CLR43: ST X+,R20
CPI XL,$74
BRNE CLR43 ;清除显示区$6C--$73
SEI
HH43: RCALL DSPA ;背景程序:显示捕获频率信号之周期,单位:毫秒
BRTC HH43
RCALL FIL2 ;T=1,已捕获到数据在R4,R5/先关显示
CLT
MOV R14,R4
MOV R15,R5
LDI R16,3
MOV R12,R16
LDI R16,$E8 ;取立即数1000(=$3E8)
MOV R13,R16
RCALL MUL16 ;乘以1000
LDI R16,$9C ;使周期单位为毫秒
MOV R10,R16
LDI R16,$42 ;$9C42=40002
MOV R11,R16
RCALL DIV16 ;除以立即数40002,得到被测脉冲周期之单位为毫秒,且含因子100
MOV R16,R14
MOV R17,R15
LDI R18,3
LDI R19,$E8
RCALL CONVT ;二翻十,得千位
STS $70,R11 ;送入显示区
CLR R18
LDI R19,$64
RCALL CONVT ;二翻十,得百位
LDI R19,-$29 ;在百位处加小数点(百位实为个位)
SUB R11,R19
STS $71,R11 ;送入显示区
LDI R19,10
RCALL CONVT ;二翻十,得十位
STS $72,R11
STS $73,R17 ;小数送入显示区
RJMP HH43 ;转去显示新采样数据
CONVT: CLR R11
COVLOP:SUB R17,R19
SBC R16,R18 ;减去十进制数某位之权
BRCS CONVCM
INC R11 ;够减,增权
RJMP COVLOP
CONVCM:ADD R17,R19 ;否则恢复余数
ADC R16,R18
RET
T1_CA43:SEI
IN R1,SREG
IN R24,TCCR1A
SBRS R24,6
RJMP OUTLW ;当前输出低电平,转
IN R24,OCR1AL
IN R25,OCR1AH
SUBI R24,$DF ;LOW(-20001)
SBCI R25,$B1 ;HIGH(-20001)/$B1DF为20,001之补码
OUT OCR1AH,R25
OUT OCR1AL,R24 ;写入高电平维持时间超前值
LDI R24,$80 ;比较匹配A达到时,OC1A输出为低
OUT TCCR1A,R24
OUT SREG,R1
RETI
OUTLW: IN R24,OCR1AL
IN R25,OCR1AH
SUBI R24,$BE ;LOW(-40002)
SBCI R25,$63 ;HIGH(-40002)/$63BE为40,002之补码
OUT OCR1AH,R25 ;
OUT OCR1AL,R24 ;写入低电平维持时间超前值
LDI R24,$C0 ;比较匹配A达到时,OC1A输出为高
OUT TCCR1A,R24
OUT SREG,R1
RETI
T1_CP43:IN R3,SREG ;T/C1捕获中断
IN R5,ICR1L
IN R4,ICR1H
MOV R17,R21
MOV R21,R5
SUB R5,R17
MOV R17,R20
MOV R20,R4 ;与上一次采集的频率量相减,得到频率值
SBC R4,R17 ;在R4,R5中
SET ;建采集频率量标
OUT SREG,R3
RETI
T1_OV43:SEI
SBI PORTA,3 ;OUTPUT THE 61HZ PULS
SBI PORTA,3
SBI PORTA,3
SBI PORTA,3
CBI PORTA,3 ;脉冲宽度2微秒
RETI
;范例98
;智能型RS-232与RS-485标准转换程序
;MAX232'R1OUT接MAX483'DI/MAX483'RO接MAX232'T1IN
;由TCNT0配合PB0以软件接收RS-232数据 对485进行监控:PB1接DE和/RE
;AVR对485发来数据不接收,该数据经MAX483'RO->MAX232'T1IN-->RS-232远端
;数据起始位下降沿引起中断接收,中断服务一开始,将对RS-485的控制改为允发禁收使RS-
;232发来数据直接通过RS-485向远端发送
;当收到RS-232数据结束符$03后,经半位延时,对RS-485的控制改为允收禁发 使能接收RS-
;485远端发来数据(故要求经RS-232发来数据要以$03为结束符,对来自RS-485数据无此要求)
;可采用avr专门管理两种标准转换方案(可采用少脚ATtiny系列),也可采取主avr兼管方案.
;主avr兼管时,它既接收处理完整串行数据块(及执行其它程序),又控制通讯标准转换.
.EQU DATA4=$100
.ORG 0 ;R16:THE BIT SEQUENCE COUNTER R17:WORKING
;REG.R18:FLAG UNIT
STRT3S: RJMP RST3S ;BAUD RATE:9600 USE 8515/may REPLACE BY ATtiny serials
.ORG $007 ;$007(8515)
RJMP T0_OF
.ORG $00D
RST3S: LDI R17,HIGH(ramend)
OUT SPH,R17
LDI R17,LOW(ramend)
OUT SPL,R17
LDI R17,$02 ;8535:$01
OUT TIMSK,R17 ;timsk,1(允许tcnt0中断)
LDI R17,6 ;设外部脉冲计数
OUT TCCR0,R17
CBI DDRB,0 ;T0 为输入
LDI R17,$FF
OUT TCNT0,R17 ;计1个数即中断
SBI DDRB,1 ;PB1输出,控制DE和/RE
CBI PORTB,1 ;禁止485发送
SEI
CLR R18
CLR R16
HERE0: SBRC R18,0
BRNE RST3S ;无错误标志循环
SBRS R18,1
BRNE HERE0 ;未收到数据块结束符($03)循环
LDI R16,64
HERE1: DEC R16
BRNE HERE1 ;延时(48+3.5=)52微秒(超过半位,以等待半个停止位发过去)
RJMP RST3S ;以使远端485正确收到停止位
T0_OF: SBI PORTB,1 ;允许485发送
IN R11,SREG
PUSH R17
CPI R16,0 ;接收起始位?
BRNE T0SV11
LDI R17,2 ;YES
OUT TCCR0,R17 ;改为内定时,8分频(4MHZ/8)
LDI R17,232 ;半位定时常数24,定出48微秒(<52微秒)
OUT TCNT0,R17
RJMP T0SV7
T0SV11: CPI R16,1 ;半位定时后,查起始位有效性
BRNE T0SV12
SBI PORTB,0
SBIC PINB,0 ;低电平为有效
RJMP T0ER ;否则转错误处理
RJMP T0SV62 ;
T0SV12: CPI R16,10 ;停止位?
BRNE T0SV3S
CLR R16 ;是
SBI PORTB,0 ;停止位为l?
SBIS PINB,0
RJMP T0ER ;否,转错误处理
MOV R17,R15
CPI R17,3 ;收到结束符$03?
BRNE T0SV13
ORI R18,2 ;结束符收到
OUT TCCR0,R16 ;停止TCNT0
RJMP T0SV63
T0SV13: LDI R17,6
OUT TCCR0,R17 ;改为外定时
LDI R17,$FF ;停止位下降沿即中断
OUT TCNT0,R17
RJMP T0SV63
T0SV3S: BRCC T0ER ;出错(位计数器超过10)
CLC ;2--9:接收一位数据
SBI PORTB,0 ;本位为1?
SBIC PINB,0
SEC
ROR R15 ;接收数据组织到R15
T0SV62: IN R17,TCNT0 ;读入TCNT0自然计数值
INC R17
SUBI R17,52 ;1位时间常数为52
OUT TCNT0,R17 ;补偿后回送定时常数
T0SV7: INC R16 ;位计数器增1
T0SV63: POP R17
OUT SREG,R11
RETI
T0ER: SBR R18,1 ;出错标志 ERR. FLAG
CLR R16
OUT TCCR0,R16 ;停止TCNT0
RJMP T0SV63
;范例99
; 串行日历/时钟芯片DS1302的应用子程序。AVR与DS1302接口为:PC0--SCLK,PC1--DATA,PC2--/RST。请参看本范例之附图。
; 结构与运作特点如下:
;(1)采用标准频率晶体(32768HZ),便于调整(可加电容补偿),可对PC0/PC1/PC2加提拉电阻。
;(2)DS1302只有8只脚,小巧精悍,耗电省,抗干扰.便于与单片机接口,以串行方式按位读写数据.
;(3)以备用电池供电保存数据,断电后自动执行写保护,故可靠性高。上电后须用指令解除写保护。
;(4)片内除8个时钟日历单元外还有31个RAM单元,可作为系统断电保护数据存储单元
;(5)可以并发(BURST,即连续)方式读写8个时钟日历单元(秒/分/时/日/月/周/年/年)或读写31个RAM单元,
; 命令如下:
; $BE为以并发方式写8个时钟日历单元,$BF为以并发方式读8个时钟日历单元。
; $FE为以并发方式写31个RAM单元,$FF为以并发方式读31个RAM单元。
;(6)除以并发方式读写外,还可按字节读写,但读写前须先写入命令。
; 读写命令格式为:1 Y A4 A3 A2 A1 A0 X,最高位为1表示命令有效,Y=0,选择读写时间/日期
; Y=1,选择读写片内RAM,A4-A0,片内RAM/时钟单元地址,X=0,选择写操作,X=1,选择读
;操作.
;(7)串行时钟上升沿写入一位数据,下降沿读出一位数据;且读写只有在/RST信号为高时才有效。
; 故要求/RST信号有效前时钟信号应已就绪。
;(8)本程序AVR时钟为4MHZ,若使用其他时钟,重新调整读写延时时间(程序中NOP之个数)
;(9)对RAM并发读写方法可参考并发读写时钟日历子程序进行.
;1)并发(BURST)方式写时钟日历单元(时钟日历数据 秒,分,时,日,月,周,年,年分别在R8--R15,)
WBURST: CLR YH ;
LDI YL,8 ;数据指针,首指秒单元R8
RCALL DEPRV ;解除写保护(写入$8E00)
CBI PORTC,0 ;为上升沿写作准备(SCLK升高)
NOP
NOP
NOP
SBI PORTC,2 ;复位信号变高(SETB RST)
NOP
NOP
NOP
NOP
NOP
NOP
LDI R18,$BE ;BURST(wr.) ADDR.&INSTRUC.(命令$BE)
RCALL WBYTE ;
WLOP: LD R18,Y+
RCALL WBYTE ;写入1字节数据
CPI YL,16
BRNE WLOP ;数据都写完?
CBI PORTC,2 ;禁止读写
NOP
NOP
NOP
NOP
CBI PORTC,0
RET
;2)并发(BURST)方式读时钟日历单元(时钟日历数据 秒,分,时,日,月,周,年,
;分别读到R8--R14中)
RBURST: CLR YH ;首指R8
LDI YL,8
SBI DDRC,0 ;SCLK 输出
SBI DDRC,2 ;WR/RD ENABLE 输出
SBI PORTC,0 ;时钟SCLK初始输出为低
NOP
NOP
NOP
SBI PORTC,2 ;复位有效,允许时钟相关沿有效
NOP
NOP
NOP
NOP
NOP
NOP
LDI R18,$BF ;BURST(rd.) ADDR.&INSTRUC.
RCALL WBYTE ;写入并发读命令
RLOP: RCALL RBYTE ;读出一字节时钟/日历数据
ST Y+,R18 ;存储
CPI R28,15
BRNE RLOP ;数据都读完?
CBI PORTC,2 ;禁止读写
NOP
NOP
NOP
NOP
CBI PORTC,0 ;使SCLK变低
RET
;3)解除写保护子程序(对DS1302写入$8E,$00)
DEPRV: SBI DDRC,0 ;SCLK 输出
SBI DDRC,2 ;WR/RD ENABLE 输出
CBI PORTC,0 ;时钟SCLK初始输出为低
NOP
NOP
NOP
SBI PORTC,2 ;复位有效,允许时钟相关沿有效
NOP
NOP
NOP
NOP
NOP
NOP
LDI R18,$8E
RCALL WBYTE
NOP
NOP
CLR R18
RCALL WBYTE ;写入$8E和$00
CBI PORTC,2 ;禁止读写
NOP
NOP
NOP
NOP
CBI PORTC,0
RET
;4)对DS1302秒,分,时单元写入3字节数据
WTIME: CLR YH ;
LDI R17,$80 ;写秒单元命令
LDI YL,8 ;R8(秒)R9(分)R10(时)
LDI R19,3
WCOM: RCALL DEPRV ;解除写保护
WLOP1: CBI PORTC,0 ;时钟SCLK初始输出为低
NOP
NOP
NOP
SBI PORTC,2 ;复位有效,允许时钟相关沿有效
NOP
NOP
NOP
NOP
NOP
NOP
MOV R18,R17
RCALL WBYTE ;写入一字节命令
SUBI R17,$FE ;指向时间下一单元
LD R18,Y+
RCALL WBYTE ;写入时间单元1字节
CBI PORTC,2 ;禁止读写
NOP
NOP
NOP
NOP
CBI PORTC,0
DEC R19
BRNE WLOP1 ;写完规定字节?
RET
;5)写入日期子程序
WDATE: CLR YH ;
LDI YL,11 ;R11(日)R12(月)R13(周)R14(年)
LDI R17,$86 ;写日单元命令
LDI R19,4
RJMP WCOM
;6)读出时间子程序
RTIME: CLR YH ;
LDI R17,$81 ;读秒单元命令
LDI YL,8 ;读出数据送到R8(秒)R9(分)R10(时)
LDI R19,3
RCOM: SBI DDRC,0 ;SCLK 输出
SBI DDRC,2 ;WR/RD ENABLE 输出
RLOP1: CBI PORTC,0 ;时钟SCLK初始输出为低
NOP
NOP
NOP
SBI PORTC,2 ;允许读写
NOP
NOP
NOP
NOP
NOP
NOP
MOV R18,R17
RCALL WBYTE ;写入读命令
SUBI R17,$FE ;指向下一单元地址
RCALL RBYTE ;读出一字节数据
ST Y+,R18
CBI PORTC,2 ;禁止读写
NOP
NOP
NOP
NOP
CBI PORTC,0 ;时钟变低
DEC R19
BRNE RLOP1 ;已读出规定字节?
RET
;7)读出日期子程序
RDATE: CLR YH
LDI YL,11 ;读出数据放入R11(日)R12(月)R13(周)R14(年)
LDI R17,$87 ;读出日单元命令
LDI R19,4
RJMP RCOM
;8)将R18中数据写入DS1302
WBYTE: LDI R16,8 ;8位/字节
SBI DDRC,1 ;PC1为输出
WB1: CBI PORTC,0 ;时钟SCLK初始输出为低
ROR R18 ;一位数据传到进位C
BRCC WB10
SBI PORTC,1
RJMP WB2
WB10: CBI PORTC,1 ;1位数据输出到数据线(DS1302'DATA BUS)
WB2: NOP
NOP
NOP
NOP
SBI PORTC,0 ;上升沿写入一位
DEC R16
BRNE WB1 ;8位数据都写完?
RET
;9)读出DS1302一字节数据在r18中
RBYTE: LDI R16,8 ;8位/字节
CBI DDRC,1 ;PC1输入
RD1: CBI PORTC,0 ;下降沿读出一位数据
NOP
NOP
NOP
NOP
SBI PORTC,1 ;上拉电阻激活
CLC
SBIC PINC,1
SEC ;读出一位数据并-->C
ROR R18 ;组织数据
SBI PORTC,0 ;SCLK升高,为下位读准备
DEC R16
BRNE RD1 ;8位数据都写完?
RET
;范例100 ;DALLAS 18B20测温程序
; DS18B20为美国DALLAS公司(已被MAXIM公司并购)生产的单线数字温度传感器,
;可将温度信号直接转换成数字信号供单片机处理,所测温度范围-55°C~125°C,精度
;达0.5°C,转换时间为750毫秒。该器件出厂时带有固化的8字节‘身份’编号,最低
;位字节为家族号码$28,接下来6字节为器件流水线编号,最高位字节为CRC校验码。
;有读ROM,匹配ROM,启动温度变换,读RAM数据等十余种命令对18B20操作。使用
;18B20之前要用读ROM命令读出其身份编号并记录。一条单总线上可挂接任意多个
;18B20,单片机通过单总线发出启动转换命令之后,所有18B20同时进行温度转换。
;经等待延时后,单片机通过发出匹配ROM命令,18B20编号,读RAM数据等命令等,
;读取各18B20温度数据组(每组数据共9字节)。程序中对每组数据都进行CRC校验。
;温度数据占2字节,为补码形式。最高位为符号位,0为正1为负。高位字节和低位
;字节的高4位为温度整数部分,最低4位为温度小数部分。程序中对温度数据进行取
;补、左移将整数部和小数部分分离,再将它们分别转成十进制数。整数二翻十用减
;十进一法,小数二翻十采用按权累加法(并以减负替代加正),再将它们冠以数符
;并加小数点送入DSPA子程序的显示缓存区,调该子程序进行显示。
; 由于DSPA子程序中含0.462秒定时复位看门狗指令,故以调用DSPA为主循环程序
;不必考虑对看门狗管理问题(初始化设置看门狗溢出周期为0.49秒)。
; DS18B20不象一般串行器件既有数据线又有时钟线,它只有一条数据线,故它
;只能靠较严格的时序脉冲信号进行读写,程序中多种延时环节就是为调整时序所
;设。本程序AVR使用4MHZ时钟,如改变时钟,应按定时时间重新确定延时常数。
; 18B20的使用可采用窃电方式,此种方式要将18B20电源端接地。在线缆长测点
;的应用场合,可控制MOS管取得数据线的强上拉,以提高总线驱动能力。
;对18B20的ROM操作命令如下:
; 命令 代码
; 读ROM $33
; 匹配ROM $55
; 跳过ROM $CC
; 搜索ROM $F0
; 告警搜索 $EC
; 对18B20的存储器操作命令如下:
; 命令 代码
; 写暂时存储器 $4E
; 读暂时存储器 $BE
; 复制暂时存储器 $48
; 启动温度变换 $44
; EEPROM内容调出 $B8
; 读电源 $B4
; 有关18B20初始化,读写命令,读写时序等请参看参考文献9和10,18B20与AVR接口
;见程序附图,CRC检测请参看4.8.4小节。
START2:LDI R16,2
OUT SPH,R16
LDI R16,$5FH
OUT SPL,R16 ;堆栈指针初始化
SBI DDRA,2
CBI PORTA,2 ;MOS管不上拉
RCALL RESET ;复位18B20
WDR
LDI R16,$0D
OUT WDTCR,R16 ;启动看门狗,溢出时间为0.49秒
CLR R2 ;执行请除看门狗指令WDR的定时器初始化请除
LDI R16,$CC ;跳越ROM(SKIP ROM)
RCALL WB
LDI R16,$44 ;START DS18B20 TEMPORATURE CONVERTING
RCALL WB
CLR XH
CLR YH ;指针高位字节清除
LDI YL,$6C
CLR44:ST Y+,YH
CPI YL,$74
BRNE CLR44 ;清除显示缓存区($6C~$74)
LDI R17,163 ;4.618×163=753(ms)
STR0: RCALL DSPA
DEC R17
BRNE STR0 ;总共延时753ms,等待转换完成
RCALL RESET ;再次复位DS18B20
LDI XL,$60 ;温度数据指针
LDI R17,4 ;总共4只DS18B20
LDI ZH,HIGH(DATA*2)
LDI ZL,LOW(DATA*2);18B20身份数据指针
LOOP0:LDI R16,$55 ;匹配ROM命令 (match rom)
RCALL WB ;写入18B20
LDI R18,8 ;18B20身份数据共8个字节固化在FLASH中
LOOP4:LPM ;取数据
MOV R16,R0 ;转入R16
RCALL WB ;写入18B20 1字节
ADIW ZL,1 ;指向下一字节
DEC R18
BRNE LOOP4 ;共写入8个字节
LDI R16,$BE ;读18B20数据存储器命令
RCALL WB ;写入该命令
LDI YL,$74
LOP40:RCALL RB ;读出18B20数据共9个字节
ST Y+,R16 ;存入$74-$7C
CPI YL,$7D
BRNE LOP40
RCALL RESET ;再次复位18B20
LDI YL,$74
RCALL CRC9 ;对读得数据进行CRC校验
TST R15
BREQ LLL
ERROR:LDI R16,15 ;CRC余式不为零,温度数据错误
LDI YL,$6C
EER1: ST Y+,R16
CPI YL,$74
BRNE EER1
ERR1: RCALL DSPA ;显示$FFFFFFFF,等待按键
SBRC R16,7
RJMP ERR1
RJMP START2 ;有键按下,重新启动
LLL: LDS R16,$74
LDS R15,$75 ;取温度数据 R15为HIGH BYTE
ST X+,R16
ST X+,R15 ;温度转入SRAM
BST R15,7 ;数符存于T
BRTC PLUS ;正数转
COM R16
COM R15
LDI R18,255
SUBI R16,R18
SBCI R15,R18 ;负数求补
PLUS: LDI R18,4
LOOP5:ADD R16,R16
ADC R15,R15
DEC R18
BRNE LOOP5 ;整数部分在R15
MOV R19,R16 ;小数部分转入R19
CLR R9 ;百位BCD予清
LDI R16,100
CP R15,R16
BRCS LOP51
INC R9 ;百位BCD存在(EXISTED)!
SUB R15,R16 ;减去100
LOP51:LDI R16,10
CLR R10
LOP52:SUB R15,R16
BRCS LOP53
INC R10
RJMP LOP52 ;十位及个位BCD转换
LOP53:ADD R15,R16 ;十位在R10,个位在R15
CLR R16
SBRC R19,7
SUBI R16,-$50 ;小数最高位值为0.5
SBRC R19,6 ;其余折半递减
SUBI R16,-$25 ;0.25
SBRC R19,5
SUBI R16,-$13 ;0.125
SBRC R19,4
SUBI R16,-6 ;0.0625
CPI R16,$0A ;产生非法BCD?(只可能在低位产生)
BRHC LOP54
SUBI R16,$FA ;小数部分二翻十/调整(在R16中)
LOP54:MOV R11,R16
LDI YL,$6C
LDI R16,$24
ST Y+,R16
ST Y+,R16
ST Y,R16
RTC LOP55
LDI R16,$14 ;负温度,加负号!
ST Y,R16
LOP55:INC YL
ST Y+,R9 ;百位BCD装入 $6F 单元
ST Y+,R10 ;十位BCD直接装入$70单元
MOV R16,R15
SUBI R16,-$29 ;个位BCD加小数点后
ST Y+,R16 ;装入$71单元
MOV R16,R11
SWAP R16
ANDI R16,$0F
ST Y+,R16
MOV R16,R11
ANDI R16,$0F
ST Y+,R16 ;分解小数BCD/并装入$72及$73单元
CLR R8
NORML:RCALL DSPA ;显示温度数据2.4秒
RCALL DSPA ;4.62ms×2×256=2.4s
DEC R8
BRNE NORML
DEC R17
BREQ HALT ;采集完4点温度?
RJMP LOOP0 ;未完循环
HALT: LDI R16,$1D
OUT WDTCR,R16
LDI R16,$15
OUT WDTCR,R16 ;已采集到4点温度,关看门狗
RDSPA:RCALL DSPA
SBRC R16,7
RJMP RDSPA ;无键按下,显示最后采集的温度
RJMP START2 ;否则再次启动
DATA: .DB $28,$3A,$13,$08,$00,$00,$00,$E5 ;18B20身份数据
.DB $28,$4A,$4D,$08,$00,$00,$00,$14
.DB $28,$3A,$19,$08,$00,$00,$00,$5E
.DB $28,$32,$33,$08,$00,$00,$00,$66
RESET: SBI DDRA,3 ;PA3为输出
CBI PORTA,3 ;负脉冲前沿
LDI R19,4
RES1: RCALL DL170
DEC R19
BRNE RES1 ;延时682.75微秒 (最短可555微秒)
SBI PORTA,3 ;负脉冲结束
LDI R18,146
RES2: DEC R18
BRNE RES2 ;延时110微秒
RCALL DL170 ;总共280微秒
CBI DDRA3 ;转为输入(CHANGE TO INPUT)
SBI PORTA,3 ;上拉电阻激活(PULL UP MOS ACTIVED)
CLC
SBIC PINA,3 ;18B20存在标志存于 C
SEC
RCALL DL170 ;再次延时
RET
DL170: LDI R18 ,224 ;延时170.75微秒(含RCALL和RET时间)
LP170: DEC R18
BRNE LP170
RET
WB: LDI R19,8 ;写入1字节数据
MOV R15,R19
SBI DDRA,3
LOOP2: CBI PORTA,3 ;数据线输出为低
LDI R19,23
LOP21: DEC R19
BRNE LOP21 ;延时17微秒
ROR R16
BRCC LOP22 ;1位数据由进位C转入PC3
SBI PORTA,3
RJNP LOP23
LOP22: CBI PORTA,3
LOP23: LDI R19,88
LOP24: DEC R19
BRNE LOP24 ;延时66微秒
SBI PORTA,3
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
DEC R15
BRNE LOOP2
RET
RB: LDI R19,8 ;读出1字节数据
MOV R15,R19
LOOP3: SBI DDRA,3
SBI PORTA,3 ;数据线输出为高
LDI R19,5
LOP31: DEC R19
BRNE LOP31 ;延时3.5微秒
CBI PORTA,3 ;数据线输出为低
LDI R19,6
LOP3A:DEC R19
BRNE LOP3A ;延时4.5微秒
SBI PORTA,3 ;数据线输出为高
LDI R19,26
LOP32: DEC R19
BRNE LOP32 ;延时19微秒
CBI DDRA,3 ;转为输入
SBI PORTA,3 ;上拉MOS管激活
CLC
SBIC PINA,3
SEC ;读出1位数据到C
LDI R19,88
LOP33:DEC R19
BRNE LOP33 ;延时66微秒
ROR R16
DEC R15
BRNE LOOP3
RET
CRC9: LDI R18,9 ;9字节数据CRC检测程序
CRC90: CLR R15 ;异或工作单元
LDI R19,$8C
MOV R14,R19
LP6: LDI R19,8
LD R16,Y+
LP7: LSR R16
ROR R15
BRCC NXRL
EOR R15,R14
NXRL: DEC R19
BRNE LP7
DEC R18
BRNE LP6
RET
;范例101 产生循环冗余检测(CRC)校验码表格子程序
;本子程序为生成$00--$FF共256个数据之双字节CRC校验码表子程序,生成多项式为
;P(X)=X16+X15+X2+1=$18005。因每一字节都生成两字节的CRC校验码,故CRC校
;验码表格长度为512字节。程序中规定将其放在片内SRAM$100--$2FF之中。也可将该
;表存放地址作为子程序的入口条件,在主程序中规定存放地址。使用的单片机为MEGA8
;/16/128;若使用8515单片机,须使用外部扩展SRAM;本子程序产生的CRC校验码表,
;可直接烧录到FLASH,或另行作为文件保存。
;若采用4字节的CRC校验码,表格长度达1024字节,则必须使用MEGA103/128等高档AVR
;单片机,或外扩SRAM的8515;故若处理的位序列信息不是很长,或对CRC检测的实时性
;要求不是很强,不必采用查表处理方式。
CRCTABL:LDI XH,$01 ;CRC-CODE-TABLE -GENERATING SUBPROGRAM
CLR XL ;CRCTABLE FROM $100 TO $2FF
CLR R16 ;USE MEGA8/16/128
LDI R17,$05
LDI R18,$80 ;P(X)=$18005
CRCT0: LDI R19,8
CLR R14
CLR R15 ;add 2bytes $00 behind a Bi
CRCT1: LSL R14
ROL R15
ROL R16
BRCC CRCT2
EOR R14,R17
EOR R15,R18
CRCT2: DEC R19
BRNE CRCT1
ST X+,R14
ST X+,R15
INC R16
BRNE CRCT0
RET
;范例102 快速生成位序列校验码/或对接收位序列进行循环冗余检测子程序
;100字节位序列m0,m1,m2,m3,m4,...m98,m99在发送方以递推方式生成CRC校验码子程序
;或在接收方对该序列进行CRC检测之子程序
;在发送方,本程序为CRC校验码生成子程序。将此位序列除以生成多项式P(X)
;=X16+X15+X2+1,将生成的CRC校验码(即余式)装入位序列的最低两位字节
;(冲掉m0,m1),将最终处理的位序列发送出去。
;在接收方,本程序为CRC检测子程序。将接收到的位序列除以生成多项式P(X)
;=X16+X15+X2+1,若将原位序列最低两位字节m0,m1恢复(即除得的余式R15R14
;与原始位序列最高两位字节相等),则为正确接收。
;本程序中循环次数为98,比位序列字节数少2。因为位序列最低两个字节m0,m1直
;接作为(第一个)余式,不对它们查取CRC校验码。
;X为按字节寻址位序列指针
;寻址CRC校验码表格先按字计算地址指针,将其增倍后变为按字节寻址。
CRCOUT:LDI XH,$1 ;THE BIT SEQUENCE IS IN $100---$163
CLR XL ;TOTAL 100 BYTES
LDI R16,$62 ;THE DATA BLOCK LENGTH IS 98(=100-2)
LD R14,X+ ;m0
LD R15,X+ ;m1
CRCO1:LD R13,X+ ;fetch m2 at the first!
LDI ZH,HIGH(DATA5)
LDI ZL,LOW(DATA5)
ADD R30,R13
CLR R13
ADC R31,R13
LSL R30
ROL R31 ;point to the CRC CODE!
LPM
EOR R14,R0
ADIW R30,1
LPM
EOR R15,R0 ;CRC CODE IN R14&R15(HIGH)!
DEC R16
BRNE CRCO1
STS $101,R15
STS $100,R14 ;将生成的CRC校验码放在位序列的最低两位字节中
RET ;或将原始位序列的最低两位字节恢复
DATA5:.DB $00,$00,$80,$05 ;THE CRC CODE TABLE
.DB $80,$0F,$00,$0A ;与范例101中SRAM$100--$2FF单元内容完全相同!
.DB $80,$1B,$00,$1E
;.................... ;其余略
end
离线