標(biāo)題: STC8G單片機(jī)MDU16位乘除法器C語(yǔ)言改匯編程序 [打印本頁(yè)]

作者: dalaoshi    時(shí)間: 2021-4-10 01:02
標(biāo)題: STC8G單片機(jī)MDU16位乘除法器C語(yǔ)言改匯編程序
最近需要用到16位乘16位,記得STC有硬件的16位乘除法器,看了說(shuō)明書(shū),找到了例程,卻只有C語(yǔ)言的,看來(lái)匯編已經(jīng)快被拋棄了,只好自己改寫(xiě),C語(yǔ)言就是一堆難懂的符號(hào),像這句“ARCON = 4 << 5;    //16位*16位,乘法模式"就看不懂,但只要看原理說(shuō)明就知道,這乘除法器就設(shè)在傳統(tǒng)51單片結(jié)構(gòu)外,利用一個(gè)P_SW2的寄存器做開(kāi)關(guān),開(kāi)關(guān)打開(kāi)后,就可以用DPTR指針往外面的寄存器(MD0-MD5)賦值,再打開(kāi)一個(gè)外面的開(kāi)關(guān)OPCON,就會(huì)開(kāi)始運(yùn)算,等若干時(shí)鐘后把運(yùn)算結(jié)果讀進(jìn)來(lái),再把P_SW2關(guān)閉就可以了。明白了原理后寫(xiě)匯編就很簡(jiǎn)單了。為了驗(yàn)證寄存器沒(méi)有搞錯(cuò),將結(jié)果通過(guò)UART1顯示出來(lái),網(wǎng)上有不少HEX的運(yùn)算器,我把數(shù)字放上去計(jì)算,出來(lái)的結(jié)果都看不懂,最后是把16位的乘數(shù)和被乘數(shù)都轉(zhuǎn)換成是進(jìn)制,再用五元的家用計(jì)算器算出結(jié)果,再把結(jié)果轉(zhuǎn)為HEX,0107HX0208H=00021638H,答案正確吧?

;C語(yǔ)言:

;============================================
;16位乘以16位乘法:被乘數(shù):{MD1,MD0} 乘數(shù):{MD5,MD4} 積:{MD3,MD2,MD1,MD0}

;define MD3 (*(unsigned char volatile xdata *)0xfcf0)
;#define MD2 (*(unsigned char volatile xdata *)0xfcf1)
;#define MD1 (*(unsigned char volatile xdata *)0xfcf2)
;#define MD0 (*(unsigned char volatile xdata *)0xfcf3)
;#define MD5 (*(unsigned char volatile xdata *)0xfcf4)
;#define MD4 (*(unsigned char volatile xdata *)0xfcf5)
;#define ARCON (*(unsigned      char volatile xdata *)0xfcf6)
;#define OPCON (*(unsigned      char volatile xdata *)0xfcf7)
;sfr              P_SW2                =              0xBA;            
;////////////////////////////////////////////////////////////////////////////////
;//16位乘16位//////////////////////////////////////////////////////////////////////////////
;// unsigned long res; unsigned int dat1, dat2;
;P_SW2 |= 0x80;     //訪問(wèn)擴(kuò)展寄存器xsfr
;MD1U16 = dat1;     //dat1用戶給定MD5U16 = dat2; //dat2用戶給定
;ARCON = 4 << 5;    //16位*16位,乘法模式
;OPCON = 1;         //啟動(dòng)計(jì)算
;while((OPCON & 1) != 0); //等待計(jì)算完成
;res = MD3U32; //32位結(jié)

;匯編:
HEADBUFFER1 EQU 0A0H
LASTBUFFER1 EQU 0FFH   ;第一組緩沖區(qū)
AUXR EQU 8EH
AUXR2 EQU 0A2H
WAKE_CLKO EQU 08FH   

MD0 EQU 0FCF3H
MD1 EQU 0FCF2H
MD2 EQU 0FCF1H
MD3 EQU 0FCF0H
MD4 EQU 0FCF5H
MD5 EQU 0FCF4H
ARCON EQU 0FCF6H
OPCON EQU 0FCF7H
P_SW2 EQU 0BAH            ;當(dāng)需要訪問(wèn) XFR 時(shí),必須先將 EAXFR 置 1,才能對(duì) XFR 進(jìn)行正常的讀寫(xiě)

ORG 0000H
LJMP MAIN
ORG 0023H
LJMP UART1    ;UART1 RECEIVED INTERRUPT
ORG 0100H

MAIN:
LCALL DELAY1  ;用STC-ISP的串口助手,必須給點(diǎn)時(shí)間切換,否則上載后來(lái)不及接收結(jié)果(00 02 16 38)接收口波特率為115200 晶振:11.0592 STC8G2K32S4
LCALL DELAY1
LCALL DELAY1

LCALL IOSET

CLR P1.0

MOV WAKE_CLKO,#00000001B     ;ENABLE BRT(=4),T1(=2) T0(=1) HAVE CLOCK OUTPUT BRT@P1.0 T1@P3.5 T0@P3.4
MOV AUXR,#11111100B          ;T0X12,T1X12,UART_M0X6,BRTRUN,S2SMOD,BRTX12,EXTRAM,S1BRS
MOV AUXR2, #00000000B        ;#00010000B=SHIFT UART2
MOV TMOD, #00100010B         ;TIMER0, TIMER1 AS MOD2(8 BYTE AUTO RELOAD TIMER)
                             ;GATE, C/T,M1,M0(T1) GATE, C/T,M1,MO(T0)
MOV PCON, #00000000B         ;THIS DOUBLE THE BRT AND T0 T1 RATE; SMOD IS AT PCON.7 249(3.64=32US) 219(18M= 2USX16=32US MIDI VIEW AT P3.5)

LCALL INITIAL_UART1        ;USE T1 AS SERIAL BAUD GENERATE FOR UART1
CLR RI
CLR TI
SETB  EA                  ;ENABLE ALL INTERRUPT

MOV P_SW2,#80H            ;訪問(wèn)X寄存器打開(kāi)

MOV DPTR,#MD1             ;
MOV A, #01H               ;必須通過(guò)A才能送到
MOVX @DPTR,A

MOV DPTR,#MD0             ;
MOV A, #07H               ;必須通過(guò)A才能送到
MOVX @DPTR,A

MOV DPTR,#MD5             ;
MOV A, #02H               ;必須通過(guò)A才能送到
MOVX @DPTR,A

MOV DPTR,#MD4             ;
MOV A, #08H               ;必須通過(guò)A才能送到
MOVX @DPTR,A

MOV DPTR,#ARCON           ;
MOV A, #10000000B         ;b7,b6,b5 4=16X16 5=16/16
MOVX @DPTR,A

MOV DPTR,#OPCON           ;啟動(dòng)運(yùn)算
MOV A, #00000001B            
MOVX @DPTR,A

WAIT:
MOVX A, @DPTR
ANL A, #00000001B
JNZ  WAIT

MOV DPTR, #MD3            
MOVX A, @DPTR

LCALL SENTONEBYTE1

MOV DPTR,#MD2           
MOVX A, @DPTR

LCALL SENTONEBYTE1

MOV DPTR, #MD1            
MOVX A, @DPTR

LCALL SENTONEBYTE1

MOV DPTR,#MD0         
MOVX A, @DPTR

LCALL SENTONEBYTE1

MOV P_SW2,#00H            ;訪問(wèn)完畢要關(guān)閉

LED:                      ;停機(jī)

JMP LED

NEXTBUFFER:
CJNE R0, #LASTBUFFER1, NEXTBUFFER2
MOV R0, #HEADBUFFER1
JMP NEXTBUFFEREXIT
NEXTBUFFER2:
INC R0  ;POINT TO NEXT BYTE
NEXTBUFFEREXIT:
RET

SENTONEBYTE1:                ;SENT OUT A
CHECKBUSY1:
JB 40H, CHECKBUSY1
SETB 40H
MOV SBUF, A
RET

UART1:      ;RECEIVED DATA FROM AIR
PUSH ACC
PUSH PSW
JNB RI, UART1CHECKTI
MOV A, SBUF ;READ THE CHARACTER FROM THE SERIAL PORT
CLR RI      ;CLEAR RECEICED FLAG
MOV @R1, A  ;SAVE TO BUFFER
CJNE R1, #LASTBUFFER1, NEXTREADBUFFER
MOV R1, #HEADBUFFER1
JMP UART1EXIT
NEXTREADBUFFER:
INC R1  ;POINT TO NEXT BUFFER
JMP UART1EXIT
UART1CHECKTI:
CLR TI
CLR 40H      
UART1EXIT:
POP PSW
POP ACC
RETI

INITIAL_UART1:           ;115200
MOV SCON, #01010000B     ;SET AS BAUD VERIABLE, NO ODD/EVEN CHECK
MOV TH1, #253            ;247(11.0592, 38400BPS) FOR TIMER_1 251=115200(18.4320M 115200BPS) 253(11.0592M 115200BPS) IF PCON.7=0   
MOV TL1, #253
SETB PS                  ;SERIAL PORT PRORITY HIGH
SETB TR1                 ;RUN TIMER_1
SETB ES                  ;ENABLE UART1 INTERRUPT
RET

IOSET:
;-----------I/O CONFIGUE
MOV 93H, #00000000B      ;SET P0 0,0=I/0, 0,1=HIGH CURRENT OUTPUT, 1,0=HIGH IMPEDENY INPUT 1,1=OPEN COLLECTIVE OUTPUT
MOV 94H, #00000000B      ;SET P0 (CONMAIN WITH 93H THIS IS SENCOND BIT)
MOV 91H, #00000000B      ;SET P1
MOV 92H, #00000000B      ;SET P1
MOV 95H, #00000000B      ;SET P2
MOV 96H, #00000000B      ;SET P2
MOV 0B1H, #00000000B     ;SET P3
MOV 0B2H, #00000000B     ;SET P3
MOV 0B3H, #00000000B     ;SET P4
MOV 0B4H, #00000000B     ;SET P4
MOV 0C9H, #00000000B     ;SET P5
MOV 0CAH, #00000000B     ;SET P5
;MOV 0CBH, #00000000B     ;SET P6
;MOV 0CCH, #00000000B     ;SET P6
;MOV 0E1H, #00000000B     ;SET P7
;MOV 0E2H, #00000000B     ;SET P7
RET

DELAY1:
LCALL DELAY2
LCALL DELAY2
SETB P1.0
LCALL DELAY2
LCALL DELAY2
CLR P1.0
RET

DELAY2:
MOV 35H, #255
SLOWDOWN0:
MOV 34H, #170
SLOWDOWN:
MOV 36H, #2
SLOWDOWN2:
DJNZ 36H, SLOWDOWN2
DJNZ 34H, SLOWDOWN
DJNZ 35H, SLOWDOWN0
RET

END



作者: youlinys    時(shí)間: 2022-3-9 21:59
感謝朋友的代碼
作者: haokanma77    時(shí)間: 2022-4-26 09:53
感謝朋友的乘除法代碼
作者: dalaoshi    時(shí)間: 2022-5-28 00:46
用“逼”作匯編位運(yùn)算的思考:

ANL:
11001100   原值
11010000   逼值
11000000   結(jié)果   

ANL是用來(lái)逼0的,逼值放0的位結(jié)果全變?yōu)?,放1的結(jié)果保留原值,用來(lái)保留你要的有效位。

ORL:
11001100   原值
11010000   逼值
11011100   結(jié)果
   
ORL是用來(lái)逼1的,逼值放1的位結(jié)果全變?yōu)?,放0的結(jié)果保留原值,用來(lái)打開(kāi)你要的某個(gè)位,而而其他位維持不變。

XOL:
11001100   原值
11010000   逼值
00011100   結(jié)果   

XOL是用來(lái)比較每個(gè)位的,相等的位就變0,不等的位就變1


作者: hhh402    時(shí)間: 2022-6-3 01:16
這么復(fù)雜誰(shuí)用?直接計(jì)算就好,慢不了多少,單片機(jī)主要是控制IO,復(fù)雜計(jì)算留給上位機(jī)。
作者: lijn    時(shí)間: 2022-6-6 11:27
感謝樓主的解析,請(qǐng)教  UART1是常用的串口軟件嗎?
作者: dalaoshi    時(shí)間: 2022-6-6 16:06
lijn 發(fā)表于 2022-6-6 11:27
感謝樓主的解析,請(qǐng)教  UART1是常用的串口軟件嗎?

UART不是常用,而是必不可少(除非只是想點(diǎn)亮一個(gè)LED而已),開(kāi)發(fā)過(guò)程中可以用來(lái)輸出結(jié)果,在PC上查看,STC的燒錄軟件可以在燒錄后即可打開(kāi)UART接收來(lái)自單片機(jī)UART1的數(shù)值,非常方便。
作者: lijn    時(shí)間: 2022-6-30 17:04
請(qǐng)教樓主,目前STC已經(jīng)有32位單片機(jī),用匯編程序也行嗎?

作者: dalaoshi    時(shí)間: 2022-6-30 17:28
lijn 發(fā)表于 2022-6-30 17:04
請(qǐng)教樓主,目前STC已經(jīng)有32位單片機(jī),用匯編程序也行嗎?

我還沒(méi)有玩STC32,因?yàn)檫沒(méi)有必要用到32位,估計(jì)也不算難,學(xué)會(huì)匯編底子好,你先玩玩看。
作者: zhxzhx    時(shí)間: 2022-6-30 18:09
說(shuō)C看不懂的,就是給自己找理由,C有的概念,匯編都有,
你要愿意,完全可以把C寫(xiě)成匯編
作者: dalaoshi    時(shí)間: 2022-7-29 03:12
近日有所發(fā)現(xiàn),KEIL4在編譯匯編語(yǔ)言的時(shí)候,無(wú)法發(fā)現(xiàn)偽指令ORG所指定的位置會(huì)覆蓋生成的代碼部分,比如:

ORG 0000H ;開(kāi)頭部分
LJMP MAIN
ORG 0003H
LJMP EXT_INT0 ;EXTERNAL INTERRUPT0
ORG 000BH
LJMP TIMER_0  ;TIMER0 INTERRUPT
ORG 0013H
LJMP EXT_INT1 ;EXTERNAL INTERRUPT1
ORG 001BH
LJMP TIMER_1  ;TIMER1 INTERRUPT
ORG 0023H
LJMP UART1    ;UART1 RECEIVED INTERRUPT
ORG 002BH
LJMP ADC      ;T2
ORG 0033H
LJMP LVD
ORG 003BH
LJMP PCA
ORG 0043H
LJMP UART2    ;UART2 RECEIVED INTERRUPT
ORG 004BH
LJMP SPI
ORG 0100H     

------------程序部分-----------

ORG 1700H ;數(shù)據(jù)部分(共256字節(jié))
DB 00H,40H,41H,3EH,41H,40H,41H,3CH,41H,40H,41H,3EH,41H,40H,00H,3BH ;0 16 0F
DB 41H,40H,41H,3EH,41H,40H,41H,3CH,41H,40H,41H,3EH,41H,40H,41H,39H ;0 16 1F
DB 41H,40H,41H,3EH,41H,40H,41H,3CH,41H,40H,41H,3EH,41H,40H,41H,3BH ;0 16 2F
DB 41H,40H,41H,3EH,41H,40H,41H,3CH,41H,40H,41H,3EH,41H,40H,41H,37H ;0 16 3F
DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;0 16 4F
DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;0 16 5F
DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;0 16 6F
DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;0 16 7F
DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;0 16 8F
DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;0 16 9F
DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;0 16 AF
DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;0 16 BF
DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;0 16 CF
DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;0 16 DF
DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;0 16 EF
DB 00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H,00H ;0 16 FF

編譯之后,顯示CODE=6144 (1800H) ,如果將數(shù)值部分(ORG 1700H)部分COMMENT, 編譯后
CODE=5926 (1726H),  顯然如果包含ORG 1700H 的數(shù)值,CODE的后面26H字節(jié)會(huì)被覆蓋, 上載到單片機(jī)后會(huì)出現(xiàn)意想不到的錯(cuò)誤,如果不能警覺(jué)這個(gè)問(wèn)題,會(huì)DEBUG到暈倒,把 ORG 改為1800H后,一切就正常了,但為什么編譯器不會(huì)發(fā)現(xiàn)問(wèn)題,沒(méi)有任何警告呢?
作者: 188610329    時(shí)間: 2022-7-29 03:59
dalaoshi 發(fā)表于 2022-7-29 03:12
近日有所發(fā)現(xiàn),KEIL4在編譯匯編語(yǔ)言的時(shí)候,無(wú)法發(fā)現(xiàn)偽指令ORG所指定的位置會(huì)覆蓋生成的代碼部分,比如:
...

所以, 如果需要絕對(duì)定位的盡量用 CSEG AT 1700H  這樣的格式, 盡量不要用 ORG 1700H 這樣的格式。
假如不需要絕對(duì)定位,就盡量用 RSEG 讓KEIL來(lái)自動(dòng) 分配。就不會(huì)出現(xiàn)你遇到的問(wèn)題了。
作者: Y_G_G    時(shí)間: 2022-7-29 06:44
dalaoshi 發(fā)表于 2022-7-29 03:12
近日有所發(fā)現(xiàn),KEIL4在編譯匯編語(yǔ)言的時(shí)候,無(wú)法發(fā)現(xiàn)偽指令ORG所指定的位置會(huì)覆蓋生成的代碼部分,比如:
...

STM32搞了個(gè)代碼生成軟件,引腳選好了,就生成代碼給你,復(fù)制就行,為什么呢?因?yàn)镾T覺(jué)得直接用C語(yǔ)言去寫(xiě)代碼太麻煩了,給你點(diǎn)幾下鼠標(biāo)就有代碼了
你倒好,覺(jué)得C看不明白,倒退回去用匯編
在單片機(jī)片上資源越來(lái)越豐富的今天,匯編只能不斷的放棄自己的江山
玩單片機(jī),會(huì)匯編是好事,但并不是說(shuō)什么都是匯編
而且,不是我說(shuō)你,你就算是用匯編,但也對(duì)匯編并不了解,竟然去懷疑編譯器
在你使用了ORG 1700H之后,1700H以前空間都會(huì)被使用,不管有沒(méi)有代碼,代碼長(zhǎng)度都是以O(shè)RG 1700H+后面占用的空間為總長(zhǎng)度,那么你這個(gè)代碼總長(zhǎng)度就是1700H+所有的DB=1800H
如果你不用ORG 1700H,代碼總長(zhǎng)度就是你其它代碼+DB占用的空間
可以計(jì)算出來(lái),你匯編的代碼如果沒(méi)有DB這一部分,長(zhǎng)度就是:5670
這么多的代碼,估計(jì)問(wèn)題就出在別的地方,要么是這DB部分放在代碼中間了,查表的時(shí)候也許是指針指過(guò)頭了,程序就到處跑
作者: dalaoshi    時(shí)間: 2022-7-29 17:53
Y_G_G 發(fā)表于 2022-7-29 06:44
STM32搞了個(gè)代碼生成軟件,引腳選好了,就生成代碼給你,復(fù)制就行,為什么呢?因?yàn)镾T覺(jué)得直接用C語(yǔ)言去寫(xiě)代碼 ...

開(kāi)始寫(xiě)的時(shí)候,把表放在1700H就覺(jué)得很夠了,后來(lái)程序越寫(xiě)也大,終于超過(guò)1700H的范圍,而編譯器編譯時(shí)沒(méi)有任何警告,上載后運(yùn)作就發(fā)生異常了,我之所以能比較快意識(shí)到這個(gè)問(wèn)題是因?yàn)槲屹N了一段新代碼在最末尾,運(yùn)作時(shí)發(fā)現(xiàn)該代碼沒(méi)有運(yùn)作,將該段代碼轉(zhuǎn)到中間部分,再運(yùn)行時(shí)該代碼就有運(yùn)作了,這才發(fā)現(xiàn)問(wèn)題所在,為了讓其他用匯編的網(wǎng)友警覺(jué),就貼上來(lái)分享了。

C語(yǔ)言的確強(qiáng)大和省事,但只會(huì)用C語(yǔ)言永遠(yuǎn)不可能玩出D,F(xiàn),G。。語(yǔ)言的。
作者: Hephaestus    時(shí)間: 2022-7-29 18:50
dalaoshi 發(fā)表于 2022-7-29 17:53
開(kāi)始寫(xiě)的時(shí)候,把表放在1700H就覺(jué)得很夠了,后來(lái)程序越寫(xiě)也大,終于超過(guò)1700H的范圍,而編譯器編譯時(shí)沒(méi)有 ...

編譯的時(shí)候絕對(duì)不可能報(bào)錯(cuò)或者警告的,如果你了解編譯連接過(guò)程的話。如果要警告,那也是BL51.exe連接器給出警告。
作者: Y_G_G    時(shí)間: 2022-7-29 19:16
dalaoshi 發(fā)表于 2022-7-29 17:53
開(kāi)始寫(xiě)的時(shí)候,把表放在1700H就覺(jué)得很夠了,后來(lái)程序越寫(xiě)也大,終于超過(guò)1700H的范圍,而編譯器編譯時(shí)沒(méi)有 ...

這本身就是你的問(wèn)題呀
編譯器只會(huì)執(zhí)行你的代碼,它只會(huì)識(shí)別語(yǔ)法和硬件上的錯(cuò)誤,比如RAM使用過(guò)頭了,或者是少了個(gè)逗號(hào)沒(méi)寫(xiě)
至于代碼本身的邏輯問(wèn)題,它是不會(huì)有什么警告的
匯編只有在個(gè)別極限要求下,比如時(shí)序嚴(yán)格到一個(gè)時(shí)鐘,或者是內(nèi)存實(shí)在太小的情況下,還有優(yōu)勢(shì)
其它的,什么所謂效率,了解硬件的.......一點(diǎn)優(yōu)勢(shì)都沒(méi)有
玩單片機(jī)的,只會(huì)C不會(huì)匯編的人,大有人在,你敢說(shuō)他們的技術(shù)都是在你之下?
嚴(yán)格遵循C語(yǔ)言規(guī)范寫(xiě)出來(lái)的程序,不見(jiàn)得比匯編差
不知道你玩不玩王者
匯編只作為一個(gè)BUFF,有BUFF你就打得過(guò)人家?
我之前就是用匯編的,現(xiàn)在基本就是只要能用C的,絕對(duì)不用匯編,連都不想看一眼




歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1