打印
[AVR单片机]

AVR汇编百例大全

[复制链接]
15408|48
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
123jj|  楼主 | 2010-8-2 12:46 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 123jj 于 2010-8-5 10:21 编辑

费话少说,上菜!

------------------------------------------------------------------


根据网上资料收集整理,AVR汇编百例大全

目录:
AVR汇编百例之一   ---- 定点运算和定点数制转换
AVR汇编百例之二   ---- 计算程序
AVR汇编百例之三   ---- 实用程序
AVR汇编百例之四   ---- 输入输出
AVR汇编百例之五   ---- 电机控制
AVR汇编百例之六   ---- 精确定时及时钟日历走时
AVR汇编百例之七   ---- 串行通讯
AVR汇编百例之八   ---- 脉宽调制(PWM)
AVR汇编百例之九   ---- 断电保护
AVR汇编百例之十   ---- 码制转换
AVR汇编百例之十一 ---- 浮点程序库
AVR汇编百例之十二 ---- 晋级篇-参考程序

相关帖子

沙发
123jj|  楼主 | 2010-8-2 12:47 | 只看该作者
AVR汇编百例之一   ---- 定点运算和定点数制转换

;范例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

使用特权

评论回复
板凳
123jj|  楼主 | 2010-8-2 12:47 | 只看该作者
AVR汇编百例之二   ---- 计算程序

;范例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

使用特权

评论回复
地板
123jj|  楼主 | 2010-8-2 12:48 | 只看该作者
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


;范例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

使用特权

评论回复
5
123jj|  楼主 | 2010-8-2 12:48 | 只看该作者
AVR汇编百例之四   ---- 输入输出

;时钟日历芯片62×42×读写程序,时钟日历数据读入到显示缓存区$6C--$73
    ;范例24           ;USE 8515!使用DSPA子程序
.EQU   RTCH=$40         ;rtc地址高八位
RDATE: RCALL   BSYT       ;初始化,兼冻结RTC
    LDI   XL,$6D     ;数据缓存区首地址
    LDI   YL,$06     ;首指日单元
RDLP:   LD     R16,Y+     ;$6b 6c 6d   6e 6f 70 71 72 73
    ANDI   R16,15     ;   2 9(D) - 1 0(M) - 0 2(Y)
    CPI   R16,10
    BRCS   RDL1
    ANDI   R16,$7F     ;容错处理
RDL1:   ST     X,R16$
    DEC   R26
    CPI   R26,$6B
    BRNE   RDLP1
    LDI   XL,$70
RDLP1: CPI   R26,$6E
    BRNE   RDLP2
    LDI   R16,$14     ;送‘-’到$6E单元
    ST     X,R16
    LDI   XL,$73
RDLP2: CPI   R26,$71
    BRNE   RDLP
    LDI   R16,$14     
    ST     X,R16     ;送‘-’到$71单元并结束子程序
RDINVL: RJMP   WCRT

RTIME: RCALL   FIL2       ;请除缓存区
    RCALL   BSYT
    LDI   XL,$73
    LDI   YL,$02     ;指向分单元(只读时分)
RCL:   LD     R16,Y+
    ANDI   R16,15
    CPI   R16,10
    BRCS   RCL0      
    ANDI   R16,$7F     ;容错处理
RCL0:   ST     X,R16
    DEC   R26
    CPI   R26,$71
    BRNE   RCL1
    LDI   R16,$14     ;写入‘-’
    ST     X,R16
    DEC   R26
RCL1:   CPI   R26,$6E     ;$6c 6d 6e 6f 70 71 72 73
    BRNE   RCL       ;       1 6 - 3 5
    CLR   R16
    ST     Y,R16
    LDS   R17,$9FFB   ;时制存储单元
    LDS   R16,$6f
    SWAP   R16
    LDS   R15,$70
    ADD   R16,R15     ;合成小时
    SUBI   R16,$24     ;模24
    RCALL   SUDAA     ;BCD码减法调整
    BRCC   RCL2       ;够减,转
    SUBI   R16,-36     ;否则恢复被减数
RCL2:   CPI   R17,2
    BRNE   PRTD1     ;24小时制,转
    SUBI   R16,$12
    RCALL   SUDAA
    BRCC   PRTD1     ;12小时制处理
    SUBI   R16,-18     
PRTD1: MOV   R17,R16
    SWAP   R16
    ANDI   R16,$0F
    ANDI   R17,$0F
    STS   $6F,R16
    STS   $70,R17     ;小时数据送入显示区
    RJMP   WCRT

WDATE: RCALL   WRTC       ;将显示缓存区中日期数据写入RTC
    LDI   XL,$6F
    LD     R16,X
    CPI   R16,10
    BRCC   WDRT       ;非法数据,退出
    LDI   YL,6
WDLP:   LD     R16,X
    DEC   R26
    CPI   R16,$24     ;SPC?
    BRNE   WD0
    CLR   R16       ;变为0
WD0:   ST     Y+,R16
    CPI   R26,$6D
    BRNE   WD1       ;$6d 6e 6f   70 71   72 73
    LDI   XL,$71     ;   2 9(日) 1 1(月) 0 2 (年)
    RJMP   WDLP
WD1:   CPI   R26,$6f
    BRNE   WD2
    LDI   R26,$73
WD2:   CPI   R26,$71
    BRNE   WDLP
LWDRT: RJMP   WCRT

WTIME: RCALL   WRTC       ;将显示缓存区中时间数据写入RTC
    LDI   R26,$73
    LD     R16,X
    CPI   R16,10
    BRCC   WCRT       ;非法数据,退出
    LDI   YL,2
WLOP:   LD     R16,X
    CPI   R16,$24
    BRNE   WT1
    CLR   R16       ;容错处理
WT1:   ST     Y+,R16
    DEC   R26
WLP:   CPI   R26,$6F
    BRNE   WLOP       ;$6E 6f 70 71 72 73
WCRT:   CLR   R16       ;     1 5 3 8
    LDI   YL,$0D
    ST     Y,R16     ;解除对RTC之冻结
    IN     R16,MCUCR     
    CBR   R16,$C0
    OUT   MCUCR,R16   ;禁止读写外部RAM
    RET
    ;对rtc初始化/冻结时钟
BSYT:   LDI   YH,RTCH     ;rtc地址高八位
    LDI   YL,$0D     ;指向D寄存器
    IN     R16,MCUCR
    SBR   r16,$C0     ;允许读写外部RAM并选一个时钟周期等待时间
    OUT   MCUCR,R16
    LDI   R16,5     ;设置冻结位和中断申请位
    ST     Y,R16
    CLR   XH
BSRT:   RET
    ;写RTC初始化子程序
WRTC:   RCALL   BSYT
    LDI   YL,$0E     ;指向寄存器E
    LDI   R16,6
    ST     Y+,R16     ;指向寄存器F
    LDI   R16,1     ;设置时制位
    ST     Y,R16
    LDI   R16,4     ;选24小时制
    ST     Y,R16
    CLR   R16       ;请除时制位
    ST     Y,R16
    RJMP    BSYT


;范例25           ;显示保护子程序/晶振4MHZ
DSPRV: LDI   R16,HIGH(ramend)
    OUT   SPH,R16
    LDI   R16,LOW(ramend)
    OUT   SPL,R16
    CLR   R2       ;调DSPY次数寄存器清除
    WDR
    LDI   R16,$0D     ;启动看门狗,溢出时间为0.49s
    OUT   WDTCR,R16   ;写入看门狗控制寄存器
    CLR   XH      
    LDI   XL,$6C
DSPVL: ST     X+,XH     ;清显示缓存区($6c-$73)
    CPI   XL,$74
    BRNE   DSPVL
DSPV0: LDI   R16,$66
    MOV   R9,R16
    LDI   R16,$82     ;$6582=25986,高位字节增1为$66
    MOV   R10,R16     ;调25986次DSPA耗时120s
DSNEX: LDI   XL,$74     ;将显示区十进制数据增1以演示数据变化
DSLOP: LD     R16,-X     ;实用时可以采样数据更新显示(参考范例96)
    INC   R16
    ST     X,R16
    CPI   R16,$0A
    BRNE   DSPRV1
    CLR   R16
    ST     X,R16
    CPI   R26,$6C
    BRNE   DSLOP     ;增1后如有进位则调整
DSPRV1: DEC   R10
    BRNE   DSPGN
    DEC   R9
    BRNE   DSPGN     ;2分钟定时到?
DSCLOS: RCALL   FIL2       ;将显示缓存区充入空白($24)
    RCALL   DSPA       ;其效果相当于关显
    SBRC   R16,7      
    RJMP   DSCLOS     
    RJMP   DLFUNC     ;有键按下,转出;否则继续关显
DSPGN: RCALL   DSPA       ;未到,显示数据
    SBRC   R16,7
    RJMP   DSNEX     ;无键按下,继续显示

DLFUNC: CPI   R16,12     ;关显键键值为12
    BEEQ   DSCLOS     ;关显键按下,转关闭显示
    ;.
    ;.
    ;.
    ;.
    ;(其他键值处理,参考范例26 DEALKY程序)
    RJMP   DSPV0     ;执行功能后转入二分钟定时


;范例26           ;键值处理程序
DEALKY: LDI   R16,HIGH(ramend)
    OUT   SPH,R16
    LDI   R16,LOW(ramend)
    OUT   SPL,R16
    CLR   R2       ;调DSPY次数寄存器清除
    WDR
    LDI   R16,$0D     ;启动看门狗,溢出时间为0.49”
    OUT   WDTCR,R16   ;写入看门狗控制寄存器     
DEALK0: RCALL   DSPA
    SBRC   R16,7
    RJMP   DEALK0     ;无键按下,反复查询
    CPI   R16,10
    BRCC   FNCKY     ;功能键按下,跳转
    RCALL   FIL2       ;键值<10为数字键 ,先清除显示缓存区
NUMKY: RCALL   LSDD8     ;8位数字左移,新键值加入序列尾
DSLP:   RCALL   DSPA
    SBRC   R16,7
    RJMP   DSLP       ;无键按下,继续显示
    CPI   R16,11     
    BRCS   NUMKY     ;键入数字形成左移序列/按清除键则清除所有键入数据
    BRNE   DSLP       ;键值大于11无效
                  ;11为回车键,对键入数字进行处理(如将其两两合并为BCD
                                  ;码,再转为二进制数等)
    RJMP   DEALK0     ;转回

FNCKY: SUBI   R16,10     ;功能键散转处理,先计算键值偏移量
    LDI   R31,HIGH(FKYTB)
    LDI   R30,LOW(FKYTB);散转表表首
    ADD   R30,R16
    CLR   R16
    ADC   R31,R16     ;偏移量加入指针
    IJMP           ;散转
FKYTB: RJMP   CLTTL     ;10:清除累加和
    RJMP   DSTTL     ;11:显示累加和
    RJMP   DSCLS     ;12:关显示
    RJMP   SLFTS     ;13:自检
    RJMP   FDPAP     ;14:打印机走纸
    RJMP   PRSMP     ;15:打印采样
    RJMP   PRTTL     ;16:打印累加和
    RJMP   DSCLK     ;17:显示系统时钟
    ;.............     ;.........
    ;.............     ;.........

CLTTL: ;.............     ;程序内容略
    ;.............
    RJMP   DEALK0     ;程序执行完毕,转回
DSTTL: RCALL   BRTTL     ;分解累加和送显示缓存区
    RCALL   DSPA       ;显示累加和
    SBRC   R16,7
    RJMP   DSTTL     ;任一键按下,结束显示累加和
    RJMP   DEALK0     ;程序执行完毕,转回
DSCLS: RJMP   DSCLOS     ;转去关显示
SLFTS: ;.............
    ;.............
    RJMP   DEALK0     ; 自检程序执行完毕,转回

FDPAP: ;.............
    ;.............
    RJMP   DEALK0     ; 走纸程序执行完毕,转回
PRSMP: ;.............
    ;.............
    RJMP   DEALK0     ; 打印采样程序执行完毕,转回
PRTTL: ;.............
    ;.............
    RJMP   DEALK0     ;打印累加和程序执行完毕,转回

DSCLK: RCALL   BRCLK     ;分解系统时钟送入显示缓存区      
    RCALL   DL1S     ;延时1秒
    RCALL   DSPA     ;显示时钟
    SBRC   R16,7     ;任一键按下,结束显示时钟
    RJMP   DSCLK     
    RJMP   DEALK0     ;程序执行完毕,转回

    ;.............
    ;.............     ;其他功能键处理略
    ;.............


;范例27           ;主显子程序
DSPA:   SBRC   R16,7     ;USE R0,R2,R11,R12,r13,r14,r15,r16,r17&Z,X POINTERS
    RJMP   DSA2       ;无键按下,跳转
DSA0:   CLR   R12
    INC   R12       ;有键按下,将计数器置1
DSA1:   RCALL   DSPY
    DEC   R12
    BRNE   DSA1       ;等待键释放
DSA2:   RCALL   DSPY
    LDS   R16,$A3     
    SBRS   R16,7     ;有进入功能表程序标志?
    RET             ;没有返回
    SBI   PORTA,0     ;
    SBIS   PINA,0     ;退出功能表程序吗?
    RET            
    CBR   R16,$80     ;是,清除进入功能表程序标志($A3,7)
    STS   $A3,R16
    RCALL   FIL2
    LDI   R16,$0F     ;'F'
    STS   $6C,R16
    LDI   R16,$0E     ;'E'
    STS   $6E,R16
    LDI   R16,$17     ;'n'
    STS   $6F,R16
    LDI   R16,$0D     ;'d'
    STS   $70,R16     ;显示‘F End'
    RCALL   DL2S       ;2秒后
    RJMP   DIPA1     ;转到主程序(包括对堆栈)初始化
DL2S:   RCALL   DL1S       ;延时2秒子程序
DL1S:   LDI   R16,217     ;延时1秒子程序/4MHz clk
    MOV   R11,R16     ;4.618×217=1000ms
DLCOM: RCALL   DSPA
    DEC   R11
    BRNE   DLCOM
    RET


;范例28           ;基显子程序,显示缓存区:$6C--$73,执行时间4.618ms/晶振4MHZ
                  ;主程序应对看门狗初始化,设置溢出时间为0.49秒!
DSPY:   LDI   R17,$0F     ;使用R0,R2,R12,R13,R14,R15,R16&R17/z&x pointer!
    OUT   DDRA,R15   ;PA7--PA4为键列值输入
    CLR     R15
    COM       R15        
    OUT   DDRB,R15
    OUT   DDRC,R15   ;口B:段选输出,口C:位选输出
    OUT   PORTC,R15   ;关显
DPY1:   LDI   R26,$6C     ;指向显示缓存区首址:$6C
    CLR   R27
    LDI   R17,$7F
    MOV   R13,R17     ;位选初始化(首显最高位)
L0D:   LD     R17,X+
    LDI   R31,HIGH(table*2)
    LDI   R30,LOW(table*2)
    ADD   R30,R17
    ADC   R31,R27
L0C:   LPM             ;取段选码
    OUT   PORTB,R0   ;送段选口
    OUT   PORTC,R13   ;位选口
    SEC             ;
    ROR   R13       ;指下一位位选
    LDI   R17,3     ;4MHz(6 if 8MHz)
    CLR   R14
DLOP:   DEC   R14
    BRNE   DLOP
    DEC   R17
    BRNE   DLOP       ;延时0.5762毫秒
        IN       R16,PORTA
    ORI   R16,$F0       ;保护PA3--PA0输出
    OUT   PORTA,R16   ;提拉PA7-PA4
    IN     R14,PINA   ;读入列值
NEX:   ROL   R14       ;use high 4bits!
    BRCC   L1       ;有键按下,跳转
NEX1:   INC   R17       ;指向下一列
    CPI   R17,4
    BRNE   NEX       ;各列都查完?
NEX2:   SER   R17
    OUT   PORTC,R17   ;将$FF写入位选口(关显)
    CPI   R26,$74
    BRNE   L0D       ;每位LED都显示一遍??
    MOV   R16,R15     ;YES
    INC   R2       ;增一调DSPY次数寄存器
    MOV   R17,R2
    CPI   R17,100     ;到100次?
    BRNE   NEX3      
    CLR   R2       ;清除看门狗定时器时间到计数器/4.618ms×100=0.462s(<0.49s)
    WDR             ;看门狗定时器复位
NEX3:   RET            
L1:   LDS   R16,$73     ;计算键值代码/查键值
    SUB   R16,R26     ;$73-(r26)-->r16
    LSL   R16
    LSL   R16       ;行值*4
    ADD   R16,R17     ;键值代码=行值*4+列值
    LDI   R30,LOW(TABL0*2)
    ADD   R30,R16
    LDI   R31,HIGH(TABL0*2)
    ADC   R31,R27
LA00:   LPM             ;查出键值
    MOV   R15,R0     ;放在R15
LA10:   INC   R12       ;计数器增1以备判断键释放
    RJMP   NEX1       ;转回查下一列
TABL0: .DB   10,0,11,20,1,2,3,16,4,5,6,22,7,8,9,18,12,15,19,23,14,17,21,13
TABLE: .DB     $3F,$06,$5B,$4F,$66,$6D,$7D,$07,$7F,$67,$77,$7C,$39 ;0--C
    .DB     $5E,$79,$71,$6F,$74,$04,$1F,$40,$38,$37,$54,$5C   ;'d'---'o'
    .DB     $73,$67,$50,$6D,$78,$1C,$3E,$7E,$F8,$6E,$49,$00
    .DB     $48,$52,$D3,$76 ;$25(=),$26(/)$27(?) END AT $28(H)
    .DB     $BF,$86,$DB,$CF,$E6,$ED,$FD,$87,$FF,$E7;THE 0.($29)--9.($32)
    .DB     $D7,$C9,$80     ;THE 'X.' 'Z.' &'.'($33--$35)
    .DB     $DE,$EF,$B8,$F3,$E7,$D0,$DC,$ED,$86,$F9,$B9H,$F7,$F1,$B7,$D4
          ;the d.,g.,L.,p.,q.,r.,o.,s.,l.,E.,C.,A.,F.,M.,n.(36--44h)


;范例29 ;键入数字序列左移处理子程序
LSDD8: LDI   R26,$6C     ;8bcd码($6C--$73H)
    LDS   R27,$A3
    CBR   R27,8     ;清$A3,3
    STS   $A3,R27
    CLR   R27
    CPI   R16,10     ;10为清除键
    BRNE   DDL
    RCALL   FIL2       ;清除显示缓存区($6c-$73)!
    LDS   R16,$A3
    SBR   R16,8
    STS   $A3,R16     ;建清除显示缓存区标志$A3,3=1
    RET
DDL:   INC   R26       ;数字键按下,序列左移
    LD     R16,X     ;
    SUBI   R16,$29     ;数字带小数点?
    BRCC   DD4       ;若带则将其复原(参考DSPY子程序段码表)
    SUBI   R16,$D7     ;恢复
DD4:   ST     -X,R16     ;移入左邻单元
DD5:   INC   R26      
    CPI   R26,$73     
    BRNE   DDL       ;各数字都左移了一位?
    ST     X,R15     ;新键入数字进入数字序列末位
    LDI   R26,$6C
DEL:   LD     R16,X
    CPI   R16,10     ;是BCD码?
    BRCS   DEL2      
    CPI   R16,$29
    BRCC   DELRT     ;大于$29为错误!
DELA:   INC   R26       ;0--9/$24/$14为有效!
    CPI   R26,$73
    BRNE   DEL       ;缓存区检查完毕?
    RJMP   DELRT
DEL2:   CPI   R16,0
    BRNE   DELRT
    LDI   R16,$24     ;0改为空白
    ST     X,R16
    RJMP   DELA       ;
DELRT: LDS   R16,$A0     ;小数点位置单元
    TST   R16
    BREQ   DDRET     ;($a0)=0,无小数点
    NEG   R16
    ADD   R16,$73
    MOV   R26,R16     ;找到缓存区内带小数点的数据位
    LD     R16,X
    SUBI   R16,$D7     ;加上小数点
    ST     X,R16
    CPI   R16,$4D     ;在空白码加了小数点($24(空白)+$29=$4d)?
    BRNE   STLR1
    LDI   R16,$29
    ST     X,R16     ;是,将其改为'0.'
STLR1: CPI   R26,$73
    BREQ   DDRET     ;并将其后所有空白都改为0
    INC   R26
    LD     R16,X
    CPI   R16,$24
    BRNE   DDRET
    CLR   R16
    ST     X,R16
    RJMP   STLR1
DDRET: RET

FIL2:   LDI   R26,8     ;在显示缓存区内填充空白
    MOV   R14,R26
FIL2A: LDI   R26,$6C
FIL:   CLR   R27
    LDI   R16,$24
FILP:   ST     X+,R16
    DEC   R14
    BRNE   FILP
    RET


;范例30           ;双键输入检查数据子程序,Ky1数据键/Ky2回车键
KYIN2: LDI   R26,$60     ;寄存器地址:portb:$18/ddrb:$17/pinb:$16
    CLR   R27       ;指向数据区首地址
    CBI   DDRB,7
    CBI   DDRB,6     ;pb7和pb6皆为输入口
    SER   R17
    OUT   DDRC,R17   ;c口为数据显示口
LA0:   LD     R17,X     ;取数据
    CPI   R17,$0A
    BRCS   LA1
    CLR   R17
LA1:   LDI   R31,HIGH(table*2)
    LDI   R30,LOW(table*2);DSPY段选码表
    ADD   R30,R17
    ADC   R31,R27     
    LPM
    COM   R0       ;段选码取出并取反
    OUT   PORTC,R0   ;送C口
    SBI   PORTB,7
    SBIC   $16,7
    RJMP   NXA1       ;数字键未按下,转
    RCALL   DL50       ;否则延时
XA2:   SBI   PORTB,6
    SBIC   $16,6
    RJMP   XA0       ;只有数字键按下,转
XA20:   RCALL   DL50       ;两键都按下,先延时50mS
    SBI   PORTB,6
    SBIS   $16,6
    RJMP   XA20
    SBI   PORTB,7
    SBIS   $16,7
    RJMP   XA20       ;等两键都释放
    RCALL   DL50
XA21:   SBI   PORTB,6
    SBIS   $16,6
    RJMP   XA21       ;等待释放
    SBI   PORTB,7
    SBIS   $16,7
    RJMP   XA21       ;再次等待释放
    RJMP   NXA6       ;先按数字键,再按回车键,待2都键释放后退出子程序
XA0:   SBI   PORTB,7
    SBIS   $16,7
    RJMP   XA2       ;等待数字键释放
XA1:   RCALL   DL50       ;延时
    SBI   PORTB,7
    SBIS   $16,7
    RJMP   XA1       ;再次等待释放
    INC   R17       ;数字增1
    CPI   R17,10
    BRCS   NXA1
    CLR   R17       ;超过10,将键值归为0
NXA1:   SBI   PORTB,6
    SBIC   $16,6
    RJMP   LA1       ;回车键也未按下,重新查键
    RCALL   DL50       ;延时
NXA3:   SBI   PORTB,6
    SBIS   $16,6
    RJMP   NXA3       ;再次等待回车键释放
    RCALL   DL50
    SBI   PORTB,6
    SBIS   $16,6
    RJMP   NXA3      
    ST     X+,R17     ;数字转入缓存区
    SER   R17
    OUT   PORTB,R17   ;关显
    RCALL   DL50       ;
    CPI   R26,$70     ;到规定数字个数?
    BRNE   LA0       ;
    LDI   R17,$86     ;显示'E'nd
    OUT   PORTC,R17   ;
NXA4:   SBI   PORTB,6
    SBIS   $16,6
    RJMP   NXA5       ;回车键按下,转
    SBI   PORTB,7
    SBIC   $16,7     ;数字键按下,转
    RJMP   NXA4       ;否则反复查键
NXA40: RCALL   DL50
    SBI   PORTB,7
    SBIS   $16,7
    RJMP   NXA40     
    SBI   PORTB,7
    SBIS   $16,7
    RJMP   NXA40     ;等待键释放
    RJMP   KYIN2     ;转检查键入数据
NXA5:   RCALL   DL50
    SBI   PORTB,6
    SBIS   $16,6     
    RJMP   NXA5
    SBI   PORTB,6
    SBIS   $16,6
    RJMP   NXA5       ;等回车键释放
NXA6:   SER   R17
    OUT   PORTB,R17   ;关显,结束子程序
    RET
DL50: ;RCALL   DL25       ;延时50毫秒子程序/8Mhz(去掉指令前“;”号)
DL25:   CLR   R14       ;延时50毫秒子程序/4Mhz
    CLR   R15
DL50L: DEC   R15
    NOP
    BRNE   DL50L
    DEC   R14
    BRNE   DL50L
    RET


;范例31
LPRNT: SER   R17       ;宽行打印机检测及控打程序
    OUT   DDRC,R17   ;C口为打印机输出口!
    SBI   DDRD,7
    CBI   DDRD,3     ;pd7为选通输出口,pd3(INT1)查忙输入口
    SBI   PORTD,3
    SBIC   PIND,3     ;查打印机忙信号
    RJMP   ERR5       ;打印机尚未工作忙信号即已为高,打印机不能打印
    LDI   R17,$0D     ;写回车命令给打印机
    OUT   PORTC,R17
    CBI   PORTD,7     ;发出选通信号
    NOP            
    NOP
    NOP
    SBI   PORTD,7     ;strobe
    LDI   R16,50
TSPRT: SBI   PORTD,3
    SBIc   PIND,3     
    RJMP   LPRT2     ;50次内忙信号高起来为正常
    DEC   R16       ;否则为非正常状态
    BRNE   TSPRT
ERR5:   LDI   R16,5
    RCALL   ERRX       ;显示5号错误
    RJMP   DIPA1     ;转主程序初始化
LPRT2: LDI   R25,1     
    CLR   R24       ;point to $100
    LDI   R17,$80
    OUT   GIMSK,R17   ;允许int1中断
    LDI   R17,$0A
    OUT   MCUCR,R17   ;INT1下降沿中断
    SEI             ;general interrupt enable
    RET
EX_INT1:PUSH   R26
    PUSH   R27
    IN     R27,SREG
    PUSH   R27
    PUSH   R17       ;保护现场
    MOV   R27,R25     ;取数据指针
    MOV   R26,R24
    LD     R17,X+     ;
    MOV   R25,R27
    MOV   R24,R26     ;增1后将指针送回
    CPI   R17,3     ;是停止符?
    BRNE   INT1SD
    CLR   R17
    OUT   GIMSK,R17   ;禁止INT1中断
    RJMP   INT1ED
INT1SD: OUT   PORTC,R17   ;打印数据输出到打印口
    CBI   PORTD,7     ;clr ($12,7)
    NOP
    NOP
    NOP
    SBI   PORTD,7     ;向打印机发出选通
INT1ED: POP   R17
    POP   R27
    OUT   SREG,R27
    POP   R27
    POP   R26       ;恢复现场
    RETI

使用特权

评论回复
6
123jj|  楼主 | 2010-8-2 12:48 | 只看该作者
AVR汇编百例之五   ---- 电机控制

;范例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

使用特权

评论回复
7
123jj|  楼主 | 2010-8-2 12:49 | 只看该作者
AVR汇编百例之六   ---- 精确定时及时钟日历走时

;精确定时及时钟日历走时子程序
    ;范例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

使用特权

评论回复
8
123jj|  楼主 | 2010-8-2 12:50 | 只看该作者
AVR汇编百例之七   ---- 串行通讯

;范例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

使用特权

评论回复
9
123jj|  楼主 | 2010-8-2 12:50 | 只看该作者
;范例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             ;是,结束

使用特权

评论回复
10
123jj|  楼主 | 2010-8-2 12:50 | 只看该作者
AVR汇编百例之八   ---- 脉宽调制(PWM)

;脉宽调制(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

使用特权

评论回复
11
123jj|  楼主 | 2010-8-2 12:51 | 只看该作者
AVR汇编百例之九   ---- 断电保护

;范例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           ;弹出断点,开放中断

使用特权

评论回复
12
murex| | 2010-8-2 12:51 | 只看该作者
:lol发的好辛苦,先捧下

使用特权

评论回复
13
123jj|  楼主 | 2010-8-2 12:51 | 只看该作者
AVR汇编百例之十   ---- 码制转换

    ;范例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

使用特权

评论回复
14
123jj|  楼主 | 2010-8-2 12:52 | 只看该作者
AVR汇编百例之十一 ---- 浮点程序库
抢位,待传!

使用特权

评论回复
15
123jj|  楼主 | 2010-8-2 12:52 | 只看该作者
AVR汇编百例之十一 ---- 浮点程序库
抢位,待传!

使用特权

评论回复
16
123jj|  楼主 | 2010-8-2 12:52 | 只看该作者
AVR汇编百例之十一 ---- 浮点程序库
抢位,待传!

使用特权

评论回复
17
123jj|  楼主 | 2010-8-2 12:52 | 只看该作者
AVR汇编百例之十一 ---- 浮点程序库
抢位,待传!

使用特权

评论回复
18
123jj|  楼主 | 2010-8-2 12:52 | 只看该作者
AVR汇编百例之十一 ---- 浮点程序库
抢位,待传!

使用特权

评论回复
19
123jj|  楼主 | 2010-8-2 12:52 | 只看该作者
AVR汇编百例之十一 ---- 浮点程序库
抢位,待传!

使用特权

评论回复
20
123jj|  楼主 | 2010-8-2 12:53 | 只看该作者
AVR汇编百例之十二 ---- 晋级篇-参考程序
抢位,待传!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2

主题

4727

帖子

8

粉丝