你拼了命的去研究霸王龍的生活習性,然后回家種香蕉,有多大意義呢?
1.這個程序非常不嚴謹,實際中用不了,DPTR,R0的初始值沒有確定,程序有問題
2.猛的搞那么一段代碼出來,絕大多數人不會知道它在實際電路中能有什么用
3.所用器件已經過時了,現在沒有人用這玩意,也就沒有人知道怎么真正的寫完一個完整的程序出來
4.這破爛一樣的程序沒頭沒尾的,給誰都不會知道R0從哪里來,DPTR的值是多少,作者也不想寫,就像是走走過場,應付一下的把這代碼交代出來而已
以下才是匯編真正完整樣子,可以燒錄到單片機中正確運行,有晶振頻率,端口指定,電路編號,備注
;===============基于STC8的4*USB充電電流電壓顯示器===============================================;
;名稱:基于STC8的4*USB充電電流電壓顯示器 ;
;作者:老玉 ;
;日期:2019/03/14 ;
;功能:可以顯示4個USB充電端口的充電電流 ;
;單片機型號:STC8A4K32S2A12 ;
;電路與PCB編號:YGG_190314.0_DA ;
;晶振:使用片上的24.0MHZ振蕩電路 ;
;功能: ;
;最后更新日期:20190320 ;
;備注說明; 程序已經測試OK ;
;如果電流數據不對,就把電路中四個運放放大電路的增益改成50倍,如果是對的,就不用改動 ; ;
;================================================================================================
;端口指定========================================================================================
P4 EQU 0C0H ;P4 端口的地址
P5 EQU 0C8H ;P5端口的地址
OUT EQU P0 ;P0作為輸出端口
;====================================================================================================
;12864顯示屏的端口指定===============================================================================
RS BIT P1.2 ;
RW BIT P1.1 ;
E BIT P1.0 ;
PSB BIT P3.6 ;
RST_12864 BIT P3.5 ;
;====================================================================================================
;標志位指定==========================================================================================
MODE BIT 20H ;設定模式標示位
MIAO BIT 21H ;秒閃標志位
I_FU BIT 24H ;完全顯示標志位
;====================================================================================================
;STC8的端口IO模式控制寄存器指定======================================================================
P0M0 EQU 094H ;
P0M1 EQU 093H ;控制P0端口輸出模式的寄存器
P1M0 EQU 092H ;
P1M1 EQU 091H ;控制P1端口輸出模式的寄存器
P2M0 EQU 096H ;
P2M1 EQU 095H ;控制P2端口輸出模式的寄存器
P3M0 EQU 0B2H ;
P3M1 EQU 0B1H ;控制P3端口輸出模式的寄存器
P4M0 EQU 0B4H ;
P4M1 EQU 0B3H ;控制P4端口輸出模式的寄存器
P5M0 EQU 0CAH ;
P5M1 EQU 0C9H ;控制P5端口輸出模式的寄存器
;====================================================================================================
;STC8的ADC相關寄存器指定=============================================================================
ADCCFG DATA 0DEH ;ADC配置寄存器
ADC_CONTR DATA 0BCH ;ADC控制寄存器
ADC_RES DATA 0BDH ;ADC緩沖器高4位
ADC_RESL DATA 0BEH ;ADC緩沖器低8位
ADC_P13 EQU 083H ;P13ADC端口
ADC_P14 EQU 084H ;P14ADC端口
ADC_P15 EQU 085H ;P15ADC端口
ADC_P16 EQU 086H ;P16ADC端口
ADC_P17 EQU 087H ;P17ADC端口
;====================================================================================================
WDT_CONTR EQU 0C1H ;看門狗地址
COUNT DATA 030H ;存放計數用的
COUNT_1 DATA 031H ;計數用的
DATA_BUF DATA 032H ;運算過程中用到的數據緩存器
COUNT_2 DATA 033H ;計數用的
TWIN DATA 035H ;
LED_1 DATA 036H ;個位保存器
LED_10 DATA 037H ;十位保存器
LED_100 DATA 038H ;百位保存器
LED_1000 DATA 039H ;千位保存器
DIV_L DATA 03AH ;除法高位用的緩存器
DIV_H DATA 03BH ;除法低位用的緩存器
DATA_BUF_L DATA 03CH ;數據暫存器的低位
DATA_BUF_H DATA 03DH ;數據暫存器的高位
ADC_SUM_H DATA 03FH ;ADC累加計算的高位存儲器
ADC_SUM_L DATA 040H ;ADC累加計算的低位存儲器
ADDR_12864 DATA 041H ;指定12864的顯示地址
DEL_1 DATA 042H ;延時用的
DEL_2 DATA 04FH ;誤差值存放用的寄存
D_P14 DATA 050H ;通道0誤差值
D_P15 DATA 051H ;通道1誤差值
D_P16 DATA 052H ;通道2誤差值
D_P17 DATA 053H ;通道3誤差值
ADC_ADD_H DATA 054H ;ADC總電流計算的高位存儲器
ADC_ADD_L DATA 055H ;ADC總電流計算的低位存儲器
I_OUT DATA 056H ;用于提示有沒有充電電流的寄存器
I_ALL_L DATA 057H ;用于保存總電流的低位數
I_ALL_H DATA 058H ;用于保存總電流的高位數
;程序開始==============================================================================================
ORG 0000H
JMP STAR
ORG 0100H
STAR: MOV ADCCFG,#02FH ;設置ADC的時鐘和轉換結果存放格式
MOV 0BAH,#80H ;地址位于XDATA區,要訪問之前,必須先把0BAH地址中的EAXFR位置位才能訪問,只有用MOVX @DPTR,A和MOVX A,@DPTR讀寫
MOV A,#00000111B ;選擇P1.0,P1.1,P1.2內部上拉電阻
MOV DPTR,#0FE11H ;
MOVX @DPTR,A ;
MOV A,#0FFH ;選擇P2內部上拉電阻
MOV DPTR,#0FE12H ;
MOVX @DPTR,A ;
MOV A,#11111111B ;選擇P4內部上拉電阻
MOV DPTR,#0FE14H ;
MOVX @DPTR,A ;
MOV 0BAH,#00 ;
MOV P0M1,#00000000B ;
MOV P0M0,#00000000B ;P0測定成默認的傳統8051端口
MOV P1M1,#11111000B ;P1.0 P1.1 P1.2作為傳統端口,P1.3 P1.4 P1.5 P1.6 P1.7作為ADC端口
MOV P1M0,#00000000B ;
MOV P2M1,#00000000B ;
MOV P2M0,#00000000B ;
MOV P3M1,#00000000B ;
MOV P3M0,#00000000B ;
MOV P4M1,#00000000B ;P4端口設定
MOV P4M0,#00000000B ;
MOV P5M1,#00000000B ;P5端口設定
MOV P5M0,#00000000B ;
CALL RESET_12864 ;12864初始化
CALL MUTE_12864 ;
MOV COUNT_1,#5 ;
MOV COUNT_2,#100 ;
MOV SP,#080H ;
MOV WDT_CONTR,#24H ;設定看門狗
;======================================================================================================
MAIN: CALL DISPLAY_VIN
CALL DISPLAY_AD1
CALL DISPLAY_AD0
CALL DISPLAY_AD2
CALL DISPLAY_AD3
CALL DISP_I_ALL
CPL MIAO
CALL MUTE_12864 ;
MAIN_END: ORL WDT_CONTR,#10H ;看門狗清除
CALL DELAY ;延時一次
DJNZ COUNT_2,MAIN_END ;延長顯示和ADC的時間,使顯示看起來更加穩定
MOV COUNT_2,#250 ;
JMP MAIN
;================================================================================================================
;顯示通道P1.3 顯示輸入電壓 顯示地址:095H,最后顯示的單位是"V"=86
DISPLAY_VIN: SETB I_FU ;
MOV A,#ADC_P13 ;選擇通道
CALL ADC_P1 ;選擇該通道進行ADC
MOV ADDR_12864,#085H;選擇顯示的地址
MOV R1,#86 ;<<<====最后顯示的單位是"V"=86
CALL DISPLAY_ADC ;顯示
CLR I_FU ;
MOV I_ALL_L,#0 ;
MOV I_ALL_H,#0 ;
RET
;================================================================================================================
;================================================================================================================
;顯示通道P1.4 顯示充電電流 顯示地址:08CH,最后顯示的單位是"A"=65
DISPLAY_AD0: MOV A,#ADC_P14 ;選擇通道
CALL ADC_P1 ;選擇該通道進行ADC
MOV ADDR_12864,#08CH;選擇顯示的地址
MOV R1,#65 ;<<<====最后顯示的單位是"A"=65
CALL DISPLAY_ADC ;顯示
MOV A,#09CH ;<<<===選擇要顯示的地址
CALL WRITE12864_INS ;寫入地址
JNB MIAO,DISPLAY_AD0_1;
MOV I_OUT,#32 ;秒到了就顯示空白
DISPLAY_AD0_1: MOV A,I_OUT ;
CALL WRITE12864_DATA ;
RET
;================================================================================================================
;================================================================================================================
;顯示通道P1.7 顯示充電電流 顯示地址:08EH,最后顯示的單位是"A"=65
DISPLAY_AD1: MOV A,#ADC_P17 ;選擇通道
CALL ADC_P1 ;選擇該通道進行ADC
MOV ADDR_12864,#08AH;選擇顯示的地址
MOV R1,#65 ;<<<====最后顯示的單位是"A"=65
CALL DISPLAY_ADC ;顯示
MOV A,#09AH ;<<<===選擇要顯示的地址
CALL WRITE12864_INS ;寫入地址
JNB MIAO,DISPLAY_AD1_1;
MOV I_OUT,#32 ;秒到了就顯示空白
DISPLAY_AD1_1: MOV A,I_OUT ;
CALL WRITE12864_DATA ;
RET
;================================================================================================================
;================================================================================================================
;顯示通道P1.5 顯示充電電流 顯示地址:088H,最后顯示的單位是"A"=65
DISPLAY_AD2: MOV A,#ADC_P15 ;選擇通道
CALL ADC_P1 ;選擇該通道進行ADC
MOV ADDR_12864,#08EH;選擇顯示的地址
MOV R1,#65 ;<<<====最后顯示的單位是"A"=65
CALL DISPLAY_ADC ;顯示
MOV A,#09EH ;<<<===選擇要顯示的地址
CALL WRITE12864_INS ;寫入地址
JNB MIAO,DISPLAY_AD2_1;
MOV I_OUT,#32 ;秒到了就顯示空白
DISPLAY_AD2_1: MOV A,I_OUT ;
CALL WRITE12864_DATA ;
RET
;================================================================================================================
;================================================================================================================
;顯示通道P1.6 顯示充電電流 顯示地址:08AH,最后顯示的單位是"A"=65
DISPLAY_AD3: MOV A,#ADC_P16 ;選擇通道
CALL ADC_P1 ;選擇該通道進行ADC
MOV ADDR_12864,#088H;選擇顯示的地址
MOV R1,#65 ;<<<====最后顯示的單位是"A"=65
CALL DISPLAY_ADC ;顯示
MOV A,#098H ;<<<===選擇要顯示的地址
CALL WRITE12864_INS ;寫入地址
JNB MIAO,DISPLAY_AD3_1;
MOV I_OUT,#32 ;秒到了就顯示空白
DISPLAY_AD3_1: MOV A,I_OUT ;
CALL WRITE12864_DATA ;
RET
;================================================================================================================
DISP_I_ALL: SETB I_FU ;
MOV A,I_ALL_L ;
SUBB A,#30 ;總電流小于30.不顯示
MOV A,I_ALL_H ;
SUBB A,#0 ;
JNC DISP_I_ALL_1 ;
MOV I_ALL_L,#0 ;
MOV I_ALL_H,#0 ;
DISP_I_ALL_1: MOV A,I_ALL_H ;
MOV B,I_ALL_L ;
CALL DATA_DISP ;處理總電流數據
MOV ADDR_12864,#094H;選擇顯示的地址
MOV R1,#65 ;<<<====最后顯示的單位是"A"=65
CALL DISPLAY_ADC ;顯示
MOV I_ALL_H,#0 ;
MOV I_ALL_L,#0 ;顯示完一次總電流就要歸零一次
CLR I_FU ;
RET
;=====================================================================================
;ADC_P1 使用到的共用寄存器: A B R0 COUNT DEL_1 DEL_2
;調用此程序之前,要先把通道選擇放入A,把誤差什放入R0
;轉換完成之后,ADC結果的高位存放在:ADC_SUM_H,低位存放在:ADC_SUM_L
;功能:進行ADC轉換,并把轉換結果進行平均,此子程序一共進行10次ADC,再平均得到最后的數據
ADC_P1: MOV ADC_CONTR,A ;選擇ADC通道A,A要在進入ADC之前先指定好
MOV COUNT,#8 ;ADC一共在進行16次,然后再平均
MOV ADC_RES,#0 ;
MOV ADC_RESL,#0 ;
MOV ADC_SUM_L,#0 ;
MOV ADC_SUM_H,#0 ;ADC的兩個累加存儲先清除
ADC_P1_1: CLR C ;
MOV A,#01000000B ;
ORL ADC_CONTR,A ;使用"或"啟動ADC
ADC_P1_2: MOV A,#00100000B ;
ANL A,ADC_CONTR ;
JZ ADC_P1_2 ;
ANL ADC_CONTR,#11011111B;清除ADC中斷標志位
CLR C
MOV A,ADC_RESL ;高位值傳送到緩存器
ADD A,ADC_SUM_L ;ADC運算結果的低位相加
MOV ADC_SUM_L,A ;把運算結果保存到累加存儲器
MOV A,ADC_RES ;
ADDC A,ADC_SUM_H ;ADC運算結果的高位相加
MOV ADC_SUM_H,A ;把運算結果保存到累加存儲器
DJNZ COUNT,ADC_P1_1 ;一共要進行10次的ADC
MOV COUNT,#2 ;
ADC_LOOP: CLR C
MOV A,ADC_SUM_H
RRC A
MOV ADC_SUM_H,A
MOV A,ADC_SUM_L
RRC A
MOV ADC_SUM_L,A
DJNZ COUNT,ADC_LOOP ;以上進行的是ADC之后累加值的平均
;===========================================;
MOV R0,#03 ;默認顯示為愛心
CLR C ;
MOV A,ADC_SUM_L ;
SUBB A,#20 ;R0為誤差值存放寄存器
MOV A,ADC_SUM_H ;
SUBB A,#0 ;
JNC ADC_END_1 ;C為0就表示ADC的結果是大于20的
MOV R0,#32 ;32為空格,就是不顯示,空白
ADC_END_1: CLR C
MOV I_OUT,R0 ;送充電指示標志
MOV A,ADC_SUM_L
SUBB A,#04 ;04是固有的誤差
MOV A,ADC_SUM_H ;
SUBB A,#0 ;
JNC ADC_END_2 ;
MOV ADC_SUM_L,#0 ;
MOV ADC_SUM_H,#0 ;
ADC_END_2: MOV A,ADC_SUM_H ;高位ADC的結果存放到A
MOV B,ADC_SUM_L ;低位ADC的結果存放到B
;===============計算總電流================================================
CLR C
MOV A,I_ALL_L ;
ADD A,ADC_SUM_L ;
MOV I_ALL_L,A ;
MOV A,I_ALL_H ;
ADDC A,ADC_SUM_H ;
MOV I_ALL_H,A ;
;=======================================================================
MOV A,ADC_SUM_H ;高位ADC的結果存放到A
MOV B,ADC_SUM_L ;低位ADC的結果存放到B
CALL DATA_DISP ;對ADC轉換結果的高低位進行拆分,拆分成4個數分別存放在4個地址
RET
;===================================================================================
;DATA_DISP==============數據拆分,把一個數拆分成四個數,用于顯示======================
;把16進制的高低兩個字節分別放到A和B,處理之后,個十百千位會分別放到4個地址中,使用減法運算來達到除法的效果
;進入之前要先把高位數據存放到A,低位數據存放到B
DATA_DISP: MOV LED_1,#0
MOV LED_10,#0
MOV LED_100,#0
MOV LED_1000,#0 ;先把四個清除
MOV DATA_BUF_H,A ;
MOV DATA_BUF_L,B ;把數據傳送到緩沖器中
MOV R0,#0E8H ;
MOV R1,#03H ;1000的16進制為03E8H
MOV R2,#100
MOV R3,#10
MOV R4,#0
SUB_1000: CLR C
MOV A,DATA_BUF_L
SUBB A,R0
MOV DIV_L,A;
MOV A,DATA_BUF_H;
SUBB A,R1
MOV DIV_H,A
JC SUB_100
MOV DATA_BUF_L,DIV_L
MOV DATA_BUF_H,DIV_H
INC LED_1000
JMP SUB_1000
SUB_100: CLR C
MOV A,DATA_BUF_L
SUBB A,R2
MOV DIV_L,A
MOV A,DATA_BUF_H;
SUBB A,R4
MOV DIV_H,A
JC SUB_10
MOV DATA_BUF_L,DIV_L
MOV DATA_BUF_H,DIV_H
INC LED_100
JMP SUB_100
SUB_10: MOV A,DATA_BUF_L
MOV B,R3
DIV AB
MOV LED_10,A
MOV LED_1,B
RET
;============================================================================
;這一段是把拆分之后的四個數字的數據分別關去查表,并用于12864的顯示
;調用程序之前: 要先把準備顯示的地址放到ADDR_12864 要顯示的單位放到 R1
;四個顯示的數值要先分解好放到四個地址中
DISPLAY_ADC: MOV A,LED_1 ;
MOV DPTR,#TAB2 ;
MOVC A,@A+DPTR ;
MOV LED_1,A ;
MOV A,LED_10 ;
MOV DPTR,#TAB2 ;
MOVC A,@A+DPTR ;
MOV LED_10,A ;
MOV A,LED_100 ;
MOV DPTR,#TAB2 ;
MOVC A,@A+DPTR ;
MOV LED_100,A ;
MOV A,LED_1000 ;
MOV DPTR,#TAB2 ;
MOVC A,@A+DPTR ;
MOV LED_1000,A ;
MOV A,ADDR_12864 ;<<<<=====寫入要顯示的地址
LCALL WRITE12864_INS ;
MOV A,LED_1000 ;
CALL WRITE12864_DATA ;顯示千位
MOV A,#46 ;顯示點"."
CALL WRITE12864_DATA ;顯示點
MOV A,LED_100 ;
CALL WRITE12864_DATA ;顯示百位
JNB I_FU,D_A_2 ;如果不是在顯示總電流就直接不顯示后面的,只要1.0 這種形式
D_A_1: MOV A,LED_10 ;
CALL WRITE12864_DATA ;顯示十位
MOV A,LED_1 ;
CALL WRITE12864_DATA ;顯示個位
MOV A,R1 ;<<<<=====寫入在最后顯示的單位
CALL WRITE12864_DATA ;顯示最后的單位
D_A_2: ; CALL DELAY ;
RET
;===============================================================================
;===================延時子程序==================================================
DELAY: MOV DEL_2,#50
MS5DISP1: MOV DEL_1,#255
DJNZ DEL_1,$
DJNZ DEL_2,MS5DISP1
RET
;===================向12864寫入數據=============================================
WRITE12864_DATA: CALL ASK_BF ;查BF是否忙
SETB RS
CLR RW
MOV OUT,A
SETB E
CLR E
CALL DELAY
RET
;===================向12864寫入指令=============================================
WRITE12864_INS: CALL ASK_BF ;查BF是否忙
CLR RS
CLR RW
MOV OUT,A
SETB E
CLR E
CALL DELAY
RET
;===================查BF是否忙==================================================
ASK_BF: MOV OUT,#0FFH ;釋放P0端口
CLR RS
SETB RW
SETB E
JB OUT.7,ASK_BF
CLR E
CALL DELAY
RET
;================================================================================
;================================================================================================================
;菜單顯示
MUTE_12864: MOV A,#080H ;把要顯示的地址傳送到顯示的緩沖器上
LCALL WRITE12864_INS ;寫入要顯示的地址
MOV DPTR,#TAB3 ;
MUTE_1: CLR A ;
MOVC A,@A+DPTR ;查表
JZ MUTE_2 ;A的值為0就表示已經讀到了最后一個內容了
CALL WRITE12864_DATA ;調用寫入數據子程序
INC DPTR ;地址加1,顯示下一個地址的數據
JMP MUTE_1 ;再去查表顯示
MUTE_2: MOV A,#090H ;把要顯示的地址傳送到顯示的緩沖器上
LCALL WRITE12864_INS ;寫入要顯示的地址
MOV DPTR,#TAB4 ;
MUTE_2_1: CLR A ;
MOVC A,@A+DPTR ;查表
JZ MUTE_END ;A的值為0就表示已經讀到了最后一個內容了
CALL WRITE12864_DATA ;調用寫入數據子程序
INC DPTR ;地址加1,顯示下一個地址的數據
JMP MUTE_2_1 ;再去查表顯示
MUTE_END:
RET
;==============================================================================================
;================================================================================================================
;12864初始化
RESET_12864: CLR RST_12864 ;12864復位
RESET_1: CALL DELAY ;延時
DJNZ R0,RESET_1 ;
SETB RST_12864 ;關閉12864復位
SETB PSB ;8位數據模式
MOV A,#06H ;設定整體顯示
LCALL WRITE12864_INS ;寫入指令
MOV A,#030H ;設定使用基本指令
LCALL WRITE12864_INS ;寫入指令
MOV A,#0CH ;設定顯示狀態開關
LCALL WRITE12864_INS ;寫入指令
MOV A,#01H ;清除屏幕
LCALL WRITE12864_INS ;寫入指令
RET
;================================================================================================================
ORG 1000H
TAB2: DB '0123456789' ;顯示數字的0-9
TAB3: DB '電源電壓',':',0H ;以0H作為結果標志
TAB4: DB '總電流',':',0H ;
END
|