公告

Gentoo交流群:87709706 欢迎您的加入

#1 2022-08-26 14:56:38

batsom
管理团队
注册时间: 2022-08-03
帖子: 594
个人网站

100例汇编程序

定点运算和定点数制转换   
        ;范例1
LSDAA:  ADC     R16,R16      ;十进制数(在R16中)左移调整子程序
ADDAA:  IN      R6,SREG      ;bcd码相加调整子程序,先保存相加后的
        LDI     R17,$66      ;状态the old status
        ADD     R16,R17      ;再将和预加立即数$66
        IN      R17,SREG     ;输入相加后新状态(the new status)
        OR      R6,R17       ;新旧状态相或
        SBRS    R6,0         ;相或后进位置位则跳行
        SUBI    R16,$60      ;否则减去$60(十位bcd不满足调整条件)
        SBRS    R6,5         ;半进位置位则跳行
        SUBI    R16,6        ;否则减去$06(个位bcd不满足调整条件)
        ROR     R6           ;向高位字节BCD返还进位位!
        RET
       ;范例2
       
SUDAA:  BRCC    SBD1         ;bcd码减法调整子程序,差在R16中
        BRHC    SBD3         
        SUBI    R16,$66      ;进位半进位都置位,将差减去立即数$66
        SEC                  ;并恢复借位C
        RET                  ;ret. with seC
SBD1:   BRHC    SBD2         ;进位半进位都清位,返回
        SUBI    R16,6        ;进位清除而半进位置位,将差减去6
SBD2:   RET                  ;ret. with clC
SBD3:   SUBI    R16,$60      ;进位置位而半进位清除,将差减去$60
        SEC                  ;并恢复借位C
        RET                  ;ret. with seC

       ;范例3
RSDAA:  SBRC    R16,7        ;bcd码(在R16中)右移调整子程序
        SUBI    R16,$30      ;十位BCD最高位为1(代表8),将其变为5(否则跳行)
        SBRC    R16,3         
        SUBI    R16,3        ;个位BCD最高位为1(代表8),将其变为5(否则跳行)
        RET
       
       ;范例4
ADBCD4: MOV     R16,R15      ;4字节压缩bcd码相加子程序
        ADD     R16,R11      ;R12,R13,R14,R15内为被加数,R8,R9,R10,R11内为加数
        RCALL   ADDAA        ;相加后调整
        MOV     R15,R16      ;并返还调整后结果
        MOV     R16,R14
        ADC     R16,R10
        RCALL   ADDAA
        MOV     R14,R16
        MOV     R16,R13
        ADC     R16,R9
        RCALL   ADDAA
        MOV     R13,R16
        MOV     R16,R12
        ADC     R16,R8       
        RCALL   ADDAA
        MOV     R12,R16
        RET
       
       ;范例5
ADBCD:  LDI     R16,4        ;多字节压缩bcd码相加子程序
        MOV     R7,R16       ;(r7):字节数
        CLC
ADLOP:  LD      R16,-X       ;X-1指向被加数; 
        LD      R6,-Y        ;Y-1指向加数
        ADC     R16,R6
        RCALL   ADDAA        ;相加后调整
        ST      X,R16        ;返还调整后结果
        DEC     R7         
        BRNE    ADLOP
        RET
       
       ;范例6
SUBCD4: MOV     R16,R15       ;4字节压缩bcd码减法子程序
        SUB     R16,R11       ;R12,R13,R14,R15内为被减数,R8,R9,R10,R11内为减数
        RCALL   SUDAA         ;相减后调整
        MOV     R15,R16       ;并返还调整后结果
        MOV     R16,R14
        SBC     R16,R10
        RCALL   SUDAA
        MOV     R14,r16
        MOV     R16,R13
        SBC     R16,R9
        RCALL   SUDAA
        MOV     R13,R16
        MOV     R16,R12
        SBC     R16,R8
        RCALL   SUDAA
        MOV     R12,R16
        RET
       
       ;范例7
SUBCD:  LDI     R16,4        ;多字节压缩bcd码相减子程序
        MOV     R7,R16       ;(r7):压缩bcd码字节数
        CLC
SUBLP:  LD      R16,-X       ;X-1指向被减数
        LD      R6,-Y        ;Y-1指向减数
        SBC     R16,R6
        RCALL   SUDAA        ;相减后调整
        ST      X,R16        ;返还调整后结果
        DEC     R7
        BRNE    SUBLP
        RET
       ;范例8                ;16位被乘数*16位乘数-->32位积
MUL16:  LDI     R16,17       ;(r10r11)*(r14r15)-->r12r13r14r15
        ClR     R12
        ClR     R13          ;积的高位字预清除
        CLC                  ;第1次只右移,不相加
MLOOP:  BRCC    MUL1         ;
        ADD     R13,R11      ;乘数右移移出位为1,将被乘数加入部分积
        ADC     R12,R10
MUL1:   ROR     R12
        ROR     R13
        ROR     R14
        ROR     R15          ;部分积连同乘数整体右移1位
        DEC     R16
        BRNE    MLOOP        ;17次右移后结束
        RET
       
       ;范例9                ;16位整数被乘数*16位小数乘数-->16位整数积,精确到0.5
MUL165: RCALL   MUL16        ;先得到32位积
        SBRS    R14,7        ;积小数部分最高位为1,将整数部分加1
        RET                  ;否则返回
        LDI     R17,255
        SUB     R13,R17
        SBC     R12,R17      ;以减去-1($FFFF)替代加1
        RET
       
       ;范例10               ;32位被除数/16位除数-->16位商,精确到1
DIV16:  LDI     R16,16       ;(r12r13r14r15)/(r10r11)-->r14r15
DLOOP:  LSL     R15         
        ROL     R14
        ROL     R13
        ROL     R12          ;被除数左移1位
        BRCS    DI1
        SUB     R13,R11
        SBC     R12,R10      ;移出位为0,被除数高位字减去除数试商
        BRCC    DI2          ;够减,本位商为1
        ADD     R13,R11
        ADC     R12,R10      ;否则恢复被除数
        RJMP    DI3          ;本位商0
DI1:    SUB     R13,R11
        SBC     R12,R10      ;移出位为1,被除数高位字减去除数
DI2:    INC     R15          ;本位商1
DI3:    DEC     R16
        BRNE    DLOOP
        RET
       
       ;范例11               ;32位被除数/16位除数-->16位商,精确到0.5
                             ;可能产生溢出!例$7FFFC000/$8000=$FFFF.8->$10000!
DIV165: RCALL   DIV16        ;(r12r13r14r15)/(r10r11)-->r14r15
        LSL     R13         
        ROL     R12          ;余数乘2
        BRCS    D165         ;有进位,转5入
        SUB     R13,R11
        SBC     R12,R10      ;否则,余数乘2减去除数
        BRCS    D164         ;不够减,转4舍
D165:   CLR     R13          ;否则将商增1
        SEC                 
        ADC     R15,R13
        ADC     R14,R13
        ADC     R13,R13      ;若有溢出,溢出位在R13中
        RET
D164:   CLR     R13
        RET
       ;范例12               ;32位整数/16位整数->16整数+16位小数->4字节浮点数
                             ;(r12r13r14r15)/(r10r11)-->r12r13r14r15
DIV16F: RCALL   DIV16        ;先做整数除法
        MOV     R9,r15       
        MOV     R8,r14       ;保存整数部分
        CLR     R15
        CLR     R14
        RCALL   DIV16        ;除得小数部分
        MOV     R11,R15
        MOV     R15,R14
        MOV     R13,R8
        MOV     R14,R9       ;整数部分在r13r14,小数部分在r15r11
        LDI     R17,$90      ;预设阶码$90(整数为16位)
        MOV     R12,R17
        LDI     R17,32       ;设32次右移
DIV16L: SBRC    R13,7     
        RJMP    NMLDN        ;最高位为1,已完成规格化
        LSL     R11          ;否则继续右移R13,R14,R15,R11
        ROL     R15
        ROL     R14
        ROL     R13         
        DEC     R12          ;阶码减1
        DEC     R17
        BRNE    DIV16L       
        CLR     R12          ;右移达32次,浮点数为零,置零阶
        RET
NMLDN:  SBRS    R11,7       
        RJMP    DIVRT        ;欲舍去部分(R11)最高位为0,转4舍
        RCALL   INC3         ;否则尾数部分增1
        BRNE    DIVRT
        INC     R12          ;尾数增1后变为0,改为0.5,并将阶码增1
DIVRT:  LDI     R17,$7F      ;将尾数最高位清除,表示正数(负数不要清除)
        AND     R13,R17      ;规格化浮点数在R12(阶码)R13R14R15(尾数)中
        RET
       
       ;范例13               ;(R16,R12,R13,R14,R15)/(R10,R11)-->R13,R14,R15
DIV24:  CLR     R16          ;32位整数/16位整数->24位整数,要求(R10)不为0;否则
                                                   ;要求(R12)<(R11)
DIV40:  LDI     17,24        ;40位整数/16位整数->24位整数 要求(R16,R12)
LXP:    LSL     R15          ; <(R10,R11)
        ROL     R14
        ROL     R13
        ROL     R12
        ROL     R16
        BRCC    LXP1
        SUB     R12,R11      ;右移后C=1 够减
        SBC     R16,R10      ;被除数减去除数
        RJMP    DIV0         ;本位商为1
LXP1:   SUB     R12,R11      ;C=0
        SBC     R16,R10      ;被除数减去除数试商
        BRCC    DIV0         ;C=0 够减,本位商1
        ADD     R12,R11
        ADC     R16,R10      ;否则恢复被除数,本位商0
        RJMP    DIV1
DIV0:   INC     R15          ;记本位商1
DIV1:   DEC     R17
        BRNE    LXP
        LSL     R12
        ROL     R16
        BRCS    GINC         ;C=1,5入
        SUB     R12,R11
        SBC     R16,R10
        BRCS    RET3         ;不够减,舍掉
GINC:   RCALL   INC3         ;将商增1
RET3:   RET

       ;范例14               ;定点整数(最大$FFFFFFFF)开平方子程序
INTSQR: LDI     R16,17       ;SQR(R12,R13,R14,R15)-->(r15r8r9)
        CLR     R8           ;R8,R9存储平方根
        CLR     R9           ;r10,r11,r12,r13,r14,r15
        CLR     R10          ; r8, r9(根)          r16 (counter)
        CLR     R11          ;r10,r11:被开平方数扩展字节
        LDI     R17,$40     
SQR0:   SUB     R12,R17
        SBC     R11,R9
        SBC     R10,R8
        BRCS    SQR1
        SEC                  ;试根够减,本位根1
        RJMP    SQR2
SQR1:   ADD     R12,R17
        ADC     R11,R9
        ADC     R10,R8
        CLC                  ;否则恢复被开平方数,本位根0
SQR2:   DEC     R16
        BRNE    SQR3         ;when the No.17bit of root be getting
SQR20: ADC     R9,R15       ;R15 HAVE BEEN CLEARED!
        ADC     R8,R15
        ADC     R15,R15      ;将开出之根4舍5入,使根最大可达65536(=$10000)!
        RET                  ;for example:sqr.($ffff0001)≈$10000
SQR3:   ROL     R9
        ROL     R8           ;记本位根
        LSL     R15
        ROL     R14
        ROL     R13
        ROL     R12         
        ROL     R11
        ROL     R10          ;被开平方数连同其扩展字节左移一位
        LSL     R15
        ROL     R14
        ROL     R13
        ROL     R12
        ROL     R11
        ROL     R10          ;被开平方数连同其扩展字节再次左移一位/左移2位开出1位根
        BRCS    SQR20        ;被开平方数左移2位后,若进位置位,则仅表明第17位根
                                                   ;已被提前开出且该位根=1,将平方根增1,开平方结束。
        RJMP    SQR0         ;否则转试下一位根   
       
       ;范例15               ;定点整数二翻十
CONV1:  LDI     R17,24       ;r12r13r14r15<--(r9r10r11)左移24次
        MOV     R7,R17       ;例:16777215<--$FFFFFF
        CLR     R12
        CLR     R13          ;68719476735<--$FFFFFFFFF
        CLR     R14          ;1099511627775<--$FFFFFFFFFF
        CLR     R15          ;十进制数存储区予清除
CV1:    LSL     R11
        ROL     R10
        ROL     R9           ;二进制数整体左移一位
        MOV     R16,R15
        RCALL   LSDAA
        MOV     R15,R16
        MOV     R16,R14
        RCALL   LSDAA
        MOV     R14,R16
        MOV     R16,R13
        RCALL   LSDAA
        MOV     R13,R16     
        MOV     R16,R12
        RCALL   LSDAA         ;十进制数左移并调整
        MOV     R12,R16
        DEC     R7
        BRNE    CV1
        RET
       
       ;范例16               ;定点整数十翻二
CONV2:  LDI     R17,24       ;(r9r10r11)-->r13r14r15,右移24次
        CLR     R31          ;例:999999-->$0F423F
        MOV     R7,R17       ; 99999999-->$05F5E0FF
CV2:    LSR     R9
        ROR     R10
        ROR     R11         
        ROR     R13
        ROR     R14
        ROR     R15           ;十进制数连同二进制数右移一位
        LDI     R30,12        ;数据指针
CV2L:   LD      R16,-Z
        RCALL   RSDAA         ;十进制数右移调整
        ST      Z,R16
        CPI     R30,9         ;十进制数各字节调整完毕?
        BRNE    CV2L
        DEC     R7            ;右移次数(24次)完成?
        BRNE    CV2
        RET
       
       ;范例17               ;定点小数二翻十
CONV3:  LDI     R17,24       ;(r13r14r15)--->r9r10r11r12右移24次
CONV31: MOV     R7,R17
        CLR     R9           
        CLR     R10          ;例:$0.FFFFFF-->0.99999994
        CLR     R11          ;$0.FFFFFFFF-->0.999999999767
        CLR     R12          ;$0.FFFFFFFFF->0.999999999985448
        CLR     R31
CV3:    LSR     R13
        ROR     R14
        ROR     R15
        ROR     R9
        ROR     R10
        ROR     R11
        ROR     R12          ;二进制数连同十进制数右移一位
        LDI     R30,9
CV3L:   LD      R16,Z
        RCALL   RSDAA        ;十进制数右移调整
        ST      Z+,r16
        CPI     R30,13
        BRNE    CV3L         ;十进制数各字节调整完毕?
        DEC     R7
        BRNE    CV3          ;右移次数(24次)完成?
        RET
       
       ;范例18               ;定点小数十翻二
CONV4:  LDI     R17,32       ;r12r13r14r15<--r8r9r10r11<--(r12r13r14r15)
        MOV     R7,R17       ;左移32次
CV4:    CLC                  ;例:$0.FFFFFFD5<--0.99999999
        MOV     R16,R15      ;$0.FFFFFFFF92<--0.9999999999
        RCALL   LSDAA
        MOV     R15,R16
        MOV     R16,R14
        RCALL   LSDAA
        MOV     R14,R16
        MOV     R16,R13
        RCALL   LSDAA
        MOV     R13,R16
        MOV     R16,R12
        RCALL   LSDAA
        MOV     R12,R16      ;定点十进制小数左移并调整
        ROL     R11
        ROL     R10
        ROL     R9
        ROL     R8           ;定点二进制小数带进位位左移一位
        DEC     R7
        BRNE    CV4
        MOV      R12,R8       ;最终结果转入R12--R15
     MOV      R13,R9
     MOV      R14,R10
     MOV     R15,R11
     RET
    
AVR实用程序                           
       ;范例19               ;等步距线性内插计算子程序
.EQU    TBLGTH=10
CHETA:  LDI     R16,TBLGTH-1 ;r16<--表长(即字数)-1
        LDI     R31,HIGH(chtbl*2);y0(函数初值)在r14r15,STEP(步长)在r10r11,自变量X在r12r13
        LDI     R30,LOW(chtbl*2+1);查表指针,首指数据表第1字之高位字节!
        RCALL   CPMR1        ;X与表中第一个字型数据(X0)比较
        BRCC    CHRET        ;X<X0 查表结束,Y=Y0
CHET1:  RCALL   CMPR1        ;X与表中下一个数据比较
        BRCC    NX33         ;X<X(i+1) 找到插值区间
        ADD     R15,R11      ;否则Y0中加入一个STEP:Yk=Y0+k*step(步距为负时则
                                                   ;减去|STEP|)
        ADC     R14,R10
        DEC     R16         
        BRNE    CHET1        ;未查到表格终值,循环;否则结束,Y取得最大值Yn
CHRET:  RET
NX33:   SBIW    R30,5        ;指针退回(-5),指向Xi
        MOV     R8,R14
        MOV     R9,R15       ;保存Y0+i*STEP
        RCALL   SUBS         ;(X-Xi)-->r16r17
        MOV     R15,R17
        MOV     R14,R16      ;转入r14r15
        RCALL   MUL16        ;(X-Xi)*STEP-->r12r13r14r15
        MOV     R10,R12
        MOV     R11,R13      ;保存乘积高位字
        LPM                  ;X(i+1)低位字节
        MOV     R13,R0
        ADIW    R30,1
        LPM                  ;X(i+1)高位字节
        MOV     R12,R0
        SBIW    R30,3        ;指针指向Xi
        RCALL   SUBS         ;X(i+1)-Xi-->r16r17
        MOV     R12,R10
        MOV     R13,R11      ;取回乘积高位字
        MOV     R10,R16
        MOV     R11,R17      ;X(i+1)-Xi-->r10r11
        RCALL   DIV165       ;(X-Xi)*STEP/[X(i+1)-Xi]-->r14r15
        ADD     R15,R9
        ADC     R14,R8       ;Y0+i*STEP+(X-Xi)*STEP/[X(i+1)-Xi]-->r14r15
        RET                  ;若STEP为负值则改为计算(r8r9)减去(r14r15)之值
CMPR1:  LPM                  ;取数据高位字节
        ADIW    R30,2        ;指向下一数据的高位字节
        CP      R0,R12       ;与X高位字节相比较
        BRNE    CPRT1        ;不相等即转出
        SBIW    R30,3        ;否则调整指针
        LPM                  ;取数据低位字节
        ADIW    R30,3        ;指向下一数据的高位字节
        CP      R0,R13       ;与X低位字节相比较
CPRT1:  RET                  ;以进位C带回比较结果
SUBS:   LPM                  ;计算(X-Xi)或[X(i+1)-Xi]并送入r16r17
        MOV     R5,R0        ;取Xi低位字节
        ADIW    R30,1
        LPM                  ;取Xi高位字节
        SBIW    R30,1        ;仍指向Xi低位字节
        SUB     R13,R5
        MOV     R17,R13
        SBC     R12,R0
        MOV     R16,R12       ;计算差并将其转入R16R17
        RET
       ;自变量x表长为12字
CHTBL:DW 19214,23404,27600,32799,37009,40211,45414,48618,51821,55029,57787,60070
       ;步距表长为11字
STEPT:  DW  356,366,379,395,415,440,471,509,555,603,657
       ;不等步距线性内插计算子程序,步距表首址在R6R7中
       ;自变量X在R12R13之中, 函数初值Y0在R14R15中
       
       ;范例20               ;表长(字个数)-1在R16中
CHTSTP: LDI     R31,HIGH(chtbl*2)
        LDI     R30,LOW(chtbl*2+1);查表指针
        LDI     R16,LOW(stept*2)
        MOV     R7,R16
        LDI     R16,HIGH(stept*2)
        MOV     R6,R16        ;步距表指针
        LDI     R16,TBLGTH-1 ;r16<--表长(字个数)-1
        RCALL   CMPR1        ;X与表首数据比较
        BRCC    CHSTPT       ;X<X0 查表结束,有Y=Y0
CHSTP1: RCALL   CMPR1        ;否则与表中下一数据比较
        BRCC    CHSTP3       ;X<X(i+1),找到插值区间!
        RCALL   GTSTP        ;查表取STEP字型变量
        ADD     R15,R11      ;Y0<--Y0+STEPk
        ADC     R14,R10
        DEC     R16         
        BRNE    CHSTP1       ;未查到表格终值循环;否则结束,Y取得最大值Yn
CHSTPT: RET                 
CHSTP3: SBIW    R30,5        ;指针退回,指向Xi低位字节
        MOV     R8,R14
        MOV     R9,R15       ;Y0+∑STEPk送入r14 r15
        RCALL   SUBS         ;(X-Xi)->r16r17
        MOV     R15,R17
        MOV     R14,R16      ;(X-Xi)转入R14R15
        RCALL   GTSTP        ;查表取STEPi-->R10R11
        RCALL   MUL16        ;(X-Xi)*STEPi-->R12R13R14R15
        MOV     R10,R12
        MOV     R11,R13      ;保存积高位字
        LPM
        MOV     R13,R0
        ADIW    R30,1
        LPM
        MOV     R12,R0
        SBIW    R30,3
        RCALL   SUBS         ;(X(i+1)-Xi)-->r16 r17
        MOV     R12,R10
        MOV     R13,R11
        MOV     R10,R16
        MOV     R11,R17      ;取回积高位字 &(X(i+1)-Xi)-->r10r11
        RCALL   DIV165       ;(X-Xi)*STEPi/[X(i+1)-Xi]-->r14r15
        ADD     R15,R9       ;
        ADC     R14,R8       ;Y0+∑STEPk+(X-Xi)*STEPi/[X(i+1)-Xi]-->r14r15
        RET
GTSTP:  MOV     R5,R6        ;查取STEP字型变量/POINTER in r6r7!
        MOV     R6,R30
        MOV     R30,R5
        MOV     R5,R7
        MOV     R7,R31
        MOV     R31,R5       ;(r6r7)<-->Z
        LPM
        MOV     R11,R0
        ADIW    R30,1
        LPM
        MOV     R10,R0       ;STEPk取到r10r11
        ADIW    R30,1       
        MOV     R5,R6
        MOV     R6,R30
        MOV     R30,R5
        MOV     R5,R7
        MOV     R7,R31
        MOV     R31,R5       ;指针增2后送回r6r7
        RET
       
       ;范例21               ;功能表程序
FUNC2:  LDS     R16,$A3      ;use r0,r8,r9,r10,r11,r16&r17/& subprogram dspa
        SBR     R16,$80      ;功能表程序标志
        STS     $A3,R16
        LDI     YH,2
        LDI     YL,0         ;功能内容表SRAM地址
        RCALL   FLFUNC       ;CLR r27!
        LDI     R16,2
        ST      X,R16        ;显示'FUNC.2'
        RCALL   DL2S
        CLR     R9           ;功能内容寻址偏移量R9!
        CLR     R8           ;功能名称寻址偏移量(R8)=(r9)*3
FFUNC0: RCALL   DSF_         ;显示'F-  '
FF0:    RCALL   DSPA         ;in subprogram dspy clr. r27!
        CPI     R16,11       ;回车键按下?
        BRNE    FF2P
FF0C:   RCALL   COMBNO       ;合成功能名称送入r16
        CPI     R16,20       ;是最后一个功能名称?
        BRNE    FF1
        CLR     R9           ;是,两偏移量初始化!
        CLR     R8           
FF1:    LDI     ZH,HIGH(FTABL*2)
        LDI     ZL,LOW(FTABL*2);功能名称表指针
        ADD     ZL,R8
        ADC     ZH,R27       ;(r27)=0 ALWAYS
        LPM
        MOV     R16,R0
        RCALL   BRA3A        ;分解新功能名称到$6E/$6F
FF0G:   LDI     R28,0
        ADD     R28,R9       ;功能内容指针加偏移量
        LD      R16,Y
        LDI     R26,$72
        RCALL   BRAX         ;将新功能内容分解到$72/$73
FF0A:   RCALL   DSPA         ;显示新功能名称/内容
        CPI     R16,11
        BRNE    FF0B         ;回车键按下?
        INC     R8           
        INC     R8
        INC     R8           ;是,功能名称寻址偏移量加3
        INC     R9           ;功能内容寻址偏移量加1
        RJMP    FF0C         ;转回
FF2P:   RJMP    FF2
FF0B:   CPI     R16,10
        BRNE    FF0D
        RCALL   DSF_         ;清除键按下,清除显示区后,显示‘F-’
FF1B:   RCALL   DSPA
        CPI     R16,11
        BREQ    FF1          ;转恢复当前显示
        CPI     R16,10
        BRCC    FF1B
        RJMP    FF2D         ;只有数字键按下才转出去处理
FF0D:   CPI     R16,10
        BRCC    FF0A
FF1D:   LDI     R17,$24      ;
        STS     $73,R17      ;数字键处理,先在缓存区内放一空白
FF0E:   LDS     R17,$73
        STS     $72,R17      ;键入数字左移
        STS     $73,R16      ;存入新数字
FF0F:   RCALL   DSPA
        CPI     R16,10         
        BREQ    FF0G         ;清除键按下,恢复显示旧功能内容
        BRCS    FF0E         ;键入数字左移更新
        CPI     R16,11
        BRNE    FF0F
        LDS     R26,$72      ;回车键按下
        RCALL   COMBA        ;合成新功能内容(combin $72&$73 into binary(r16))
        MOV     R17,R8
        INC     R17
        LDI     ZH,HIGH(FTABL*2)
        LDI     ZL,LOW(FTABL*2)
        ADD     ZL,R17       ;取当前功能内容下限
        ADC     ZH,R27
FF1F:   LPM
        CP      R16,R0
        BRCS    DSER2        ;新功能内容小于下限,错误
        INC     R17
        LDI     ZH,HIGH(FTABL*2)
        LDI     ZL,LOW(FTABL*2)
        ADD     ZL,R17       ;取当前功能内容上限
        ADC     ZH,R27
        LPM
        CP      R0,R16
        BRCS    DSER3        ;新功能内容大于上限,错误
FF7:    LDI     R28,0
        ADD     R28,R9       ;功能内容表首地址为$200!
        ST      Y,R16        ;合法的新功能内容进入功能内容表
        INC     R9           
        INC     R8
        INC     R8
        INC     R8           ;调整偏移量,进入下一个功能显示
        RJMP    FF0C
FF1P:   RJMP    FF1
DSER2:  RCALL   FERR2        ;显示'F Err.2'2秒
        RCALL   EXCH0       
        RJMP    FF0G         ;恢复原数据显示
DSER3:  RCALL   FERR3        ;显示'F Err.3'2秒
        RCALL   EXCH0       
        RJMP    FF0G         ;恢复原数据显示
FF2:    CPI     R16,10
        BRCS    FF2D         ;功能键按下,转初始
        RJMP    FF0         
FF2D:   LDI     R17,$24      ;数字键按下,在显示缓存区内左移
        STS     $6F,R17      ;
FF3:    LDS     R17,$6F
        STS     $6E,R17
        STS     $6F,R16
FF4:    RCALL   DSPA
        CPI     R16,10
        BRNE    FF41
        RCALL   DSF_         ;清除数字,显示‘F-’
FF40:   RCALL   DSPA
        CPI     R16,11
        BREQ    FF1P         ;转回显示当前功能名称及内容
        CPI     R16,10
        BRCC    FF40         ;无效键按下,转回
        RJMP    FF2D         ;否则转数字处理
FF41:   BRCS    FF3
        CPI     R16,11
        BRNE    FF4
        RCALL   COMBNO       ;合成新功能名称
        CLR     R10          ;功能名称偏移量计数器清除
        CLR     R11          ;功能内容偏移量计数器清除
SFFLP:  LDI     ZH,HIGH(FTABL*2)
        LDI     ZL,LOW(FTABL*2)
        ADD     ZL,R10
        ADC     ZH,R27
        LPM
        CP      R0,R16       ;
        BREQ    SFFND        ;在功能名称表中找到新名称
        INC     R11          ;
        INC     R10
        INC     R10
        INC     R10          ;调整偏移量
        LDI     R17,60
        CP      R10,R17      ;功能名称指针偏移量超过59?
        BRCS    SFFLP        ;否,继续查功能名称表
        RCALL   FERR1        ;查完功能名称表未查到键入功能名称!
        RJMP    FFUNC0       ;转回恢复原显示
SFFND:  MOV     R9,R11       ;得到功能内容指针偏移量
        MOV     R8,R10       ;得到功能名称指针偏移量
        RJMP    FF0G         ;转显示新功能名称及内容
FTABL:  .DB   1,0,1,2,1,8,3,0,2,4,0,1 5,1,2,6,0,4,7,1,4,8,1,2,9,2,7,10,1,5,11,1
        .DB   5,12,0,5,13,1,2,14,1,7,15,1,10,16,1,4,17,2,4,18,2,5,19,1,2,20,1,3
COMBNO: LDI     XL,$6E       ;取$6E$6F中的BCD码,合成新功能名称子程序
COMBA:  LD      R16,X+       
        CPI     R16,$24
        BRNE    CMBA
        CLR     R16
CMBA:   MOV     R0,R16
        LSL     R16
        LSL     R16
        ADD     R16,R0
        LSL     R16          ;高位BCD乘10
        LD      R0,X
        ADD     R16,R0       ;加低位BCD
        RET
DSF_:   RCALL   FIL8         ;准备显示'F-  '
        LDI     R16,$0F
        STS     $6C,R16
        LDI     R16,$14
        STS     $6D,R16
        RET
BRA3A:  LDI     XL,$6E       ;二进制数转换为两位BCD码并显示
BRAX:   LDI     R17,$24      ;十位为0时显示空白
        ST      X,R17
BRHOUR: CLR     R0           ;
BRX0:   SUBI    R16,10       ;减10
        BRCS    BRX2
        INC     R0
        RJMP    BRX0
BRX2:   SUBI    R16,-10      ;不够减恢复出十位BCD
        TST     R0
        BREQ    BRX1
        ST      X,R0         ;放入显示区
BRX1:   INC     R26
        ST      X,R16
BRART:  RET
FERR1:  LDI     XL,$71       ;显示'F Err.1'
        LDI     R16,1
        ST      X,R16
        RJMP    FER123
FERR2:  RCALL   MOVE1        ;显示'F Err.2'
        LDI     R16,2
        STS     $71,R16
        RJMP    FER123
FERR3:  RCALL   MOVE1        ;显示'F Err.3'
        LDI     R16,3
        STS     $71,R16
FER123: LDI     XL,$6C
        LDI     R16,$0F
        ST      X+,R16
        LDI     R16,$24
        ST      X+,R16
        LDI     R16,$0E
        ST      X+,R16
        LDI     R16,$1B
        ST      X+,R16
        LDI     R16,$3B
        ST      X+,R16       ;显示'F Err.1/2/3'
        LDI     R16,$24      ;2秒
        STS     $72,R16
        STS     $73,R16
        RCALL   DL2S
        RET
FIL8:   LDI     R26,8        ;将显示缓存区充空白
        MOV     R10,R26
        LDI     R26,$6C
        CLR     R27
        LDI     R16,$24
FILP:   ST      X+,R16
        DEC     R10
        BRNE    FILP
        RET
FLFUNC: RCALL   FIL8         ;准备显示'Func.'
        LDS     R26,$6C
        LDI     R16,$0F      ;'F'
        ST      X+,R16
        LDI     R16,$1E      ;'u'
        ST      X+,R16
        LDI     R16,$17      ;'n'
        ST      X+,R16
        LDI     R16,$40      ;'c.'
        ST      X+,R16
        RET
EXCH0:  LDI     ZL,$14       ;将显示缓存区内容转移$6C-$73<-->$214-$21B
        LDI    ZH,2
        LDI     XL,$6C
EXL:    LD      R16,X
        LD      R17,Z
        ST      X+,R17
        ST      Z+,R16
        CPI     R26,$74
        BRNE    EXL
        RET
MOVE1:  LDI     ZL,$14       ;将显示缓存区内容传送到$214-$21B       
             LDI     ZH,2       
        LDI     XL,$6C
MV1:    LD      R16,X+
        ST      Z+,R16
        CPI     R26,$74
        BRNE    MV1
        RET
       ;EEPROM 读写程序
       
       ;范例22                           ;读出EEPROM子程序
REEP:   LDI     YH,1
        LDI     YL 0         ;EEPROM 读出首地址:$100
        LDI     XL,$60       ;读出数据存放首地址:$60
        CLR     XH
REEP1:  SBIC    $1C,1        ;查EEWE位,EEWE=1为当前尚有写入操作未结束
        RJMP    REEP1        ;等待EEWE=0
        OUT     $1F,YH
        OUT     $1E,YL       ;读出地址写入EEPRO地址寄存器
        SBI     $1C,0        ;设置读出使能位(EERE)
        IN      R16,$1D      ;从EEPROM数据寄存器中读出数据
        ST      X+R16        ;存入缓存区
        INC     YL
        BRNE    REEP1        ;
        INC     YH
        CPI     YH,2         ;EEPROM最末数据(地址为$1FF)读完?
        BRNE    REEP1
        RET
       
       ;范例23               ;写入EEPROM子程序
WEEP:   LDI     YH,1
        LDI     YL 0         ;EEPROM 写入之首地址:$100
        LDI     XL,$60       ;写入数据存储区首地址:$60
        CLR     XH
WEEP1:  SBIC    $1C,1        ;查EEWE位,EEWE=1为当前尚有写入操作未结束
        RJMP    WEEP1        ;等待EEWE=0
        OUT     $1F,YH
        OUT     $1E,YL       ;送写入地址到EEPRO地址寄存器
        LD      R16,X+       ;取写入数据并调整数据指针
        OUT     $1D,R16      ;送到EEPROM数据寄存器
        SBI     $1C,2        ;设置EEPROM写入总使能位EEMWE
        SBI     $1C,1        ;设置EEPROM写入使能位EEWE
        INC     YL
        BRNE    WEEP1       
        INC     YH
        CPI     YH,2         ;EEPROM最末写入单元地址为$1FF
        BRNE    WEEP1
        RET
       
       ;时钟日历芯片62×42×读写程序,时钟日历数据读入到显示缓存区$6C--$73
       ;范例24               ;USE 8515!使用DSPA子程序
.EQU    RTCH=$40             ;rtc地址高八位
RDATE:  RCALL   BSYT         ;初始化,兼冻结RTC
        LDI     XL,$6D       ;数据缓存区首地址
        LDI     YL,$06       ;首指日单元
RDLP:   LD      R16,Y+       ;$6b 6c 6d   6e 6f 70  71 72 73
        ANDI    R16,15       ;     2  9(D) - 1  0(M) - 0  2(Y)
        CPI     R16,10
        BRCS    RDL1
        ANDI    R16,$7F      ;容错处理
RDL1:   ST      X,R16$
        DEC     R26
        CPI     R26,$6B
        BRNE    RDLP1
        LDI     XL,$70
RDLP1:  CPI     R26,$6E
        BRNE    RDLP2
        LDI     R16,$14      ;送‘-’到$6E单元
        ST      X,R16
        LDI     XL,$73
RDLP2:  CPI     R26,$71
        BRNE    RDLP
        LDI     R16,$14     
        ST      X,R16        ;送‘-’到$71单元并结束子程序
RDINVL: RJMP    WCRT

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

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

WTIME:  RCALL   WRTC         ;将显示缓存区中时间数据写入RTC
        LDI     R26,$73
        LD      R16,X
        CPI     R16,10
        BRCC    WCRT         ;非法数据,退出
        LDI     YL,2
WLOP:   LD      R16,X
        CPI     R16,$24
        BRNE    WT1
        CLR     R16          ;容错处理
WT1:    ST      Y+,R16
        DEC     R26
WLP:    CPI     R26,$6F
        BRNE    WLOP         ;$6E 6f 70 71 72 73
WCRT:   CLR     R16          ;        1  5  3  8
        LDI     YL,$0D
        ST      Y,R16        ;解除对RTC之冻结
        IN      R16,MCUCR     
        CBR     R16,$C0
        OUT     MCUCR,R16    ;禁止读写外部RAM
        RET
       ;对rtc初始化/冻结时钟
BSYT:   LDI     YH,RTCH      ;rtc地址高八位
        LDI     YL,$0D       ;指向D寄存器
        IN      R16,MCUCR
        SBR     r16,$C0      ;允许读写外部RAM并选一个时钟周期等待时间
        OUT     MCUCR,R16
        LDI     R16,5        ;设置冻结位和中断申请位
        ST      Y,R16
        CLR     XH
BSRT:   RET
       ;写RTC初始化子程序
WRTC:   RCALL   BSYT
        LDI     YL,$0E       ;指向寄存器E
        LDI     R16,6
        ST      Y+,R16       ;指向寄存器F
        LDI     R16,1        ;设置时制位
        ST      Y,R16
        LDI     R16,4        ;选24小时制
        ST      Y,R16
        CLR     R16          ;请除时制位
        ST      Y,R16
        RJMP    BSYT
       
       ;范例25               ;显示保护子程序/晶振4MHZ
DSPRV:  LDI     R16,HIGH(ramend)
        OUT     SPH,R16
        LDI     R16,LOW(ramend)
        OUT     SPL,R16
        CLR     R2           ;调DSPY次数寄存器清除
        WDR
        LDI     R16,$0D      ;启动看门狗,溢出时间为0.49s
        OUT     WDTCR,R16    ;写入看门狗控制寄存器
        CLR     XH           
        LDI     XL,$6C
DSPVL:  ST      X+,XH        ;清显示缓存区($6c-$73)
        CPI     XL,$74
        BRNE    DSPVL
DSPV0:  LDI     R16,$66
        MOV     R9,R16
        LDI     R16,$82      ;$6582=25986,高位字节增1为$66
        MOV     R10,R16      ;调25986次DSPA耗时120s
DSNEX:  LDI     XL,$74       ;将显示区十进制数据增1以演示数据变化
DSLOP:  LD      R16,-X       ;实用时可以采样数据更新显示(参考范例96)
        INC     R16
        ST      X,R16
        CPI     R16,$0A
        BRNE    DSPRV1
        CLR     R16
        ST      X,R16
        CPI     R26,$6C
        BRNE    DSLOP        ;增1后如有进位则调整
DSPRV1: DEC     R10
        BRNE    DSPGN
        DEC     R9
        BRNE    DSPGN        ;2分钟定时到?
DSCLOS: RCALL   FIL2         ;将显示缓存区充入空白($24)
        RCALL   DSPA         ;其效果相当于关显
        SBRC    R16,7         
        RJMP    DSCLOS       
        RJMP    DLFUNC       ;有键按下,转出;否则继续关显
DSPGN:  RCALL   DSPA         ;未到,显示数据
        SBRC    R16,7
        RJMP    DSNEX        ;无键按下,继续显示

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

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

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

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

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

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

       ;.............
       ;.............        ;其他功能键处理略
       ;.............
       
       ;范例27               ;主显子程序
DSPA:   SBRC    R16,7        ;USE R0,R2,R11,R12,r13,r14,r15,r16,r17&Z,X POINTERS
        RJMP    DSA2         ;无键按下,跳转
DSA0:   CLR     R12 
        INC     R12          ;有键按下,将计数器置1
DSA1:   RCALL   DSPY
        DEC     R12
        BRNE    DSA1         ;等待键释放
DSA2:   RCALL   DSPY
        LDS     R16,$A3     
        SBRS    R16,7        ;有进入功能表程序标志?
        RET                  ;没有返回
        SBI     PORTA,0      ;
        SBIS    PINA,0       ;退出功能表程序吗?
        RET                 
        CBR     R16,$80      ;是,清除进入功能表程序标志($A3,7)
        STS     $A3,R16
        RCALL   FIL2
        LDI     R16,$0F      ;'F'
        STS     $6C,R16
        LDI     R16,$0E      ;'E'
        STS     $6E,R16
        LDI     R16,$17      ;'n'
        STS     $6F,R16
        LDI     R16,$0D      ;'d'
        STS     $70,R16      ;显示‘F End'
        RCALL   DL2S         ;2秒后
        RJMP    DIPA1        ;转到主程序(包括对堆栈)初始化
DL2S:   RCALL   DL1S         ;延时2秒子程序
DL1S:   LDI     R16,217      ;延时1秒子程序/4MHz clk
        MOV     R11,R16      ;4.618×217=1000ms
DLCOM:  RCALL   DSPA
        DEC     R11
        BRNE    DLCOM
        RET
       
       ;范例28               ;基显子程序,显示缓存区:$6C--$73,执行时间4.618ms/晶振4MHZ
                             ;主程序应对看门狗初始化,设置溢出时间为0.49秒!
DSPY:   LDI     R17,$0F      ;使用R0,R2,R12,R13,R14,R15,R16&R17/z&x pointer!
        OUT     DDRA,R15     ;PA7--PA4为键列值输入
        CLR      R15
      COM        R15       
        OUT     DDRB,R15
        OUT     DDRC,R15     ;口B:段选输出,口C:位选输出
        OUT     PORTC,R15    ;关显
DPY1:   LDI     R26,$6C      ;指向显示缓存区首址:$6C
        CLR     R27
        LDI     R17,$7F
        MOV     R13,R17      ;位选初始化(首显最高位)
L0D:    LD      R17,X+
        LDI     R31,HIGH(table*2)
        LDI     R30,LOW(table*2)
        ADD     R30,R17
        ADC     R31,R27
L0C:    LPM                  ;取段选码
        OUT     PORTB,R0     ;送段选口
        OUT     PORTC,R13    ;位选口
        SEC                  ;
        ROR     R13          ;指下一位位选
        LDI     R17,3        ;4MHz(6 if 8MHz)
        CLR     R14
DLOP:   DEC     R14
        BRNE    DLOP
        DEC     R17
        BRNE    DLOP         ;延时0.5762毫秒
              IN       R16,PORTA
        ORI    R16,$F0          ;保护PA3--PA0输出
        OUT     PORTA,R16    ;提拉PA7-PA4
        IN      R14,PINA     ;读入列值
NEX:    ROL     R14          ;use high 4bits!
        BRCC    L1           ;有键按下,跳转
NEX1:   INC     R17          ;指向下一列
        CPI     R17,4
        BRNE    NEX          ;各列都查完?
NEX2:   SER     R17
        OUT     PORTC,R17    ;将$FF写入位选口(关显)
        CPI     R26,$74
        BRNE    L0D          ;每位LED都显示一遍??
        MOV     R16,R15      ;YES
        INC     R2           ;增一调DSPY次数寄存器
        MOV     R17,R2
        CPI     R17,100      ;到100次?
        BRNE    NEX3         
        CLR     R2           ;清除看门狗定时器时间到计数器/4.618ms×100=0.462s(<0.49s)
        WDR                  ;看门狗定时器复位
NEX3:   RET                 
L1:     LDS     R16,$73      ;计算键值代码/查键值
        SUB     R16,R26      ;$73-(r26)-->r16
        LSL     R16
        LSL     R16          ;行值*4
        ADD     R16,R17      ;键值代码=行值*4+列值
        LDI     R30,LOW(TABL0*2)
        ADD     R30,R16
        LDI     R31,HIGH(TABL0*2)
        ADC     R31,R27
LA00:   LPM                  ;查出键值
        MOV     R15,R0       ;放在R15
LA10:   INC     R12          ;计数器增1以备判断键释放
        RJMP    NEX1         ;转回查下一列
TABL0:  .DB     10,0,11,20,1,2,3,16,4,5,6,22,7,8,9,18,12,15,19,23,14,17,21,13
TABLE:  .DB      $3F,$06,$5B,$4F,$66,$6D,$7D,$07,$7F,$67,$77,$7C,$39 ;0--C
        .DB      $5E,$79,$71,$6F,$74,$04,$1F,$40,$38,$37,$54,$5C   ;'d'---'o'
        .DB      $73,$67,$50,$6D,$78,$1C,$3E,$7E,$F8,$6E,$49,$00 
        .DB      $48,$52,$D3,$76  ;$25(=),$26(/)$27(?) END AT $28(H)
        .DB      $BF,$86,$DB,$CF,$E6,$ED,$FD,$87,$FF,$E7;THE  0.($29)--9.($32)
        .DB      $D7,$C9,$80      ;THE 'X.' 'Z.' &'.'($33--$35)
        .DB      $DE,$EF,$B8,$F3,$E7,$D0,$DC,$ED,$86,$F9,$B9H,$F7,$F1,$B7,$D4
                ;the d.,g.,L.,p.,q.,r.,o.,s.,l.,E.,C.,A.,F.,M.,n.(36--44h)
               
       ;范例29  ;键入数字序列左移处理子程序
LSDD8:  LDI     R26,$6C      ;8bcd码($6C--$73H)
        LDS     R27,$A3
        CBR     R27,8        ;清$A3,3
        STS     $A3,R27
        CLR     R27
        CPI     R16,10       ;10为清除键
        BRNE    DDL
        RCALL   FIL2         ;清除显示缓存区($6c-$73)!
        LDS     R16,$A3
        SBR     R16,8
        STS     $A3,R16      ;建清除显示缓存区标志$A3,3=1
        RET
DDL:    INC     R26          ;数字键按下,序列左移
        LD      R16,X        ;
        SUBI    R16,$29      ;数字带小数点?
        BRCC    DD4          ;若带则将其复原(参考DSPY子程序段码表)
        SUBI    R16,$D7      ;恢复
DD4:    ST      -X,R16       ;移入左邻单元
DD5:    INC     R26         
        CPI     R26,$73     
        BRNE    DDL          ;各数字都左移了一位?
        ST      X,R15        ;新键入数字进入数字序列末位
        LDI     R26,$6C
DEL:    LD      R16,X
        CPI     R16,10       ;是BCD码?
        BRCS    DEL2         
        CPI     R16,$29
        BRCC    DELRT        ;大于$29为错误!
DELA:   INC     R26          ;0--9/$24/$14为有效!
        CPI     R26,$73
        BRNE    DEL          ;缓存区检查完毕?
        RJMP    DELRT
DEL2:   CPI     R16,0
        BRNE    DELRT
        LDI     R16,$24      ;0改为空白
        ST      X,R16
        RJMP    DELA         ;
DELRT:  LDS     R16,$A0      ;小数点位置单元
        TST     R16
        BREQ    DDRET        ;($a0)=0,无小数点
        NEG     R16
        ADD     R16,$73
        MOV     R26,R16      ;找到缓存区内带小数点的数据位
        LD      R16,X
        SUBI    R16,$D7      ;加上小数点
        ST      X,R16
        CPI     R16,$4D      ;在空白码加了小数点($24(空白)+$29=$4d)?
        BRNE    STLR1
        LDI     R16,$29
        ST      X,R16        ;是,将其改为'0.'
STLR1:  CPI     R26,$73
        BREQ    DDRET        ;并将其后所有空白都改为0
        INC     R26
        LD      R16,X
        CPI     R16,$24
        BRNE    DDRET
        CLR     R16
        ST      X,R16
        RJMP    STLR1
DDRET:  RET

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

       ;范例30               ;双键输入检查数据子程序,Ky1数据键/Ky2回车键
KYIN2:  LDI     R26,$60      ;寄存器地址:portb:$18/ddrb:$17/pinb:$16
        CLR     R27          ;指向数据区首地址
        CBI     DDRB,7
        CBI     DDRB,6       ;pb7和pb6皆为输入口
        SER     R17
        OUT     DDRC,R17     ;c口为数据显示口
LA0:    LD      R17,X        ;取数据
        CPI     R17,$0A
        BRCS    LA1
        CLR     R17
LA1:    LDI     R31,HIGH(table*2)
        LDI     R30,LOW(table*2);DSPY段选码表
        ADD     R30,R17
        ADC     R31,R27     
        LPM
        COM     R0           ;段选码取出并取反
        OUT     PORTC,R0     ;送C口
        SBI     PORTB,7
        SBIC    $16,7
        RJMP    NXA1         ;数字键未按下,转
        RCALL   DL50         ;否则延时
XA2:    SBI     PORTB,6
        SBIC    $16,6
        RJMP    XA0          ;只有数字键按下,转
XA20:   RCALL   DL50         ;两键都按下,先延时50mS
        SBI     PORTB,6
        SBIS    $16,6
        RJMP    XA20
        SBI     PORTB,7
        SBIS    $16,7
        RJMP    XA20         ;等两键都释放
        RCALL   DL50
XA21:   SBI     PORTB,6
        SBIS    $16,6
        RJMP    XA21         ;等待释放
        SBI     PORTB,7
        SBIS    $16,7
        RJMP    XA21         ;再次等待释放
        RJMP    NXA6         ;先按数字键,再按回车键,待2都键释放后退出子程序
XA0:    SBI     PORTB,7
        SBIS    $16,7
        RJMP    XA2          ;等待数字键释放
XA1:    RCALL   DL50         ;延时
        SBI     PORTB,7
        SBIS    $16,7
        RJMP    XA1          ;再次等待释放
        INC     R17          ;数字增1
        CPI     R17,10
        BRCS    NXA1
        CLR     R17          ;超过10,将键值归为0
NXA1:   SBI     PORTB,6
        SBIC    $16,6
        RJMP    LA1          ;回车键也未按下,重新查键
        RCALL   DL50         ;延时
NXA3:   SBI     PORTB,6
        SBIS    $16,6
        RJMP    NXA3         ;再次等待回车键释放
        RCALL   DL50
        SBI     PORTB,6
        SBIS    $16,6
        RJMP    NXA3         
        ST      X+,R17       ;数字转入缓存区
        SER     R17
        OUT     PORTB,R17    ;关显
        RCALL   DL50         ;
        CPI     R26,$70      ;到规定数字个数?
        BRNE    LA0          ;
        LDI     R17,$86      ;显示'E'nd
        OUT     PORTC,R17    ;
NXA4:   SBI     PORTB,6
        SBIS    $16,6
        RJMP    NXA5         ;回车键按下,转
        SBI     PORTB,7
        SBIC    $16,7        ;数字键按下,转
        RJMP    NXA4         ;否则反复查键
NXA40:  RCALL   DL50
        SBI     PORTB,7
        SBIS    $16,7
        RJMP    NXA40       
        SBI     PORTB,7
        SBIS    $16,7
        RJMP    NXA40        ;等待键释放
        RJMP    KYIN2        ;转检查键入数据
NXA5:   RCALL   DL50
        SBI     PORTB,6
        SBIS    $16,6       
        RJMP    NXA5
        SBI     PORTB,6
        SBIS    $16,6
        RJMP    NXA5         ;等回车键释放
NXA6:   SER     R17
        OUT     PORTB,R17    ;关显,结束子程序
        RET
DL50:  ;RCALL   DL25         ;延时50毫秒子程序/8Mhz(去掉指令前“;”号)
DL25:   CLR     R14          ;延时50毫秒子程序/4Mhz
        CLR     R15
DL50L:  DEC     R15
        NOP
        BRNE    DL50L
        DEC     R14
        BRNE    DL50L
        RET
       
       ;范例31
LPRNT:  SER     R17          ;宽行打印机检测及控打程序
        OUT     DDRC,R17     ;C口为打印机输出口!
        SBI     DDRD,7
        CBI     DDRD,3       ;pd7为选通输出口,pd3(INT1)查忙输入口
        SBI     PORTD,3
        SBIC    PIND,3       ;查打印机忙信号
        RJMP    ERR5         ;打印机尚未工作忙信号即已为高,打印机不能打印
        LDI     R17,$0D      ;写回车命令给打印机
        OUT     PORTC,R17
        CBI     PORTD,7      ;发出选通信号
        NOP                 
        NOP
        NOP
        SBI     PORTD,7      ;strobe
        LDI     R16,50
TSPRT:  SBI     PORTD,3
        SBIc    PIND,3       
        RJMP    LPRT2        ;50次内忙信号高起来为正常
        DEC     R16          ;否则为非正常状态
        BRNE    TSPRT
ERR5:   LDI     R16,5
        RCALL   ERRX         ;显示5号错误
        RJMP    DIPA1        ;转主程序初始化
LPRT2:  LDI     R25,1       
        CLR     R24          ;point to $100
        LDI     R17,$80
        OUT     GIMSK,R17    ;允许int1中断
        LDI     R17,$0A
        OUT     MCUCR,R17    ;INT1下降沿中断
        SEI                  ;general interrupt enable
        RET
EX_INT1:PUSH    R26
        PUSH    R27
        IN      R27,SREG
        PUSH    R27
        PUSH    R17          ;保护现场
        MOV     R27,R25      ;取数据指针
        MOV     R26,R24
        LD      R17,X+       ;
        MOV     R25,R27
        MOV     R24,R26      ;增1后将指针送回
        CPI     R17,3        ;是停止符?
        BRNE    INT1SD
        CLR     R17
        OUT     GIMSK,R17    ;禁止INT1中断
        RJMP    INT1ED
INT1SD: OUT     PORTC,R17    ;打印数据输出到打印口
        CBI     PORTD,7      ;clr ($12,7)
        NOP
        NOP
        NOP
        SBI     PORTD,7      ;向打印机发出选通
INT1ED: POP     R17
        POP     R27
        OUT     SREG,R27
        POP     R27
        POP     R26          ;恢复现场
        RETI
       
       ;范例32               ;步进电机控制程序
       .ORG     0
STRT10: RJMP    RST10        ;8535/8515/晶振4MHZ
       .ORG     $011
RST10:  LDI     R16,HIGH(ramend)
        OUT     SPH,R16
        LDI     R16,LOW(ramend)
        OUT     SPL,R16
        SER     R16
        OUT     DDRB,R16     ;B口为输出
        LDI     R17,8
        OUT     PORTB,R16    ;接通总开关
        LDI     R16,50       ;50次基本运作
        RCALL   DELAY5       ;延时5毫秒
LOOPX:  LDI     R17,$68      ;step1时序脉冲控制
        OUT     PORTB,R17
        RCALL   DELAY2       ;延时2毫秒
        LDI     R17,$38      ;step2时序脉冲控制
        OUT     PORTB,R17
        RCALL   DELAY2       ;延时2毫秒
        LDI     R17,$98      ;step3时序脉冲控制
        OUT     PORTB,R17
        RCALL   DELAY2       ;延时2毫秒
        LDI     R17,$C8      ;step4时序脉冲控制
        OUT     PORTB,R17
        RCALL   DELAY2       ;延时2毫秒
        DEC     R16
        BRNE    LOOPX        ;到50次?
        LDI     R17,8
        OUT     PORTB,r17    ;关闭各相位开关
        RCALL   DELAY5
        RCALL   DELAY5       ;延时10毫秒
        CLR     R17
        OUT     PORTB,R17    ;关闭所有相位开关和总开关
HH0:    RJMP    HH0          ;踏步
DELAY1: LDI     R17,$06      ;延时1毫秒
        MOV     R15,R17      ;1000/0.75=1333=$535,外層计数器装入$06
        LDI     R17,$35      ;DEC+BRNE=0.75微秒
        RJMP    DLCOM
DELAY2: LDI     R17,$0B      ;延时2毫秒
        MOV     R15,R17      ;2000/0.75=2666=$0A6A,外層计数器装入$0B
        LDI     R17,$6A
DLCOM:  DEC     R17
        BRNE    DLCOM
        DEC     R15
        BRNE    DLCOM
        RET
DELAY5: LDI     R17,$1B      ;延时5毫秒
        MOV     R15,R17      ;5000/0.75=6666=$1A0A,外層计数器装入$1B
        LDI     R17,$0A
        RJMP    DLCOM
       
       ;范例33
       .ORG     0            ;8515采用定时器中断输出时序脉冲方式控制电机转动
STRT11: RJMP    RST11        ;晶振4MHZ
       .ORG     $007
        RJMP    T0_OVF        ;中断服务程序与STRT12共用
       .ORG     $00D
RST11:  LDI     R17,HIGH(ramend)
        OUT     SPH,R17
        LDI     R17,LOW(ramend)
        OUT     SPL,R17
        LDI     R17,$68
        MOV     R7,R17       ;初始脉冲为0B01101000
        SER     R17
        OUT     DDRB R17     ;B口为输出
        LDI     R17,N        ;运作次数N(N>0)
        RCALL   STPDRV       ;初始化子程序
HH20:   RJMP    HH20         ;实用时改为具体的背景程序!
STPDRV: TST     R17
        BRNE    STPDR1
        INC     R17          ;N=0时,将其改为1
STPDR1: MOV     R6,R17
        INC     R6           ;N+1-->r6(max.is 256;“植树问题”,N必需增1!
        LDI     R17,$A4
        CBR     R17,$20
        STS     $A4,R17      ;清除连续转动电机标志
        LDI     R17,$08
        OUT     PORTB,R17    ;接通总开关
        LDI     R17,4        ;0B00000100/ 256分频(4兆/256=1兆/64)
        OUT     TCCR0,R17   
        LDI     R17,178      ;78*64=4.992ms
        OUT     TCNT0,R17    ;时间常数,首定时为5毫秒
        LDI     R17,$02
        OUT     TIMSK,R17    ;允许T/C0溢出中断
        SEI                 
HH21:   SJMP    HH21
       ;范例34
       .ORG     $000         ;步进电机手动控制程序(8515)晶振4MHZ
STRT12: RJMP    RST12
       .ORG     $007
        RJMP    T0SEV
       .ORG     $00D
RST12:  LDI     R17,HIGH(ramend)
        OUT     SPH,R17
        LDI     R17,LOW(ramend)
        OUT     SPL,r17
        LDI     R17,$68
        MOV     R7,R17       ;第一个时序脉冲
        LDI     R17,$F8
        OUT     DDRB,R17     ;PB7-PB3输出,PB2-PB0输入
        CLR     R17
        OUT     PORTB,R17    ;输出为低电平
        LDS     R17,$A4
        SBR     R17,$20      ;设置连续转动标志
        CBR     R17,$40      ;设置电机正转标志
TSTLP1: SBI     PORTB,1      ;PB1接地,正转
        SBIS    PINB,1
        RJMP    TSTL11       ;
TSTL10: SBI     PORTB,2
        SBIC    PINB,2       ;PB2接地,反转
        RJMP    TSTLP1       ;PB1,PB2都未接地,反复查询
        SBR     R17,$40      ;设置电机反转
TSTL11: STS     $A4,R17      ;保存标志
        CLR     R6
        INC     R6           ;R6中装入1,减一次即为0!
        LDI     R17,$08
        OUT     PORTB,R17    ;接通总开关
        LDI     R17,4        ;0B00000100/256分频(256/4=64微秒)!
        OUT     TCCR0,R17   
        LDI     R17,178      ;178之补为78,78*64=4.992ms
        OUT     TCNT0,R17    ;
        LDI     R17,$02
        OUT     TIMSK,R17    ;允许T/C0中断(toie1=$39,7 toie0=$39,1)
                             ;8535,toie1:$39,2 toie0:$39,0
        SEI                 
TSTLP2: SBI     PORTB,1
        SBI     PORTB,2
        IN      R17,PINB
        ANDI    R17,6
        CPI     R17,6       
        BRNE    TSTLP2       ;两开关未全部打开,查询等待
        LDS     R17,$A4
        CBR     R17,$20      ;清除连续转动标志
        STS     $A4,R17      ;
TSTLP3: IN      R17,TIMSK
        SBRC    R17,1        ;已禁止8515中断?(8535:timsk,0)
        RJMP    TSTLP3       ;未,查询等待
        RJMP    RST12

T0_OVF: PUSH    R17          ;电机控制中断服务子程序
        IN      R17,SREG
        PUSH    R17
        LDS     R17,$A4
        SBRC    R17,7
        RJMP    T0SV2        ;$A4,7:关电机前10毫秒延时标志
        MOV     R17,R7
        CPI     R17,$68
        BRNE    T0SV0
        LDS     R17,$A4
        SBRC    R17,5
        RJMP    T0SV0        ;电机连续转动,不减R6
        DEC     R6           ;R6减为0,将停止电机
        BREQ    T0SV1        ;
T0SV0:  LDI     R17,225      ;每步进延时(256-225)*64=1.984MS err.<0.8%
        OUT     TCNT0,R17    ;
        OUT     PORTB,R7     ;步进控制脉冲输出
        LDS     R17,$A4
        SBRC    R17,6
        RJMP    T0SVA        ;$A4,6=1 为连续反转
        CLC
        SBRC    R7,4         ;组织下一步控制脉冲
        SEC
        ROR     R7
        LDI     R17,$08      ;正转
        OR      R7,R17       ;01101***->00111***->10011***->11001***->01101***.......
        RJMP    T0RET
T0SVA:  MOV     R17,R7       ;
        SBR     R17,$04
        ROL     R17          ;组织下一步控制脉冲(反转)
        BRCS    T0SVB
        CBR     R17,$10      ;01101***->11001***->10011***->00111***->01101***.......!
T0SVB:  MOV     R7,R17
        RJMP    T0RET
T0SV1:  LDS     R17,$A4
        SBR     R17,$80
        STS     $A4,R17      ;总开关关断前10毫秒延时标志
        LDI     R17,$08
        OUT     PORTB,R17    ;关断4个相位开关
        LDI     R17,100      ;156(256-100)*64=9.984ms
        OUT     TCNT0,R17    ;
        RJMP    T0RET
T0SV2:  LDI     R17,$07
        OUT     PORTB,R17    ;关闭所有开关
        CLR     R17
        OUT     TCCR0,R17    ;关T/C0中断
        OUT     TIMSK,R17   
        LDS     R17,$A4
        CBR     R17,$C0
        STS     $A4,R17      ;清除10毫秒延时和反向转动标志
T0RET:  POP     R17
        OUT     SREG,R17
        POP     R17
        RETI
       ;精确定时及时钟日历走时子程序
       ;范例35
.EQU    DTPNT=$75            ;年年月日时分秒(from $7B to $75)
       .ORG     $000
STRT20: RJMP    RST20        ;晶体实测频率4.000119MHZ
       .ORG     $006         ;8515 t1 overflow INT.vector
        RJMP    T1_OVF
       .ORG     $00D
RST20:  LDI     R16,HIGH(ramend)
        OUT     SPH,R16
        LDI     R16,LOW(ramend)
        OUT     SPL,R16
        LDI     R16,2        ;8分频,4000119/8=500015
        OUT     TCCR1B,R16   
        LDI     R16,$5E      ;500015=65536*8-24273=8*$10000-$5ed1/TCC=$5Ed1
        OUT     TCNT1H,R16   ;
        LDI     R16,$D1      ;
        OUT     TCNT1L,R16   ;将TCC写入TCNT1
        LDI     R16,$80     
        OUT     TIMSK,R16    ;允许T/C1溢出中断
        LDI     R16,8        ;8次中断出秒号
        MOV     R6,R16
        SEI                 
HH10:   RJMP    HH10         ;可改为具体的实用程序
T1_OVF: PUSH    R16
        PUSH    R17
        IN      R7,SREG
        DEC     R6           ;到8次中断?
        BRNE    GOON1       
        IN      R17,TCNT1L   ;*
        IN      R16,TCNT1H   ;*读回TCNT1自然计数值
        SUBI    R17,$2F      ;*$5ED1之补为$A12F,以减法替代加法修正TCC
        SBCI    R16,$A1      ;*减去$A12E可不做下面的加1修正
        SUBI    R17,$FF      ;*8条修正指令占用一个计数单位时间
        SBCI    R16,$FF      ;*修正后TCC=$5ED1+(TCNT1)+1
        OUT     TCNT1H,R16   ;*
        OUT     TCNT1L,R17   ;*将修整后TCC写入TCNT1
        LDI     R16,8
        MOV     R6,R16       ;重装中断次数8
        ;.                   
        ;.
        RCALL   ACLK         ;时钟走时
GOON1:  POP     R17
        POP     R16
        OUT     SREG,R7
        RETI
       ;范例36
.EQU    DTPNT=$75            ;yyyy mm dd hh mm ss(from $7B--$75)
       .ORG   $000           ;晶体实测频率8.000267MHZ,8分频
                             ;INT(8000267/8)=1000033
STRT21: RJMP    STRT21
       .ORG     $006         ;8515 t1 overflow INT. vector
        RJMP    T1_OVF
       .ORG     $00D
STRT21: LDI     R16,HIGH(ramend)
        OUT     SPH,R16
        LDI     R16,LOW(ramend)
        OUT     SPL,R16
        LDI     R16,2       
        OUT     TCCR1B,R16   ;8分频
        LDI     R16,1        ;1000033=62332*15+65053
                             ;=($10000-$0C84)*15-$10000-$1E3
        OUT     TCNT1H,R16   ;主常数62332(补码为$0C84) 补尝常数TCC=$01E3
        LDI     R16,$E3      ;$FE1D=65053\65053+62332*15=1000033
        OUT     TCNT1L,R16
        CLR     R16
        OUT     TCCR1A,R16   ;DISABLE CMPA/CMPB/PWM!
        LDI     R16,$80      ;8515
        OUT     TIMSK,R16    ;允许T/C1溢出中断
        LDI     R16,16       ;16次中断
        MOV     R6,R16
        SEI                 
HH11:   RJMP    HH11         ;
T1_OVF: PUSH    R17
        PUSH    R16
        IN      R7,SREG
        DEC     R6           ;中断次数到?未到转装入主常数
        BRNE    COMP         ;否则重装入TCC
        IN      R17,TCNT1L   ;*
        IN      R16,TCNT1H   ;*读回自然计数值
        SUBI    R17,$1D      ;*
        SBCI    R16,$FE      ;*减去TCC之补码
        SUBI    R17,255      ;*再加1
        SBCI    R16,255      ;*修正后TCC=$01E3+(TCNT1)+1
        OUT     TCNT1H,R16   ;*
        OUT     TCNT1L,R17   ;*
        LDI     R16,16
        MOV     R6,R16       ;重写中断次数
        ;.               
        ;.
        RCALL   ACLK         ;时钟走时
        RJMP    GOON2
COMP:   IN      R17,TCNT1L   ;*
        IN      R16,TCNTIH   ;*读回TCNT1自然计数值
        SUBI    R17,$7C      ;*先减去$0C84$'补码$F37C
        SBCI    R16,$F3      ;*再作加1补偿
        SUBI    R17,$FF      ;*
        SBCI    R16,$FF      ;*修整后重装值=[$0C84+(TCNT1)+1]
        OUT     TCNT1H,R16   ;*
        OUT     TCNT1L,R17   ;*
GOON2:  POP     R16
        POP     R17
        OUT     SREG,R7
        RETI
       ;范例37                ;8515使用T/C0定时,64分频,晶振频率4000131HZ
       .ORG     $000
       .EQU    DTPNT=$75
STRT22: RJMP    RST22
       .ORG     $007
        RJMP    T0_OVF       ;INT(4000131/64)=62502=245*256-218
       .ORG     $00D
RST22:  LDI     R16,245      ;245次中断
        MOV     R6,R16
        LDI     R16,3
        OUT     TCCR0,R16    ;主频FCK(4000131HZ)64分频
        LDI     R16,$02
        OUT     TIMSK,R16    ;允许T/C0溢出中断
        LDI     R16,218
        OUT     TCNT0,R16    ;TCC=218
        SEI
HH12:   RJMP    HH12         ;
T0_OVF: IN      R7,SREG
        DEC     R6
        BRNE    DECL1        ;
        IN      R16,TCNT0    ;1秒时间到!
        SUBI    R16,38       ;218之补
        OUT     TCNT0,R16    ;
        LDI     R16,245
        MOV     R6,R16       ;重装中断次数
        RCALL   ACLK         ;时钟走时
DECL1;  OUT     SREG,R7
        RETI
       ;范例38               ;8535异步时钟定时程序
       .ORG     $000         ;时钟频率32768HZ
       .EQU     DTPNT=$75
STRT23: RJMP    RST23
       .ORG     $004
        RJMP    T2_OVF
       .ORG     $011
RST23:  LDI     R16,8
        OUT     ASSR,R16     ;选异步时钟
                           
        LDI     R16,5
        OUT     TCCR2,R16    ;128分频
        CLR     R16
        OUT     TCNT2,R16    ;时间常数256($00)
        LDI     R16,$40
        OUT     TIMSK,R16    ;允许T/C2溢出中断
       ;............       
        SEI
HH13:   LDI     R16,$70      ;掉电休眠模式
        OUT     MCUCR,R16   
        SLEEP                ;进入休眠
        RJMP    HH13         ;
T2_OVF  IN      R7,SREG      ;
        RCALL   ACLK         ;时钟走时
       ;...........         
        OUT     SREG,R7
        RETI
       ;范例39
ACLK:   PUSH    R16
        PUSH    R27
        PUSH    R26
        PUSH    R7
        LDI     R26,LOW(dtpnt);
        LDI     R27,HIGH(dtpnt);时钟日历单元指针
        RCALL   DHM3         ;秒单元加1调整
        CPI     R16,$60      ;
        BRNE    COM0         ;未到60秒返回
        RCALL   DHM          ;分单元加1调整
        CPI     R16,$60     
        BRNE    COM0         ;未到60分返回
        RCALL   DHM          ;时单元加1调整
        CPI     R16,$24     
        BRNE    COM0         ;未到24时返回
        RCALL   DHM          ;日单元加1调整
        SUBI    R16,$29     
        BRCS    COM0         ;小于29返回
        BRNE    T30          ;转继续测试30/31/32日
        ADIW    R26,1        ;29,指向月
        LD      R16,X     
        CPI     R16,2
        BRNE    COM0         ;非二月返回
        ADIW    R26,1        ;指向年
        LD      R16,X        ;取年十个位
        TST     R16
        BRNE    TYLB
        ADIW    R26,1
        LD      R16,X        ;年十个位为0,取年千百位
TYLB:   SWAP    R16
        ANDI    R16,15
        MOV     R7,R16
        LSL     R7
        LSL     R7           ;高位BCD乘4
        ADD     R16,R7       ;乘5
        LSL     R16          ;乘10
        LD      R7,X         ;加个位BCD
        ADD     R16,R7       ;年十个位(千百位)转成二进制数
        ANDI    R16,3        ;该二进制数末两位皆为0,为闰年
        BREQ    COM0         ;返回(二月有29日)
        RJMP    DAY1         ;否则为3月1日
T30:    SUBI    R16,7        ;减7调整
        BRNE    T31          ;$30-$29-7=0
        ADIW    R26,1        ;指向月
        LD      R16,X       
        CPI     R16,2             
        BRNE    COM0         ;非2月返回
        RJMP    DAY1         ;闰年的2月30日为3月1日
T31:    DEC     R16          ;$31-$29-7=1&$32-$29-7=2
        BRNE    DAY1         ;日为32 ,为下月1日
        ADIW    R26,1        ;日为31 ,指向月
        LD      R16,X
        SUBI    R16,8        ;月份减去8
        BRCC    SCHY
        INC     R16          ;月份小于8,差增1,奇数变偶数
SCHY:   SBRS    R16,0             
        RJMP    COM0         ;1-7月奇数月为大月/8-12月偶数月为大月;有31日,返回
DAY1:   LDI     R26,LOW(dtpnt+3)
        LDI     R27,HIGH(dtpnt+3);指向日
        LDI     R16,1        ;
        RCALL   DHM1         ;日置为1,月加1
        CPI     R16,$13
        BRNE    COM0
        LDI     R16,1        ;月变为13,改为1
        RCALL   DHM1         ;年十个位加1调整,可能有$99+1=$A0
        CPI     R16,$A0
        BRNE    COM0         ;
        RCALL   DHM          ;年千百位加1调整
COM0:   POP     R7
        POP     R26
        POP     R27
        POP     R16
        RET
DHM:    CLR     R16          ;秒,分,时单元清除,高位加1
DHM1:   ST      X+,R16
DHM3:   LD      R16,X
        INC     R16          ;
        CPI     R16,$0A      ;若个位BCD码未变成$0A
        BRHS    DHM2         ;例如$58+1=$59,不须调整;
        SUBI    R16,$FA      ;否则做减$FA调整:例如$49+1-$FA=$50
DHM2:   ST      X,R16        ;并将调整结果送回
        RET
       ;范例40
       .ORG     0            ;8535UART串行通讯程序,晶振4MHZ
.EQU    DTPINT=$180          ;UBRR=12 波特率19200(REL.ERR.=0.16%)
.EQU    DRPINT=$1D0
STRT30: RJMP    RST30
       .ORG     $00B
        RJMP    U_RXC        ;UART接收完成中断
       .ORG     $00C
        RJMP    U_TXC        ;UART发送寄存器空中断
       .ORG     $011
RST30:  LDS     R16,$A3      ;
        CBR     R16,3
        STS     $A3,R16      ;清完整ASCII数据块接收到标志($A3,1),错误标志(FE/OR)($A3,0)
        LDI     R16,12
        OUT     UBRR,R16     ;BAUD RATE=FCP/16(UBRR+1)=19200
        LDI     R27,HIGH(DIPINT)
        MOV     R6,R27
        LDI     R26,LOW(DTPINT)
        MOV     R7,R26       ;发送数据指针在r6r7(dtpint)
        CLR     R11
        INC     R11
        LDI     R16,$30      ;发送数据块长度为$30
        MOV     R12,R16
        RCALL   CRC0         ;得到CRC检测之余式(冲掉$0D&$0A)
        INC     XL
        INC     XL
        LDI     R16,$0D
        ST      X+,R16
        LDI     R16,$0A
        ST      X,R16        ;在数据块末尾加$0D&$0A,实际发送数据块长度为$32
        LDI     R16,$B8      ;允许UART发送和接收,接收中断,发送寄存器空中断,8位数据
        OUT     UCR,R16     
        LDI     R16,HIGH(DRPINT)
        MOV     R8,R16
        LDI     R16,LOW(DRPINT)
        MOV     R9,R16       ;r8,r9:接收缓存区指针(FIRST POINT TO $1D0)
        CLR     R10          ;接收数据块长预先清除
        SEI                  ;
HH30:   LDS     R16,$A3
        SBRC    R16,0        ;错误接收?
        RJMP    RCVER        ;错误处理
        SBRS    R16,1        ;接收数据完成?
        RJMP    HH30         ;否,转再查询
RCVEF:  CLR     R11          ;块长予处理
        INC     R11
        DEC     R10
        DEC     R10          ;$0D&$0A不算块长度之内(故将块长减2)
        MOV     R12,R10      ;(R11,R12):块长
        LDI     XH,HIGH(DRPINT)
        MOV     R8,XH
        LDI     XL,LOW(DRPINT)
        MOV     R9,XL
        RCALL   CRC0         ;恢复出CRC余式
        LDI     R16,$0D
        CP      R16,R14
        BRNE    CRCER
        LDI     R16,$0A
        CP      R16,R15      ;恢复出$0D$0A为正确接收
        BREQ    HH30
CRCER:  ;.                   ;循环冗余检测错误处理
        ;.
        ;.
        RJMP    STRT30
RCVER:  CBI     UCR,RXCIE
        ;.                   ;接收错误(FE/OR)处理
        ;.                   ;(过程略)
        ;.
        RJMP    STRT30
       :UART接收数据块程序   
U_RXC:  PUSH    R16         
        IN      R16,SREG
        PUSH    R16
        PUSH    R26
        PUSH    R27
RSC1:   IN      R16,USR      ;UART状态寄存器
        ANDI    R16,$18      ;FE/OR ERROR?
        BRNE    RVERR        ;错误转
        INC     R10          ;块长加1
        MOV     XH,R8
        MOV     XL,R9        ;r8r9:接收数据指针,首指$1D0
        IN      R16,UDR
        ST      X+,r16       ;
        MOV     R8,XH
        MOV     R9,XL
        CPI     R16,$0A      ;收到最末字符(回车命令LF)?
        BRNE    RSCOM
        LDS     R16,$A3     
        SBR     R16,2        ;建立数据块接收完毕标志
        STS     $A3,R16     
        CBI     UCR,RXCIE    ;禁止接收中断
        RJMP    RSCOM
RVERR:  LDS     R16,$A3
        SBR     R16,1
        STS     $A3,R16      ;$A3,0:FE/OR错误接收标志
RSCOM:  POP     R27
        POP     R26
        POP     R16
        OUT     SREG,R16
        POP     R16
        RETI
;       UART发送数据块程序
U_TXC:  PUSH    R16
        IN      R16,SREG
        PUSH    R16
        PUSH    R26
        PUSH    R27
SPSV1:  MOV     XH,R6         
        MOV     XL,R7        ;发送数据指针,首指$180
        LD      R16,X+       ;取发送数据,调指针
        MOV     R6,XH
        MOV     R7,XL
SPS11:  OUT     UDR,R16      ;送入数据寄存器,移入发送移位寄存器后即引起数据寄存器空中断
        CPI     R16,$0A
        BRNE    SPCOM
        CBI     UCR,UDRIE    ;发送最末字符后禁止发送寄存器空中断
        LDI     R16,HIGH(DRPINT)
        MOV     R8,R16
        LDI     R16,LOW(DRPINT)
        MOV     R9,R16       ;接收数据指针初始化,指向$1D0
       ;CBI     USR,6        ;
SPCOM:  POP     R27
        POP     R26
        POP     R16
        OUT     SREG,R16
        POP     R16
        RETI
       .DSEG
       .ORG    $180
DTPINT:.BYTE   $32
        ;$41,$45,$65,$73,$46,$42,$40,$6F,$33,$44,$66,$8C,$4D,$4B,$2F,$67
        ;$42,$4F,$66,$78,$47,$45,$44,$63,$32,$48,$60,$7C,$6D,$45,$2A,$63
        ;$43,$56,$55,$53,$4D,$4F,$40,$2E,$31,$42,$67,$4C,$47,$4A,$38,$39
        ;$0D,$0A
        .EQU     DRPINT=$1D0
        .ORG     $1D0
DRPINT: .BYTE    $34   ;(内容略)

       ;范例41               ;外部中断int0接收ASCII码数据块
       .ORG     0            ;8515/8535/晶振4MHZ
STRT31: RJMP    RST31
        RJMP    EX_INT0
       .ORG     $00D         ;8535外部中断0
RST31:  LDI     R17,HIGH(ramend)
        OUT     SPH,R17
        LDI     R17,LOW(ramend)
        OUT     SPL R17
        LDI     R17,2
        OUT     TCCR1B,R17   ;4mhz/8分频,计数单位为2微秒,TCCR1B:$2e
        LDI     R17,$40
        OUT     GIMSK,R17    ;gimsk,6(允许int0中断)
        LDI     R17,2
        OUT     MCUCR,R17    ;设INT0为下降沿中断(mcucr'b1&b0=10)
        CBI     DDRD,2       ;int0 为输入
        ;.
        ;.                   ;其他初始化略
        SEI                  ;
CLRBUF: LDI     R27,1
        CLR     R26          ;接收数据缓存区首址$100
        LDI     R17,$40
        OUT     GIMSK,R17    ;gimsk,6
        CLR     R17
CLRLOP: ST      X+,R17
        CPI     R26,$48
        BRNE    CLRLOP       ;清接收缓存区($100--$147)
        LDS     R16,$A3
        CBR     R16,$60
        STS     $A3,R16      ;接收错误($A3,6)和接收完成($A3,5)标志清除
CLR5:   ;.
        ;.                   ;背景程序略
        RJMP    CLR5         ;
RCVST:  CBI     DDRD,2       ;int0 为输入
              SER     R16          ;接收开始
        OUT     PORTC,R16    ;关显
        LDI     R27,1
        CLR     R26          ;接收数据指针,首指$100
        LDI     R17,18       ;接收18个字符,其末尾为$0D$0A
        MOV     R14,R17
        RCALL   RVBYT1       ;接收第一个字符
        RJMP    RVBYT
RVBLOP: RCALL   RVBYT2       ;接收第二个字符及其后字符
RVBYT:  LDS     R17,$A3
        SBRC    R17,6
        RJMP    CLRBUF       ;接收出错,转去清除$100--$14F
        SBRC    R17,5
        RJMP    DTCOM        ;接收完整数据块,转去处理
        ST      X+,R16
        DEC     R14
        BRNE    RVBLOP       ;未收完18个字符,继续
        CPI     R26,$42      ;指针达到$142?
        BREQ    DTCOM        ;接收完整数据块,转去处理
        DEC     R26
        DEC     R26          ;$0D$0A(CR&LF)丢掉
RCVLP:  LDI     R17,18       
        MOV     R14,R17
        RJMP    RVBLOP
DTCOM:  LDI     R27,1
        CLR     R26          ;接收数据首地址:$100
DLLOP:  CLR     R29
        LDI     R28,$90      ;处理ASCII码程序acum要求将数据放在$90--$9f
        LD      R16,X
        CPI     R16,$50      ;第一个字符约定为‘P’才有效
        BRNE    RVCOM1       ;也是判断处理结束符
DLLOP1: LD      R16,X+   
        ST      Y+,R16
        CPI     R28,$A0
        BRNE    DLLOP1       ;传16个字符
        PUSH    R26
        PUSH    R27
        RCALL   ACUM         ;ASCII变BCD再变为二进制数,累加
        POP     R27
        POP     R26
        BRTS    RVCOM1       ;ASCII码无效,转出!
        RJMP    DLLOP
RVCOM1:
        CLT
        RJMP    CLRBUF       ;转去清缓存区,重新接收
                             ;晶振采用4MHZ,指令(DEC+BRNE)耗时0.75微秒)!
EX_INT0:POP     R16          ;int0中断服务子程序
        POP     R16          ;废弃返回地址
        LDI     R16,HIGH(RCVST)
        PUSH    R16
        LDI     R16,LOW(RCVST)
        PUSH    R16          ;设置返回地址
        IN      R16,GIMSK    ;禁止int0中断
        CBR     R16,$40
        OUT     GIMSK,R16
        RETI
RVBYT1: LDI     R17,2        ;查到0接收时,再做一次接收
        MOV     R15,R17     
        LDI     R17,50       ;第一个起始位半位延时(50*0.75=38微秒)
        MOV     R12,R17
        RJMP    RVBCM
RVBYT2: LDI     R17,2
        MOV     R15,R17     
RVBY2:  LDI     R17,147      ;110微秒>1位宽/9600baud,110/0.75=147
        MOV     R12,R17
TEST3:  SBI     PORTD,2
        SBIS    PIND,2       ;停止位超宽测试
        RJMP    RVST
        DEC     R12
        BRNE    TEST3
        LDS     R16,$A3      ;110微秒内查到低电平为起始位
        ORI     R16,$20
        STS     $A3,R16      ;否则为接收结束,令$A3,5=1
        RET
RVST:   LDI     R17,60       ;60*0.75=45微秒(半位延时)
        MOV     R12,R17     
RVBCM:  DEC     R12
        BRNE    RVBCM
        LDI     R17,9        ;1位起始+8位数据
        MOV     R13,R17
        SBI     PORTD,2
        SBIC    PIND,2
        RJMP    RVER1        ;无效起始位(半位测试)
RVLOP:  LDI     R17,130       ;may be 128-132/位延时常数
        MOV     R12,R17
RVLP1:  DEC     R12          ;0.25微秒
        BRNE    RVLP1        ;0.5微秒/if condition is true
        SEC
        SBI     PORTD,2
        SBIS    PIND,2
        CLC
        DEC     R13       
        BRNE    OVRRC        ;不是停止位,转数据位接收
        BRCC    RVER1        ;无效停止位,出错
        TST     R16          ;
        BRNE    RBYRT        ;不为0,收到一个有效字符
        DEC     R15
        BRNE    RVBY2        ;2次接收到$00,出错
RVER1:  LDS     R16,$A3
        ORI     R16,$40      ;接收出错标志
        CBR     R16,$20     
        STS     $A3,R16     
RBYRT:  RET
OVRRC:  ROR     R16          ;组织数据
        RJMP    RVLOP        ;100.7微秒/程序实设位宽

       ;范例42               ;8535'T0中断发送ASCII码程序,晶振4MHZ
       .EQU      DATA2=$150
       .ORG     $000
STRT32: RJMP    RST32
       .ORG     009
        RJMP    T0_OVF
       .ORG     $011
RST32:  SER     R17
        OUT     DDRB,R17     ;B口为输出
        OUT     PORTB,R17    ;输出高电平
        LDI     R16,2        ;0B00000010/8 DIVIDED(4fc/8:2微秒)
        OUT     $33,R17      ;写入tccr0
        LDI     R16,204      ;(256-204)*2=104微秒/9600baud 104微秒/位!
        OUT     TCNT0,R17    ;
        LDI     R17,HIGH(ramend)
        OUT     SPH,R17
        LDI     R17,LOW(ramend)
        OUT     SPL,R17
        LDI     R25,HIGH(DATA2)
        LDI     R24,LOW(DATA2);发送数据指针
        LDS     R17,$A3
        CBR     R17,$14      ;发送出错标志($A3,4)/发送完毕标志位($A3,2)清除!
        STS     $A3,R17
        SEI                 
        LDI     R17,1
        OUT     TIMSK,R17    ;允许T/C0溢出中断
        CLR     R17          ;位计数器请除
HH32:   LDS     R16,$A3
        SBRC    R16,4
        RJMP    HHER32       ;出错
        SBRS    R16,2        ;
        RJMP    HH32         ;查询等待数据块发送完成
       ;.                    ;其他程序略
       ;.                    ;可安排接收对方发来数据程序,见STRT33
        RJMP    RST32       
HHER32:;.
       ;.                    ;错误处理略
        RJMP    RST32
T0_OVF: PUSH    R16
        IN      R16,SREG
        PUSH    R16
        PUSH    R26
        PUSH    R27
        IN      R16,TCNT0
        INC     R16
        SUBI    R16,52       ;重写入一位定时常数(带修正)
        OUT     TCNT0,R16
        MOV     R26,R24      ;数据指针
        MOV     R27,R25
        CPI     R17,10
        BREQ    SND10
        TST     R17
        BRNE    SND9
SND0:   CBI     PORTB,0      ;发起始位(0)
        RJMP    SVCOM
SND9:   CPI     R17,9
        BRNE    SND18        ;1-8为数据位
        SBI     PORTB,0      ;9为停止位(1)
        CLR     R17          ;停止位发完后,位计数器清除
        ADIW    R24,1        ;指针增1,指下一位数据
        LD      R16,X
        CPI     R16,$0A      ;本次发送的是$0A?
        BRNE    SVCOM1
        LDI     R17,10       ;停止位标志
        RJMP    SVCOM1     
SND10:  LDS     R16,$A3
        SBR     R16,4        ;发送完成标志
        STS     $A3,R16      ;
SND11:  CLR     R16
        OUT     TCCR0,R16    ;关闭T/C0
        CLR     R17          ;清位计数器
        LDI     R24,LOW(DATA2);发送指针初始化
        LDI     R25,HIGH(DATA2)
        RJMP    SVCOM1
SENDER: LDS     R16,$A3
        SBR     R16,$10
        STS     $A3,R16      ;建出错标志
        RJMP    SND11
SND18:  BRCC    SENDER       ;大于10为错误
        LD      R16,X
        ROR     R16          ;发送位传到进位C
        BRCC    S182
        SBI     PORTB,0      ;C(=1)-->PB0($18,0)
        BRCS    S183
S182:   CBI     PORTB,0      ;C(=0)-->PB0($18,0)
S183:   LD      R16,X
        ROR     R16          ;
        ST      X,R16        ;保存剩余位
        MOV     R24,R26      ;存数据指针
        MOV     R25,R27
SVCOM:  INC     R17          ;位计数器增1
SVCOM1: POP     R27
        POP     R26
        POP     R16
        OUT     SREG,R16
        POP     R16          ;恢复现场
        RETI
       ;范例43               ;8515/8535/晶振4MHZ RECEIVING ASCII CHAR. BY TCNT0&PB0
       .EQU     DATA3=$100   ;UES R11 SAVE SREG, R12 R13:数据指针DATA3
                         ;R14: 块长(BLOCK LENGTH) ,R15:接收字符暂存寄存器
       .ORG     0            ;R16:(THE BIT SEQUENCE COUNTER)位序列计数器
                             ;R17:WORKING REG.R18:FLAG UNIT, BAUD RATE:9600
STRT33: RJMP    RST33        ;X&Y:POINTER/接收数据缓存区首地址:$100
       .ORG     $009         ;$007(8515)
        RJMP    T0_OVF1
       .ORG     $011         ;$00D(8515)
RST33:  LDI     R17,HIGH(ramend)
        OUT     SPH,R17
        LDI     R17,LOW(ramend)
        OUT     SPL,R17
        LDI     R17,HIGH(DATA3)
        MOV     R12,R17
        LDI     R17,LOW(DATA3)
        MOV     R13,R17      ;R12R13:接收数据指针
CLRBF1: CLR     R16         
CLRLP:  ST      X+,R16
        CPI     R26,$48
        BRNE    CLRLP        ;接收数据缓存区请除
        CLR     R18          ;标志寄存器请除/R18,2:完整数据块收到,R18,1
                                                   ;第一字符(块长)收到:R18,0:出错
        LDI     R17,$02      ;8535:$01
        OUT     TIMSK,R17    ;允许T/C0溢出中断
        LDI     R17,6        ;外部脉冲下降沿计数
        OUT     TCCR0,R17
        CBI     DDRB,0       ;PB0为输入
        LDI     R17,$FF
        OUT     TCNT0,R17    ;计一个数即中断
                             ;
        SEI                  ;
TEST1:  RCALL   DSPLY3       ;调串行移位显示子程序
        SBRC    R18,0        ;
        RJMP    DLERR        ;出错,转错误处理
        SBRS    R18,2        ;数据块接收完成?
        RJMP    TEST1
        LDI     R16,128       
DECLP:  DEC     R16
        BRNE    DECLP       
        RJMP    DTCOM0       ;先延时,再转处理数据块
DLERR:  ;.                   ;出错处理
        ;.
        ;.
        RCALL   DL50         ;延时50毫秒后
        RJMP    RST33        ;重新接收
DTCOM0: LDI     R27,1
        CLR     R26          ;数据存储区首地址$100
DLLOP0: CLR     R29
        LDI     R28,$90      ;ASCII码处理区为$90--$9f
        LD      R16,X
        CPI     R16,$50      ;字母P打头才有效
        BRNE    RVCOM0       ;否则为无效字串或ASCII码处理结束
DLLO1:  LD      R16,X+
        ST      Y+,R16
        CPI     R28,$A0
        BRNE    DLLO1        ;传送16个字符
        PUSH    R26
        PUSH    R27
        RCALL   ACUM         ;处理一组ASCII码数据
        POP     R27
        POP     R26
        BRTC    DLLOP0       ;T=1,ASCII码数据无效
        CLT                 
       ;.                    ;错误处理
        RJMP    STRT33
RVCOM0:;.                    ;错误处理
       ;.                   
        RJMP    STRT33
T0_OVF1:IN      R11,SREG     ;T/C0中断服务
        PUSH    R17
        CPI     R16,0        ;起始位下降沿中断?
        BRNE    T0SV10
        LDI     R17,2        ;YES
        OUT     TCCR0,R17    ;改为内定时(4MHZ/8分频)
        LDI     R17,232      ;半位时间常数24 定48微秒(<52)
        OUT     TCNT0,R17
        RJMP    T0SV6
T0SV10: CPI     R16,1        ;1,半位定时到
        BRNE    T0SV2
        SBI     PORTB,0     
        SBIC    PINB,0       
        RJMP    T0ERR        ;高电平,错误
        RJMP    T0SV60       ;低电平,有效起始位
T0SV2:  CPI     R16,10       ;
        BRNE    T0SV3
        SBI     PORTB0       ;10,接收停止位
        SBIS    PINB,0
        RJMP    T0ERR        ;低电平,错误
        LDI     R17,6
        OUT     TCCR0,R17    ;改为外部脉冲下降沿计数,为接受下一位字符准备
        LDI     R17,$FF      ;计一个数即中断
        OUT     TCNT0,R17
        CLR     R16          ;位计数器请除
        SBRC    R18,1        ;是第一个字符(r18,1=0)?
        RJMP    T0SV21       ;否,为块内数据
        MOV     R14,R15      ;块长转入r14
        SBR     R18,2        ;块长已收到
        RJMP    T0SV61
T0SV21: PUSH    XL
        PUSH    XH
        MOV     XH,R12
        MOV     XL,R13        ;取缓存区指针
        ST      X+,R15       ;字符送入缓存区
        MOV     R12,XH
        MOV     R13,XL
        POP     XH
        POP     XL
        DEC     R14
        BRNE    T0SV61
        SBR     R18,4        ;块长减为0,完整数据块收到
        CLR     R16
        OUT     TCCR0,R16    ;停止TCNT0
        RJMP    T0SV61
T0SV3:  BRCC    T0ERR        ;出错(大于10)
        CLC                  ;2--9:数据位
        SBI     PORTB,0      ;接收一位数据
        SBIC    PINB,0
        SEC
        ROR     R15          ;数据组织到R15
T0SV60: IN      R17,TCNT0    ;读TCNT0计数值
        INC     R17          ;
        SUBI    R17,52
        OUT     TCNT0,R17    ;写入补偿后的时间常数
T0SV6:  INC     R16          ;位序列计数器增1
T0SV61: POP     R17
        OUT     SREG,R11
        RETI
T0ERR:  CLR     R16
T0ERL:  SBR     R18,1        ;错误接收标志
        OUT     TCCR0,R16    ;停止TCNT0
        RJMP    T0SV61
       ;范例44
        .ORG    0            ;8535多机通讯主机程序/振4MHZ
.EQU    DTPINT=$180          ;UBRR=12,波特率19200(REL.ERR.=0.16%)
.EQU    DRPINT=$1C0          ;主机发往#1,#2,#3,#分机数据在
                             ;$180-18F,$190-19F,$1A0-1AF和$1B0-1BF
STRT34: RJMP  RST34          ;主机接收#1,#2,#3,#4分机之数据块分别在
                             ;$1C0-1CF,$1D0-1DF,$1E0-1EF和$1F0-1FF
       .ORG     $00B         
        RJMP    U_RXC        ;UART接收完成中断
       .ORG     $00C
        RJMP    U_TXC        ;UART 发送完成中断
       .ORG     $011
RST34:  LDI     R16,12
        OUT     UBRR,R16     ;BAUD RATE=FCP/16(UBRR+1)=4000000/(16*13)=19200
        CLR     R15          ;分机号初始化
        LDI     R27,HIGH(DTPINT)
        LDI     R26,LOW(DTPINT);发送数据指针,首指$180
        LDI     R29,HIGH(DRPINT)
        LDI     R28,LOW(DRPINT);接收数据指针(POINT TO $1C0)
NEXTNO: LDI     R16,$18
        OUT     UCR,R16      ;允许UART接收和发送,8位数据模式
        INC     R15          ;指向分机
OUTLP:  OUT     UDR,R15      ;呼分机号
TSLOP:  IN      R16,USR
        SBRS    R16,7
        RJMP    TSLOP        ;分机返回机号?
        IN      R16,UDR
        CP      R16,R15      ;与发送分机号符合?
        BRNE    OUTLP        ;不符再发
TXLOP:  LD      R16,X+
        OUT     UDR,R16      ;向分机发送数据块
TESTL:  IN      R17,USR
        SBRS    R17,5        ;发送寄存器空?
        RJMP    TESTL       
        CPI     R16,$0A
        BRNE    TXLOP        ;发完整个数据块?
RXTST:  IN      R17,USR
        SBRS    R17,7        ;RXC=1 分机发来数据
        RJMP    RXTST
        IN      R16,UDR     
        ST      Y+,R16       ;接收数据转入内存
        CPI     R16,$0A     
        BRNE    RXTST        ;接收完整数据块后
        MOV     R16,R15
        CPI     R16,4        ;转与下一分机通讯(只有4台分机)
        BRNE    NEXTNO       ;直到轮询完毕
HH34:   RJMP    HH34         ;可改为处理分机发来数据,再转入下一周轮询
       .DSEG
       .ORG     $180
DTPINT:.BYTE    $40
        $41 $45 $65 $73 $46 $42 $40 $6F $33 $44 $66 $5C $4D $4B $0D $0A
        $42 $4F $66 $78 $47 $45 $44 $63 $32 $48 $60 $7C $6D $45 $0D $0A
        $43 $56 $55 $53 $4D $4F $40 $2E $31 $42 $67 $4C $47 $4A $0D $0A
        $45 $54 $59 $63 $3D $4B $48 $2F $35 $48 $69 $3C $77 $43 $0D $0A
        .ORG     $1C0
DRPINT: .BYTE    $40
        ;范例45
        .ORG     0           ;8535多机通讯1#分机程序,晶振4MHZ
.EQU    DTPIT1=$180          ;UBRR=12 波特率19200(REL.ERR.=0.16%)
.EQU    DRPNT1=$1C0
STRT35: RJMP    RST35
       .ORG     $00B
        RJMP    UARXC        ;UART接收完成中断
       .ORG     $00C
        RJMP    UATXC        ;UART发送寄存器空中断
.ORG     $011         
RST35: CLR     R18          ;请除主机发来完整数据块标志(R18,7)/主机呼号选中分机
                             ;标志(R18,6)
        LDI     R16,12
        OUT     UBRR,R16     ;[BAUD RATE=FCP/16(UBRR+1)]
        LDI     R16,HIGH(DRPNT1)
        MOV     R8,R16
        LDI     R16,LOW(DRPNT1)
        mov     R9,R16       ;r8,r9:接收数据指针(FIRST POINT TO $1C0)
        LDI     R16,$98      ;允许UART发送,接收,接收完成中断
        OUT     UCR,R16
        SEI
     CLR     R15
     INC     R15            ;1#分机设为1/2#分机设为2/3#分机设为3/4#分机设为4
RXDTS:  SBRS    R18,6        ;收到主机发来呼号?
        RJMP    RXDTS
        OUT     UDR,R15      ;将分机号反还主机
TXDON:  IN      R16,USR
        SBRS    R16,5
        RJMP    TXDON        ;发送寄存器空?
RCVBLK: SBRS    R18,7
        RJMP    RCVBLK       ;等待接收主机发来数据块
        LDI     R16,HIGH(DTPIT1)
        MOV     R6,R16
        LDI     R16,LOW(DTPIT1)
        MOV     R7,R16       ;设置发送数据指针r6r7,首指$180
        SBI     UCR,5        ;UDRIE=1 ,引起发送寄存器空中断
TXDN:   SBIC    UCR,5   
        RJMP    TXDN
        RJMP    RST35        ;等待UDRIE=0 ,向主机发送数据块完毕后,转下一轮通讯

       :UART中断接收程序
UARXC:  IN      R14,SREG
        TST     R18
        BREQ    NUMB         ;无主机呼号选中标志,查机号
        PUSH    R26
        PUSH    R27
        IN      R17,UDR      ;读入接收数据
        MOV     XH,R8
        MOV     XL,R9        ;r8r9:接收数据缓存区指针,首指$1C0
        ST      X+,R17       
        MOV     R8,XH
        MOV     R9,XL
        CPI     R17,$0A      ;收到换行符?
        BRNE    RSCOM1
        SBR     R18,$80      ;建立数据块接收完毕标志
RSCOM1: POP     R27
        POP     R26
DRETI:  OUT     SREG,R14
        RETI
NUMB:   IN      R17,UDR
        CP      R17,R15      ;主机呼号与本分机号符合?
        BRNE    DRETI        ;不符,转
        SBR     R18,$40      ;建选中标志
        RJMP    DRETI
;       UART中断发送数据程序
UATXC:  IN      R16,SREG    ;r6 r7:the sendDATA pointer(FIRST POINT TO $180)
        PUSH    R16
        PUSH    R26
        PUSH    R27
        MOV     XH,R6
        MOV     XL,R7        ;发送数据指针
        LD      R16,X+       
        MOV     R6,XH
        MOV     R7,XL
        OUT     UDR,R16      ;发送数据写入数据寄存器
        CPI     R16,$0A      ;发送LF?
        BRNE    SDCOM
        CBI     UCR,5        ;禁止数据寄存器空中断(清UDRIE)
        LDI     R16,HIGH(DRPINT)
        MOV     R8,R16
        LDI     R16,LOW(DRPINT)
        MOV     R9,R16       ;为接收作准备(FIRST POINT TO $1C0)
SDCOM:  POP     R27
        POP     R26
        POP     R16
        OUT     SREG,R16
        POP     R16
        RETI
       .DSEG
       .ORG     $180
DTPIT1: .BYTE   $10
        ;$41 $45 $65 $73 $46 $42 $40 $6F $33 $44 $66 $5C $4D $4B $0D $0A
       .ORG     $1C0
DRPNT1: .BYTE   $10
        ;$41 $45 $65 $73 $46 $42 $40 $6F $33 $44 $66 $5C $4D $4B $0D $0A
        ;范例46
        .ORG     $000        ;RS232<->RS485通讯标准转换/晶振4MHZ
STRT36: RJMP    RST485       ;使用8515!
       .ORG      $009
        RJMP    U_RXC        ;UART 接收中断
       .ORG     $00D
RST485: LDI     R16,2
        OUT     SPH,R16
        LDI     R16,$5f      ;
        OUT     SPL,R16
        LDI     R16,$98      ;允许UART接收和发送,允许接收中断
        OUT     UCR,R16
        LDI     R16,12
        OUT     UBRR,R16     ;波特率19200
        SBI     DDRB,7
        SBI     DDRB,6       ;PB7,PB6为输出
        CBI     PORTB,7
        CBI     PORTB,6      ;PB7控制485发送(高有效)PB6控制485接收(低有效)
        SEI
HERE0:  CPI     R16,3        ;收到停止符?
        BRNE    HERE0         ;未收到循环等待
HERE1:  SBIS    USR,6        ;
        RJMP    HERE1        ;等待停止符发送完毕
        CBI     PORTB,7      ;禁止485发送
        CBI     PORTB,6      ;允许485接收
        SBI     USR,6        ;写‘1’清除发送完成标志!
        CLR     R16
        RJMP    HERE0        ;转等待下一轮中转
U_RXC:  SBI     PORTB,7      ;允许485发送
        SBI     PORTB,6      ;禁止485接收,
        IN      R16,UDR      ;读出接收数据,同时清除接收中断标志
TSAGN:  SBIS    USR,6         ;上一数据发送完毕?
        RJMP    TSAGN
        SBI     USR,6         ;清除发送完成标志
        OUT     UDR,R16      ;转发本次接收数据
        RETI
       ;范例47
       .EQU     DATA4=$220
       .ORG     $000         ;同步串口通讯主机程序,晶振4MHZ
STRT37: RJMP    RST37
       .ORG     $00A         ;8535 SPI中断矢量(8515为$008)
        RJMP    SPINT       
       .ORG     $011         ;$00D(8515)
RST37:  LDI     R16,2
        OUT     SPH,R16
        LDI     R16,$5f
        OUT     SPL,R16      ;堆栈指针初始化
        LDI     R16,$A0
        OUT     DDRB,R16     ;SCK,MOSI为输出
        LDI     R16,$DC
        OUT     SPCR,R16     ;允许SPI中断,先发送高位,主控方式,时钟为主频4分
                             ;频,后沿有效
        LDI     XH,HIGH(DATA4)
        LDI     XL,LOW(DATA4);数据指针
        LDI     R16,$30
        MOV     R15,R16      ;数据块长
        LDI     R16,12       ;0.25微秒
SPI0:   DEC     R16          ;0.25微秒
        BRNE    SPI0         ;0.5微秒  总延时9微秒
        LD      R16,X
        OUT     SPDR,R16     ;写发送数据寄存器,启动发送
        SEI
HH37:   RJMP    HH37         ;背景程序略

SPINT:  IN      R14,SREG
        IN      R16,SPDR     ;读出接收数据
        ST      X+,R16       
        DEC     R15
        BRNE    SPI1         ;数据收发完毕?
        OUT     SPCR,R15     ;是,停止收发
        OUT     SREG,R14
        RETI
SPI1:   LDI     R16,6        ;0.25微秒
SPI1A:  DEC     R16          ;0.25微秒
        BRNE    SPI1A        ;0.5微秒 总共4.5微秒
        LD      R16,X
        OUT     SPDR,R16     ;发下一个数据
        OUT     SREG,R14
        RETI
       ;范例48
       .ORG     $000
STRT37S:RJMP    RST37S       ;同步串口通讯从机程序(8515) 晶振4MHZ
       .ORG     $008         ;$00A(8535)
        RJMP    SPINTS       ;同步串口中断矢量
       .ORG     $00D         ;$011(8535)
RST37S: LDI     R16,2
        OUT     SPH,R16
        LDI     R16,$5f
        OUT     SPL,R16     
        LDI     R16,$40
        OUT     DDRB,R16     ;MISO为输出
        LDI     R16,$CC
        OUT     SPCR,R16     ;允许SPI中断,先发送高位,从控方式,时钟为主频4分频,后沿有效
        LDI     YH,HIGH(DATA4)
        LDI     YL,LOW(DATA4);数据指针
        LDI     R16,$30      ;数据长度
        LD      R15,Y
        OUT     SPDR,R15     ;写入数据寄存器
        SEI
HH37S:  RJMP    HH37S        ;背景程序从略
SPINTS: IN      R14,SREG
        IN      R15,SPDR     ;读接收数据
        ST      Y+,R15       
        DEC     R16
        BRNE    SPI2         ;数据块收发完毕
        OUT     SPCR,R16     ;停止中断收发
        RJMP    SPI3
SPI2:   LD      R15,Y
        OUT     SPDR,R15     ;发下一数据
SPI3:   OUT     SREG,R14
        RETI
       ;范例49  以模拟串口与串行移位寄存器74165通讯,以74165驱动LED显示子程序
DSPLY3: SBI     DDRC,1       ;PC1,串行数据输出
        SBI     DDRC,0       ;PC0,移位时钟
        CBI     PORTC,0      ;
        LDI     R17,8        ;8字节显示缓存区$60(高)--$67(低))
        MOV     R8,R17
        CLR     XH
        LDI     XL,$60       ;指针,首指最高位($60)
SRDLOP: LDI     R17,8        ;8位/字节
        MOV     R9,R17
        LD      R10,X+
        LDI     ZH,HIGH(TABLE*2)
        LDI     ZL,LOW(TABLE*2);使用DSPY子程序段选表
        ADD     ZL,R10       ;加代码寻址
        BRCC    DSPL1
        INC     ZH
DSPL1:  LPM                  ;取段选码
        COM     R0           ;取为反码
SENDLP: ROR     R0           ;段选码右移一位 C<--R0最低位
        CBI     PORTC,1
        BRCC    SNDL1        ;进位C传给PC1
        SBI     PORTC,1     
SNDL1:  SBI     PORTC,0      ;移位时钟,上升沿有效
        CBI     PORTC,0      ;移位时钟变低
        DEC     R9   
        BRNE    SENDLP       ;8位段选码循环右移
        DEC     R8
        BRNE    SRDLOP       ;8位LED显示数据都更新一遍?
        RET                  ;是,结束
       ;脉宽调制(PWM)输出程序
       ;范例50               ;以定时器定时产生精确半秒信号,以PD5输出精确秒号 
       .ORG     $000         ;晶体实测频率为8000367HZ
STRT40: RJMP    RST40        ;USE 8535
       .ORG     $008         ;t/C1 overflow vector
        RJMP    T1_OVF
       .ORG     $011
RST40:  LDI     R16,HIGH(ramend)
        OUT     SPH,R16
        LDI     R16,LOW(ramend)
        OUT     SPL,R16
        SBI     DDRD,5       ;PD5(OC1A)为输出
        CBI     PORTD,5      ;初始输出为低
        LDI     R16,2        ;8分频 INT(8000367/8)=1000046) 折半500023定半秒
        OUT     TCCR1B,R16   ;T/C1控制寄存器(I/O ADDR:$2E)
        LDI     R16,$5E      ;500023=65536*8-24265=$10000*8-$5EC9
        OUT     TCNT1H,R16   ;TCC=$5EC9 先写高位字节
        LDI     R16,$C9
        OUT     TCNTIL,R16
        LDI     R16,$04
        OUT     TIMSK,R16    ;允许T/C1溢出中断/8535C/t1:timsk,2&t0:timsk,0
        LDI     R17,8        ;8次中断定半秒
        CLR     R16
        OUT     TIFR,R16     ;清除定时/计数器中断标志
        SEI                  ;
HH40:   RJMP    HH40         ;背景程序略
T1_OVF: IN      R5,SREG      ;保存状态寄存器
        DEC     R17         
        BRNE    COMP1        ;定时时间到?
        IN      R16,PORTD    ;读入PD5当前状态
        LDI     R17,$20
        EOR     R16,R17      ;求反PD5(OC1A)输出
        OUT     PORTD,R16
         IN      R17,TCNT1L   ;*
         IN      R16,TCNT1H   ;*读回TCNT1计数值
         SUBI    R17,$37      ;*
         SBCI    R16,$A1      ;*减去$5EC9之补码$A137
         SUBI    R17,$FF      ;*补偿指令8条占一个计数单位
         SBCI    R16,$FF      ;*补偿后TCC=$5EC9+(TCNT1)+1
         OUT     TCNT1H,R16   ;*
         OUT     TCNT1L,R17   ;*写入TCNT1
        LDI     R17,8        ;重新写入中断次数
COMP1:  OUT     SREG,R5
        RETI
        ;范例51              ;以比较匹配A达到时交替输出高低电平及写入其维持
                            ;时间常数之方法实现脉宽调制输出
       .ORG     $000
STRT41: RJMP    RST41       ;5.008MS(高):10.000MS(低) 晶振4MHZ
       .ORG     $006
        RJMP    T1_CMPA      ;USE 8535
       .ORG     $011
RST41:  LDI     R16,HIGH(RAMEND)
        OUT     SPH,R16
        LDI     R16,LOW(RAMEND)
        OUT     SPL,R16
        LDI     R16,$80      ;T/C1比较匹配A达到时,清除输出脚oc1a
        OUT     TCCR1A,R16
        LDI     R16,$0B      ;64分频 ctc1=1 比较匹配达到清tcnt1
        OUT     TCCR1B,R16
        SBI     DDRD,5
        SBI     PORTD,5      ;pd5(oc1a)初始化输出为高
        CLR     R16
        OUT     TCNT1H,R16   ;予清除tcnt1
        OUT     TCNT1L,R16
        LDI     R16,1
        OUT     OCR1AH,R16
        LDI     R16,$39      ;写比较匹配寄存器(313*0.25*64=5.008MS)
        OUT     OCR1AL,R16
        LDI     R16,$10
        OUT     TIMSK,R16    ;允许比较匹配A中断       
        SEI
HH41:   RJMP    HH41         ;背景程序略
T1_CMPA:IN      R5,SREG
        IN      R16,TCCR1A
        SBRS    R16,6       
        RJMP    OUTLOW       ;当前输出低电平,转
        LDI     R16,1
        OUT     OCR1AH,R16
        LDI     R16,$39      ;写入高电平维持时间313
        OUT     OCR1AL,R16
        LDI     R16,$80      ;比较匹配A达到时,OC1A输出为低
        OUT     TCCR1A,R16
        OUT     SREG,R5
        RETI
OUTLOW: LDI     R16,2
        OUT     OCR1AH,R16
        LDI    R16,$71        ;写入低电平维持时间625(=$271) (625*0.25*64=10.000MS)
        OUT     OCR1AL,R16
        LDI     R16,$C0       ;比较匹配A达到时,OC1A输出为高
        OUT     TCCR1A,R16
        OUT     SREG,R5
        RETI
       ;范例52                 ;以比较匹配达到时求反输出并按高低电平写入 
       .ORG     $000          ;维持时间之方法实现脉宽调制输出
STRT42: RJMP    RST42         ;5.008MS(高):10.000MS(低) 晶振4MHZ
       .ORG     $006
        RJMP    T1_CMPA
       .ORG     $011
RST42:  LDI     R16,HIGH(ramend)
        OUT     SPH,R16
        LDI     R16,LOW(RAMEND)
        OUT     SPL,R16
        LDI     R16,$40      ;比较匹配A达到时,对OC1A输出求反
        OUT     TCCR1A,R16
        LDI     R16,$0C      ;256分频 ctc1=1 比较匹配达到时 清除cnt1
        OUT     TCCR1B,R16
        SBI     DDRD,5       ;PD5(oc1a)为输出
        SBI     PORTD,5      ;初始输出为高
        CLR     R16
        OUT     TCNT1H,R16   ;清除tcnt1
        OUT     TCNT1L,R16
        OUT     OCR1AH,R16
        LDI     R16,78       ;高电平时间常数78
        OUT     OCR1AL,R16
        LDI     R16,$10
        OUT     TIMSK,R16    ;允许比较匹配A中断
        SEI
HH42:   RJMP    HH42         ;背景程序略
T1_CMPA:IN      R5,SREG      ;
        IN      R16,PORTD
        SBRC    R16,5
        RJMP    T1CM1        ;当前oc1a为高,转
        LDI     R16,0
        OUT     OCR1AH,R16
        LDI     R16,156      ;低电平时间常数156
        OUT     OCR1AL,R16
        OUT     SREG,R5
        RETI
T1CM1:  LDI     R16,0
        OUT     OCR1AH,R16
        LDI     R16,78       ;高电平时间常数78
        OUT     OCR1AL,R16
        OUT     SREG,R5
        RETI
                             ;模/数转换和数/模转换及脉宽调制输出应用
       ;范例53                ;模拟量采集和3路脉宽调制输出(OCR1A/OCR1B&OCR2)综合程
                             ;序/晶振4MHZ
       .ORG     $000         
STRT50: RJMP    RST50        ;avr is AT90S8535
       .ORG     $00E
        RJMP    ADCOM        ;模数转换完成中断
       .ORG     $011
RST50:  LDI     R16,HIGH(ramend)
        OUT     SPH,R16
        LDI     R16,LOW(ramend)
        OUT     SPL,R16      ;堆栈指针初始化
        CLR     R11          ;通道号初始化
        CLR     R12
        CLR     R13          ;累加和予清除
        OUT     $07,R11      ;ADC通道初始化,指向0#通道
        LDI     R16,$6C      ;T/C2为自运行pwm输出,加法计数匹配清除OC2,减法计
                             ;数匹配置位OC2(正向PWM);对晶振64分频
        OUT     TCCR2,R16    ;tccr2' ADDR.:$25
        LDI     R16,$ED      ;使能,启动ADC/自由运行/转换完成中断/对晶振32分频
        OUT     ADCSR,R16    ;ADDR:$06 adc控制状态寄存器
        IN      R16,ASSR
        CBR     R16,8
        OUT     ASSR,R16     ;TCNT2 用主时钟!
        INC     R11
        OUT     $07,R11      ;予切换到1号ADC通道
        SBI     DDRD,4
        SBI     PORTB,4      ;pd4:oc1b
        SBI     DDRD,5       ;pd5:oc1a pd4,pd5 皆为输出 oc1b初始输出为高
        SBI     DDRD,7       ;oc2 输出
        LDI     R16,$E3      ;0B11100011,自运行PWM,COM1A1/0=11,COM1B1/0=10
        OUT     TCCR1A,R16   ;减法计数匹配清除OC1A,加法计数匹配置位OC1A(反向PWM);加法计
                             ;数匹配清除OC1B,减法计数匹配置位OC1B(正向PWM)
        LDI     R16,2
        OUT     TCCR1B,R16   ;tcnt1 8分频
        LDI     R16,0
        OUT     TCNT1H,R16   ;wr.high B at first
        OUT     TCNT1L,R16   ;清除TCNT1
        OUT     TCNT2,R16    ;清除TCNT2
        OUT     DDRA,R16     ;A口输入
        OUT     PORTA,R16    ;输入为高阻态
        SEI                 
COMLP:  CPI     R11,1
        BREQ    COMLP        ;通道号初始为1,等待切换过去
COML0:  CPI     R11,1
        BRNE    COML0        ;通道号再次为1时,0#通道正在转换,7#通道已转换完毕,
                             ;已得到8个A/D采样累加和
        ASR     R12
        ROR     R13
        ASR     R12
        ROR     R13
        ASR     R12
        ROR     R13          ;累加和除以8
        BRCC    COML1
        CLR     R16
        ADC     R13,R16
        ADC     R12,R16      ;四舍五入
COML1:  OUT     OCR1AH,R12
        OUT     OCR1AL,R13   
        OUT     OCR1BH,R12
        OUT     OCR1BL,R13   ;10位数据写入比较匹配寄存器
        ASR     R12
        ROR     R13
        ASR     R12
        ROR     R13
        BRCC    COML2
        INC     R13
        BRNE    COML2
        DEC     R13
COML2:  OUT     OCR2,R13     ;8位数据写入比较匹配寄存器
        CLR     R12
        CLR     R13          ;累加和清除
        RJMP    COMLP
ADCOM:  IN      R15,ADCL     ;ADC完成中断
        IN      R14,ADCH
        ADD     R13,R15      ;模拟数值加入累加和
        ADC     R12,R14
        INC     R11
        SBRC    R11,3
        CLR     R11          ;total 8 chanales!&8 CHANGED TO 0
        OUT     $07,R11      ;$07:admux'address REGISTER
        RETI
        ;范例54               ;以R-2R电阻网络和C口配合组成DAC与输入模拟量比较实现模数转换
        .ORG     $000        ;电阻网络DAC最大输出(AIN0)只能达到3.32V(PCi输出只能达到5V)
STRT51: RJMP    RST51        ;输入模拟量最大为4.98V,故应将DAC输出放大1.5倍再与前者比较
       .ORG     $011         ;也可将输入模拟量衰减为2/3再与DAC输出比较
RST51:  LDI     R16,2        ;但应将转换结果乘以1.5以使其复原,程序取后者
        OUT     SPH,R16      ;堆栈指针初始化
        LDI     R16,$5F
        OUT     SPL,R16
        SER     R16
        OUT     DDRC,R16     ;C口全部为输出,DAC输出为AIN0输入
        CLR     R16
        OUT     DDRB,R16     ;B口为输入
        LDI     R16,$F3
        OUT     PORTB,R16    ;PB2(AIN0),PB3(AIN1)输入为高阻状态
        CLR     R15          ;模数转换结果予清除
        LDI     R16,$80      ;逼近增量初始值
CMPLP:  ADD     R15,R16      ;模数转换阶段值加逼近增量
        OUT     PORTC,R15    ;转成模拟量
        NOP
        NOP
        NOP                  ;4MHZ/等待1微秒
        SBIC    ACSR,ACO     ;输入模拟量大于DAC模拟量,清除ACO
        SUB     R15,R16      ;否则去掉逼近增量
        LSR     R16          ;逼近增量折半
        BRNE    CMPLP        ;逼近增量变为0?
        MOV     R16,R15      ;*是,转换结束
        LSR     R15          ;*
        ADC     R15,R16      ;*将转换结果乘以1.5
HH50:   RJMP    HH50         ;背景程序略

       ;范例55               ;40点平均在r18r19,累加和在r5r6r7;20点平均在R14R15,累加和在R1R3R4
SLPAV:  PUSH    R26          ;采样在R8R9,采样数据存储区$150--$19F/工作寄存器r1--r19&r26 r27
        PUSH    R27
        LDI     R27,1
        LDS     R26,$14F     ;数据存储区首地址$14F
        ADD     R7,R9
        ADC     R6,R8        ;采样加入40点平均累加和
        BRCC    SLP1
        INC     R5           ;有进位,高位字节增1
SLP1:   ADD     R4,R9
        ADC     R3,R8        ;采样加入20点平均累加和
        BRCC    SLP2
        INC     R1           ;有进位,高位字节增1
SLP2:   LD      R16,X
        ST      X+,R9
        MOV     R9,R16       ;置换出最旧采样低位字节
        LD      R16,X
        ST      X+,R8
        MOV     R8,R16       ;置换出最旧采样高位字节
        CPI     R26,$A0
        BRNE    SLPA1
        LDI     R26,$50      ;采样放满存储区后,指针初始化($1A0=$150)
        STS     $14F,R26
        LDS     R16,$A4
        SBRC    R16,4       
        RJMP    SLPA2         ;40点平均时间达到,转
        SBR     R16,$10      ;设置40点平均时间达到标志
        STS     $A4,R16
        RJMP    SLDIV        ;转去计算40点平均
SLPA1:  STS     $14F,R26     ;暂存指针
        LDS     R16,$A4
        SBRS    R16,4
        RJMP    SLPB0        ;还未到40点平均,转
SLPA2:  SUB     R7,R9
        SBC     R6,R8        ;到40点平均后除加上新采样外,还要减去最旧采样
        BRCC    SLDIV       
        DEC     R5           ;不够减,高位字节减1
SLDIV:  CLR     R12
        LDI     R16,40
        MOV     R11,R16
        CLR     R10
        MOV     R13,R5
        MOV     R14,R6
        MOV     R15,R7
        RCALL   DIV165       ;计算40点平均
        MOV     R18,R14
        MOV     R19,R15       ;存入r18r19
SLPB0:  CPI     R26,$78
        BRNE    SLPB1
        LDS     R16,$A4
        SBRC    R16,3
        RJMP    SLPB2
        SBR     R16,8        ;建20点平均时间到标志
        STS     $A4,R16
        RJMP    SLPDV        ;
SLPB1:  LDS     R16,$A4
        SBRS    R16,3
        RJMP    SLRET        ;20点平均时间未到
SLPB2:  SUBI    R26,42       ;指针退回42字节,指向20点平均最旧数据
        CPI     R26,$50      ;不小于80,未超出采样数据存储区
        BRCC    SLPB20
        SUBI    R26,-80      ;否则加80调整回$150-$19F
SLPB20: LD      R11,X+       ;
        LD      R10,X
        SUB     R4,R11
        SBC     R3,R10       ;找到20点平均最旧采样,并将其从累加和中减去!
        BRCC    SLPDV
        DEC     R1
SLPDV:  LDI     R16,20
        MOV     R11,R16
        CLR     R10
        CLR     R12
        MOV     R13,R1
        MOV     R14,R3
        MOV     R15,R4
        RCALL   DIV165       ;20点平均在r14r15中
SLRET:  POP     R27
        POP     R26
        RET
       ;范例56                  ;断电保护芯片MAX704,/RESET脚接8515同名脚
                                ;/PFO接INT0,由VOUT脚给UT6264(或UT62256)/62x42x供电,
                                 ;本程序不涉及休眠!
       .ORG     $000         ;AT90S8515/时钟4MHZ
STRT60: RJMP    RST60       
        RJMP    EX_INT0      ;外部中断0
        RJMP    EX_INT1      :外部中断1
       .ORG     $009         ;uart_rxc interrupt
        RJMP    RCVSV
       .ORG     $010
RST60:  LDI     R16,2
        OUT     SPH,R16
        LDI     R16,$5f
        OUT     SPL,R16      ;堆栈指针初始化,指向$25f
        CLR     XH
        LDI     XL,$60
        CLR     R16
CLRX:   ST      X+,R16
        CPI     XL,$5E
        BRNE    CLRX
        CPI     XH,2
        BRNE    CLRX         ;清除$60--$25d
        LDI     R16,$F0
        OUT     DDRB,R16     ;PB3-PB0输入 PB7-PB4输出
        OUT     PORTB,R16    ;上拉PB7-PB4
        SBI     PORTB,0
        SBIS    PINB,0
        RJMP    BG1A         ;若将PB0接地,不做断电启动
        LDI     R16,70
        CLR     R12
        CLR     R11
DLOPX:  DEC     R11
        BRNE    DLOPX
        DEC     R12
        BRNE    DLOPX
        DEC     R16
        BRNE    DLOPX        ;延时3.4秒(clk 4mhz)
        CLR     R27
        LDI     R26,$60
        CLR     R16
LOPX1:  ST      X+,R16
        CPI     R26,$5E
        BRNE    LOPX1
        CPI     R27,2        ;清除$60--$25d
        BRNE    LOPX1
        CLI
        LDI     R16,$80
        OUT     GIMSK,R16    ;int1中断使能
        LDI     R16,$DA      ;激活外部RAM,加1等待周期,不休眠,int0/int1下降沿有效
        OUT     MCUCR,R16   
       ;.
       ;.
       ;.                    ;
        LDS     R16,$9FFE    ;片外sram $8000-$9fff)
        CPI     R16,$55
        BRNE    BG1A         ;查断电标志
        LDS     R16,$9FFF
        CPI     R16,$AA
        BREQ    BG2B         ;查到
BG1A:   LDI     R27,$80
        LDI     R26,0
        CLR     R16
CLOPX:  ST      X+,R16
        CPI     R27,$A0
        BRNE    CLOPX        ;清除$8000--$9FFF
        LDI     R16,$AA
        ST      -X,R16       ;$AA-->($9fff)
        COM     R16
        ST      -X,R16       ;$55-->($9ffe)
BG1A0:  IN      R16,GIMSK
        SBR     R16,$40
        OUT     GIMSK,R16    ;允许int0中断
        RJMP    NRMST       
                       
BG2B:   LDS     R16,$9FFD    ;$9FFD:最高位为生产标志
        SBRS    R16,7
        RJMP    NRMST        ;无生产标志转平常启动
BG5C:   CBI     PORTB,7      ;指示断电启动
        LDI     R27,$80
        LDI     R26,2        ;SRAM 8002-825F传回片内
        LDI     R29,0
        LDI     R28,2       
        CLR     R0           ;检查和清除
APX0:   LD      R1,X+
        ST      Y+,R1        ;传送数据块
        ADD     R0,R1
        CPI     R28,26       ;指向r26?
        BRNE    APX0
        LD      R1,X+        ;取r26
        ADD     R0,R1
        LD      R1,X+        ;取r27
        ADD     R0,R1
        LD      R1,X+        ;取r28
        ADD     R0,R1
        LD      R1,X+        ;取r29/ r26--r29为数据指针,不能当作数据传送
        ADD     R0,R1
        LDI     R28,30
APX2:   LD      R1,X+
        ADD     R0,R1
        ST      Y+,R1
        CPI     R28,$5F
        BRNE    APX2
        INC     XL
        INC     YL           ;SREG不断变化,不能加入累加和!
APX3:   LD      R1,X+
        ADD     R0,R1
        ST      Y+,R1
        CPI     R28,$60
        BRNE    APX3
        CPI     R29,2
        BRNE    APX3         ;到$25f?
        LDS     R1,$9FFC     ;取检查和
        ADD     R0,R1        ;检查和(CHECKSUM)正确?
        BREQ    BG5D
        RJMP    BG1A         ;错,转总清
BG5D:   WDR
        LDI     R16,$0D      ;看门狗初始化,溢出时间0.49"
        OUT     WDTCR,R16   
        CLR     R2           ;调DSPA次数计数器清除
        IN      R16,GIMSK
        SBR     R16,$40
        OUT     GIMSK,R16    ;允许int0中断
        LDS     R26,$235
        OUT     SPH,R26
        LDS     R26,$234
        OUT     SPL,R26
        POP     R26
        POP     R27
        POP     R28
        POP     R29          ;数据指针出栈
        POP     R1
        OUT     SREG,R1      ;
        POP     R1
        POP     R0
        RETI                 ;弹出断点,开放中断
NRMST:  WDR
        LDI     R16,$0D      ;看门狗初始化,溢出时间0.49"
        OUT     WDTCR,R16   
        CLR     R2
       ;.......             
        SEI
       ;(略)                 
RCVSV: ;.
       ;.
       ;.
EX_INT0:PUSH    R0           ;断电中断服务 I BE CLEARED!
        PUSH    R1
        IN      R1,SREG
        PUSH    R1
        PUSH    R29
        PUSH    R28
        PUSH    R27
        PUSH    R26          ;保护X,Y指针
        LDI     R26,$1D
        OUT     WDTCR,R26
        LDI     R26,$15
        OUT     WDTCR,R26    ;禁止看门狗
        IN      R26,SPL
        STS     $234,R26
        IN      R26,SPH
        STS     $235,R26     ;保护堆栈指针
        LDI     R27,0
        LDI     R26,2       
        LDI     R29,$80
        LDI     R28,2        ;SRAM $002-25F 转片外$8002-$825f
        CLR     R0           ;检查和予清除
ALPX1:  LD      R1,X+
        ST      Y+,R1       
        ADD     R0,R1        ;加入累加和
        CPI     R26,26       ;
        BRNE    ALPX1        ;
        POP     R1           ;R26~R29从堆栈中取!
        ADD     R0,R1
        ST      Y+,R1
        POP     R1           ;取R27
        ADD     R0,R1
        ST      Y+,R1
        POP     R1           ;取R28
        ADD     R0,R1
        ST      Y+,R1
        POP     R1           ;取R29
        ADD     R0,R1         
        ST      Y+,R1
        IN      R26,SPL
        SUBI    R26,4        ;恢复堆栈指针,抵消4个POP
        OUT     SPL,R26
        LDI     R26,30       ;越过R26-R29,指向R30
APX10:  LD      R1,X+
        ST      Y+,R1
        ADD     R0,R1
        CPI     R26,$5F
        BRNE    APX10
        INC     XL           ;SREG 越过!
        INC     YL
APX20:  LD      R1,X+
        ST      Y+,R1
        ADD     R0,R1
        CPI     R26,$60
        BRNE    APX20
        CPI     R27,2
        BRNE    APX20        ;完成到$8002-825F之转移
        NEG     R0
        STS     $9FFC,R0     ;SAVE THE CHECKSUM TO $9FFC
        LDI      R26,62
        CLR      R27
        CLR      R28
DLPX5:  DEC      R28
        BRNE     DLPX5
        DEC      R27
        BRNE     DLPX5
        DEC      R26
        BRNE     DLPX5       ;延时3秒(49.16ms*62=3")
        LDI     R27,$80
        LDI     R26,2        ;$8002-$825F
        LDI     R29,0
        LDI     R28,2        ;$002-25F
        CLR     R0
APX1A:  LD      R1,X+
        ST      Y+,R1        ;将片外SRAM数据传回片内
        ADD     R0,R1
        CPI     R28,26
        BRNE    APX1A
        LD      R1,X+        ;R26
        ADD     R0,R1
        LD      R1,X+        ;R27
        ADD     R0,R1
        LD      R1,X+        ;R28
        ADD     R0,R1
        LD      R1,X+        ;R29
        ADD     R0,R1
        LDI     R28,30
APX1B:  LD      R1,X+
        ST      Y+,R1
        ADD     R0,R1
        CPI     R26,$5F
        BRNE    APX1B
        INC     XL           ;越过SREG!
        INC     YL
APX2A:  LD      R1,X+
        ADD     R0,R1
        ST      Y+,R1
        CPI     R28,$60       
        BRNE    APX2A
        CPI     R29,2
        BRNE    APX2A        ;到$25f?
        LDS     R1,$9FFC
        ADD     R0,R1       
        BRNE    ERRDL       
        RJMP    BG5D         ;检查和正确
ERRDL:  (略)                 ;错误处理
       ;范例57
       ;使用干电池便携系统断电保护程序 MAX704 RESET引脚接8535同名脚
       ;/PFO接8535INT0 断电时由电池给AT90LS8535供电
       ;晶振4MHZ
       .ORG     $000         ;AT90LS8535只使用片内sram;在片内RAM中保护数据
STRT61: RJMP    RST61       
        RJMP    EX_INT0     
        RJMP    EX_INT1     
       .ORG     $00B
        RJMP    RVCMPLT      ;串行数据接收完成
       .ORG     $011
RST61:  LDI     R16,$00
        OUT     DDRA,R16     ;PA7-PA0为输入
        LDI     R16,21
        CLR     R12
        CLR     R13
DLPX:   DEC     R13
        BRNE    DLOPX
        DEC     R12
        BRNE    DLPX
        DEC     R16
        BRNE    DLOPX        ;延时1秒(clk 4mhz)
        LDI     R16,2
        OUT     SPH,R16
        LDI     R16,$5f
        OUT     SPL,R16      ;堆栈指针$25f
        CLR     R2           ;调DSPB次数预清除
        WDR
        LDI     R16,$0D      ;设置看门狗溢出时间0.49"
        OUT     WDTCR,R16   
        LDI     R16,$0F
        OUT     PORTA,R16
        IN      R16,PINA
        CBR     R16,$F0      ;清除无用的高4位
        CPI     R16,15
        BRNE    BG3A         ;K0-K3有键按下,转
        LDS     R16,$23E     ;
        CPI     R16,$55
        BRNE    BG3A         
        LDS     R16,$23F     
        CPI     R16,$AA
        BRNE    BG3A         ;无断电标志,转
        CLR     R16
        STS     $23E,R16     ;清除断电标志
        CLI
        LDI     R16,$C0
        OUT     GIMSK,R16    ;
        LDI     R16,$60      ;掉电休眠,
        OUT     MCUCR,R16    ;int0 INT0 电平中断
        ;.
        ;.                   ;其他初始化程序略
        ;.                   ;
        RJMP    REST2        ;转断电启动!
RVCMPLT:;(MISSING)
BG3A:   CLR     R27
        LDI     R26,$60
        CLR     R16
LOPX1:  ST      X+,R16
        CPI     R26,$60
        BRNE    LOPX1
        CPI     R27,2
        BRNE    LOPX1        ;清除$60--$25f
        LDI     R16,2
        OUT     SPH,R16
        LDI     R16,$5FH
        OUT     SPL,R16
        CLI
        LDI     R16,$C0
        OUT     GIMSK,R16    ;允许int0/int1中断
        LDI     R16,$60      ;掉电休眠
        OUT     MCUCR,R16    ;INT0/INT1 电平中断
        ;.
        ;.                   ;其他初始化程序略
        ;.
        SEI
HH61:   RCALL   DSPB         ;液晶显示子程序略
        LDI     R16,$0F      ;激活上拉电阻
        OUT     PORTA,R16    ;
        IN      R16,PINA     ;读入键状态
        CBR     R16,$F0
        CPI     R16,$0F      ;有键按下?
        BRNE    HH61         ;等待释放
        IN      R16,TIMSK
        SBR     R16,$C0
        OUT     TIMSK,R16    ;重新允许INT1中断
        SLEEP                ;进入掉电休眠
        RJMP    HH61         ;唤醒后显示新采集的数据
EX_INT1:SEI                  ;允许INT0中断
        PUSH    R16          ;K0/K1/K2/K3有按下者,产生电平中断唤醒MCU,采集数据
        IN      R16,SREG
        PUSH    R16         
        SBI     PORTA,3     
        SBIS    PINA,3
        RJMP    DLK63        ;K3按下采集数据
        SBI     PORTA,2
        SBIS    PINA,2
        RJMP    DLK62        ;K2按下采集数据
        SBI     PORTA,1
        SBIS    PINA,1
        RJMP    DLK61        ;K1按下采集数据
        RJMP    DLK60        ;K0按下采集数据
DLKRT:  IN      R16,TIMSK
        CBR     R16,$80
        OUT     TIMSK,R16    ;禁止INT1中断(键未释放或抖动时不引起中断)
        POP     R16
        OUT     SREG,R16
        POP     R16
        RETI               
DLK60:  ;.                   ;采集、处理数据,数据处理后送入显示缓存区
        ;.
        ;.
        RJMP    DLKRT
DLK61:  ;.                   ;采集、处理数据,数据处理后送入显示缓存区,
        ;.
        ;.
        RJMP    DLKRT
DLK62:  ;.                   ;采集、处理数据,数据处理后送入显示缓存区
        ;.
        ;.
        RJMP    DLKRT
DLK63:  ;.                   ;采集、处理数据,数据处理后送入显示缓存区
        ;.
        ;.
        RJMP    DLKRT
EX_INT0:PUSH    R0           ;掉电中断服务子程序
        PUSH    R2
        PUSH    R12
        PUSH    R13          ;CLI ALREADY!
        PUSH    R14
        PUSH    R15
        PUSH    R16
        PUSH    R17
        PUSH    R26
        PUSH    R27
        PUSH    R30
        PUSH    R31
        IN      R16,SREG
        PUSH    R16          ;保护状态寄存器
        LDI     R16,$1D     
        OUT     WDTCR,R16
        LDI     R16,$15
        OUT     WDTCR,R16    ;停止看门狗
        IN      R16,SPL
        STS     $23C,R16
        IN      R16,SPH
        STS     $23D,R16     ;保护堆栈指针
        LDI     R16,$55
        STS     $23E,R16
        COM     R16
        STS     $23F,R16     ;写断电标志
        SER     R16
        OUT     PORTC,R16    ;关显示
        CLR     R16
        OUT     GIMSK,R16    ;禁止外部中断(INT0&INT1)
        SLEEP                ;进入掉电休眠
REST2:  LDS     R16,$23D
        OUT     SPH,R16
        LDS     R16,$23C
        OUT     SPL,R16      ;取出堆栈指针
        POP     R16
        OUT     SREG,R16     ;恢复状态寄存器
        POP     R31
        POP     R30
        POP     R27
        POP     R26
        POP     R17
        POP     R16
        POP     R15
        POP     R14
        POP     R13
        POP     R12
        POP     R2
        POP     R0           ;恢复工作寄存器,主程序初始化时只能使用这些寄存器!
        RETI                 ;弹出断点,开放中断

       ;范例58
.EQU    DPOINT=$100          ;DATA BLOCK from $100 to $22b
CRCST:  LDI     R16,2        ;最末2字节在发送方已清为零(或仍为$0D$0A)
        MOV     R11,R16      ;在接收方则为对方计算出的CRC校验码(余式)
        LDI     R16,$2C
        MOV     R12,R16      ;(r11r12)内装入$22C,块长为$12C
CRCST1: LDI     R26,HIGH(DPOINT)
        LDI     R27,LOW(DPOINT);数据指针
CRC0:   CLR     R14
        CLR     R15
      LDI     R17,$80      ;      16  15  2
      LDI        R18,$05     ;P(X)=X  +X  +X +1=$18005
CRC1:   LDI     R16,8
        MOV     R13,R16      ;8位/字节
        LD      R16,X+
CRC2:   LSL     R16
        ROL     R15
        ROL     R14
        BRCC    CRC3
        EOR     R14,R17     
        EOR     R15,R18      ;移出位为1时,将寄存器r14r15内容异或立即数$8005
CRC3:   DEC     R13          ;位数减1
        BRNE    CRC2
        DEC     R12          ;字节数减1
        BRNE    CRC1
        DEC     R11
        BRNE    CRC1         
        ST      -X,R15
        ST      -X,R14       ;除得余数放在数据块尾部(或将原始数据恢复)!
        RET
       ;范例58A              ;DS18B20读出温度数据CRC检测子程序,生成多项式为P(X)=X8+X4+X3+1
CRCSTA:LDI      XL,$70       ;温度数据指针
     CLR      XH
     LDI      R16,9        ;温度数据,上、下限......CRC校验码等共9字节
     CLR      R15           ;异或除法工作单元
     LDI      R18,$8C
CRC1A: LD      R14,X+
     LDI      R17,8
CRC2A: LSR      R14
     ROR      R15           ;位序列右移
     BRCC    CRC3A
     EOR      R15,R18      ;移出位为1时,位序列异或立即数$8C
CRC3A: DEC      R17
     BRNE    CRC2A      ;右移次数减1       
     DEC      R16
     BRNE    CRC1A         ;块长减1
     RET                   ;(R15)=0 接收正确!
       ;范例59
DEMCRC: LDI     R27,1        ;CRC演示程序(校验码16位)
        CLR     R26          ;数据块首地址为$100
DEMLP:  ST      X+,R26       ;
        CPI     R26,$2A      ;在$100-$229中充入数据
        BRNE    DEMLP       
        CPI     R27,2
        BRNE    DEMLP        ;$100--$229中充入$00--$FF和$00-$29
        CLR     R16       
        ST      X+,R16
        ST      X,R16        ;$22A,$22B两单元请除,将计算出余式(即CRC校验码)放在其中
        RCALL   CRCST        ;在发送方计算出CRC校验码
RETEST: RCALL   CRCST        ;在接收方做CRC检测(余式在r14r15)
        OR      R15,R14      ;r14r15恢复为$0000(或恢复出原数据为正确接收)
        BRNE    ERCRC
HCRC:   RJMP    HCRC
ERCRC:  ;.                   ;出错处理,要求对方重发
        ;.
        RJMP    RETEST       ;重新CRC检测
        .DSEG
        .ORG     $100
DPOINT: .BYTE    $12C
        ;  $00 $01 $02 $03 $04 $05 $06 $07 $08 $09 $0a $0b $0c $0d $0e $0f
        ;  $10 $11 $12 $13 $14 $15 $16 $17 $18 $19 $1a $1b $1c $1d $1e $1f
        ;  $20 $21 $22 $23 $24 $25 $26 $27 $28 $29 $2a $2b $2c $2d $2e $2f
        ;  $30 $31 $32 $33 $34 $35 $36 $37 $38 $39 $3a $3b $3c $3d $3e $3f
        ;  $40 $41 $42 $43 $44 $45 $46 $47 $48 $49 $4a $4b $4c $4d $4e $4f
        ;  $50 $51 $52 $53 $54 $55 $56 $57 $58 $59 $5a $5b $5c $5d $5e $5f
        ;  $60 $61 $62 $63 $64 $65 $66 $67 $68 $69 $6a $6b $6c $6d $6e $6f
        ;  $70 $71 $72 $73 $74 $75 $76 $77 $78 $79 $7a $7b $7c $7d $7e $7f
        ;  $80 $81 $82 $83 $84 $85 $86 $87 $88 $89 $8a $8b $8c $8d $8e $8f
        ;  $90 $91 $92 $93 $94 $95 $96 $97 $98 $99 $9a $9b $9c $9d $9e $9f
        ;  $a0 $a1 $a2 $a3 $a4 $a5 $a6 $a7 $a8 $a9 $aa $ab $ac $ad $ae $af
        ;  $b0 $b1 $b2 $b3 $b4 $b5 $b6 $b7 $b8 $b9 $ba $bb $bc $bd $be $bf
        ;  $c0 $c1 $c2 $c3 $c4 $c5 $c6 $c7 $c8 $c9 $ca $cb $cc $cd $ce $cf
        ;  $d0 $d1 $d2 $d3 $d4 $d5 $d6 $d7 $d8 $d9 $da $db $dc $dd $de $df
        ;  $e0 $e1 $e2 $e3 $e4 $e5 $e6 $e7 $e8 $e9 $ea $eb $ec $ed $ee $ef
        ;  $f0 $f1 $f2 $f3 $f4 $f5 $f6 $f7 $f8 $f9 $fa $fb $fc $fd $fe $ff
        ;  $00 $01 $02 $03 $04 $05 $06 $07 $08 $09 $0a $0b $0c $0d $0e $0f
        ;  $10 $11 $12 $13 $14 $15 $16 $17 $18 $19 $1a $1b $1c $1d $1e $1f
        ;  $20 $21 $22 $23 $24 $25 $26 $27 $28 $29 $00 $00
       ;码制转换
       ;范例60
        ;地址              $90  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f  $a0
        ;ascii码数据         P  i  ,  A  S  , +/- x  x  x  x  .  x  x  k  g
.EQU    DPNT=$90   ;the first ascii character addr.
;DataPoint(.'sit):$a0/weighing unit:$a1,$a2
;P1-P4'no.:$a6$a7--$ac$ad/max.no.:$ae$af
.EQU    TPTR=$b0   ;the first total(total1($b0-$b3)) addr.
.EQU    CPTR=$C0   ;print char. buffer addr.
.EQU    SREG=$3F
.EQU    SPH=$3E
.EQU    SPL=$3D
ACUM:   CLR     R29
        CLR     R27          ;ASCII码存放区为$90-9F
        LDI     R26,$90     
        LD      R16,X
        CPI     R16,$50      ;P打头方为有效
        BRNE    ACRT
        ADIW    R26,2        ;指向$92
        LD      R16,X
        CPI     R16,$2C      ;是','?
        BREQ    DOP0
ACRT:   SET                  ;非法数据!
        RET
DOP0:   LDI     R17,4
        LDI     R26,$99      ;设指针,寻找小数点
DOP1:   LD      R16,X+
        CPI     R16,$2E
        BREQ    DOP3         ;找到'.'
DOP2:   DEC     R17
        BRNE    DOP1
DOP3:   LDI     R28,$A0      ;小数点放入$A0,1,2,3,4表示小数点后有1,2,3,4位数据
        ST      Y+,r17       ;0表示无小数点
        LDI     R26,$9E      ;指向质量单位
        LD      R17,X+
        ST      Y+,R17
        LD      R17,X+
        ST      Y,R17        ;质量单位(kg/ t)-->$a1,$a2
        LDI     R28,11
        CLR     R9
        CLR     R10
        CLR     R11          ;予请除,存放BCD码
        LDI     R26,$9E
F1:     LD      R16,-X       ;减1后指向$9d!
        CPI     R16,$2E      ;从低位到高位顺序将ASCII转为BCD,两两合成1字节压缩BCD码
        BREQ    F1           ;遇到小数点跳过
F2:     BRCS    FEND         ;遇空格/+/-等结束
        SUBI    R16,$30      ;十进制数ascii变bcd
        MOV     R12,R16
        ST      Y,R16
F3:     LD      R16,-X
        CPI     R16,$2E
        BREQ    F3
F4:     BRCS    FEND         ;小于$2E转换结束
        SUBI    R16,$30
        SWAP    R16
        ADD     R16,R12
        ST      Y,R16
        DEC     R28
        CPI     R28,8
        BRNE    F1
FEND:   MOV     R17,R9
        OR      R17,R10
        OR      R17,R11
        BREQ    ACRT         ;0数据转出
        RCALL   CONV2        ;整数二翻十(r9r10r11-->r13r14r15)
        MOV     R5,R13
        MOV     R6,R14
        MOV     R7,R15
        CLR     R12
        LDS     R16,$96      ;取数据符号
        CPI     R16,$2d      ;'-'ASCII码
        BRNE    F09
        LDI     R26,16
        RCALL   NEG4         ;负数取补
F09:    LDI     R26,$91      ;指向数据序号ASCII码
        LD      R16,X+
        SUBI    R16,$31      ;将ASCII码序号$31--$34变为0--3,
        CPI     R16,4
        BRCC    FRET         ;大于3为无效
        MOV     R9,R16       ;暂存
        LSL     R16
        LSL     R16          ;乘4
        LDI     R26,$B0      ;$B0为第一个累加和首地址(TPTR)
        ADD     R26,R16      ;得到实际首地址
        LDI     R16,4
        LDI     R28,16       ;数据指针
        CLC
LACM:   LD      R17,X        ;取累加和一字节数据
        LD      R10,-Y       
        ADC     R17,R10
        ST      X+,R17
        DEC     R16
        BRNE    LACM         ;r12,13,14,15 加入累加和
        LSL     R9           ;序号乘2
        LDI     R26,$AE      ;指向最大累加次数
        LDI     R28,$A6      ;指向第一个累加次数
        ADD     R28,R9       ;指向实际累加次数
        LD      R11,X+
        LD      R10,X        ;取最大累加次数(2字节)
        LD      R13,Y
        INC     R13          ;实际累加次数增1
        ST      Y+,R13       ;低位字节送回
        LD      R12,Y     
        TST     R13
        BRNE    F10
        INC     R12          ;低位字节增1后为0,高位字节增1
        ST      Y,R12
F10:    SUB     R11,R13
        SBC     R10,R12      ;与最大累加次数相比较
        BRCC    F12
        ST      X,R12
        ST      -X,R13       ;存最大累加次数
F12:    MOV     r15,r7
        MOV     r14,r6
        MOV     r13,r5
        LDI     R17,$98      ;予设阶码(假定为24位整数)
        MOV     R12,R17
F120:   SBRC    R13,7
        RJMP    F13
        LSL     R15
        ROL     R14
        ROL     R13
        DEC     R12
        RJMP    F120
F13:    LDS     R0,$A0       ;取小数点位数(0,1,2,3,4)
        TST     R0
        BREQ    F14          ;整数转
F130:   RCALL   G01          ;取浮点数0.1(范例70)
        RCALL   FPMU         ;(范例65)
        DEC     R0
        BRNE    F130         ;小数点位置决定乘几个0.1
F14:    LDS     R16,$96
        CPI     R16,$2B      ;负数?
        BRNE    F9
        LDI     R16,$7F
        AND     R13,R16      ;正数清除数符位
F9:     CLT                  ;合法数据出口(T=0)
        RET
FRET:   SET                  ;非法数据出口(T=1)
        RET
NEG4:   LDI     R16,4        ;4字节二进制数据求补
        CLC
NG4L:   CLR     R17
        LD      R11,-X       ;X-1指向最低位字节
        SBC     R17,R11
        ST      X,R11
        DEC     R16
        BRNE    NG4L
        RET

FLSPC:  LDI     R26,$C0      ;准备一行空格字符,为打印一行空格做准备
        CLR     R31
        LDI     R16,$20      ;SPC
FSLOP:  ST      X+,R16
        CPI     r30,$d0
        BRNE    FSLOP
        LDI     R16,$0D      ;$0D-->($D0)
        ST      X+,R16
        LDI     R16,$0A      ;$0A-->($D1)
        ST      X+,R16
        RET
BRDT:   RCALL   CONV1A       ;二翻十并将压缩BCD码转换为ASCII码
        RCALL   FLSPC
        LDI     R28,$A3      ;$A1,$A2 is the weighing unit
        CLR     R29          ;取质量单位到打印数据存储区
        LDI     R26,$D0
        LD      R16,-Y
        ST      -X,R16       ;'g'-->($D0-1)
        LD      R16,-Y
        ST      -X,R16       ;取质量单位:($A1)-->$ce &($A2)-->$CF
        LD      R10,-Y       ;取小数点位置:($A0)->R10
LP59:   LDI     R28,15
LP60:   LD      R16,Y
        RCALL   BTOA         ;低位BCD变为ASCII码
        LD      R16,Y
        RCALL   BTOA0        ;高位BCD变为ASCII码
        DEC     R28
        CPI     R28,10       ;r11,12,13,14,15 都分解完毕?
        BRNE    LP60
DL30H:  LDI     R26,$C5
        BRTC    DL300        ;数据为负?
        LDI     R16,$2D
        ST      X,R16        ;负数加'-',送入$C5
        CLT                  ;并清除负数标志
DL300:  INC     R26
        LD      R16,X
        CPI     R16,$30
        BRCS    DL300        ;去掉数据头无效的零ASCII码$30
DL301:  CPI     R16,$30
        BRNE    DLRT         ;非零结束
        INC     R26
        LD      R16,X
        CPI     R16,$30
        BRCS    DLRT         ;小于$30结束(质量单位 t)
        CPI     R16,$3A
        BRCS    DL302        ;大于$3A结束(质量单位kg)
DLRT:   RET
DL302:  DEC     R26
        LDI     R16,$20      ;无效零充以空格
        ST      X+,R16
        LD      R16,X
        RJMP    DL301
BTOA0:  SWAP    R16
BTOA:   ANDI    R16,15
        SUBI    R16,$D0      ;加$30变为ASCII码
        ST      X,R16
        DEC     R26
        DEC     R10
        BRNE    BART
        LDI     R16,$2E      ;加入小数点ASCII码
        ST      X,R16
        DEC     R26
BART:   RET

PRAV:   LDI     R17,4        ;打印4组平均数据
        MOV     R0,R17
        DEC     R0
PRV:    MOV     R17,R0
        LSL     R17         
        LSL     R17          ;组别序号之偏移量
        LDI     R26,$B0      ;TOTAL1首趾
        ADD     R26,R17      ;得到实际组别之首地址
        LDI     R28,16       ;将TOTAL取入 R12R13R14&R15
        CLR     R10
BRV:    LD      R16,X+
        ST      -Y,R16
        OR      R10,R16
NOC:    CPI     R28,12
        BRNE    BRV
        TST     R10
        BREQ    NBR          ;TOTAL为零不打印!
BRV1:   BST     R12,7        ;数符位送入T
        BRTC    BRV2
        LDI     R26,16
        RCALL   NEG4         ;负数求补
BRV2:   MOV     R26,R0
        LSL     R26
        SUBI    R26,-$A6     ;取本组累加和之累加次数(第一组从$A6开始)
        LD      R11,X+       
        LD      R10,X+
        RCALL   DIV24        ;计算平均值(在r13r14r15中)
        CLR     R7
        MOV     R8,R13
        MOV     R9,R14
        MOV     R10,R15      ;r11r12r13r14r15<--r7r8r9r10
        RCALL   BRDT         ;二翻十,再将BCD码转为ASCII码,如为负数将'-'装入$c5!
        LDI     R26,$C5
        LDI     R16,$56      ;'V'
        ST      -X,R16       ;start from $c4!
        LDI     R16,$41      ;'A'
        ST      -X,R16
        LDI     R16,$2C      ;','
        ST      -X,R16
        MOV     R16,R0       ;i(=1/2/3/4)
        SUBI    R16,$CF      ;加上$31
        ST      -X,R16       
        LDI     R16,$50
        ST      -X,R16       ;'P'
        RCALL   PR1          ;打印一行
NBR:    DEC     R0
        BRNE    PRV
        RET
PRNO:   RCALL   FLSPC        ;打印最大累加次数(整数),不加小数点
        LDI     R26,$CD      ;存放ASCII码指针
        LDI     R28,$AE      ;指向最大累加次数
        LD      R10,Y+
        LD      R9,Y         ;最大累加次数取到R9R10
        CLR     R8
        CLR     R7
        RCALL   CONV1A       ;二进制数变为BCD码
BRN:    CLR     R10          ;不加 '.'
        RCALL   LP59         ;转为ASCII码
        LDI     R26,$C4
        LDI     R16,$2E      ;'.'
        ST      -X,R16
        LDI     R16,$4F      ;'O'
        ST      -X,R16
        LDI     R16,$4E
        ST      X,R16        ;'N',加上‘NO.’后
        RJMP    PR1          ;打印

PRTL:   LDI     R17,4
        MOV     R0,r17       ;取序号之偏移量
        DEC     R0
PRL:    MOV     R17,R0
        LSL     R17
        LSL     R17          ;乘4:累加和为4字节
        CLR     R27
        LDI     R26,$B0      ;第一个累加和TOTAL1之首地址
        ADD     R26,R17      ;累加和之实际地址
        CLR     R15
        LDI     R28,11
BRL:    LD      R16,X+
        ST      -Y,R16
        OR      R15,R16
        CPI     R28,7
        BRNE    BRL          ;累加和取到r7r8r9r10
NINC:   TST     R15
        BREQ    NBL          ;累加和为零,不打印
        BST     R7,7
        BRTC    BRTL1
        LDI     R26,11
        RCALL   NEG4         ;累加和为负数,取补
BRTL1:  RCALL   BRDT         ;BCD转为ASCII
        LDI     R26,$C5
        LDI     R16,$4C      ;加'L'
        ST      -X,R16
        LDI     R16,$54      ;加'T'
        ST      -X,R16
        LDI     R16,$2C
        ST      -X,R16       ;加','
        MOV     R16,R0
        SUBI    R16,$CF      ;i(=1/2/3/4)/加上$30变为ASCII码
        ST      -X,R16
        LDI     R16,$50
        ST      -X,R16       ;加'P'
        RCALL   PR1          ;打印一行累加和数据(一个TOTAL)
NBL:    DEC     R0
        BRNE    PRL          ;共打印4行
        RET

PR1:    LDI     R26,$C0      ;打印区首地址
        CLR     R27
        LDI     R16,$28      ;允许UART发送,允许发送寄存器空中断,8位数据
        OUT     UCR,R16     
        SEI                  ;使能总中断
        RET
CONV1A: LDI     R17,32       ;整数二翻十(最大$FFFFFFFF=4294967295)
        MOV     R0,R17
        CLR     R11
        CLR     R12          ;r11r12r13r14r15(BCD)<--(r7r8r9r10二进制)
        CLR     R13
        CLR     R14             
        CLR     R15          ;十进制数存储区清除
CV1A:   LSL     R10
        ROL     R9
        ROL     R8
        ROL     R7           ;二进制数左移一位
        MOV     R16,R15
        RCALL   LSDAA
        MOV     R15,R16
        MOV     R16,R14
        RCALL   LSDAA
        MOV     R14,R16
        MOV     R16,R13
        RCALL   LSDAA
        MOV     R13,R16      ;十进制数带进位左移并调整
        MOV     R16,R12
        RCALL   LSDAA
        MOV     R12,R16
        MOV     R16,R11
        RCALL   LSDAA
        MOV     R11,R16
        DEC     R0
        BRNE    CV1A
        RET
       ;范例61               ;格雷码与二进制数相互转换
GTB8:   LDI     R16,7        ;8格雷码(在R17中)翻为二进制数
        CLR     R15
        LSL     R17
        ADC    R17,R15       ;将左移移出位加到末位上
GB1:    SBRC    R17,0
        SUBI    R17,$80      ;Bi⊕G(i+1)-->B(i+1)     
GB2:    LSL     R17
        ADC    R17,R15        ;将左移移出位加到末位上
        DEC     R16
        BRNE    BG1          ;循环7次,结束
        RET                  ;二进制数在r17中

GTB9:   LDI     R16,8          ;9位格雷码(最高位在进位C,低8位在R17中)翻为二进制数
        CLR     R15
        INC     R15          ;1-->r15
        ROL     R17          ;9位格雷码带进位循环左移一位
GB90:   ROL     R17          ;the ORIGINAL highest bit->r17,1 AT THE FIRST!
        SBRC    R17,1
        EOR     R17,R15      ;Bi⊕G(i+1)-->B(i+1)
        DEC     R16
        BRNE    GB90         
        RET                   ;结果仍在进位C和r17中

BTG8:   LDI     R16,7        ;8位二进制数翻为格雷码
        CLR     R15
        INC     R15          ;1-->r15
        CLC
        ROL     R17          ;0-->r17,0&B1-->C
        BRCC    BGLOP       
        INC     R17          ;B1-->r17.0
BGLOP:  ROL     R17
        BRCC    BG4
        EOR     R17,R15      ;Bi⊕B(i+1)-->G(i+1)/FOR EXAMPLE:(1110-->1001)
BG4:    DEC     R16
        BRNE    BGLOP       
        RET                  ;结果在R17
AVR浮点程序库
       ;范例62
       .ORG     $A00         
EXCH:   MOV     R5,R8        ;两浮点数交换子程序
        MOV     R8,R12
        MOV     R12,R5
EXCH1:  MOV     R5,R9        ;尾数交换
        MOV     R9,R13
        MOV     R13,R5
        MOV     R5,R10       ;双字节交换
        MOV     R10,R14
        MOV     R14,R5
        MOV     R5,R11
        MOV     R11,R15
        MOV     R15,R5
        RET
DP:     ANDI    R16,$7F      ;处理积/商数符,计算积/商阶码子程序
        SBRC    R9,7
        SUBI    R16,$80
        SBRC    R13,7
        SUBI    R16,$80      ;积/商符号放在r16,7
        ADD     R12,R8       ;移码相加(除数阶码已求补)
        LDI     R17,$80
        BRCC    DP1
        ADD     R12,R17      ;移码求和有进位,将和再加上$80,再有进位为溢出
        RET
DP1:    SUB     R12,R17      ;移码求和无进位,将和减去$80,有借位
        RET                  ;或差为0也为溢出
NEG3:   COM     R15          ;3字节数据求补
        COM     R14          ;先求反后加1
        COM     R13
INC3:   LDI     R17,255     
        SUB     R15,R17      ;以减去-1代替加1
        SBC     R14,R17
        SBC     R13,R17
        RET
       ;范例63               ;浮点数比较大小子程序 X1为被减数 X2为减数
FPCP:   SBRC    R9,7         ;X1为正,跳行
        RJMP    CP1         
        SBRC    R13,7        ;X2为正,跳行
        RJMP    CP2          ;X1,X2异号
FPCP1:  CP      R11,R15      ;X1,X2皆为正,以尾数低位字节,中位字节,高位字节和
        CPC     R10,R14      ;阶码的顺序(按无符号数)进行比较
        CPC     R9,R13       ;不等,阶码大者浮点数值也大;只有阶码和尾数对应相等,
        CPC     R8,R12       ;两浮点数才相等
        RET                  ;比较结果:Z=1时X1=X2,否则C=0时X1>X2,C=1时X1<X2
CP1:    SBRC    R13,7
        RJMP    CP3          ;两负数比较,转       
CP2:    CP      R13,R9       ;正数与负数比较,只比较尾数高位字节即可
        RET
CP3:    CP      R15,R11      ;X1,X2皆为负,以尾数低位字节,中位字节,高位字节和
        CPC      R14,R10     ;阶码的顺序(按无符号数)进行比较
        CPC     R13,R9       ;但要将X1、X2交换位置后按正数比较过程进行
        CPC     R12,R8     
CP4:    RET                  ;比较结果:Z=1时X1=X2,否则C=0时X1>X2,C=1时X1<X2
       ;范例64
FPSU:   LDI     R17,$80      ;浮点减法子程序
        SUB     R13,R17      ;减数数符求反后作为加数
FPAD:   TST     R8           ;浮点加法子程序
        BREQ    DON1         ;被加数为0,加数为和
        TST     R12
        BRNE    FPLAD        ;加数为0,取被加数为和
SAV0:   MOV     R12,R8       ;传送被加数取代加数
        MOV     R13,R9
        MOV     R14,R10
        MOV     R15,R11     
DON1:   RET
FPLAD:  ANDI    R16,$3f      ;清除被加数,加数数符
        SBRC    R9,7
        ORI     R16,$80      ;被加数数符取到(R16,7)
        SBRC    R13,7
        ORI     R16,$40      ;加数数符取到(R16,6)
        LDI     R17,$80
        OR      R9,R17
        OR      R13,R17      ;恢复尾数最高位
        MOV     R17,R12
        SUB     R17,R8       ;计算阶差
        BREQ    GOON         ;两阶相等,转
        BRCC    NX3
        NEG     R17          ;不够减求补
        CPI     R17,24
        BRCC    EXAD          ;|阶差|>24,取被加数为和
NX2A:   LSR     R13
        ROR     R14
        ROR     R15
        DEC     R17
        BRNE    NX2A         ;加数阶小,右移加数对阶
        MOV     R12,R8       ;取被加数阶为和之阶
        BRCC    GOON
        RCALL   INC3         ;舍入移出位
        RJMP    GOON
NX3:    CPI     R17,24
        BRCC    COM1         ;阶差>24,取加数为和
LOOP:   LSR     R9
        ROR     R10
        ROR     R11
        DEC     R17
        BRNE    LOOP         ;加数阶大,右移被加数对阶
        BRCC    GOON
        RCALL   INC3A        ;舍入移出位
GOON:   SBRC    R16,6
        SUBI    R16,$80
        SBRS    R16,7        ;判别两数是否同号
        RJMP    SAMS         ;同号转
        SUB     R15,R11      ;异号,执行减法,加数为被减数
        SBC     R14,R10
        SBC     R13,R9
        BRCC    NOM          ;够减转
        SUBI    R16,$40      ;否则被减数数符求反为和之数符
        RCALL   NEG3         ;并将差求补
NOM:    MOV     R17,R13
        OR      R17,R14
        OR      R17,R15
        BREQ    DON0         ;差为0转
NMLOP:  SBRC    R13,7
        RJMP    COM1
        LSL     R15
        ROL     R14
        ROL     R13         
        DEC     R12
        BRNE    NMLOP        ;规格化
OV1:    SEV                  ;阶码变为0,下溢(可取为0,不算溢出)
        RET
SAMS:   ADD     R15,R11
        ADC     R14,R10
        ADC     R13,R9       ;两数同号,执行加法
        BRCC    COM1
        ROR     R13
        ROR     R14
        ROR     R15
        INC     R12          ;有进位时右规1次($7F+1=$80溢出)
        BREQ    OV1          ;阶码增1后变为0为上溢
        BRNC    COM1
        RCALL   INC3
COM1:   CLV
        SBRC    R16,6
        RET
COMA:   LDI     R17,$7F
        AND     R13,R17      ;正数数符为0
DON:    RET
EXAD:   RCALL   SAV0         ;取被加数为和
        SBRS    R16,7
        RJMP    COMA         ;配置数符
        RET
DON0:   CLR     R12          ;浮点数为0
        RET
       ;范例65               ;浮点乘法子程序
FPMU:   TST     R8
        BREQ    M0           ;被乘数为0,积为0
        TST     R12
        BRNE    M1           ;乘数为0,积也为0
M0:     RJMP    G0           
M1:     RCALL   DP           ;处理积符号,计算积之阶码
        BRCS    OV2
        BREQ    OV2          ;判断溢出
        LDI     R17,$80
        OR      R9,R17
        OR      R13,R17      ;恢复尾数最高位
        MOV     R5,R13
        MOV     R6,R14
        MOV     R7,R15       ;乘数转入R5,R6,R7
        LDI     R17,25       ;设右移部分积次数
        CLR     R13
        CLR     R14
        CLR     R15          ;r13r14r15清除,存放积
        CLC
LOOP1:  BRCC    M2
        ADD     R15,R11
        ADC     R14,R10
        ADC     R13,R9       ;乘数右移移出位为1,被乘数加入部分积1次
M2:     ROR     R13
        ROR     R14
        ROR     R15
        ROR     R5
        ROR     R6
        ROR     R7           ;部分积连同乘数右移1位
        DEC     R17
        BRNE    LOOP1        ;尾数相乘计算完成?
        SBRC    R13,7       
        RJMP    M3           ;乘积最高位为1 转
        ROL     R5
        ROL     R15
        ROL     R14
        ROL     R13          ;乘积最高位为0,高4位字节左移1位
        SBRS    R5,7
        RJMP    M5
        RCALL   INC3         ;末位字节舍入
        BRNE    M5
        SEC                  ;舍入后R13变为0
        ROR     R13          ;将其改为$80(即0.5)
        RJMP    COM2
M5:     DEC     R12          ;舍入后R13不为0
        BRNE    COM2         ;阶码减1
OV2:    SEV                   ;变为0为溢出
        RET
M3:     SBRC    R5,7
        RCALL   INC3         ;乘积低3位字节舍入
COM2:   LDI     R17,$7F
        SBRS    R16,7
        AND     R13,R17      ;正数将符号位请除
DON2:   CLV
        RET
       ;范例66
FPDI:   TST     R12          ;浮点除法子程序
        BREQ    OV3          ;除数为0,溢出
        TST     R8
        BRNE    D1
        RJMP    G0           ;被除数为0,商为0
D1:     NEG     R12          ;除数阶码求补,以加补码代替减原码
        RCALL   DP           ;处理商符号,计算商之阶码
        BRCS    OV3
        BREQ    OV3          ;判断溢出
        LDI     R17,$80
        OR      R9,R17
        OR      R13,R17      ;恢复尾数最高位
FPD3:   LDI     R17,25       ;左移相减试商25次,最后1次舍入
        SUB     R11,R15
        SBC     R10,R14
        SBC     R9,R13
        BRCS    D2           ;第一次尾数相减试商
        INC     R12          ;够减,商阶增1
        SEC
        BRNE    D3           ;商阶增1后不为0,转计商;否则为溢出
OV3:    SEV
        RET
D2:     ADD     R11,R15
        ADC     R10,R14
        ADC     R9,R13       ;不够减则恢复被除数
LOOP2:  LSL     R11
        ROL     R10
        ROL     R9           ;被除数算术左移
        BRCS    D4           ;进位位为1,够减,本位商1
        SUB     R11,R15
        SBC     R10,R14
        SBC     R9,R13       ;否则相减试商
        BRCS    D2A         
        SEC
        RJMP    D3           ;够减,本位商1
D2A:    ADD     R11,R15      ;不够减,恢复被除数
        ADC     R10,R14
        ADC     R9,R13       
        CLC                  ;本位商0
        RJMP    D3
D4:     SUB     R11,R15
        SBC     R10,R14
        SBC     R9,R13       ;被除数减去除数
D3:     DEC     R17
        BRNE    D5           ;除法未完成,循环(1-1=0,不溢出)
        MOV     R13,R5
        MOV     R14,R6
        MOV     R15,R7       ;取回商
        BRCC    COM3
        RCALL   INC3         ;第25位商舍入($800000-$FFFFFF不溢出,故INC3不会溢出!)
COM3:   LDI     R17,$7F
        SBRS    R16,7
        AND     R13,R17      ;配置商数符
DON3:   RET
D5:     ROL     R7           ;在R5,R6,R7中记商(不必预先清除)
        ROL     R6
        ROL     R5           ;商数左移1位并记商
        RJMP    LOOP2
       ;范例67
FPSQ:   ANDI    R16,$7F      ;模拟手算开平方子程序
        SBRC    R13,7
        ORI     R16,$80     ;负数 建虚根标志
FPS0:   TST     R12
        BREQ    DON4         ;0的平方根为0
        LDI     R17,$80
        OR      R13,R17      ;恢复尾数最高位
        LSR     R12          ;阶码算术右移1位
        BRCC    FSQ2
        INC     R12          ;移出位舍入
        RCALL   INC3         ;先将位数增1(提前舍入)
        BRCS    FSQ1         ;C=1,不够减
        SEC
        ROR     R13          ;若尾数变为0将其改为0.5($80-->r13)
        RJMP    FSQ2
FSQ1:   LSR     R13
        ROR     R14
        ROR     R15          ;否则将为数算术右移
FSQ2:   LDI     R17,25       ;开出25位根,末位舍入
        MOV     R8,R17
        LDI     R17,$40
        ADD     R12,R17      ;根恢复为移码
        CLR     R5
        CLR     R6
        CLR     R7           ;根扩展区清除
        CLR     R9
        CLR     R10
        CLR     R11          ;根存储区清除
FSQ3:   SUB     R13,R17
        SBC     R7,R11
        SBC     R6,R10
        SBC     R5,R9        ;试根
        BRCS    FSQ3A
        SEC
        RJMP    FSQ4         ;够减,本位根1
FSQ3A:  ADD     R13,R17
        ADC     R7,R11
        ADC     R6,R10
        ADC     R5,R9        ;否则恢复开平方数之尾数
        CLC                  ;本位商0
FSQ4:   DEC     R8
        BRNE    FSQ5         ;开出第25位根?
FQDON:  MOV     R13,R9
        MOV     R14,R10
        MOV     R15,R11      ;回送根尾数
        BRCC    COM4
        RCALL   INC3         ;第25位根舍入
COM4:   LDI     R17,$7F
        AND     R13,R17      ;根尾数为正数
DON4:   RET
FSQ5:   ROL     R11
        ROL     R10
        ROL     R9           ;根尾数带进位左移,记根

        LSL     R15
        ROL     R14
        ROL     R13
        ROL     R7
        ROL     R6
        ROL     R5
        LSL     R15
        ROL     R14
        ROL     R13
        ROL     R7
        ROL     R6
        ROL     R5           ;开平方数之尾数连同扩展区左移2位
        BRCC    FSQ3         ;未产生进位,循环
        RJMP    FQDON        ;否则进位为第25位根(不须试,并结束子程序)!
       ;范例68               ;牛顿迭代开平方子程序
FSQR:   TST     R12
        BREQ    SQRT         ;0的平方根为0
        ANDI    R16,$7E
        SBRC    R13,7
        ORI     R16,$80      ;虚根标志
        SBRC    R12,0
        INC     R16          ;阶码为奇数
        LDI     R17,$7F
        AND     R13,R17      ;尾数变为正数
        LSR     R12
        LDI     R17,$40
        ADC     R12,R17      ;得到根之移码
        PUSH    R12          ;暂存
        LDI     R17,$80
        MOV     R12,R17
        SBRC    R16,0
        INC     R12          ;得到X1的阶码(0.5≤X1<2)
        RCALL   LD1          ;存 X1
        LSR     R13
        ROR     R14
        ROR     R15
        LDI     R17,$40
        SBRS    R16,0        ;阶码为奇数时算术右移尾数即得到X1之尾数;否则将其最
                                                   ;高位字节加上$40
        OR      R13,R17      ;得到首次根r0=(1+x1)/2
        LDI     R17,3
        MOV     R0,R17       ;迭代3次
FSQLP:  RCALL   LD2
        RCALL   GET1
        RCALL   FPDI
        RCALL   GET2
        RCALL   FPAD
        DEC     R12          ;计算r(i+1)=(x1/ri+ri)/2
        DEC     R0
        BRNE    FSQLP        ;r3的尾数为根之尾数
        POP     R12          ;取回根之阶码
SQRT:   RET                  ;r16,7=1 为虚数根
       ;范例69                ;基本运算程序的演示程序
DMST1: .EQU     SPL=$3D
       .EQU     SPH=$3E
        LDI     R16,2        ;high(ramend)
        OUT     SPH,R16
        LDI     R16,$5F      ;low(ramend)
        OUT     SPL,R16
        LDS     R11,$60      ;r11,7:数符 r11,6 :阶符 r11,5--0:阶(最大为38)
        LDS     R12,$61      ;r12-r15:尾数
        LDS     R13,$62
        LDS     R14,$63
        LDS     R15,$64      ;尾数共8位BCD码
        RCALL   DTOB         ;转为二进制浮点数
        RCALL   LD2          ;暂存
        LDS     R11,$65      ;r11,7:数符 r11,阶符 r11,5--0:阶(最大为38)
        LDS     R12,$66      ;r12-r15:尾数
        LDS     R13,$67
        LDS     R14,$68
        LDS     R15,$69     
        RCALL   DTOB         ;转为二进制浮点数
        RCALL   GET2         ;取第一操作数
        RCALL   FPAD         ;调基本运算子程序之一(FPSU/FPMU/FPDI)
        RCALL   BTOD         ;转回十进制浮点数
DMRET:  RJMP    DMRET
       ;范例70                ;辅助子程序
KP2:    MOV     R8,R12       ;复制第二操作数
        MOV     R9,R13
        MOV     R10,R14
        MOV     R11,R15
        RET
LD1:    STS     $70,R12      ;存浮点数
        STS     $71,R13
        STS     $72,R14
        SYS     $73,R15
        RET
LD2:    STS     $74,R12      ;存浮点数
        STS     $75,R13
        STS     $76,R14
        STS     $77,R15
        RET
LD3:    STS     $78,R12      ;存浮点数
        STS     $79,R13
        STS     $7A,R14
        STS     $7B,R15
        RET
GET1:   LDS     R8,$70       ;取浮点数
        LDS     R9,$71
        LDS     R10,$72
        LDS     R11,$73
        RET
GET2:   LDS     R8,$74       ;取浮点数
        LDS     R9,$75
        LDS     R10,$76
        LDS     R11,$77
        RET
GET3:   LDS     R8,$78       ;取浮点数
        LDS     R9,$79
        LDS     R10,$7A
        LDS     R11,$7B
        RET
INVPI:  LDI     R17,$86      ;取浮点数180/л
        MOV     R8,R17
        LDI     R17,$65
        MOV     R9,R17
        LDI     R17,$2E
        MOV     R10,R17
        LDI     R17,$E1
        MOV     R11,R17
        RET
G90:    LDI     R17,$87                   ;取浮点数90
        MOV     R8,R17
        LDI     R17,$34
        MOV     R9,R17
        CLR     R10
        CLR     R11
        RET
DTOR:   RCALL   PI18         ;角度化为弧度
        RJMP    FPMU
RTOD:   RCALL   INVPI        ;弧度化为角度
        RJMP    FPMU
GHPI:   LDI     R17,$81      ;取浮点数л/2
        MOV     R8,R17
        LDI     R17,$49
        MOV     R9,R17
        LDI     R17,$0f
        MOV     R10,R17
        LDI     R17,$DB
        MOV     R11,R17
        RET
G01:    LDI     R17,$7D          ;取浮点数0.1
        MOV     R8,R17
        LDI     R17,$4C
        MOV     R9,R17
        LDI     R17,$CC
        MOV     R10,R17
        LDI     R17,$CD
        MOV     R11,R17
        RET
G1:     LDI     R17,$81      ;取浮点数1
        MOV     R8,R17
        CLR     R9
        CLR     R10
        CLR     R11
        RET
PI18:   LDI     R17,$7B        ;取浮点数л/180
        MOV     R8,R17
        LDI     R17,$0E
        MOV     R9,R17
        LDI     R17,$FA
        MOV     R10,R17
        LDI     R17,$35
        MOV     R11,R17
        RET
GINT:   LDI     R17,R12             ;浮点数取整
        CPI     R17,$81 
        BRCC    GINT1
        RCALL   G0           ;阶码<$81,结果为0
        RJMP    KP2
GINT1:  ANDI    R16,$DD
        SBRC    R13,7
        ORI     R16,2        ;记数符
        CPI     R17,$98
        BRCC    GOVER        ;阶码>$97,溢出
        RCALL   BRK          ;分解出整数部分(在R9 R10 R11)   
        SBRS    R16,1
        RET                  ;正数返回
NEG3A:  COM     R11          ;负数求(r9 r10 r11)之补
        COM     R10
        COM     R9
INC3A:  LDI     R17,255
        SUBI    R11,R17
        SBCI    R10,R17
        SBCI    R9,R17        ;求反后加1
        RET
GOVER:  ORI     R16,$20      ;设整数部分超过23位标志
        RET
BRK:    ANDI    R16,$DF      ;将正浮点数分解为整数/小数两部分
        LDI     R17,$80
        OR      R13,R17      ;恢复尾数最高位
        CLR     R9
        CLR     R10
        CLR     R11
        MOV     R17,R12
        SUBI    R17,$80
        BREQ    BRKRT
        BRCS    LOOPT
        CPI     R17,$19      ;整数部分超过24位
        BRCC    GOVER        ;为溢出
LOOP4:  LSL     R15
        ROL     R14
        ROL     R13
        ROL     R11
        ROL     R10
        ROL     R9
        DEC     R17
        BRNE    LOOPT        ;左移位数为阶码-$80,整数部分进入r9-r11中
BRKRT:  RET
LOOPT:  LSR     R13          ;只有小数部分右移尾数($80-阶码)位
        ROR     R14
        ROR     R15
        INC     R17
        BRNE    LOOPT
        RET
NRML:   ANDI    R16,$BF      ;1字节正整数(在R13中)规格化为浮点数
        CLR     R14
        CLR     R15
        LDI     R12,$88       ;设阶码
        RJMP    NMLOP
G10:    LDI     R17,$84       ;取浮点数10
        MOV     R8,R17
        LDI     R17,$20
        MOV     R9,R17
        CLR     R10
        CLR     R11
        RET
GLN2:   LDI     R17,$80      ;取浮点数ln2(=0.6931471806)
        MOV     R8,R17
        LDI     R17,$31
        MOV     R9,R17
        LDI     R17,$72
        MOV     R10,R17
        LDI     R17,$18
        MOV     R11,R17
        RET
GLN10:  LDI     R17,$82      ;取浮点数ln10(=2.302585093)
        MOV     R8,R17
        LDI     R17,$13
        MOV     R9,R17
        LDI     R17,$5D
        MOV     R10,R17
        LDI     R17,$8E
        MOV     R11,R17
        RET
INVX:   TST     R12          ;计算1/X, X=0时溢出
        BRNE    INV
OV4:    SEV
        RET
INV:    RCALL   G1           ;取1
        RJMP    FPDI         
       ;范例71               ;用荷纳法计算多项式值子程序
FPLN1:  ORI     R16,$10      ;设计算奇函数(lnx,sinx,arcsinx 等)标志
        RCALL   LD3          ;存X
        RCALL   KP2         
        RCALL   FPMU         ;计算X2
        RJMP    FLN0         ;                                       
FPLN2:  ANDI    R16,$EF      ;设计算偶函数(EXP,COSX等)标志           
FLN0:   RCALL   LD1          ;存T,T=X 或T=X2
        POP     R30       
        POP     R31          ;系数表数据地址进入Z
        LSL     R30
        ROL     R31          ;由按字取数变为按字节取数
        LPM                  ;r0<--(z)取阶码
        MOV     R8,R0
        ADIW    R30,1        ;指针增1
        LPM                  ;取尾数高位字节
        MOV     R9,R0
        ADIW    R30,1        ;z+1
        LPM                  ;取尾数中位字节
        MOV     R10,R0
        ADIW    R30,1        ;z+1
        LPM                  ;取尾数低位字节
        MOV     R11,R0       ;取浮点数到r8 r9 r10&r11
        ADIW    R30,1        ;z+1
PLN:    RCALL   M1           ;计算(....((An*T+A(n-1))*T+A(n-2))*T+....+Ai)*T
        LPM
        MOV     R8,R0
        ADIW    R30,1
        LPM
        MOV     R9,R0
        ADIW    R30,1
        LPM
        MOV     R10,R0
        ADIW    R30,1
        LPM
        MOV     R11,R0       ;取A(i-1)
        ADIW    R30,1
        RCALL FPLAD           ;计算(....((An*T+A(n-1))*T+A(n-2))*T+....+Ai)*T+A(i-1)
        LPM
        RCALL   GET1
        DEC     R0
        BRNE    PLN          ;1为停止符号;否则继续计算
PEND:   SBRS    R16,4
        RJMP    REND
        RCALL   GET3         ;奇函数 取出自变量
        RCALL   M1           ;自变量乘以计算结果才是函数值
REND:    LSR     R31
        ROR     R30          ;Z指针折半后
        ADIW    R30,1        ;增1为后继指令地址
        IJMP                 ;转到该地址去执行
       ;范例72
LNX:    TST     R12          ;对数函数子程序
        BREQ    OV5
        SBRS    R13,7
        RJMP    LN1
OV5:    SEV                  ;求负数或0的对数为错误
        RET
LN1:    ANDI    R16,$7E      ;R16,7:(T-1)/(T+1)或(2T-1)/(2T+1)之符号 R16,0:p之符号
                             ;     m
        MOV     R0,R12       ;设X=2 *T, 则LnX=m*Ln2+LnT,存入p=m
        LDI     R17,$F3
        CP      R15,R17
        LDI     R17,$04
        CPC     R14,R17
        LDI     R17,$35
        CPC     R13,R17       ;   _
        BRCC    LN5          ;T>√2/2时跳转
        DEC     R0           ;取p=m-1  LnX=(m-1)*Ln2+LN(2T)
        MOV     R17,R15
        OR      R17,R14
        OR      R17,R13
        MOV     R12,R17
        BREQ    LN5A         ;2T-1=0 只须计算(m-1)Ln2
        RCALL   KP2          ;R12 NOUSED!
        LSL     R9
        ROL     R10
        ROL     R11          ;(2T-1)
        LSR     R13
        ROR     R14
        ROR     R15
        LDI     R17,$80
        OR      R13,R17      ;2T+1
        LDI     R17,$7E
        MOV     R12,R17      ;取1/(2T+1)的阶码
        RJMP    LNTLP
LN5:    ORI     R16,$80      ;(T-1)为负,数符位改为1
        RCALL   KP2
        RCALL   NEG3A
        LDI     R17,$80
        ADD     R9,R17       ;计算(T-1)
        LSR     R13
        ROR     R14
        ROR     R15
        LDI     R17,$C0
        OR      R13,R17
        LDI     R17,$7F
        MOV     R12,R17      ;取1/(T+1)的阶码
LNTLP:  LSL     R11
        ROL     R10
        ROL     R9           ;(2T-1)或(T-1)规格化
        DEC     R12          ;调整(2T-1)/(2T+1))或(T-1)/(T+1)的阶码
        SBRS    R9,7
        RJMP    LNTLP
        RCALL   FPD3         ;计算(2T-1)/(2T+1)或(T-1)/(T+1) 位r16,7为商之数符
        PUSH    R0
        RCALL   FPLN1        ;计算LnT或Ln(2T)
        .DB $7E,$12,$49,$25   ;0.14285714    ;er.total<0.000000029!
        .DB $7E,$4C,$CC,$CD   ;0.2
        .DB $7F,$2A,$AA,$AB   ;0.33333333
        .DB $81,$00,$00,$00   ;1
        .DB $01,$00           ;结束符
        INC     R12         
        POP     R0
LN5A:   LDI     R17,$80
        ADD     R0,R17
        BREQ    LN53         ;p=$80结束
        BRCS    LN51
        NEG     R0
        INC     R16          ;p为负数
LN51:   RCALL   LD1          ;存LnT或Ln(2T)
        MOV     R13,R0
        RCALL   NRML          ;|P|规格化
        RCALL   GLN2         ;取ln2
        RCALL   FPMU         ;计算|p|*ln2
        RCALL   GET1         ;取LnT或Ln(2T)
        SBRS    R16,0
        RJMP    LN52
        RCALL   FPSU         ;p<0 计算lnT-|p|*ln2或Ln(2T)-|p|*ln2
        RET
LN52:   RCALL   FPAD         ;p>0 计算lnT+|p|*ln2或Ln(2T)+|p|*ln2
LN53:   RET
       ;范例73                ;对数衍生函数子程序
LGX:    RCALL   LNX          ;计算lnx
        RCALL   GLN10        ;取ln10
        RCALL   EXCH
        RJMP    FPDI         ;转计算lgx=lnx/ln10
LGAX:   RCALL   LD2          ;存a
        RCALL   EXCH
        RCALL   LNX          ;计算lnx
        RCALL   GET2         ;取a
        RCALL   LD2          ;存lnx
        RCALL   EXCH
        RCALL   LNX          ;计算lna
        RCALL   GET2         ;转计算logax=lnx/lna
        RJMP    FPDI
       ;范例74
EXP:    MOV     R17,R12      ;指数函数子程序
        CPI     R17,$68      ;X之阶<$68
E1:     BRCC    E2
        RCALL   G0
        ROR     R12          ;(R12)=$80
        INC     R12          ;取exp=1
        RET
E2:     ANDI    R16,$3F      ;r16,6:数符
        SBRC    R13,7
        ORI     R16,$40      ;负数
        LDI     R17,$7F
        AND     R13,R17      ;取正(取|X|)
        LDI     R17,$33
        CP      R15,R17
        LDI     R17,$0F
        CPC     R14,R17
        LDI     R17,$30
        CPC     R13,R17
        LDI     R17,$87
        CPC     R12,R17      ;|X|与88.02969 比较
        BRCS    E3           ;|X|<88.02969 转
        SBRS    R16,6
        RJMP    OV6
G0:     CLR     R12          ;若x<-88.02969
        CLR     R13
        CLR     R14          ;Exp=0
        CLR     R15
        RET
OV6:    SEV                  ;x>88.02969,Exp溢出
        RET
E3:     CLR     R0           ;X整数部分予清除
        LDI     R17,$81
        MOV     R8,R17
        LDI     R17,$38
        MOV     R9,R17
        LDI     R17,$AA
        MOV     R10,R17
        LDI     R17,$3B
        MOV     R11,R17      ;取log2e(=1/ln2)
        RCALL   FPMU         ;计算X/ln2
        LDI     R17,$80
        SBRC    R16,6
        OR      R13,R17
        MOV     R17,R12
        CPI     R17,$81
        BRCS    E6           ;X/ln2整数部分为0 转
        RCALL   BRK          ;否则分解该数为整数I(在R11),小数F两部分
        LDI     R17,$80
        MOV     R12,R17
        RCALL   NOM          ;小数部分规格化为浮点数
        SBRC    R16,6
        NEG     R11          ;整数部分求补
        MOV     R0,R11       ;
E6:     PUSH    R0
        RCALL   FPLN2        ;计算EXP(F*ln2)
        .DB $69,$5A,$92,$9F   ;0.10178086 E-6    ;er.total<0.000000024
        .DB $6D,$31,$60,$11   ;0.13215487 E-5
        .DB $70,$7F,$E5,$FE   ;0.15252734 E-4
        .DB $74,$21,$84,$89   ;0.15403530 E-3
        .DB $77,$2E,$C3,$FF   ;0.13333558 E-2
        .DB $7A,$1D,$95,$5B   ;0.96181291 E-2
        .DB $7C,$63,$58,$47   ;0.55504109 E-1
        .DB $7E,$75,$FD,$F0   ;0.24022651
        .DB $80,$31,$72,$18   ;0.69314718
        .DB $81,$00,$00,$00   ;1
        .DB $01,$00           ;结束符
        POP     R0
        ADD     R12,R0       ;整数部分I 加入阶码中
        RET
       ;范例75            ;指数衍生函数子程序
DXP:    RCALL   GLN10        ;取ln10
        RJMP    EXP0         ;转计算EXP(X*ln10)
AXP:    RCALL   LD2          ;存X
        RCALL   EXCH
        RCALL   LNX          ;计算lna
        RCALL   GET2         ;取出x
EXP0:   RCALL   FPMU       
        RJMP    EXP          ;转计算EXP(X*lna)

       ;范例76             ;双曲函数和反双曲函数子程序
SHX:    RCALL   SUB11        ;计算双曲正弦
        RCALL   FPSU
        BRNE    NX48
        RET
CHX:    RCALL   SUB11        ;计算双曲余弦
        RCALL   FPAD
NX48:   DEC     R12
        RET
SUB11:  RCALL   EXP
        RCALL   LD2
        RCALL   INVX
        RJMP    GET2
ASHX:   RCALL   SUB2         ;计算反双曲正弦
        RCALL   FPAD
ASH:    RCALL   FPSQ
        RCALL   GET2
        RCALL   FPAD
        RJMP    LNX
ACHX:   RCALL   SUB2         ;计算反双曲余弦
        RCALL   EXCH
        RCALL   FPSU
        RJMP    ASH
SUB2:   RCALL   LD2          ;存X
        RCALL   KP2         
        RCALL   FPMU         ;得到X2
        RJMP    G1           ;取浮点数1
       ; 范例77              ;正弦函数子程序
SINX:   RCALL   RTOD         ;弧度化为角度
SINX1:  CLR     R16          ;X1为角度
        SBRC    R13,7
        INC     R16          ;存数符
        LDI     R17,$7F      ;X1-->|X1|
        AND     R13,R17
NX30:   RCALL   G90
        INC     R8
        INC     R8           ;取360°
        RCALL   FPCP1        ;|X1|与360°比较
        BREQ    GE0          ;相等,转出
        BRCC    NX31         ;|X1|<360° 转出
        RCALL   EXCH
        RCALL   FPSU         ;否则|X1|-360°-->|X1|
        RJMP    NX30         ;循环
NX31:   DEC     R8
        RCALL   FPCP1        ;|X1|与180°比较
        BREQ    GE0          ;相等,转出
        BRCC    NX32         ;|X1|<180°,转
        RCALL   EXCH
        RCALL   FPSU         ;否则|X1|-180°-->|X1|
        INC     R16          ;将数符求反
NX32:   RCALL   G90
        RCALL   FPCP1        ;|X1|与90°比较
        BRCC    NX36
        INC     R8
        RCALL   FPSU         ;|X1|>90°,取180°-|x1|-->|x1|
        RJMP    NX36
GE0:    RJMP    G0           ;|X1|=0 则sinX=0
NX36:   RCALL   DTOR         ;变回弧度X
        MOV     R17,R12
        CPI     R17,$79      ;阶码<$79,sinX=X
        BRCS    PP2
        RCALL   FPLN1        ;计算sin|X|
        .DB $60,$30,$92,$32   ; 0.16059044 E-9   er.total<0.0000000071
        .DB $67,$D7,$32,$2A   ;-0.25052108 E-7
        .DB $6E,$38,$EF,$1C   ; 0.27557319 E-5
        .DB $74,$D0,$0D,$01   ;-0.19841270 E-3
        .DB $7A,$08,$88,$88   ; 0.83333333 E-2
        .DB $7E,$AA,$AA,$AA   ;-0.16666667
        .DB $81,$00,$00,$00   ;1
        .DB $01,$00           ;结束符
PP2:    LDI     R17,$80
        SBRC    R16,0
PP3:    OR      R13,R17      ;配置数符
DON6:   RET
       ;范例78             ;衍生三角函数子程序
CTNX:   RCALL   RTOD         ;弧度化为角度
CTNX1:  RCALL   TANX1        ;计算tgX
        RJMP    INVX         ;取倒数为ctgX
TANX:   RCALL   RTOD         ;弧度化为角度
TANX1:  RCALL   LD2          ;存X
        RCALL   SINX1        ;计算sinX
        RCALL   GET2         ;取X
        RCALL   LD2          ;存sinX
        RCALL   EXCH
        RCALL   COSX1        ;计算cosX
        BRNE    NX39
OV7:    SEV
        RET                  ;cosX=0,溢出
NX39:   RCALL   GET2         ;取sinX
        RJMP    FPDI         ;tgX=sinX/cosX
COSX:   RCALL   RTOD         ;弧度化为角度
COSX1:  RCALL   G90          ;取浮点数90°
        RCALL   FPSU
        RJMP    SINX1        ;cosX=sin(90-X)

       ;范例79               ;反正弦函数子程序
ASINX:  MOV     R17,R12
        CPI     R17,$78     
        BRCS    DON6         ;X阶码<$78,acrsinX=X
        ANDI    R16,8        ;清除数符和|X|>0.5标志,保留计算acosx标志(R16,3)
        SBRC    R13,7
        INC     R16          ;记数符
        LDI     R17,$7F
        AND     R13,R17      ;取绝对值 X-->|X|
        RCALL   G1
        RCALL   FPCP1
        BREQ    AA
        BRCC    AA1
OV8:    SEV                  ;|X>1,溢出
        RET
AA:     RCALL   GHPI
        RCALL   EXCH
        RJMP    PP2          ;|X|=1,arcsinX=±л/2
AA1:    MOV     R17,R12     
        CPI     R17,$80     
        BRNE    AS1               ;|X|<0.5,y=|x|
        MOV     R17,R13
        OR      R17,R14
        OR      R17,R15
        BREQ    AS1               ;X=0.5,y=|x|
        ORI     R16,$20            ;X>0.5,建标
        RCALL   NEG3
        LDI     R17,$80
        ADD     R13,R17
        LDI     R17,$7F
        MOV     R12,R17      ;((1-|x|)/2)方根之阶最大为$7F
NRMLP:  LSL     R15
        ROL     R14
        ROL     R13
        DEC     R12
        SBRS    R13,7
        RJMP    NRMLP        ;  __________
        RCALL   FPS0         ;√(1-|X|)/2-->y
AS1:    RCALL   FPLN1        ;计算arcsiny
        .DB $7A,$3D,$43,$C4   ;0.11551801 E-1     er. total<0.0000000245
        .DB $7A,$64,$CC,$CD   ;0.13964844 E-1
        .DB $7B,$0E,$27,$62   ;0.17352764 E-1
        .DB $7B,$37,$45,$D1   ;0.22372159 E-1
        .DB $7B,$78,$E3,$8E   ;0.30381944 E-1
        .DB $7C,$36,$DB,$6E   ;0.44642857 E-1
        .DB $7D,$19,$99,$9A   ;0.075
        .DB $7E,$2A,$AA,$AA   ;0.16666667
        .DB $81,$00,$00,$00   ;1
        .DB $01,$00           ;结束符
        SBRS    R16,5       
        RJMP    PP2          ;|x|≤0.5 转配置数符,有acsin|x|=acsiny
        INC     R12          ;否则取2arcsiny(=arccosx)
        SBRC    R16,3        ;测试计算ARCCOSX的标志
        RJMP    ACSRT        ;有计算ARCCOSX标志,转清除该标志(其余计算在ACOSX子程序中完成) 
        RCALL   GHPI         ;否则取л/2
AS2:    RCALL   FPSU            ;|X|>0.5时,arcsin|X|=л/2 -2arcsiny
PP20:   RJMP    PP2               ;转去配置数符
       ;范例80              ;函数值为弧度的反三角函数子程序
ACOSX:  ORI     R16,8        ;设计算arccosx标志
        RCALL   ASINX        ;调反正弦函数子程序
        RCALL   GHPI         ;取л/2
        SBRC    R16,3                ;计算ARCCOS|X|标志未被清除?
        RJMP    AS3          ;是,转计算arccosx=л/2-arcsinx
        SBRS    R16,0               ;x>0且x>0.5
        RJMP    ACSRT        ;有arccosx=2arcsiny!
        INC     R8           ;否则取л;即当x<0且|X|>0.5时,有arccosX=л-2arcsiny
AS3:    RCALL   FPSU         
ACSRT:  ANDI    R16,$F7             ;清除计算arccosx标志
        RET
ATANX:  MOV     R17,R12      ;反正切函数子程序
        CPI     R17,$98     
        BRCS    AT1
        RCALL   GHPI         ;X阶码大于$98,取л/2
        RCALL   EXCH
        ROL     R9
        BRCC    AT2
        LDI     R17,$80
        OR      R13,R17               ;arctgx=л/2
AT2:    RET
AT1:    MOV     R17,R12
        CPI     R17,$74                ;X阶码小于$74,arctgX=X
        BRCS    AT2
        RCALL   KP2
        RCALL   LD1          ;存X
        RCALL   FPMU
        RCALL   G1
        RCALL   FPAD         ;      _______
        RCALL   FPSQ         ;计算 √(1+X2)
        RCALL   GET1
        RCALL   FPDI
        RJMP    ASINX        ;转计算arctgx=arcsin(X/√<(1+X2)
ACTNX:  RCALL   ATANX        ;反余切函数子程序
        RCALL   GHPI
        RJMP    FPSU         ;arcctgX=л/2-arctgx
             ;范例81             ;函数值为角度的反三角函数子程序
ASNX:   RCALL   ASINX        ;反正弦函数子程序,结果以角度表示
        RJMP    RTOD
ACSX:   RCALL   ACOSX        ;反余弦函数子程序,结果以角度表示
        RJMP    RTOD
ATNX:   RCALL   ATANX        ;反正切函数子程序,结果以角度表示
        RJMP    RTOD
ACNX:   RCALL   ACTNX        ;反余切函数子程序,结果以角度表示
        RJMP    RTOD
       ;范例82                ;函数计算子程序演示程序
DMST2:  LDI     R16,2
        OUT     SPH,R16
        LDI     R16,$5F      ;堆栈指针初始化
        OUT     SPL,R16
        LDS     R11,$65      ;取操作数(自变量X)
        LDS     R12,$66      ;r11,7:数符 r11,6:阶符
        LDS     R13,$67      ;r11,5--0:阶(最大为38)
        LDS     R14,$68     
        LDS     R15,$69      ;r12-r15:十进制尾数(8位BCD码)
        RCALL   DTOB         ;翻为二进制浮点数
        RCALL  LNX           ;调函数子程序之一
        RCALL   BTOD         ;将函数值转为十进制浮点数
DMHER:  RJMP    DMHER
       ;范例83                ;阶乘子程序
NP:     RCALL   G1           ;取浮点数1
        MOV     R17,R12      ;二进制整数N在R12中
        CPI     R17,2        ;N<2,N!=1
        BRCS    GG
        CPI     R17,34
        BRCS    NX59
OV9:    SEV                  ;N>33,溢出
        RET
GG:     RJMP    SAV0         ;取N!=1
NX59:   MOV     R0,R12       ;存N
        DEC     R0            ;N-1
        LDI     R17,1
        PUSH    R17          ;取T=1 并存入
        LDI     R17,$81
        STS     $70,R17
        CLR     R17
        STS     $71,R17
        STS     $72,R17
        STS     $73,R17      ;存储浮点数1
L43:    POP     R13          ;取T
        INC     R13          ;T+1-->T
        PUSH    R13          ;存T
        RCALL   NRML         ;T规格化
        RCALL   GET1         ;取阶段阶乘结果
        RCALL   FPMU         ;得到当前T!
        RCALL   LD1
        DEC     R0
        BRNE    L43          ;T=N时得到N!
        POP     R0
        RET
       ;范例84               ;长整数(r9,r10,r11,r12)规格化为浮点数
LINOM:  BST     R9,7         ;数符存于T
        BRTC    LI10
        CLR     R16          ;负数求补
        SUB     R16,R12
        MOV     R12,R16
        CLR     R16
        SBC     R16,R11
        MOV     R11,R16
        CLR     R16
        SBC     R16,R10
        MOV     R10,R16
        CLR     R16
        SUB     R16,R9
        MOV     R9,R16
LI10:   LDI     R16,$A0      ;取阶32(长整数共32位)
LP10:   SBRC    R9,7
        RJMP    NX63         ;最高位为1,已规格化
        LSL     R12
        ROL     R11
        ROL     R10
        ROL     R9           ;否则左规1位
        DEC     R16          ;阶码减1
        CPI     R16,$80
        BRNE    LP10
        RJMP    G0           ;左规达32次,浮点数为0
       ;范例85                ;定点十进制数翻为二进制浮点数
DTOB1:  RCALL   LD1          ;存入十进制小数
        RCALL   CONV2        ;定点整数十翻二
        RCALL   GET1         ;取出十进制小数
        RCALL   LD1
        RCALL   SAV0
        RCALL   CONV4        ;定点小数十翻二
        RCALL   GET1         ;取出二进制定点整数
        LDI     R16,$98      ;予设阶码
LP11:   SBRC    R9,7
        RJMP    NX63         ;最高位为1,已规格化
        LSL     R15
        ROL     R14
        ROL     R13
        ROL     R12
        ROL     R11
        ROL     R10
        ROL     R9           ;整数和小数部分左移一位
        DEC     R16          ;阶码减1
        CPI     R16,$60
        BRNE    LP11
        RET                  ;得到浮点数0
NX63:   MOV     R13,R9
        MOV     R14,R10
        MOV     R15,R11      ;尾数取到r13-r15
        SBRS    R12,7
        RJMP    PP6
        RCALL   INC3         ;尾数截去部分舍入
        BRNE    PP6
        INC     R16          ;尾数变为0将阶码增1
        SEC
        ROR     R13          ;$80-->r13,即将尾数变为0.5
PP6:    MOV     R12,R16      ;取回阶码
        BLD     R13,7        ;装入数符(T-->R13,7)
        RET
       ;范例86                ;浮点数十翻二
DTOB:   ANDI    R16,$FC      ;r11,7:数符  r11,6:阶符 r11,5--0:阶(最大为38)
        SBRC    R11,6        ;R12---R15;8BCD码尾数
        INC     R16          ;阶符存于R16,0
        SBRC    R11,7
        ORI     R16,2        ;数符存于R16,1
        MOV     R17,R11
        ANDI    R17,$3F      ;取阶
        MOV     R0,R17       ;存于R0
        MOV     R8,R12
        OR      R8,R13
        OR      R8,R14
        OR      R8,R15
        BREQ    PP8          ;十进制浮点数尾数为0,取二进制浮点数0
        PUSH    R16
        RCALL   CONV4        ;十进制浮点数尾数翻为二进制定点小数
        MOV     R16,R15
        MOV     R15,R14
        MOV     R14,R13
        MOV     R13,R12      ;二进制定点小数转入r13r14r15r16
        LDI     R17,$80      ;予设阶码
        MOV     R12,R17
LP14:   SBRC    R13,7
        RJMP    NX67
        LSL     R16
        ROL     R15
        ROL     R14
        ROL     R13
        DEC     R12
        RJMP    LP14         ;二进制定点小数规格化为浮点数
NX67:   SBRS    R16,7
        RJMP    NX66
        RCALL   INC3         ;调整
        BRNE    NX66
        INC     R12
        SEC                  ;调整后结果为0将其改为0.5
        ROR     R13          ;即$80-->r13
NX66:   LDI     R17,$7F
        POP     R16
        SBRS    R16,1
        AND     R13,R17      ;配置数符
        SBRS    R16,0
        RJMP    DBL4         ;正阶转
DBL1:   LDI     R17,$10
        SUB     R0,R17         
        BRCS    DBL2
        RCALL   INVDP        ;             
        RCALL   FPMU         ;阶码减10, X*10ˉ1o -->X
        RJMP    DBL1
DBL2:   ADD     R0,R17       ;不够减则恢复阶
        BREQ    PP8
DBL3:   RCALL   G01          ;取0.1
        RCALL   FPMU
        DEC     R0           ;X*0.1-->X,阶减1
        BRNE    DBl3
        RET
DBL4:   LDI     R17,$10
        SUB     R0,R17       ;阶减10
        BRCS    DBL5         
        RCALL   DDP          ;X*101o -->X
        RCALL   FPMU
        RJMP    DBL4
DBL5:   ADD     R0,R17       ;不够减则恢复阶
        BREQ    PP8
DBL6:   RCALL   G10
        RCALL   FPMU
        DEC     R0           ;X*10-->X,阶减1
        BRNE    BDL6
PP8:    RET                 
INVDP:  LDI     R17,$5F      ;取浮点数10ˉ1o
        MOV     R8,R17
        LDI     R17,$5B
        MOV     R9,R17
        LDI     R17,$E6
        MOV     R10,R17
        LDI     R17,$FF
        MOV     R11,R17
        RET                  ;         
DDP:    LDI     R17,$A2      ;取浮点数101o
        MOV     R8,R17
        LDI     R17,$15
        MOV     R9,R17
        LDI     R17,$02
        MOV     R10,R17
        LDI     R17,$F9
        MOV     R11,R17
        RET
       ;范例87               ;浮点数二翻十
BTOD:   TST     R12
        BREQ    PP4          ;转取十进制浮点数0
        ANDI    R16,$FC      ;予清十进制浮点数数符及阶符(r16,1&0)
        CLR     R0           ;予清十进制浮点数之阶
        SBRC    R13,7
        ORI     R16,2        ;取数符
        LDI     R17,$7F
        AND     R13,R17      ;取绝对值
BTA:    RCALL   DDP         
        RCALL   FPCP1        ;|X|与101o 比较
        BREQ    BTB         
        BRCC    BTC          ;|X|<101o 转
BTB:    RCALL   INVDP       
        RCALL   FPMU         ;|X|*10ˉ1o-->|X|
        LDI     R17,$10
        ADD     R0,R17       ;十进制浮点数阶加10
        RJMP    BTA
BTC:    RCALL   INVDP        ;       
        RCALL   FPCP1        ;|X|与10ˉ1o  比较
        BREQ    BTC1         ;     
        BRCS    BT0          ;|X|>10ˉ1o   转
BTE:    RCALL   DDP          ;     
        RCALL   FPMU         ;|X|*101o  -->|X|
        LDI     R17,$10
        ADD     R0,R17       ;十进制浮点数阶加10
        ORI     R16,1        ;置负阶
        RJMP    BTC         
BTC1:   LDI     R17,9        ;|X|=10ˉ1o   特别处理
        ADD     R0,R17       ;        -9
        ORI     R16,1        ;取0.1*10
        SJMP    BT4
BT0:    RCALL   G1
        RCALL   FPCP1        ;|X|与1比较
        BREQ    BT1
        BRCC    BT2          ;|X|<1转
BT1:    RCALL   G01
        RCALL   FPMU         ;|X|*0.1-->|X|
        INC     R0           ;十进制浮点数阶加1
        RJMP    BT0
BT2:    RCALL   G01
        RCALL   FPCP1        ;|X|与0.1比较
        BREQ    BT4
        BRCS    BDS          ;|X|≤0.1转出
BT3:    RCALL   G10
        RCALL   FPMU         ;|X|*10--->|X|
        INC     R0           ;十进制浮点数阶加1
        ORI     R16,1        ;置负阶
        RJMP    BT2
PP4:    RJMP     KP2          ;十进制浮点数取为0
BT4:    LDI     R17,$10
        MOV     R9,R17
        CLR     R10
        CLR     R11
        CLR     R12          ;十进制浮点数尾数取为0.10000000
BT6:    MOV     R8,R0        ;取十进制浮点数阶
        SBRS    R8,3
        RJMP    BT7
        SBRC    R8,1
        SUBI    R8,$FA       ;对产生非法BCD调整(加6)
BT7:    LDI     R17,$40
        SBRC    R16,0
        OR      R8,R17       ;配置阶符(r8,6)
        LSL     R17
        SBRC    R16,1
        OR      R8,R17       ;配置阶浮(r8,7)
        RET
BDS:    RCALL   BT6          ;BT6将十进制浮点数阶,阶符和数符配置到R8
        LDI     R17,$80
        OR      R13,R17      ;恢复尾数最高位
        LDI     R17,$98
        SUB     R17,R12      ;右移次数为($98-阶码)
        RJMP    CONV31       ;调CONV31子程序完成尾数二翻十,结果在(r9r10r11r12)
            ;范例88               ;二进制浮点数快速翻为定点十进制数,整数在r9,r10,r11中,小数在r13,r14,r15中
FBTOD:  RCALL   BRK          ;二进制浮点数分解为整数和小数两部分
        SBRC    R16,5
        RET                  ;整数部分多于24位,溢出
        MOV      R0,R13
        MOV      R5,R14
        MOV      R8,R15       ;小数部分转入R0R5R8
        RCALL   CONV1        ;定点整数二翻十,结果在R12,R13,R14,R15
        RCALL   LD1          ;十进制整数-->RAM
        MOV      R15,R8
        MOV     R14,R5
        MOV     R13,R0       ;取回二进制小数
        RCALL   CONV3        ;定点小数二翻十,结果在r9,r10,r11,r12
        RCALL   EXCH1        ;十进制定点小数转入r13,r14,r15,r12
        RCALL   GET1         ;取出十进制定点整数r8,r9,r10,r11)/小数在r13,r14,r15,r12
        CLR     R16          ;清除无用的标志!
        RET
       ;范例89
       .ORG     $E80         ;最小二乘法拟和直线子程序
.EQU    NUMB=10              ;取10点,即十对浮点数,按增地址存放Y1,X1,Y2,X2,..Yn,Xn
.EQU    TABLA=$9000          ;数据表,第一个浮点数为Y1
STRT:   LDI     R28,$70
        CLR     R29          ;POINT TO $0070
LP51:   ST      Y+,R29       ;累加和或暂存区清除(LD1,LD2,LD3,LD4和LD5子程序工作区)
        CPI     R28,$84
        BRNE    LP51
        LDI     R16,NUMB     ;取拟合点数
        MOV     R0,R16
        LDI     R29,$90     
        CLR     R28          ;参加拟合数据首地址$9000
        IN      R16,MCUCR,7 
        SBR     R16,$C0      ;片外RAM,选一个读写等待周期
        OUT     MCUCR,R16
LOOP3:  RCALL   GETA         ;取浮点数Yi 占4字节 即Yi0,Yi1,Yi2,Yi3
        RCALL   INVX         ;计算1/Yi
        RCALL   LD6          ;暂存
        RCALL   GET1         ;取累加和                  n
        RCALL   FPAD         ;1/Yi加入累加和(∑1/Yi是 ∑1/Yi 简写形式,下同)
        RCALL   LD1          ;                         i=1
        RCALL   GET6         ;取1/Yi
        PUSH    R28
        PUSH    R29          ;保护堆栈指针
        RCALL   GETA         ;取浮点数Xi(Xi0,Xi1,Xi2,Xi3)占4字节
        POP     R29
        POP     R28          ;恢复堆栈指针,仍指向Xi
        RCALL   FPMU         ;计算Xi/Yi
        RCALL   LD7          ;暂存
        RCALL   GET2
        RCALL   FPAD         ;Xi/Yi加入累加和∑(Xi/Yi)
        RCALL   LD2
        RCALL   GET7         ;取出Xi/Yi
        RCALL   SAV0         ;           
        RCALL   FPMU         ;计算(Xi/Yi)2
        RCALL   GET3                           
        RCALL   FPAD         ;(Xi/Yi)2加入累加和∑(Xi/Yi)2
        RCALL   LD3
        RCALL   GET6         ;取1/Yi
        RCALL   SAV0         ;       
        RCALL   FPMU         ;计算1/Yi2
        RCALL   LD6          ;暂存
        RCALL   GET4         
        RCALL   FPAD         ;1/Yi2 加入累加和∑1/Yi2
        RCALL   LD4         
        RCALL   GET6         ;取出1/Yi2
        RCALL   GETA         ;再取Xi 
        RCALL   FPMU          ;计算Xi/Yi2
        RCALL   GET5         
        RCALL   FPAD         ;Xi/Yi2加入累加和∑Xi/Yi2
        RCALL   LD5
        DEC     R0           ;点数减1
        BRNE    LOOP3        ;未到总点数n,循环
        RCALL   GET4
        RCALL   SAV0
        RCALL   GET3       
        RCALL   FPMU         ;计算(∑1/Yi2)*(∑(Xi/Yi)2) 并存入
        RCALL   LD6         
        RCALL   GET5         ;取出∑Xi/Yi2
        RCALL   SAV0         
        RCALL   FPMU         ;计算(∑Xi/Yi2)2
        RCALL   GET6                     
        RCALL   FPSU         ;计算c=(∑1/Yi2)*(∑(Xi/Yi)2-(∑Xi/Yi2)2
        RCALL   LD6          ;存入
        RCALL   GET2
        RCALL   SAV0
        RCALL   GET4       
        RCALL   FPMU         ;计算(∑(Xi/Yi)*(∑1/Yi2)并存入
        RCALL   LD7
        RCALL   GET1
        RCALL   SAV0
        RCALL   GET5         
        RCALL   FPMU         ;计算(∑1/Yi)*(∑(Xi/Yi2) 并存入
        RCALL   GET7         
        RCALL   FPSU         ;计算d=(∑Xi/Yi)*(∑1/Yi2)-(∑1/Yi)*(∑Xi/Yi2))
        RCALL   GET6         ;取c
        RCALL   EXCH
        RCALL   FPDI         ;计算b=d/c并存入
        RCALL   LD7         
        RCALL   GET5         ;取 ∑Xi/Yi2 
        RCALL   FPMU         ;计算(∑Xi/Yi2)*b
        RCALL   GET1         
        RCALL   FPSU         ;计算(∑1/Yi)-(∑Xi/Yi2)*b                           
        RCALL   GET4         ;取 ∑1/Yi2
        RCALL   EXCH         
        RCALL   FPDI         ;计算a=(∑1/Yi-(∑Xi/Yi2)*b)/∑1/Yi2
        RCALL   LD6          ;结果a在$84-$87中,b在$88-$8b中
        RER
GETA:   LD      R12,Y+
        LD      R13,Y+
        LD      R14,Y+
        LD      R15,Y+       ;从外部SRAM中取浮点数到R12-R15
        RET

LD4:    STS     $7C,R12      ;存浮点数
        STS     $7D,R13
        STS     $7E,R14
        STS     $7F,R15
        RET
LD5:    STS     $80,R12      ;计算∑Xi/Yi2的存储单元
        STS     $81,R13
        STS     $82,R14
        STS     $83,R15
        RET
LD6:    STS     $84,R12      ;暂存1/Yi,1/Yi2等浮点数
        STS     $85,R13
        STS     $86,R14
        STS     $87,R15
        RET
LD7:    STS     $88,R12      ;暂存Xi/Yi等浮点数
        STS     $89,R13
        STS     $8A,R14
        STS     $8B,R15
        RET

GET4:   LDS     R8,$7C       ;取浮点数
        LDS     R9,$7D
        LDS     R10,$7E
        LDS     R11,$7F
        RET                  ;         
GET5:   LDS     R8,$80       ;取∑Xi/Yi2或中间结果
        LDS     R9,$81
        LDS     R10,$82
        LDS     R11,$83
        RET
GET6:   LDS     R8,$84       ;取浮点数1/Yi,1/Yi2等
        LDS     R9,$85
        LDS     R10,$86
        LDS     R11,$87
        RET
GET7:   LDS     R8,$88       ;取浮点数Xi/Yi等
        LDS     R9,$89
        LDS     R10,$8A
        LDS     R11,$8B
        RET
       ;范例90
GETAD:  LDI     R17,0Bxxx01110;PC0&PC4输入/PC1-PC3输出&PC3(CAL)
        OUT     DDRC,R17     ;
CBI     PORTC,1
GAD1:   SBI     PORTC,4
        SBIB    PINC,4       ;查DRDY
        RJMP    GAD1         ;低为数据准备好
GAD2:   SBI     PORTC,4
        SBIC    PINC,4       ;PINC:$13/PORTB:$15
        RJMP    GAD2         ;DRDY低有效
        CBI     PORTC,2      ;置片选有效
        LDI     R16,16       ;16位数据
GETL0:  CLC                  ;予清除C
        SBI     PORTC,0
        SBIC    PINC,0       ;接收一位数据
        SEC                 
        ROL     R14          ;数据高位在前
        ROL     R13          ;在R13R14里带进位左移
        SBI     PORTC,1       
        CBI     PORTC,1      ;发出时钟,下降沿读出数据
        DEC     R16
        BRNE    GETL0
        SBI     PORTC,2      ;置片选无效
        MOV     R4,R14       ;
        MOV     R3,R13       ;保存
GADCOM: CLR     R15          ;3字节小数r13r14r15(0)规格化为浮点数
        LDI     R16,$80
        MOV     R12,R16      ;阶码为$80
GAD:    SBRC    R13,7
        RJMP    GETL2
        LSL     R14
        ROL     R13          ;尾数左移,阶码递减
        DEC     R12
        BRNE    GAD
        RET                  ;如果(r12)=0 得到0浮点数
GETL2:  LDI     R16,$7F     
        AND     R13,R16      ;正数
        LDI     R16,$82      ;取浮点数2.5(基准源为2.5v)
        MOV     R8,R16
        LDI     R16,$20
        MOV     R9,R16
        CLR     R10
        CLR     R11         
        RCALL   FPMU          ;相乘
        RET                  ;(r12)不为0
;   以下提供几个补充参考程序,都带有详细说明和指令注释.它们是主从多机通讯程序,采
;用中断方式写入EEPROM,直接对晶振分频产生0.1秒和秒号的精确定时程序,以及RS-232/
;RS-485标准转换程序,AVR频率计程序,串行时锺日历芯片DS1302读写,共享时基的PWM输出、
;输入捕获测周期程序和定时信号获取,以及DS18B20测温等程序.多机通讯主要用8和9位数
;据模式区分被选分机(9位)和其它分机(8位),达到主机只与被选分机交换数据之目的.以中
;断方式写EEPROM的优点是可与系统运行同时进行(即在线写入),占用很少机时.
;精确定时用定时/计数器1(或0)直接对MCU主频(不设分频)设定时间常数,分频精度可达到
;1HZ.RS-232/RS-485标准转换程序中AVR不作中转,使两种器件相关脚位直接连接.以TCNT0
;定时,以T0引脚接收RS-232数据.以收到RS-232字符起始位下跳沿或结束符($03)为依据,
;控制切换RS-485的收发使能.(系统中的主AVR可兼做对通信标准之监控转换,即只是在完成
;主要工作任务的同时'附带'进行).具体过程不再细述.串行时锺日历芯片DS1302具体积小,
;可靠性高,与单片机连接方便等优点.
;   以下程序请参看有关章节或程序中的注释。

       ;范例91               ;多机通讯主机程序/晶振4MHZ
       .ORG    0             ;以8/9位数据模式区分被选/未被选分机通讯
.EQU    DTPINT=$180          ;UBRR=12 波特率19200(REL.ERR.=0.16%)
.EQU    DRPINT=$1C0          ;主机对1#,2#,3#,4#分机发送数据块在$180-18F,$190-19F,$1A0-1AF)和$1B0-1BF
STRT38: RJMP    RST38        ;主机从1#,2#,3#,4#分机接收数据块在$1C0-1CF,$1D0-1DF,$1E0-1EF)和$1F0-1FF
       .ORG     $00B         ;
        RJMP    STRT38       
       .ORG     $00C
        RJMP    STRT38       ;主机不设串口中断,只以查询接收
       .ORG     $011
RST38:  LDI     R16,12
        OUT     UBRR,R16     ;设波特率:[BAUD RATE=FCP/16(UBRR+1)]
        CLR     R15          ;初始化分机号
        LDI     R27,HIGH(DTPINT)
        LDI     R26,LOW(DTPINT);发送数据指针(首指$180)
        LDI     R29,HIGH(DRPINT)
        LDI     R28,LOW(DRPINT);接收数据指针(首指$1C0)
NEXTNO: LDI     R16,$18
        OUT     UCR,R16      ;允许UART接收和发送,8位数据模式
        INC     R15          ;指向1#分机
OUTLP:  OUT     UDR,R15      ;呼分机号,1:1#/2:2#/03:3#/04:4#...
TSLOP:  IN      R16,USR
        SBRS    R16,7
        RJMP    TSLOP        ;分机返回机号?
        IN      R16,UDR
        CP      R16,R15      ;分机号正确返回?
        BRNE    OUTLP
        LDI     R16,$1C      ;改为9位数据模式 TXB8=0
        OUT     UCR,R16      ;
TXLOP:  LD      R16,X+
        OUT     UDR,R16      ;向分机发送数据块
TESTL:  IN      R17,USR
        SBRS    R17,5       
        RJMP    TESTL        ;等待发送完成
        CPI     R16,$0A
        BRNE    TXLOP        ;
RXTST:  IN      R17,USR
        SBRS    R17,7        ;RXC=1 收到数据
        RJMP    RXTST        ;等待接收分机返回数据块
        IN      R16,UDR     
        ST      Y+,R16       ;存储接收数据
        CPI     R16,$0A      ;分机数据块发完?
        BRNE    RXTST
        MOV     R16,R15
        CPI     R16,4        ;与分机轮询通讯完毕?
        BRNE    NEXTNO        ;未完转对下一分机通信
HH38:   RJMP    HH38         ;否则踏步(可改为处理分机返回的数据,之后再进行下一个轮询)
       .DSEG
       .ORG     $180
DTPINT:.BYTE    $40
        ;$41 $45 $65 $73 $46 $42 $40 $6F $33 $44 $66 $5C $4D $4B $0D $0A
        ;$42 $4F $66 $78 $47 $45 $44 $63 $32 $48 $60 $7C $6D $45 $0D $0A
        ;$43 $56 $55 $53 $4D $4F $40 $2E $31 $42 $67 $4C $47 $4A $0D $0A
        ;$45 $54 $59 $63 $3D $4B $48 $2F $35 $48 $69 $3C $77 $43 $0D $0A
       .ORG     $1C0
DRPINT:.BYTE    $40
       ;范例92
       .ORG     0            ;多机通讯1#分机程序/晶振4MHZ
.EQU    DTPIT1=$180          ;(UBRR)=12 波特率为19200(REL.ERR.=0.16%)
.EQU    DRPNT1=$1C0
STRT39: RJMP    RST39
       .ORG     $00B
        RJMP    UARXC        ;8535UART接收完成中断
       .ORG     $00C
        RJMP    UATXC        ;UART发送完成中断
       .ORG     $011
RST39:  CLR     R18          ;清除分机被选中(R18,6)和主机数据块接收完毕标志(R18,7)
        LDI     R16,12
        OUT     UBRR,R16     ;设波特率[BAUD RATE=4000000/16*(12+1)=19200]
        LDI     R16,HIGH(DRPNT1)
        MOV     R8,R16
        LDI     R16,LOW(DRPNT1)
        MOV     R9,R16       ;r8,r9:接收数据指针(FIRST POINT TO $1C0)
        LDI     R16,$98      ;允许UART中断接收,8位数据模式
        OUT     UCR,R16
        SEI
RXDTS:  SBRS    R18,6        ;主机呼号已收到(若收到,在R17中)?
        RJMP    RXDTS
        OUT     UDR,R17      ;返还该机号
TXDON:  IN      R16,USR
        SBRS    R16,5
        RJMP    TXDON        ;该机号发送完成?
        LDI     R16,$9C      ; 允许UART中断接收,9位数据模式,TXB8=0
        OUT     UCR,R16     
RCVBLK: SBRS    R18,7
        RJMP    RCVBLK       ;主机发来数据块已接收完毕?
        LDI     R16,HIGH(DTPIT1)
        MOV     R6,R16
        LDI     R16,LOW(DTPIT1)
        MOV     R7,R16       ;设发送数据指针r6r7,首指$180
        LDI     R16,$3C      ;允许UART中断发送,9位数据模式,TXB8=0
        OUT     UCR,R16
TXDN:   SBIC    UCR,5
        RJMP    TXDN         ;发送完毕?
        RJMP    RST39        ;

       :UART中断接收程序
UARXC:  SBIC    USR,4
        RETI                 ;祯错误(主机正与其它分机进行9位数据模式通信),不予接收
        IN      R14,SREG     ;保存当前状态
        TST     R18
        BREQ    NUMB         ;(R18)=0时收到数据,只可能是机号,转去核实
        PUSH    R16          ;否则为主机向本分机发来数据块(9位模式,机号已符合)
        PUSH    R26
        PUSH    R27
        IN      R17,UDR      ;接收数据
        MOV     XH,R8
        MOV     XL,R9        ;取接收数据指针
        ST      X+,R17       ;转入RAM
        MOV     R8,XH
        MOV     R9,XL        ;存数据指针
        CPI     R17,$0A      ;是数据块结束符LF?
        BRNE    RSCOM1
        SBR     R18,$80      ;收到完整数据块标志
RSCOM1: POP     R27
        POP     R26
        POP     R16
DRETI:  OUT     SREG,R14
        RETI
NUMB:   IN      R17,UDR      ;取出数据
        CPI     R17,1        ;是1#分机?2#分机与$02比较/3#分机与$03比较...
        BRNE    DRETI        ;机号不符合,转!
        SBR     R18,$40      ;建机号符合标志
        RJMP    DRETI
;       UART中断发送程序
UATXC:  PUSH    R16          ;r6 r7:发送数据指针,首指$180
        IN      R16,SREG
        PUSH    R16
        PUSH    R26
        PUSH    R27
        MOV     XH,R6
        MOV     XL,R7        ;取出发送指针
        LD      R16,X+       ;取数据,调指针
        MOV     R6,XH
        MOV     R7,XL
        OUT     UDR,R16      ;送入发送寄存器
        CPI     R16,$0A
        BRNE    SDCOM
        CBI     UCR,5        ;发送最后1个字符后,禁止发送寄存器空中断(CLR UDRIE)
        LDI     R16,HIGH(DRPINT)
        MOV     R8,R16
        LDI     R16,LOW(DRPINT)
        MOV     R9,R16       ;接收数据指针初始化(POINT TO $1C0)
SDCOM:  POP     R27
        POP     R26
        POP     R16
        OUT     SREG,R16
        POP     R16
        RETI
       .DSEG
       .ORG     $180
DTPIT1:.BYTE    $40
       .ORG     $1C0
DRPNT1:.BYTE    $10
       ;$41 $45 $65 $73 $46 $42 $40 $6F $33 $44 $66 $5C $4D $4B $0D $0A
       ;范例93
         ;以中断方式写入EEPROM(仅对8535,8515无此功能),克服查询方式占用过多机时的缺点,
         ;并可在线写入
            ;运作过程特点如下:
    ;(1)主程序初始化时设置EEPROM就绪(ready)中断使能位和中断总使能位
    ;(2)在主程序中写入第一个字节,写入完成后引起就绪中断,其他写入在中断服务中完成
    ;(3)本程序为一写入特例,写入地址为$100--$1FF,可作适当修改(如设块长计数器等)
    ;(4)为防止高优先级中断破坏写入过程,中断服务中不允许中断嵌套
    ;(5)本例为简化程序只以查询写入地址循环作为背景程序,实用时可改为具体的背景序
    ;(6)如能确信当前系统没有EEPROM正在写入,可删除对其进行查询部分.
STWEEP: LDI     R16,HIGH(ramend)
        OUT     SPH,R16
        LDI     R16,LOW(ramend)
        OUT     SPL,R16
        SBI     EECR,3       ;设置EEPROM就绪(ready)中断使能位
        SEI                  ;中断总使能
        RJMP    SRTW
       .ORG     $00F
        RJMP    EEPRDY       ;8535 EEPROM就绪(ready)中断向量
SRTW:   LDI     YH,1
        LDI     YL 0         ;EEPROM 写入首地址:$100
        LDI     XL,$60       ;欲写入数据块首地址:$60
        CLR     XH
WEEP0:  SBIC    EECR,1       ;当前有EEPROM写入操作,有则等待写入完成
        RJMP    WEEP0
        RCALL   WREEP        ;写入第一个字节,($60)->$100,写入完成后,EEWE=0时引发EEPROM就绪中断
        INC     YL           ;调整写入地址指针
HHWEEP: TST     YL
        BRNE    HHWEEP       
        CPI     YH,2         ;写入地址达到$200后,写入完成
        BRNE    HHWEEP       
        CBI     EECR,3       ;禁止EEPROM就绪(ready)中断
WDON:   RJMP    WDON         ;踏步
EEPRDY: IN      R6,SREG
        PUSH    R16
        RCALL   WREEP        ;写入一个字节
        INC     YL
        BRNE    WRETI       
        INC     YH           ;EEPROM末地址为$1FF
WRETI:  POP     R16
        OUT     SREG,R6
        RETI
WREEP:  OUT     EEARH,YH     ;
        OUT     EEARL,YL     ;写入地址送入EEAR
        LD      R16,X+       ;取数据,调指针
        OUT     EEDR,R16     ;数据写入EEPROM数据寄存器
        SBI     EECR,2       ;设置EEPROM写入总使能位EEMWE
        SBI     EECR,1       ;设置EEPROM写入使能位EEWE
        RET
       ;范例94                ;精确定时产生0.1秒信号
       ;用定时/计数器1定时,不分頻定出0.1秒信号,由PC5脚输出正脉冲。
       ;晶体4.000119MHZ,计400012个数定出0.1秒信号
       ;对定时/计数器1重装常数进行加法补偿(扣除自然计数和补偿占用时间).
       ;加法补偿若产生进位,将中断次数减1
       .ORG     $000          ;精确定时产生0.1秒信号
STRT24: RJMP    RST24       
       .ORG     $006         ;8515 t1 overflow vector
        RJMP    T1_OVFL      ;400012=65536*7-58740=7*$10000-$E574/故TCC=$E574
       .ORG     $00D         
RST24:  LDI     R16,HIGH(ramend)
        OUT     SPH,R16
        LDI     R16,LOW(ramend)
        OUT     SPL,R16
        SBI     DDRC,5       ;PC5,0.1秒号输出(高有效)
        CBI     PORTC,5     
        LDI     R16,1        ;不分頻
        OUT     TCCR1B,R16   
        LDI     R16,$E5
        OUT     TCNT1H,R16   
        LDI     R16,$74
        OUT     TCNT1L,R16    ;写入时间常数TCC
        LDI     R16,$80
        OUT     TIMSK,R16    ;允许定时/计数器1溢出中断
        LDI     R16,7        ;7次中断输出0.1秒号
        MOV     R6,R16
        SEI                  ;中断总使能
HH1A:   RJMP    HH1A         ;
T1_OVFL:PUSH    R16
        PUSH    R17
        IN      R7,SREG
        DEC     R6           ;中断次数减一
        BRNE    GOON10       ;0.1秒时间到?
        LDI     R16,7
        MOV     R6,R16       ;重新装入中断次数
        SBI     PORTC,5      ;0.1秒号输出前沿
         IN      R17,TCNT1L   ;*
         IN      R16,TCNT1H   ;*读入TCNT1自然计数值
         LDI     R18,$7C      ;*TCC=$E574
         ADD     R17,R18      ;*TCC+8=$E57C
         LDI     R18,$E5      ;*8条单周期补偿指令占用8个时钟周期
         ADC     R16,R18      ;*修正后TCC=$E574+(TCNT1)+8
         OUT     TCNT1H,R16   ;*
         OUT     TCNT1L,R17   ;*重新装入补偿修正后的TCC
        BRCC    GOON09
        DEC     R6           ;加法补偿若产生进位,将中断次数减1
GOON09: ;.                   ;数据处理略
        ;.
        ;.
        ;.
        ;.
        RCALL   ACLK1         ;0.1秒走时软时钟
        RJMP    GOON11
GOON10: CBI     PORTC,5       ;输出信号后沿
GOON11: POP     R17
        POP     R16
        OUT     SREG,R7
        RETI
       ;范例95               
       ;用定时/计数器1定时,不分頻定出1秒信号,由PC5脚输出正脉冲
       ;晶体4.000133MHZ,计4000133个数定出1秒信号
       ;对定时/计数器1重装常数进行加法补偿(扣除自然计数和补偿占用时间).
       ;加法补偿若产生进位,将中断次数减1
       .ORG     $000          ;精确定时产生秒号
STRT25: RJMP    RST25       
       .ORG     $006
        RJMP    T1_OVFB      ;4000133=62*65536-63099=62*$10000-$F67B/故TCC=$F67B
       .ORG     $00D         
RST25:  LDI     R16,HIGH(ramend)
        OUT     SPH,R16
        LDI     R16,LOW(ramend)
        OUT     SPL,R16
        SBI     DDRC,5       ;PC5输出秒信号(正脉冲)
        CBI     PORTC,5     
        LDI     R16,1        ;不分頻
        OUT     TCCR1B,R16   
        LDI     R16,$F6      ;
        OUT     TCNT1H,R16   ;写入TCC高8位
        LDI     R16,$7B      ;
        OUT     TCNT1L,R16   ;写入TCC低8位
        LDI     R16,$80      ;
        OUT     TIMSK,R16    ;允许T/C1溢出中断
        LDI     R16,62       ;62次中断定出秒号
        MOV     R6,R16
        SEI                  ;
HH1B:   RJMP    HH1B         ;等待中断
T1_OVFB:PUSH    R16
        PUSH    R17
        IN      R7,SREG
        DEC     R6           ;到62次中断?
        BRNE    GOON12       
        LDI     R17,62
        MOV     R6,R17       ;重装中断次数
        SBI     PORTC,5      ;输出秒信号
        IN      R17,TCNT1L   ;*
        IN      R16,TCNT1H   ;*读入T/C1自然计数值
        LDI     R18,$83      ;*TCC=$F67B
        ADD     R17,R18      ;*TCC+8=$F683
        LDI     R18,$F6      ;*8条单周期补偿指令占用8个时钟周期
        ADC     R16,R18      ;*
        OUT     TCNT1H,R16   ;*
        OUT     TCNT1L,R17   ;*重新装入补偿修正后的TCC

        BRCC    GOON19
        DEC     R6           ;加法补偿若产生进位,将中断次数减1
GOON19: ;.                   ;数据处理略
        ;.
        ;.
        ;.
        ;.
        RJMP    GOON13
GOON12: CBI     PORTC,5       ;秒号后沿
GOON13: POP     R17
        POP     R16
        OUT     SREG,R7
        RETI

        ;范例96
        ;AVR频率计程序
;运作特点如下:
;此程序为一完整频率测量显示程序,所测频率较高(2MHZ),使用4兆晶振
;程序兼有启动看门狗及对其管理功能
;以TCNT0精确定时输出秒号作为捕获信号,用TCNT1对被测信号频率计数
;用TCNT0直接对(8515)4兆晶振计数产生秒号,定时精度达1Hz 主常数选为256(即0)
;由PA0输出精确定时产生的秒信号(与ICP脚相连)捕获TCNT1计数值,相减计算频率
;将频率转换为十进制数,装入显示缓存区,调DSPA子程序显示之(参考范例27和图4-5)
;重装TCC时对TCC进行修正,若修正(减法)计算不产生借位,将中断次数n减1
;被测频率可近2兆,故须设1字节扩展计数器,以tcnt1溢出中断对其计数(共3字节计数器)
;在TCNT1捕获中断服务中,以3字节减法计算频率,并置位T标志;若TCNT1溢出标志置位
;必须提前增1扩展计数器,并将TCNT1溢出标志清除(不再增1扩展计数器),再计算频率.
;TCNT1溢出中断优先级高于TCNT0,故TCNT1中断服务可能影响秒号精度,导致测量误差
;可以排队法剔除坏值,即将几个连续采样按大小顺序排队,‘掐头去尾'只留中间再作平均.
;也可以监视LED显示,连续3秒稳定显示(高频测量允许有2Hz误差)即为所测频率正确值.
;若晶振采用12兆,被测信号频率(暂空比1:1或接近1:1)可接近6兆.
       .ORG     $000         
STRT26: RJMP    RST26        ;实测8515晶振频率4.000167MHZ 计4000167个数为1秒
       .ORG     $003
        RJMP    T1_CAPT      ;T/C1捕获中断
       .ORG     $006
        RJMP    T1_OVRF       ;T/C1溢出中断
       .ORG     $007
        RJMP    T0_OVFB      ;T/C0溢出中断
       .ORG     $00D         ;4000167=256*15626-89=256*$3D0A-89/故TCC=89 n=15626
RST26:  LDI     R16,HIGH(ramend)
        OUT     SPH,R16
        LDI     R16,LOW(ramend)
        OUT     SPL,R16
        SBI     DDRA,0       ;PA0输出秒定时信号,捕获频率计数值
        CBI     PORTA,0      ;初始为低
        CLR     R22
        CLR     R21           
        CLR     R20          ;R20,R21,R22为频率量瞬时计数采样
        CLR     R2
        WDR
        LDI     R16,$0D      ;启动看门狗,溢出时间为0.49"
        OUT     WDTCR,R16    ;写入看门狗控制寄存器
        CLR     XH
        LDI     XL,$6C       ;set the display buffer pointer
T26LP:  ST      X+,R2
        CPI     R26,$74
        BRNE    T26LP        ;清除$6C--$73
        LDI     R16,$01      ;T/C0为定时器,不分频
        OUT     TCCR0,R16
        LDI     R16,89       ;
        OUT     TCNT0,R16    ;写TCC到TCNT0
        LDI     R16,$C6      ;上升沿捕获,允许噪音滤除,外部脉冲计数
        OUT     TCCR1B,R16
        LDI     R16,$8A      ;允许T/C1捕获,溢出以及T/C0溢出中断
        OUT     TIMSK,R16    ;
        LDI     R16,$3E      ;设15626(=$3D0A)次中断(高位字节已增1)
        MOV     R1,R16       ;
        MOV     R19,$0A      ;
        SEI                  ;
HH1C:   BRTS    HH2C         ;已采集到频率?
        RCALL   DSPA         ;仍显示原数据
        RJMP    HH1C       
HH2C:   CLT                  ;频率量已在R3,R4,R5
    MOV      R9,R3
        MOV      R10,R4
    MOV      R11,R5    
        RCALL   CONV1        ;翻为十进制数(R12R13R14R15<--R9R10R11)
        LDI     XL,$74
        CLR     XH
        LDI     YL,15
        CLR     YH
HHLOP:  LD      R16,Y        ;分解十进制数,送入LED显示区($6C--$73)
        ADNI    R16,$0F
        ST      -X,R16
        LD      R16,Y
        SWAP    R16
        ANDI    R16,$0F
        ST      -X,R16
        DEC     YL
        CPI     R26,$6C      ;分解完毕?
        BRNE    HHLOP
        RJMP    HH1C         ;显示新数据
T0_OVFB:SEI                  ;TCNT0溢出,允许中断嵌套
        PUSH    R16
        IN      R8,SREG
        DEC     R19
        BRNE    GOON13
        CBI     PORTA,0      ;秒信号后沿
        DEC     R1           ;到15626次中断?
        BRNE    GOON13       
        SBI     PORTA,0      ;秒定时捕获信号前沿
        IN      R16,TCNT0    ;*读TCNT0自然计数值
        SUBI    R16,164      ;*89之补为167,考虑补偿操作本身耗时,减去164
        OUT     TCNT0,R16    ;*第15626次中断后,重新装入TCC=89+(TCNT0)+3到TCNT0
        LDI     R16,$3E
        MOV     R1,R16       ;重新装入中断次数
        LDI     R19,$0A
        BRCC    GOON13       ;补偿操作如有借位,将中断次数减1
        DEC     R19          ;->252 253 254 255 | 0 1 2 3 4 5...加法计数方向-->
GOON13: POP     R16          ;   |   |   |   |  | | | | | | |
        OUT     SREG,R8      ;<--15626次范围-->|<-15625次范围(补偿后进(借)位
;C=l)->
        RETI
T1_OVRF:IN      R18,SREG     ;TCNT1溢出中断服务
        INC     R3           ;R3为TCNT1扩展字节
        OUT     SREG,R18
        RETI
T1_CAPT:IN      R6,SREG      ;T/C1捕获中断
        PUSH    R16
        IN      R5,ICR1L
        IN      R4,ICR1H
        MOV     R16,R22
        MOV     R22,R5
        SUB     R5,R16
        MOV     R16,R21
        MOV     R21,R4       ;与上一次采集的频率量相减,得到频率值
        SBC     R4,R16     
        IN      R16,TIFR
         SBRS    R16,7
         RJMP    T1CP1
         INC     R3           ;8515TCNT1溢出中断,预先对扩展字节计数
         LDI     R16,$80      ;并将溢出标志清除,(中断返回后不再计数)
         OUT     TIFR,R16     ;清除TIFR,7
T1CP1:   MOV     R16,R20
         MOV     R20,R3
         SBC     R3,R16       ;采集频率量在R3,R4,R5
         SET                  ;建采集频率量标志
         POP     R16
         OUT     SREG,R6
         RETI
;范例97      时基资源共享式综合测量系统
;    本时基资源共享式综合测量系统,具有精确定时PWM输出、输入捕获测外部信号
;周期、获取TCNT1溢出中断信号等多种功能。特点是TCNT1启动之后即不停运行。
;    时基资源共享式PWM的特点在于装入比较匹配寄存器之数据方式,它不是在比较
;匹配达到时清除定时/计数器,再装入高(或低)电平时间常数:而是当比较匹配
;达到时以定时/计数器当前值加上时间常数后将和装入比较匹配寄存器,二者效果
;是相同的。可称前者为静态设置,后者为动态设置。后者因不停运行定时/计数器
;,其资源可同时用于输出比较匹配A及B、输入捕获、定时信号输出等等。
;     本程序使用晶体标称值4MHZ实测为4,000,236HZ。使用定时/计数器1直接
;对主频精确定时设定PWM高低电平的维持时间。以ICP脚输入被测周期脉冲信号。
;    本程序PWM之暂空比与范例51相同,为5毫秒(高):10毫秒。故维持
;高电平的时间常数为4,000,236÷200=20,001,维持低电平的时间常数为
;4,000,236÷100=40,002。此即输出比较匹配A达到时交替写入比较匹配寄
;存器OCR1A之对TCNT1当前内容的超前值。
;    因以TCNT1直接对主频计数,频率高周期短,输入捕获的外部信号周期不能
;大于65536÷4,000,236=0.01638(秒)即16.38毫秒(但也不能太小,对频率
;较高的脉冲信号应改为测频率)。以相邻两次捕获值相减之差除以主频得到被测信
;号之周期(单位为秒)。
;    为避免小数除法运算,可将相邻两次捕获值相减之差先乘以1,000,再将乘积
;除以主频,将得到以毫秒为单位的周期值;考虑到除法子程序DIV16只实现整数
;除法,且除数不能大于65535,可将主频缩小100倍,即以40,002作除数,故
;除得之商扩大了100倍。这样将整数商二翻十后,其末两位皆为小数。本程序采用
;这种计算方法。并在主循环程序中调DSPA子程序显示所测周期值。。
;    若将以上算法中乘以1,000改为乘以10,000,并增加对商的万位转换,
;其余保留不变,则所得商数末3位皆为小数位。本算法精度高于上一种方法,如有
;提高测量精度之必要,应采用后种算法。
;    若扩大测量信号周期,应对TCNT1溢出信号计数,做3字节减法(见范例96)
;后再计算被测信号周期(除以4,000,236)。所测信号周期可达4.194秒。
;    本示例定时精度可与范例51做如下比较:本例中高低电平分别对主频计数
;20,001个和40,002个。范例51中高低电平分别对主频计数19,968个和
;40,000个。本示例定时精度明显高于范例51。
;    本示例TCNT1产生溢出中断之周期为16.38毫秒,其频率约为61HZ。在TCNT1
;溢出中断服务子程序中由PA3以正脉冲形式输出该信号。
        .ORG     $000       ;USE 8535
STRT43: RJMP    RST43       ;5.0000MS(高):9.9999MS(低) 晶振4,OOO,236HZ
    .ORG        $005
    RJMP        T1_CP43     ;T/C1输入捕获中断
       .ORG     $006
        RJMP    T1_CA43     ;T/C1输出比较匹配A中断
       .ORG        $008
    RJMP        T1_OV43     ;TCNT1溢出中断
       .ORG     $011
RST43:  LDI     R16,HIGH(RAMEND)
        OUT     SPH,R16
        LDI     R16,LOW(RAMEND)
        OUT     SPL,R16
        LDI     R16,$80      ;T/C1比较匹配A达到时,清除输出脚OC1A
        OUT     TCCR1A,R16
        LDI     R16,$41      ;不分频,比较匹配达到不清TCNT1;上升沿捕获/禁止噪音滤除
        OUT     TCCR1B,R16
        SBI     DDRD,5
        SBI     PORTD,5      ;PD5(OC1A)初始化输出为高
        SBI     DDRA,3      ;PA3为TCNT1溢出中断信号输出
        CBI     PORTA,3     ;PA3输出为低
        LDI     R16,$4E
        OUT     OCR1AH,R16
        LDI     R16,$21      ;写比较匹配寄存器($4E21=20001脉宽5毫秒)
        OUT     OCR1AL,R16
        LDI     R16,$34      ;允许输入捕获/输出比较匹配A/TCNT1溢出中断
        OUT     TIMSK,R16   
        CLR      R21
     CLR       R20          ;捕获值暂存单元
     CLR       XH   
     LDI       XL,$6C
CLR43: ST       X+,R20
     CPI       XL,$74
     BRNE       CLR43        ;清除显示区$6C--$73
        SEI
HH43:   RCALL       DSPA         ;背景程序:显示捕获频率信号之周期,单位:毫秒
     BRTC     HH43
        RCALL    FIL2         ;T=1,已捕获到数据在R4,R5/先关显示         
        CLT
        MOV        R14,R4
        MOV        R15,R5
        LDI        R16,3
        MOV        R12,R16
        LDI        R16,$E8      ;取立即数1000(=$3E8)
        MOV        R13,R16
        RCALL        MUL16        ;乘以1000
        LDI        R16,$9C      ;使周期单位为毫秒
        MOV        R10,R16
        LDI        R16,$42      ;$9C42=40002
        MOV        R11,R16
        RCALL        DIV16        ;除以立即数40002,得到被测脉冲周期之单位为毫秒,且含因子100
        MOV        R16,R14
        MOV      R17,R15
        LDI        R18,3
        LDI      R19,$E8
        RCALL        CONVT         ;二翻十,得千位
        STS        $70,R11       ;送入显示区
        CLR        R18
        LDI        R19,$64
        RCALL        CONVT         ;二翻十,得百位
        LDI        R19,-$29      ;在百位处加小数点(百位实为个位)
       SUB        R11,R19
       STS        $71,R11       ;送入显示区
       LDI      R19,10
       RCALL        CONVT         ;二翻十,得十位
       STS        $72,R11
       STS        $73,R17       ;小数送入显示区
       RJMP        HH43          ;转去显示新采样数据
CONVT: CLR       R11
COVLOP:SUB       R17,R19
       SBC       R16,R18       ;减去十进制数某位之权
       BRCS       CONVCM
       INC       R11           ;够减,增权
       RJMP       COVLOP
CONVCM:ADD       R17,R19       ;否则恢复余数
    ADC       R16,R18
    RET
T1_CA43:SEI
        IN      R1,SREG
        IN      R24,TCCR1A
        SBRS    R24,6       
        RJMP    OUTLW         ;当前输出低电平,转
        IN      R24,OCR1AL
        IN      R25,OCR1AH
            SUBI      R24,$DF           ;LOW(-20001)
     SBCI    R25,$B1     ;HIGH(-20001)/$B1DF为20,001之补码
        OUT     OCR1AH,R25   
        OUT     OCR1AL,R24   ;写入高电平维持时间超前值
        LDI     R24,$80      ;比较匹配A达到时,OC1A输出为低
        OUT     TCCR1A,R24
        OUT     SREG,R1
        RETI
OUTLW:  IN      R24,OCR1AL
        IN      R25,OCR1AH
     SUBI      R24,$BE          ;LOW(-40002)
     SBCI      R25,$63     ;HIGH(-40002)/$63BE为40,002之补码
        OUT     OCR1AH,R25   ;
        OUT     OCR1AL,R24   ;写入低电平维持时间超前值   
        LDI     R24,$C0      ;比较匹配A达到时,OC1A输出为高
        OUT     TCCR1A,R24
        OUT     SREG,R1
        RETI
T1_CP43:IN      R3,SREG      ;T/C1捕获中断
        IN      R5,ICR1L
        IN      R4,ICR1H
        MOV     R17,R21
        MOV     R21,R5
        SUB     R5,R17
        MOV     R17,R20
        MOV     R20,R4        ;与上一次采集的频率量相减,得到频率值
        SBC     R4,R17        ;在R4,R5中
        SET                   ;建采集频率量标
        OUT     SREG,R3
     RETI
T1_OV43:SEI
        SBI       PORTA,3      ;OUTPUT THE 61HZ PULS
     SBI       PORTA,3
     SBI       PORTA,3
     SBI       PORTA,3
     CBI       PORTA,3      ;脉冲宽度2微秒
     RETI
       ;范例98
     ;智能型RS-232与RS-485标准转换程序
;MAX232'R1OUT接MAX483'DI/MAX483'RO接MAX232'T1IN
;由TCNT0配合PB0以软件接收RS-232数据 对485进行监控:PB1接DE和/RE
;AVR对485发来数据不接收,该数据经MAX483'RO->MAX232'T1IN-->RS-232远端
;数据起始位下降沿引起中断接收,中断服务一开始,将对RS-485的控制改为允发禁收使RS-
;232发来数据直接通过RS-485向远端发送
;当收到RS-232数据结束符$03后,经半位延时,对RS-485的控制改为允收禁发 使能接收RS-
;485远端发来数据(故要求经RS-232发来数据要以$03为结束符,对来自RS-485数据无此要求)
;可采用avr专门管理两种标准转换方案(可采用少脚ATtiny系列),也可采取主avr兼管方案.
;主avr兼管时,它既接收处理完整串行数据块(及执行其它程序),又控制通讯标准转换.
.EQU    DATA4=$100           
       .ORG     0            ;R16:THE BIT SEQUENCE COUNTER R17:WORKING
                              ;REG.R18:FLAG UNIT
STRT3S: RJMP    RST3S        ;BAUD RATE:9600 USE 8515/may REPLACE BY ATtiny serials
       .ORG     $007         ;$007(8515)
        RJMP    T0_OF
       .ORG     $00D
RST3S:  LDI     R17,HIGH(ramend)
        OUT     SPH,R17
        LDI     R17,LOW(ramend)
        OUT     SPL,R17
        LDI     R17,$02      ;8535:$01
        OUT     TIMSK,R17    ;timsk,1(允许tcnt0中断)
        LDI     R17,6        ;设外部脉冲计数
        OUT     TCCR0,R17
        CBI     DDRB,0       ;T0 为输入
        LDI     R17,$FF
        OUT     TCNT0,R17    ;计1个数即中断
        SBI     DDRB,1       ;PB1输出,控制DE和/RE
        CBI     PORTB,1      ;禁止485发送
        SEI                 
        CLR     R18
        CLR     R16
HERE0:  SBRC    R18,0
        BRNE    RST3S        ;无错误标志循环
        SBRS    R18,1
        BRNE    HERE0        ;未收到数据块结束符($03)循环
        LDI     R16,64       
HERE1:  DEC     R16
        BRNE    HERE1        ;延时(48+3.5=)52微秒(超过半位,以等待半个停止位发过去)
        RJMP    RST3S        ;以使远端485正确收到停止位                           

T0_OF:  SBI     PORTB,1      ;允许485发送
        IN      R11,SREG     
        PUSH    R17
        CPI     R16,0        ;接收起始位?
        BRNE    T0SV11
        LDI     R17,2        ;YES
        OUT     TCCR0,R17    ;改为内定时,8分频(4MHZ/8)
        LDI     R17,232      ;半位定时常数24,定出48微秒(<52微秒)
        OUT     TCNT0,R17
        RJMP    T0SV7
T0SV11: CPI     R16,1        ;半位定时后,查起始位有效性
        BRNE    T0SV12
        SBI     PORTB,0     
        SBIC    PINB,0       ;低电平为有效
        RJMP    T0ER          ;否则转错误处理
        RJMP    T0SV62       ;
T0SV12: CPI     R16,10       ;停止位?
        BRNE    T0SV3S
        CLR     R16           ;是
        SBI     PORTB,0      ;停止位为l?
        SBIS    PINB,0
        RJMP    T0ER          ;否,转错误处理

        MOV     R17,R15
        CPI     R17,3        ;收到结束符$03?
        BRNE    T0SV13
        ORI     R18,2        ;结束符收到
        OUT     TCCR0,R16    ;停止TCNT0
        RJMP    T0SV63
T0SV13: LDI     R17,6
        OUT     TCCR0,R17    ;改为外定时
        LDI     R17,$FF      ;停止位下降沿即中断
        OUT     TCNT0,R17
        RJMP    T0SV63
T0SV3S:  BRCC    T0ER        ;出错(位计数器超过10)
        CLC                  ;2--9:接收一位数据
        SBI     PORTB,0      ;本位为1?
        SBIC    PINB,0
        SEC
        ROR     R15          ;接收数据组织到R15
T0SV62: IN      R17,TCNT0    ;读入TCNT0自然计数值
        INC     R17         
        SUBI    R17,52       ;1位时间常数为52
        OUT     TCNT0,R17    ;补偿后回送定时常数
T0SV7:  INC     R16          ;位计数器增1
T0SV63: POP     R17
        OUT     SREG,R11
        RETI
T0ER:   SBR     R18,1        ;出错标志 ERR. FLAG
        CLR     R16
        OUT     TCCR0,R16    ;停止TCNT0
        RJMP    T0SV63
       ;范例99
  ; 串行日历/时钟芯片DS1302的应用子程序。AVR与DS1302接口为:PC0--SCLK,PC1--DATA,PC2--/RST。请参看本范例之附图。
  ; 结构与运作特点如下:
  ;(1)采用标准频率晶体(32768HZ),便于调整(可加电容补偿),可对PC0/PC1/PC2加提拉电阻。
  ;(2)DS1302只有8只脚,小巧精悍,耗电省,抗干扰.便于与单片机接口,以串行方式按位读写数据.
  ;(3)以备用电池供电保存数据,断电后自动执行写保护,故可靠性高。上电后须用指令解除写保护。
  ;(4)片内除8个时钟日历单元外还有31个RAM单元,可作为系统断电保护数据存储单元
  ;(5)可以并发(BURST,即连续)方式读写8个时钟日历单元(秒/分/时/日/月/周/年/年)或读写31个RAM单元,
  ;   命令如下:
  ;  $BE为以并发方式写8个时钟日历单元,$BF为以并发方式读8个时钟日历单元。
  ;  $FE为以并发方式写31个RAM单元,$FF为以并发方式读31个RAM单元。
  ;(6)除以并发方式读写外,还可按字节读写,但读写前须先写入命令。
  ;  读写命令格式为:1 Y A4 A3 A2 A1 A0 X,最高位为1表示命令有效,Y=0,选择读写时间/日期
  ;  Y=1,选择读写片内RAM,A4-A0,片内RAM/时钟单元地址,X=0,选择写操作,X=1,选择读
;操作.
  ;(7)串行时钟上升沿写入一位数据,下降沿读出一位数据;且读写只有在/RST信号为高时才有效。
  ;  故要求/RST信号有效前时钟信号应已就绪。
  ;(8)本程序AVR时钟为4MHZ,若使用其他时钟,重新调整读写延时时间(程序中NOP之个数)
  ;(9)对RAM并发读写方法可参考并发读写时钟日历子程序进行.
 
;1)并发(BURST)方式写时钟日历单元(时钟日历数据 秒,分,时,日,月,周,年,年分别在R8--R15,)
WBURST: CLR     YH           ;
        LDI     YL,8         ;数据指针,首指秒单元R8
        RCALL   DEPRV        ;解除写保护(写入$8E00)
        CBI     PORTC,0      ;为上升沿写作准备(SCLK升高)
        NOP
        NOP
        NOP
        SBI     PORTC,2      ;复位信号变高(SETB RST)
        NOP
        NOP
        NOP
        NOP
        NOP
        NOP
        LDI     R18,$BE      ;BURST(wr.) ADDR.&INSTRUC.(命令$BE)
        RCALL   WBYTE        ;
WLOP:   LD      R18,Y+
        RCALL   WBYTE        ;写入1字节数据
        CPI     YL,16
        BRNE    WLOP         ;数据都写完?
        CBI     PORTC,2      ;禁止读写
        NOP
        NOP
        NOP
        NOP
        CBI     PORTC,0
        RET
;2)并发(BURST)方式读时钟日历单元(时钟日历数据 秒,分,时,日,月,周,年,
;分别读到R8--R14中)
RBURST: CLR     YH           ;首指R8
        LDI     YL,8         
        SBI     DDRC,0       ;SCLK         输出
        SBI     DDRC,2       ;WR/RD ENABLE 输出
        SBI     PORTC,0      ;时钟SCLK初始输出为低 
        NOP
        NOP
        NOP
        SBI     PORTC,2      ;复位有效,允许时钟相关沿有效
        NOP
        NOP
        NOP
        NOP
        NOP
        NOP
        LDI     R18,$BF      ;BURST(rd.) ADDR.&INSTRUC.
        RCALL   WBYTE        ;写入并发读命令
RLOP:   RCALL   RBYTE        ;读出一字节时钟/日历数据
        ST      Y+,R18        ;存储
        CPI     R28,15
        BRNE    RLOP         ;数据都读完?
        CBI     PORTC,2      ;禁止读写
        NOP
        NOP
        NOP
        NOP
        CBI     PORTC,0      ;使SCLK变低
        RET
;3)解除写保护子程序(对DS1302写入$8E,$00)
DEPRV:   SBI     DDRC,0      ;SCLK         输出
         SBI     DDRC,2      ;WR/RD ENABLE 输出
        CBI     PORTC,0      ;时钟SCLK初始输出为低
        NOP
        NOP
        NOP
        SBI     PORTC,2      ;复位有效,允许时钟相关沿有效
        NOP
        NOP
        NOP
        NOP
        NOP
        NOP
        LDI     R18,$8E
        RCALL   WBYTE
     NOP
     NOP
        CLR     R18
        RCALL   WBYTE        ;写入$8E和$00
        CBI     PORTC,2      ;禁止读写
        NOP
        NOP
        NOP
        NOP
        CBI     PORTC,0     
        RET
;4)对DS1302秒,分,时单元写入3字节数据
WTIME:  CLR     YH           ;
        LDI     R17,$80      ;写秒单元命令
        LDI     YL,8         ;R8(秒)R9(分)R10(时)
        LDI     R19,3
WCOM:   RCALL   DEPRV        ;解除写保护
WLOP1:  CBI     PORTC,0      ;时钟SCLK初始输出为低
        NOP
        NOP
        NOP
        SBI     PORTC,2      ;复位有效,允许时钟相关沿有效
        NOP
        NOP
        NOP
        NOP
        NOP
        NOP
        MOV     R18,R17
        RCALL   WBYTE        ;写入一字节命令
        SUBI    R17,$FE      ;指向时间下一单元
        LD      R18,Y+
        RCALL   WBYTE        ;写入时间单元1字节
        CBI     PORTC,2      ;禁止读写
        NOP
        NOP
        NOP
        NOP
        CBI     PORTC,0
        DEC     R19
        BRNE    WLOP1        ;写完规定字节?
        RET
;5)写入日期子程序
WDATE:  CLR     YH           ;
        LDI     YL,11        ;R11(日)R12(月)R13(周)R14(年)
        LDI     R17,$86      ;写日单元命令
        LDI     R19,4
        RJMP    WCOM
;6)读出时间子程序
RTIME:  CLR     YH           ;
        LDI     R17,$81      ;读秒单元命令
        LDI     YL,8         ;读出数据送到R8(秒)R9(分)R10(时)
        LDI     R19,3
RCOM:   SBI     DDRC,0       ;SCLK         输出
        SBI     DDRC,2       ;WR/RD ENABLE 输出
RLOP1:  CBI     PORTC,0      ;时钟SCLK初始输出为低
        NOP
        NOP
        NOP
        SBI     PORTC,2      ;允许读写
        NOP
        NOP
        NOP
        NOP
        NOP
        NOP
        MOV     R18,R17
        RCALL   WBYTE        ;写入读命令
        SUBI    R17,$FE      ;指向下一单元地址
        RCALL   RBYTE        ;读出一字节数据
        ST      Y+,R18
        CBI     PORTC,2      ;禁止读写
        NOP
        NOP
        NOP
        NOP
        CBI     PORTC,0      ;时钟变低
        DEC     R19
        BRNE    RLOP1        ;已读出规定字节?
        RET
;7)读出日期子程序
RDATE:  CLR     YH           
        LDI     YL,11        ;读出数据放入R11(日)R12(月)R13(周)R14(年)
        LDI     R17,$87      ;读出日单元命令
        LDI     R19,4
        RJMP    RCOM
;8)将R18中数据写入DS1302
WBYTE:  LDI     R16,8        ;8位/字节
        SBI     DDRC,1       ;PC1为输出
WB1:    CBI     PORTC,0      ;时钟SCLK初始输出为低
        ROR     R18          ;一位数据传到进位C
        BRCC    WB10
        SBI     PORTC,1
        RJMP    WB2
WB10:   CBI     PORTC,1      ;1位数据输出到数据线(DS1302'DATA BUS)
WB2:    NOP
        NOP
        NOP
        NOP
        SBI     PORTC,0      ;上升沿写入一位
        DEC     R16
        BRNE    WB1          ;8位数据都写完?
        RET
;9)读出DS1302一字节数据在r18中
RBYTE:  LDI     R16,8        ;8位/字节
        CBI     DDRC,1       ;PC1输入
RD1:    CBI     PORTC,0      ;下降沿读出一位数据
        NOP
        NOP
        NOP
        NOP
        SBI     PORTC,1      ;上拉电阻激活
        CLC
        SBIC    PINC,1
        SEC                  ;读出一位数据并-->C
        ROR     R18          ;组织数据
        SBI     PORTC,0      ;SCLK升高,为下位读准备
        DEC     R16
        BRNE    RD1          ;8位数据都写完?
        RET
        ;范例100       ;DALLAS 18B20测温程序
;         DS18B20为美国DALLAS公司(已被MAXIM公司并购)生产的单线数字温度传感器,
;可将温度信号直接转换成数字信号供单片机处理,所测温度范围-55°C~125°C,精度
;达0.5°C,转换时间为750毫秒。该器件出厂时带有固化的8字节‘身份’编号,最低
;位字节为家族号码$28,接下来6字节为器件流水线编号,最高位字节为CRC校验码。
;有读ROM,匹配ROM,启动温度变换,读RAM数据等十余种命令对18B20操作。使用
;18B20之前要用读ROM命令读出其身份编号并记录。一条单总线上可挂接任意多个
;18B20,单片机通过单总线发出启动转换命令之后,所有18B20同时进行温度转换。
;经等待延时后,单片机通过发出匹配ROM命令,18B20编号,读RAM数据等命令等,
;读取各18B20温度数据组(每组数据共9字节)。程序中对每组数据都进行CRC校验。
;温度数据占2字节,为补码形式。最高位为符号位,0为正1为负。高位字节和低位
;字节的高4位为温度整数部分,最低4位为温度小数部分。程序中对温度数据进行取
;补、左移将整数部和小数部分分离,再将它们分别转成十进制数。整数二翻十用减
;十进一法,小数二翻十采用按权累加法(并以减负替代加正),再将它们冠以数符
;并加小数点送入DSPA子程序的显示缓存区,调该子程序进行显示。
;   由于DSPA子程序中含0.462秒定时复位看门狗指令,故以调用DSPA为主循环程序
;不必考虑对看门狗管理问题(初始化设置看门狗溢出周期为0.49秒)。
;   DS18B20不象一般串行器件既有数据线又有时钟线,它只有一条数据线,故它
;只能靠较严格的时序脉冲信号进行读写,程序中多种延时环节就是为调整时序所
;设。本程序AVR使用4MHZ时钟,如改变时钟,应按定时时间重新确定延时常数。
;  18B20的使用可采用窃电方式,此种方式要将18B20电源端接地。在线缆长测点
;的应用场合,可控制MOS管取得数据线的强上拉,以提高总线驱动能力。
;对18B20的ROM操作命令如下:
;       命令                     代码
;      读ROM                     $33
;     匹配ROM                    $55
;      跳过ROM                   $CC
;      搜索ROM                   $F0
;      告警搜索                  $EC
; 对18B20的存储器操作命令如下:
;       命令                    代码
;    写暂时存储器                $4E
;    读暂时存储器                $BE
;    复制暂时存储器              $48
;     启动温度变换               $44
;   EEPROM内容调出               $B8
;       读电源                     $B4                   
;  有关18B20初始化,读写命令,读写时序等请参看参考文献9和10,18B20与AVR接口
;见程序附图,CRC检测请参看4.8.4小节。
START2:LDI    R16,2         
       OUT    SPH,R16       
       LDI    R16,$5FH     
    OUT    SPL,R16        ;堆栈指针初始化
    SBI    DDRA,2
    CBI    PORTA,2       ;MOS管不上拉   
       RCALL    RESET         ;复位18B20     
       WDR
      LDI    R16,$0D
      OUT    WDTCR,R16     ;启动看门狗,溢出时间为0.49秒
      CLR    R2           ;执行请除看门狗指令WDR的定时器初始化请除   
      LDI    R16,$CC       ;跳越ROM(SKIP ROM)
      RCALL    WB                   
      LDI    R16,$44       ;START DS18B20 TEMPORATURE CONVERTING
      RCALL    WB           
      CLR    XH                     
      CLR    YH            ;指针高位字节清除
      LDI    YL,$6C
CLR44:ST    Y+,YH
      CPI    YL,$74
      BRNE    CLR44         ;清除显示缓存区($6C~$74)           
      LDI    R17,163       ;4.618×163=753(ms)
STR0: RCALL  DSPA               
      DEC    R17
      BRNE    STR0          ;总共延时753ms,等待转换完成
      RCALL    RESET         ;再次复位DS18B20
      LDI    XL,$60        ;温度数据指针     
      LDI    R17,4         ;总共4只DS18B20 
      LDI     ZH,HIGH(DATA*2)               
      LDI    ZL,LOW(DATA*2);18B20身份数据指针
LOOP0:LDI    R16,$55       ;匹配ROM命令  (match rom)
      RCALL    WB            ;写入18B20
      LDI    R18,8         ;18B20身份数据共8个字节固化在FLASH中
LOOP4:LPM                    ;取数据           
      MOV    R16,R0        ;转入R16         
      RCALL    WB            ;写入18B20 1字节 
      ADIW    ZL,1          ;指向下一字节     
      DEC    R18                             
      BRNE    LOOP4         ;共写入8个字节
      LDI    R16,$BE       ;读18B20数据存储器命令
      RCALL    WB            ;写入该命令               
      LDI    YL,$74
LOP40:RCALL    RB            ;读出18B20数据共9个字节 
      ST      Y+,R16           ;存入$74-$7C
      CPI    YL,$7D                         
      BRNE    LOP40                           
      RCALL    RESET         ;再次复位18B20   
      LDI    YL,$74
      RCALL    CRC9          ;对读得数据进行CRC校验
      TST    R15
      BREQ    LLL
ERROR:LDI    R16,15        ;CRC余式不为零,温度数据错误
      LDI    YL,$6C
EER1: ST     Y+,R16       
      CPI    YL,$74
      BRNE    EER1
ERR1: RCALL    DSPA          ;显示$FFFFFFFF,等待按键
      SBRC    R16,7
      RJMP    ERR1
      RJMP    START2        ;有键按下,重新启动
LLL:  LDS    R16,$74       
      LDS    R15,$75        ;取温度数据 R15为HIGH BYTE
      ST     X+,R16
      ST      X+,R15        ;温度转入SRAM
      BST    R15,7          ;数符存于T                   
      BRTC      PLUS           ;正数转               
      COM    R16                             
      COM    R15                             
      LDI    R18,255                             
      SUBI    R16,R18                             
      SBCI   R15,R18        ;负数求补           
PLUS: LDI    R18,4                               
LOOP5:ADD    R16,R16                             
      ADC    R15,R15                             
      DEC    R18                                 
      BRNE    LOOP5          ;整数部分在R15       
      MOV    R19,R16        ;小数部分转入R19       
      CLR    R9             ;百位BCD予清         
      LDI    R16,100
      CP     R15,R16
      BRCS    LOP51
      INC    R9             ;百位BCD存在(EXISTED)!
      SUB    R15,R16        ;减去100
LOP51:LDI    R16,10                               
      CLR    R10                                 
LOP52:SUB     R15,R16                           
      BRCS    LOP53                               
      INC    R10
      RJMP   LOP52           ;十位及个位BCD转换
LOP53:ADD      R15,R16       ;十位在R10,个位在R15
      CLR    R16                                 
      SBRC    R19,7                               
      SUBI    R16,-$50       ;小数最高位值为0.5   
      SBRC    R19,6          ;其余折半递减           
      SUBI    R16,-$25       ;0.25                       
      SBRC    R19,5                               
      SUBI    R16,-$13       ;0.125                     
      SBRC    R19,4                               
      SUBI    R16,-6         ;0.0625                     
      CPI    R16,$0A        ;产生非法BCD?(只可能在低位产生)                   
      BRHC   LOP54                              
      SUBI    R16,$FA        ;小数部分二翻十/调整(在R16中)
LOP54:MOV    R11,R16
      LDI    YL,$6C
      LDI    R16,$24
      ST    Y+,R16       
      ST    Y+,R16
      ST    Y,R16
      RTC    LOP55
      LDI    R16,$14         ;负温度,加负号!
      ST    Y,R16
LOP55:INC    YL
      ST    Y+,R9            ;百位BCD装入 $6F 单元
      ST    Y+,R10           ;十位BCD直接装入$70单元
      MOV    R16,R15
      SUBI    R16,-$29         ;个位BCD加小数点后
      ST    Y+,R16           ;装入$71单元
      MOV    R16,R11
      SWAP    R16
      ANDI    R16,$0F
      ST    Y+,R16
      MOV    R16,R11
      ANDI  R16,$0F
      ST    Y+,R16            ;分解小数BCD/并装入$72及$73单元
      CLR    R8
NORML:RCALL    DSPA              ;显示温度数据2.4秒
      RCALL  DSPA                ;4.62ms×2×256=2.4s
      DEC    R8
      BRNE    NORML
      DEC    R17
      BREQ    HALT              ;采集完4点温度?     
      RJMP    LOOP0             ;未完循环           
HALT: LDI    R16,$1D
      OUT    WDTCR,R16
      LDI    R16,$15
      OUT    WDTCR,R16         ;已采集到4点温度,关看门狗
RDSPA:RCALL    DSPA
      SBRC    R16,7
      RJMP    RDSPA             ;无键按下,显示最后采集的温度
      RJMP    START2            ;否则再次启动   
DATA:    .DB  $28,$3A,$13,$08,$00,$00,$00,$E5 ;18B20身份数据
       .DB  $28,$4A,$4D,$08,$00,$00,$00,$14
       .DB  $28,$3A,$19,$08,$00,$00,$00,$5E
       .DB  $28,$32,$33,$08,$00,$00,$00,$66

RESET: SBI     DDRA,3           ;PA3为输出
       CBI     PORTA,3          ;负脉冲前沿     
       LDI     R19,4                             
RES1:  RCALL   DL170             
       DEC     R19                               
    BRNE     RES1             ;延时682.75微秒 (最短可555微秒)
       SBI     PORTA,3          ;负脉冲结束     
       LDI     R18,146                           
RES2:    DEC     R18
       BRNE     RES2             ;延时110微秒     
       RCALL   DL170            ;总共280微秒                                           
       CBI     DDRA3            ;转为输入(CHANGE TO INPUT)
      SBI     PORTA,3          ;上拉电阻激活(PULL UP MOS ACTIVED)
      CLC   
      SBIC    PINA,3            ;18B20存在标志存于 C
      SEC
      RCALL    DL170              ;再次延时
    RET
DL170:    LDI    R18 ,224          ;延时170.75微秒(含RCALL和RET时间)
LP170:    DEC    R18
    BRNE    LP170
    RET   
WB:    LDI     R19,8            ;写入1字节数据
    MOV     R15,R19
    SBI    DDRA,3
LOOP2: CBI    PORTA,3            ;数据线输出为低   
       LDI    R19,23                           
LOP21: DEC    R19                               
    BRNE    LOP21             ;延时17微秒
       ROR    R16                           
       BRCC    LOP22             ;1位数据由进位C转入PC3
       SBI    PORTA,3                           
       RJNP    LOP23                             
LOP22: CBI    PORTA,3                           
LOP23: LDI    R19,88                             
LOP24:    DEC    R19   
       BRNE    LOP24             ;延时66微秒     
    SBI    PORTA,3
    NOP
    NOP
    NOP
       NOP
    NOP
    NOP
    NOP
    NOP
    DEC    R15
    BRNE   LOOP2
       RET
RB:    LDI    R19,8            ;读出1字节数据   
    MOV    R15,R19
LOOP3: SBI    DDRA,3
       SBI    PORTA,3          ;数据线输出为高   
       LDI    R19,5                             
LOP31: DEC    R19                                
    BRNE    LOP31            ;延时3.5微秒     
    CBI    PORTA,3         ;数据线输出为低   
       LDI    R19,6                           
LOP3A:DEC    R19                               
       BRNE    LOP3A            ;延时4.5微秒   
       SBI    PORTA,3          ;数据线输出为高 
       LDI    R19,26                             
LOP32: DEC    R19
    BRNE    LOP32            ;延时19微秒       
       CBI    DDRA,3           ;转为输入         
    SBI    PORTA,3          ;上拉MOS管激活
       CLC                           
    SBIC    PINA,3
    SEC                     ;读出1位数据到C
       LDI    R19,88                           
LOP33:DEC    R19                             
    BRNE    LOP33               ;延时66微秒         
       ROR    R16                               
       DEC    R15                               
    BRNE    LOOP3                             
       RET                 
CRC9:  LDI    R18,9             ;9字节数据CRC检测程序
CRC90: CLR    R15               ;异或工作单元
       LDI    R19,$8C           
    MOV    R14,R19   
LP6:   LDI    R19,8       
       LD    R16,Y+   
LP7:   LSR    R16         
    ROR    R15   
       BRCC    NXRL   
    EOR    R15,R14       
NXRL:  DEC    R19
    BRNE    LP7
    DEC    R18
    BRNE    LP6
    RET
    ;范例101        产生循环冗余检测(CRC)校验码表格子程序
    ;本子程序为生成$00--$FF共256个数据之双字节CRC校验码表子程序,生成多项式为
    ;P(X)=X16+X15+X2+1=$18005。因每一字节都生成两字节的CRC校验码,故CRC校
       ;验码表格长度为512字节。程序中规定将其放在片内SRAM$100--$2FF之中。也可将该
    ;表存放地址作为子程序的入口条件,在主程序中规定存放地址。使用的单片机为MEGA8
    ;/16/128;若使用8515单片机,须使用外部扩展SRAM;本子程序产生的CRC校验码表,
    ;可直接烧录到FLASH,或另行作为文件保存。
       ;若采用4字节的CRC校验码,表格长度达1024字节,则必须使用MEGA103/128等高档AVR
       ;单片机,或外扩SRAM的8515;故若处理的位序列信息不是很长,或对CRC检测的实时性
       ;要求不是很强,不必采用查表处理方式。
CRCTABL:LDI     XH,$01          ;CRC-CODE-TABLE -GENERATING SUBPROGRAM
       CLR     XL              ;CRCTABLE FROM $100 TO $2FF
       CLR     R16             ;USE MEGA8/16/128
    LDI     R17,$05
    LDI     R18,$80       ;P(X)=$18005
CRCT0: LDI     R19,8   
    CLR     R14
    CLR     R15             ;add  2bytes $00 behind a Bi
CRCT1: LSL     R14
    ROL     R15
    ROL     R16
    BRCC     CRCT2
    EOR     R14,R17
    EOR     R15,R18
CRCT2: DEC     R19
    BRNE     CRCT1
    ST     X+,R14
    ST     X+,R15
    INC     R16
    BRNE   CRCT0
    RET
    ;范例102     快速生成位序列校验码/或对接收位序列进行循环冗余检测子程序
    ;100字节位序列m0,m1,m2,m3,m4,...m98,m99在发送方以递推方式生成CRC校验码子程序
    ;或在接收方对该序列进行CRC检测之子程序
    ;在发送方,本程序为CRC校验码生成子程序。将此位序列除以生成多项式P(X)
    ;=X16+X15+X2+1,将生成的CRC校验码(即余式)装入位序列的最低两位字节
       ;(冲掉m0,m1),将最终处理的位序列发送出去。
    ;在接收方,本程序为CRC检测子程序。将接收到的位序列除以生成多项式P(X)
    ;=X16+X15+X2+1,若将原位序列最低两位字节m0,m1恢复(即除得的余式R15R14
       ;与原始位序列最高两位字节相等),则为正确接收。
       ;本程序中循环次数为98,比位序列字节数少2。因为位序列最低两个字节m0,m1直
       ;接作为(第一个)余式,不对它们查取CRC校验码。       
    ;X为按字节寻址位序列指针
    ;寻址CRC校验码表格先按字计算地址指针,将其增倍后变为按字节寻址。
CRCOUT:LDI    XH,$1            ;THE BIT SEQUENCE IS IN $100---$163
    CLR    XL               ;TOTAL  100 BYTES
    LDI    R16,$62          ;THE DATA BLOCK  LENGTH IS  98(=100-2)
    LD     R14,X+           ;m0
    LD    R15,X+           ;m1
CRCO1:LD    R13,X+           ;fetch m2 at the first!
      LDI    ZH,HIGH(DATA5)
      LDI    ZL,LOW(DATA5)
      ADD    R30,R13
      CLR    R13
      ADC    R31,R13     
      LSL    R30
      ROL    R31               ;point to the CRC CODE!
      LPM      
      EOR    R14,R0
      ADIW    R30,1
      LPM   
      EOR    R15,R0           ;CRC CODE IN R14&R15(HIGH)!
      DEC    R16
      BRNE    CRCO1   
      STS    $101,R15
      STS    $100,R14          ;将生成的CRC校验码放在位序列的最低两位字节中
      RET                      ;或将原始位序列的最低两位字节恢复
DATA5:.DB  $00,$00,$80,$05     ;THE CRC CODE TABLE
      .DB  $80,$0F,$00,$0A     ;与范例101中SRAM$100--$2FF单元内容完全相同!
      .DB  $80,$1B,$00,$1E
    ;....................  ;其余略
       end

离线

页脚

Powered by FluxBB

本站由XREA提供空间支持