;****************
list  p=16f877A    ; list directive to define processor
#include <p16f877A.inc> ; processor specific variable definitions
__CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _XT_OSC & _WRT_OFF & _LVP_OFF & _CPD_OFF
;---------------------
COUNTER    EQU    20H                    ;计数寄存器
COUNT1    EQU    21H
COUNT2    EQU    22H
TABADD    EQU    23H                    ;查表地址寄存器
DISPBUF    EQU    24H                    ;显示值暂存
DISPBUF_H  EQU    25H                    ;显示器高位
DISPBUF_L  EQU    26H                    ;显示器低位
BUFFER    EQU    27H                    ;BCD十进制结果存放
BUFFER1    EQU    28H                    ;BCD转换缓存
SUM        EQU    29H                    ;校正+3缓存
DIGIT      EQU    2AH                    ;数据显示寄存器
HB        EQU    2BH                    ;百位寄存器
;--------------------
            ORG        0000H            
            NOP
            GOTO        MAIN
            ORG        0005H
MAIN
;**********************    初始化程序    *********************************
          
              CLRF        PORTA
              CLRF        PORTC            ;初始化IO口
    
              BSF        STATUS,RP0        ;设置寄存器体1
              MOVLW      0EH              ;转换结果左对齐,只选1个A/D通道RA0/AN0
              MOVWF      ADCON1            ;选择VDD和VSS作参考源
              MOVLW      01H              ;RA0为模拟输入
              MOVWF      TRISA            ;RA1~5为输出
        
              MOVLW      00H              ;RC为LED段输出
              MOVWF      TRISC  
              BCF        STATUS,RP0        ;恢复寄存器体0  
              MOVLW      0FFH              ;先让数码管全部不显示
              MOVWF      PORTC
          MOVWF      PORTA
              MOVLW      81H              ;选择:时钟时钟源为FOSC/8,允许ADC工作
              MOVWF      ADCON0            ;通道AN0,暂时不启动转换过程
              CLRF        DISPBUF          ;清显示值
                  
;********************************************************************************
              
ADC
                BSF        ADCON0,GO            ;开启A/D转换过程
                BTFSS      PIR1,ADIF            ;等待A/D转换过程结束,检测ADC中断标志位
                GOTO      ADC                  ;如果没有转换结束,则返回循环检测
                MOVF      ADRESH,W              ;仅取高8位,把A/D结果读到W
                MOVWF      DIGIT                ;注入显示寄存器          
;********************************  BCD  ********************************
              
LOOP1      
          
                CALL        DISP            ;调用显示子程序
            MOVLW    8
          MOVWF    COUNTER      ;循环左移计数器置8
            CLRF    BUFFER          ;清除缓冲器
          MOVF    DIGIT,W  
          MOVWF    BUFFER1        
LOOP2    
                RLF        BUFFER1,1      ;二进制数转换成BCD码(以便显示)
            RLF      BUFFER,1
            DECFSZ    COUNTER,1      ;左移8次
          GOTO    ADJUST          ;
          MOVFW    BUFFER
          MOVWF    DISPBUF        ;是否有进位(即已达100),如已计数到100则
          GOTO    ADC
            ;GOTO    MAIN
ADJUST    
                MOVLW    3              ;二进制转BCD的调整
            ADDWF    BUFFER,W    ;每次移位后都检查低四位LSD+3是否大于7
            MOVWF    SUM            
          BTFSC    SUM,3
          MOVWF    BUFFER
          MOVLW    30H
          ADDWF    BUFFER,W        ;如果是则再加3,否则不加。
          MOVWF    SUM
          BTFSC    SUM,7
          MOVWF    BUFFER          ;接着再将高四位MSD作相同处理
            GOTO    LOOP2
;********************************  显示程序  ***************************
DISP
              CLRF      HB
              MOVLW      0C8H                ; 送入199至W,
              SUBWF      DIGIT,W            ; F-W    
              BTFSC      STATUS,C            ; 检测C是否出现借位
              GOTO      HB200              ; F>199,百位数显示2
              MOVLW      64H                ; F<199,再送99至W
              SUBWF      DIGIT,W            ; F-W
              BTFSC      STATUS,C            ; 检测C是否出现借位      
              GOTO      HB100              ; 199>F>99,百位数显示1
              GOTO      DISP10              ; F<99,百位不显示
HB200        MOVLW      2H
              MOVWF      HB                  ;百位显示数移入寄存器
              GOTO      DISP100
HB100        MOVLW      1H
              MOVWF      HB                  ;百位显示数移入寄存器
              
DISP100      MOVLW      0FFH                ;显示百位
            MOVWF      PORTC
            BCF        PORTA,2              ;RA2为百位显示
            BSF        PORTA,5
            BSF        PORTA,4
            MOVLW      TABLE                ;查表
            MOVWF      TABADD
            MOVF      HB,W
            ADDWF      TABADD,W
            CALL      CONVERT
            MOVWF      PORTC                ;显示内容送RC
            CALL      DELAY
DISP10      MOVF      DISPBUF,W        ;显示值低位处理
            ANDLW      0FH              ;屏蔽掉高位
            MOVWF      DISPBUF_L        ;存入寄存器            
            SWAPF      DISPBUF,W        ;显示值高低位交换,先处理高位
            ANDLW      0FH              ;屏蔽掉高位
            MOVWF      DISPBUF_H        ;存入寄存器
            MOVF      HB,W
            ADDWF      DISPBUF_H,W      ;如果百位和十位同为零不显示
            BTFSC      STATUS,Z
            GOTO      DISP01
            MOVLW      0FFH              ;显示十位
            MOVWF      PORTC            ;先熄灭数码管以免闪烁
            BCF        PORTA,5          ;先显示低位
            BSF        PORTA,2
            BSF        PORTA,4
            MOVLW      TABLE
            MOVWF      TABADD            ;将转换表的首地址存入TABADD  
            MOVFW      DISPBUF_H        ;计数值(W)与转换表的起始地址相加
            ADDWF      TABADD,W
            CALL      CONVERT          ;存入W后调用转换表子程序
            MOVWF      PORTC            ;送RB口显示
            CALL      DELAY            ;廷时4。7MS
DISP01      MOVLW      0FFH              ;同样方法显示个位
            MOVWF      PORTC
            BCF        PORTA,4
            BSF        PORTA,2
            BSF        PORTA,5
            MOVLW      TABLE
            MOVWF      TABADD
            MOVFW      DISPBUF_L
            ADDWF      TABADD,W
            CALL      CONVERT
            MOVWF      PORTC
            CALL      DELAY
            RETLW      0          
;******************************  查表显示  *****************************************
CONVERT  
            MOVWF    PCL            ;将W寄存器内的7段显示码地址放入PC
TABLE                                  ;PC执行新地址指令, 跳到相对的地址执行?              
          RETLW    0C0H      ;0    
          RETLW    0F9H      ;1                                
          RETLW    0A4H      ;2
          RETLW    0B0H      ;3
          RETLW    099H      ;4
          RETLW    092H      ;5
          RETLW    082H      ;6
          RETLW    0D8H      ;7
          RETLW    080H      ;8
          RETLW    090H      ;9
;***************************    延时程序    ************************************
DELAY                      ;显示廷时常数,廷时时间为3*255*6+6us+4us=4.6ms
            MOVLW    06H;6H;
      MOVWF    COUNT1
L2    
            MOVLW    0FFH;0FFH;
      MOVWF    COUNT2
L3    
            DECFSZ    COUNT2,1        
        GOTO    L3
      DECFSZ    COUNT1,1
      GOTO    L2
        RETLW    0    
;***********************************************************************
        
      END