errorlevel -302
;***********************************
__CONFIG _DEBUG_OFF&_CP_ALL&_WRT_HALF&_CPD_ON&_LVP_OFF&_BODEN_OFF&_PWRTE_ON&_WDT_OFF&_HS_OSC;
;************************************
disbuf equ 20h ;顯示緩沖區20,21,22
ledtemp equ 29h
vrevh equ 2Ah
vrevl equ 2Bh
SOUH equ 40h ;子程序入口高位
SOU equ 41h ;子程序入口低位
RLTH equ 42h ;子程序入口高位
RLT equ 43h ;子程序入口低位
CNT equ 44h ;子程序用寄存器
TEMP1 equ 45h ;子程序用
TEMP2 equ 46h ;同上
TEMP3 equ 47h ;同上
TEMP4 equ 48h ;同上
;*****************************************
org 0000h
NOP
goto start
org 0005H
start:
banksel TRISA
movlw B'00000001' ;AN0>>>>DC input DC通道上輸入,註意,這裏是打開RA0,但是在ICD上RA0 控制第二個LED.RA1
movwf TRISA ;對應第壹個LED,這壹點在顯示結果時請自已區分
movlw B'00000000'
movwf TRISC
movlw B'10000111' ;預分頻器給TMRO,且分頻比為1:256
movwf OPTION_REG
clrf STATUS
movlw 0xa0 ;TMRO初值
movwf TMR0
;***** ***************ADC初始化
;***** *****************
ATOD:
banksel ADCON1
movlw B'10001110' ;轉換結果右對齊,除RA0為模擬輸入口外,其他RA口跟RE口均為普通數字口
movwf ADCON1
CLRF STATUS
movlw B'01000001' ;轉換時鐘頻率為內部時鐘的1/8,AN0通道,允許ADC工作,暫時不開啟AD轉換
movwf ADCON0
;***** ************************
movlw 0x00
movwf disbuf
movwf disbuf+1
movwf disbuf+2
CLRF STATUS
BTFSS INTCON,T0IF ;等待和循環檢測TMR0溢出中斷標誌位
GOTO $-1 ;如果沒有發生TMR0溢出中斷則返回循環檢測
BCF INTCON,T0IF ;保證足夠的采樣時間
movlw 0xa0 ;TMRO初值
movwf TMR0
bsf ADCON0,GO ;開始轉換
ADWAIT:
btfsc ADCON0,GO
goto ADWAIT ;等待轉換完成
banksel ADRESH
movf ADRESH,w ;讀電壓值高2位
CLRF STATUS
movwf vrevh
BANKSEL ADRESL
movf ADRESL,w ;讀電壓低8位
CLRF STATUS
movwf vrevl ;裝值放入接收寄存器VERVH,VERVL,為節省時間
;采樣值可以直接放入SOUH,SOU,但運算不方便
;*******測試用B'1100001111'**********************
; movlw 0x03 ;這裏可以手動往VREVH,VrevL兩個寄存器輸入10位AD值,以便用來測試是否能
;在LED上顯示正確的電壓值,如:30F=B'1100001111'(10位采樣AD值);
;30F的實際值是3.823V,那麽在LED上將顯示3.82,寄存器21,22,23的值分別為3,8,2
;movwf vrevh ;程序正常采樣時這四句話要屏蔽;
; movlw 0x0f
; movwf vrevl
;************************************************
movf vrevh,w
movwf SOUH ;將被乘數放入SOUH,SOU
movf vrevl,w
movwf SOU
movlw 0x00 ;乘數放入RLTH,RLT
movwf RLTH
movlw 0x05 ;
movwf RLT ;這裏表示:30F*5,結果放入RLTH,RLT,SOUH,SOU;
call DUMUL ;>>>>>>5*V_gather,result>>>RLTH,RLT SOUH,SOU
movlw 0x04 ;準備除1024(400),放數入RLTH,RLT!!!!關鍵所以,要理解為重.....以下三步都是這樣的操作
movwf RLTH ;除法子程序用SOUH,SOU除以RLTH,RLT,因為上面的乘法程序不會超過兩個字節
movlw 0x00 ;5V*3FF(10位滿值)=13FB,所以在調用除法程序前不用考慮RLTH,RLT是否有其他值而被值
movwf RLT ;0X0400沖掉
call DUDIV ;調用除法程序,商在SOUH,SOU,余數在RLTH,RLT,對於余數再*0A處理.然後再除 0x0400
movf SOU,w ;這樣的話除兩次就是小數點後兩位精度
movwf disbuf ;這裏得到電壓整數值
movf RLTH,w
movwf SOUH ;送余數到SOUH,SOU,然後*0A,為小數點後壹位的運算作準備
movf RLT,w
movwf SOU
movlw 0x00
movwf RLTH
movlw 0x0A
movwf RLT
call DUMUL; >>>余數*10>>>RLTH,RLT SOUH,SOU,這裏壹般在souh,sou兩個字節,為除法作準備
movlw 0x04 ;放除數0X0400
movwf RLTH
movlw 0x00
movwf RLT
call DUDIV ;原來的余數再除以0X400
movf SOU,w
movwf disbuf+1 ;//取商到第二位電壓值,這裏是小數點的後壹位
movf RLTH,w ;然後將余數放到SOUH,SOU,為下壹次乘法作準備
movwf SOUH
movf RLT,w
movwf SOU
movlw 0x00
movwf RLTH
movlw 0x0A ;SOUH,SOU,RLTH,RLT為乘法入口
movwf RLT
call DUMUL ;>>>*10>>>RLTH,RLT SOUH,SOU,再乘以0A,出口在RLTH,RLT,SOUH,SOU
movlw 0x04
movwf RLTH
movlw 0x00
movwf RLT
call DUDIV ;再除以0X0400,除完這壹次後就不要再除了,因為是保留小數點後兩位
movf SOU,w
movwf disbuf+2 ;取電壓值,這裏是小數點後兩位值
call Led_scan
call delay_same1
goto ATOD ;循環轉換
;*********************led scan*************************
;LED掃描程序,對應於ICD,下面程序可以優化,請自已進行優化
Led_scan:
movlw ledtable ;取得表頭地址
movwf ledtemp
movf disbuf+2,w ;取得偏移量
addwf ledtemp,w ;表頭地址加上偏移量做為跳轉地址
call ledconvert ;查表
movwf PORTC ;送數碼管顯示
movlw B'11101111'
movwf PORTA ;點亮相應的數碼管
call delay_same ;延時壹段時間,保證顯示足夠亮度
movlw 0ffh
movwf PORTC ;清除顯示,防止幹擾其他位顯示
movlw ledtable
movwf ledtemp
movf disbuf+1,w
addwf ledtemp,w
call ledconvert
movwf PORTC
movlw B'11011111'
movwf PORTA
call delay_same
movlw 0ffh
movwf PORTC
movlw ledtable
movwf ledtemp
movf disbuf,w
addwf ledtemp,w
call ledconvert
andlw b'01111111' ;加上小數點
movwf PORTC
movlw B'11111011'
movwf PORTA
call delay_same
movlw 0ffh
movwf PORTC
movlw 0ffh ;關閉所有顯示
movwf PORTA
return
;*******end for led send***************************************
;;----------------數碼管查表程序-------------------------------
ledconvert
movwf 2
ledtable
RETLW 0c0h ;0
RETLW 0f9h ;1
RETLW 0a4h ;2
RETLW 0b0h ;3
RETLW 099h ;4
RETLW 092h ;5
RETLW 082h ;6
RETLW 0F8h ;7
RETLW 080h ;8
RETLW 090h ;9
return
delay_same ;延時
movlw 0F0h
movwf 70h
lop0 decfsz 70h,1
goto lop0
return
delay_same1
movlw 0F0h
movwf 71h
lop1 decfsz 71h,1
goto lop1
return
;********************************************************************************
;//是16*16進制,如果要十進制,則要進行BCD轉換
;********************DUMUL test Date:0808,ok*************************************
;具體可參考相關子程序庫
;最大實現FFFF*FFFF=FFFE0001的算法 比如:0X08 0X43 * 0X00 0X10>>>0X84 0X30
;本程序實現雙字節無符號數乘法。
;入口參數:被乘數在SOUH:SOU中,乘數在RLTH:RLT中。
;出口參數:結果在RLTH:RLT:SOUH:SOU中。
IFNDEF DUMUL1
#DEFINE DUMUL1
DUMUL MOVLW .16
MOVWF CNT
MOVF SOU,W
MOVWF TEMP3
MOVF SOUH,W
MOVWF TEMP4
CLRF SOU ;用於暫
CLRF SOUH ;存
CLRF TEMP1 ;結
CLRF TEMP2 ;果
BCF STATUS,C
LOOP3 RRF TEMP4,F
RRF TEMP3,F ;將被乘數的某壹位送到C中
BTFSC STATUS,C
CALL DUADD ;將RLTH:RLT中的被乘數加上
RRF SOUH,F
RRF SOU,F
RRF TEMP2,F
RRF TEMP1,F ;被乘數右移
DECFSZ CNT,F
GOTO LOOP3
MOVF SOUH,W ;保存結果
MOVWF RLTH
MOVF SOU,W
MOVWF RLT
MOVF TEMP2,W
MOVWF SOUH
MOVF TEMP1,W
MOVWF SOU
RETURN
;INCLUDE "DUADD.ASM"
ENDIF
;********************DUADD*********************
;本程序實現雙字節無符號數加法。
;入口參數:被加數在SOUH:SOU中,加數在RLTH:RLT中。
;出口參數:結果在SOUH:SOU中,進位位在STATUS:C中。
;占用資源:W,024H,025H,026H,027H,壹重堆棧。
IFNDEF DUADD1
#DEFINE DUADD1
DUADD MOVF RLT,W
ADDWF SOU,F
MOVF RLTH,W
BTFSC STATUS,C
INCFSZ RLTH,W
ADDWF SOUH,F
RETURN
ENDIF
;********************DUDIV*********************
;本程序實現雙字節無符號數除法。
;入口參數:被除數在SOUH:SOU中,除數在RLTH:RLT中。
;出口參數:商在SOUH:SOU中,余數在RLTH:RLT中.
;占用資源:W,STATUS,023H,024H,025H,026H,027H,028H,029H,壹重堆棧。
;說 明: 用戶在調用該子程序之前必須確定除數不為零,否則得不到正確結果.
IFNDEF DUDIV1
#DEFINE DUDIV1
DUDIV MOVLW .16 ;循環16次
MOVWF CNT
CLRF TEMP2
CLRF TEMP1 ;TEMP2:TEMP1得到余數
BCF STATUS,C
RLF SOU,F
RLF SOUH,F
RLF TEMP1,F
RLF TEMP2,F
LOOP79 MOVF RLTH,W
SUBWF TEMP2,W ;檢測是否余數大於除數
BTFSS STATUS,Z
GOTO NOCHK
MOVF RLT,W
SUBWF TEMP1,W ;如果高位相等則檢測低位
NOCHK BTFSS STATUS,C
GOTO NOGO
MOVF RLT,W ;余數減除數
SUBWF TEMP1,F
BTFSS STATUS,C
DECF TEMP2,F
MOVF RLTH,W
SUBWF TEMP2,F
BSF STATUS,C ;結果中移入1
NOGO RLF SOU,F
RLF SOUH,F
RLF TEMP1,F
RLF TEMP2,F
DECFSZ CNT,F
GOTO LOOP79
BCF STATUS,C
RRF TEMP2,W
MOVWF RLTH
RRF TEMP1,W ;恢復余數
MOVWF RLT
RETLW 0
ENDIF
;**************************************************
end