找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 6154|回复: 15
收起左侧

STC8G单片机MDU16位乘除法器C语言改汇编程序

  [复制链接]
ID:283954 发表于 2021-4-10 01:02 | 显示全部楼层 |阅读模式
最近需要用到16位乘16位,记得STC有硬件的16位乘除法器,看了说明书,找到了例程,却只有C语言的,看来汇编已经快被抛弃了,只好自己改写,C语言就是一堆难懂的符号,像这句“ARCON = 4 << 5;    //16位*16位,乘法模式"就看不懂,但只要看原理说明就知道,这乘除法器就设在传统51单片结构外,利用一个P_SW2的寄存器做开关,开关打开后,就可以用DPTR指针往外面的寄存器(MD0-MD5)赋值,再打开一个外面的开关OPCON,就会开始运算,等若干时钟后把运算结果读进来,再把P_SW2关闭就可以了。明白了原理后写汇编就很简单了。为了验证寄存器没有搞错,将结果通过UART1显示出来,网上有不少HEX的运算器,我把数字放上去计算,出来的结果都看不懂,最后是把16位的乘数和被乘数都转换成是进制,再用五元的家用计算器算出结果,再把结果转为HEX,0107HX0208H=00021638H,答案正确吧?

;C语言:

;============================================
;16位乘以16位乘法:被乘数:{MD1,MD0} 乘数:{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;     //访问扩展寄存器xsfr
;MD1U16 = dat1;     //dat1用户给定MD5U16 = dat2; //dat2用户给定
;ARCON = 4 << 5;    //16位*16位,乘法模式
;OPCON = 1;         //启动计算
;while((OPCON & 1) != 0); //等待计算完成
;res = MD3U32; //32位结

;汇编:
HEADBUFFER1 EQU 0A0H
LASTBUFFER1 EQU 0FFH   ;第一组缓冲区
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            ;当需要访问 XFR 时,必须先将 EAXFR 置 1,才能对 XFR 进行正常的读写

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

MAIN:
LCALL DELAY1  ;用STC-ISP的串口助手,必须给点时间切换,否则上载后来不及接收结果(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            ;访问X寄存器打开

MOV DPTR,#MD1             ;
MOV A, #01H               ;必须通过A才能送到
MOVX @DPTR,A

MOV DPTR,#MD0             ;
MOV A, #07H               ;必须通过A才能送到
MOVX @DPTR,A

MOV DPTR,#MD5             ;
MOV A, #02H               ;必须通过A才能送到
MOVX @DPTR,A

MOV DPTR,#MD4             ;
MOV A, #08H               ;必须通过A才能送到
MOVX @DPTR,A

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

MOV DPTR,#OPCON           ;启动运算
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            ;访问完毕要关闭

LED:                      ;停机

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


评分

参与人数 1黑币 +100 收起 理由
admin + 100 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:983641 发表于 2022-3-9 21:59 | 显示全部楼层
感谢朋友的代码
回复

使用道具 举报

ID:1001475 发表于 2022-4-26 09:53 来自手机 | 显示全部楼层
感谢朋友的乘除法代码
回复

使用道具 举报

ID:283954 发表于 2022-5-28 00:46 | 显示全部楼层
用“逼”作汇编位运算的思考:

ANL:
11001100   原值
11010000   逼值
11000000   结果   

ANL是用来逼0的,逼值放0的位结果全变为0,放1的结果保留原值,用来保留你要的有效位。

ORL:
11001100   原值
11010000   逼值
11011100   结果
   
ORL是用来逼1的,逼值放1的位结果全变为1,放0的结果保留原值,用来打开你要的某个位,而而其他位维持不变。

XOL:
11001100   原值
11010000   逼值
00011100   结果   

XOL是用来比较每个位的,相等的位就变0,不等的位就变1

回复

使用道具 举报

ID:491577 发表于 2022-6-3 01:16 | 显示全部楼层
这么复杂谁用?直接计算就好,慢不了多少,单片机主要是控制IO,复杂计算留给上位机。
回复

使用道具 举报

ID:126422 发表于 2022-6-6 11:27 | 显示全部楼层
感谢楼主的解析,请教  UART1是常用的串口软件吗?
回复

使用道具 举报

ID:283954 发表于 2022-6-6 16:06 | 显示全部楼层
lijn 发表于 2022-6-6 11:27
感谢楼主的解析,请教  UART1是常用的串口软件吗?

UART不是常用,而是必不可少(除非只是想点亮一个LED而已),开发过程中可以用来输出结果,在PC上查看,STC的烧录软件可以在烧录后即可打开UART接收来自单片机UART1的数值,非常方便。
回复

使用道具 举报

ID:126422 发表于 2022-6-30 17:04 | 显示全部楼层
请教楼主,目前STC已经有32位单片机,用汇编程序也行吗?
回复

使用道具 举报

ID:283954 发表于 2022-6-30 17:28 | 显示全部楼层
lijn 发表于 2022-6-30 17:04
请教楼主,目前STC已经有32位单片机,用汇编程序也行吗?

我还没有玩STC32,因为还没有必要用到32位,估计也不算难,学会汇编底子好,你先玩玩看。
回复

使用道具 举报

ID:378108 发表于 2022-6-30 18:09 | 显示全部楼层
说C看不懂的,就是给自己找理由,C有的概念,汇编都有,
你要愿意,完全可以把C写成汇编
回复

使用道具 举报

ID:283954 发表于 2022-7-29 03:12 | 显示全部楼层
近日有所发现,KEIL4在编译汇编语言的时候,无法发现伪指令ORG所指定的位置会覆盖生成的代码部分,比如:

ORG 0000H ;开头部分
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 ;数据部分(共256字节)
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) ,如果将数值部分(ORG 1700H)部分COMMENT, 编译后
CODE=5926 (1726H),  显然如果包含ORG 1700H 的数值,CODE的后面26H字节会被覆盖, 上载到单片机后会出现意想不到的错误,如果不能警觉这个问题,会DEBUG到晕倒,把 ORG 改为1800H后,一切就正常了,但为什么编译器不会发现问题,没有任何警告呢?
回复

使用道具 举报

ID:624769 发表于 2022-7-29 03:59 | 显示全部楼层
dalaoshi 发表于 2022-7-29 03:12
近日有所发现,KEIL4在编译汇编语言的时候,无法发现伪指令ORG所指定的位置会覆盖生成的代码部分,比如:
...

所以, 如果需要绝对定位的尽量用 CSEG AT 1700H  这样的格式, 尽量不要用 ORG 1700H 这样的格式。
假如不需要绝对定位,就尽量用 RSEG 让KEIL来自动 分配。就不会出现你遇到的问题了。
回复

使用道具 举报

ID:401564 发表于 2022-7-29 06:44 | 显示全部楼层
dalaoshi 发表于 2022-7-29 03:12
近日有所发现,KEIL4在编译汇编语言的时候,无法发现伪指令ORG所指定的位置会覆盖生成的代码部分,比如:
...

STM32搞了个代码生成软件,引脚选好了,就生成代码给你,复制就行,为什么呢?因为ST觉得直接用C语言去写代码太麻烦了,给你点几下鼠标就有代码了
你倒好,觉得C看不明白,倒退回去用汇编
在单片机片上资源越来越丰富的今天,汇编只能不断的放弃自己的江山
玩单片机,会汇编是好事,但并不是说什么都是汇编
而且,不是我说你,你就算是用汇编,但也对汇编并不了解,竟然去怀疑编译器
在你使用了ORG 1700H之后,1700H以前空间都会被使用,不管有没有代码,代码长度都是以ORG 1700H+后面占用的空间为总长度,那么你这个代码总长度就是1700H+所有的DB=1800H
如果你不用ORG 1700H,代码总长度就是你其它代码+DB占用的空间
可以计算出来,你汇编的代码如果没有DB这一部分,长度就是:5670
这么多的代码,估计问题就出在别的地方,要么是这DB部分放在代码中间了,查表的时候也许是指针指过头了,程序就到处跑
回复

使用道具 举报

ID:283954 发表于 2022-7-29 17:53 | 显示全部楼层
Y_G_G 发表于 2022-7-29 06:44
STM32搞了个代码生成软件,引脚选好了,就生成代码给你,复制就行,为什么呢?因为ST觉得直接用C语言去写代码 ...

开始写的时候,把表放在1700H就觉得很够了,后来程序越写也大,终于超过1700H的范围,而编译器编译时没有任何警告,上载后运作就发生异常了,我之所以能比较快意识到这个问题是因为我贴了一段新代码在最末尾,运作时发现该代码没有运作,将该段代码转到中间部分,再运行时该代码就有运作了,这才发现问题所在,为了让其他用汇编的网友警觉,就贴上来分享了。

C语言的确强大和省事,但只会用C语言永远不可能玩出D,F,G。。语言的。
回复

使用道具 举报

ID:883242 发表于 2022-7-29 18:50 | 显示全部楼层
dalaoshi 发表于 2022-7-29 17:53
开始写的时候,把表放在1700H就觉得很够了,后来程序越写也大,终于超过1700H的范围,而编译器编译时没有 ...

编译的时候绝对不可能报错或者警告的,如果你了解编译连接过程的话。如果要警告,那也是BL51.exe连接器给出警告。
回复

使用道具 举报

ID:401564 发表于 2022-7-29 19:16 | 显示全部楼层
dalaoshi 发表于 2022-7-29 17:53
开始写的时候,把表放在1700H就觉得很够了,后来程序越写也大,终于超过1700H的范围,而编译器编译时没有 ...

这本身就是你的问题呀
编译器只会执行你的代码,它只会识别语法和硬件上的错误,比如RAM使用过头了,或者是少了个逗号没写
至于代码本身的逻辑问题,它是不会有什么警告的
汇编只有在个别极限要求下,比如时序严格到一个时钟,或者是内存实在太小的情况下,还有优势
其它的,什么所谓效率,了解硬件的.......一点优势都没有
玩单片机的,只会C不会汇编的人,大有人在,你敢说他们的技术都是在你之下?
严格遵循C语言规范写出来的程序,不见得比汇编差
不知道你玩不玩王者
汇编只作为一个BUFF,有BUFF你就打得过人家?
我之前就是用汇编的,现在基本就是只要能用C的,绝对不用汇编,连都不想看一眼
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表