水水水木木木
发表于 2025-9-3 10:43:05
ercircle 发表于 2025-9-3 10:41
没有用库。我用库试一下。
ercircle
发表于 2025-9-3 10:46:22
水水水木木木 发表于 2025-9-3 10:43
没有用库。我用库试一下。
官网下载最新版本:
https://www.stcaimcu.com/data/download/Library/STC8_MDU16.LIB
水水水木木木
发表于 2025-9-3 10:58:16
示例中少了下面的三个定义。
#define MD1U16 (*(unsigned intvolatile xdata *)0xfcf2)
#define MD5U16 (*(unsigned intvolatile xdata *)0xfcf4)
#define MD3U32 (*(unsigned long volatile xdata *)0xfcf0)
但是就算这样,实际用示波器测量,和软件直接算没区别。总中断函数执行时间是13us左右,去掉这个乘法是3.5us左右。也就是乘法用了10us左右。硬件和软件需要的时间是差不多的。
代码如下:
MD1U16 = SWING_HW;
MD5U16 = M_q15;
ARCON = 4 << 5;
OPCON = 1; //启动硬件乘法器
while((OPCON & 1) != 0);
half_cmd = MD3U32 >> 15;
其中SWING_HW和M_q15都是uint16。实测确实是需要10us的时间。
我再用库试一下,看看咋样。
水水水木木木
发表于 2025-9-3 11:07:37
添加了MDU16的硬件库后,再执行这个代码,没效果啊。和软件算是一样的时间。
half_cmd = ((int32_t)SWING_HW * (uint16_t)M_q15) >> 15;
是不是因为运算过程中保留了32位的数据长度,而标准的运算是16*16只保留16位的长度?
上面这个运算,应该是32位*16位,所以没用调用内部的硬件乘法?那如果我想保留16*16的结果,不要截断为16位。应该怎么操作呢?
上面这种运算需要的时间比用寄存器操作慢1us左右。实测是15us左右。
如果16*16位变量运算的话,运算结果溢出就被截断了。正常做法就是添加uint32,表示按照32位长度保存结果。那是不是就不会触发内部硬件MDU16乘法操作了?还是说需要其他配置?
水水水木木木
发表于 2025-9-3 11:20:15
ercircle 发表于 2025-9-3 10:46
官网下载最新版本:
https://www.stcaimcu.com/data/download/Library/STC8_MDU16.LIB
实测了。还是10us多。可能是因为需要保留32位数据长度导致没有使用硬件乘法。比寄存器操作还慢1us。是不是要换成AI8051U?或者您有时间也可以测试一下,直接用这个语句测试就行。
水水水木木木
发表于 2025-9-3 11:36:33
ercircle 发表于 2025-9-3 10:46
官网下载最新版本:
https://www.stcaimcu.com/data/download/Library/STC8_MDU16.LIB
我将int32去掉了,实测是4.5us。确实快了很多。代码如下。
half_cmd = (SWING_HW * M_q15) >> 15;
我再将int32加上看看。下面这个语句的执行时间就是15us左右。这里的时间是我整个中断的时间,还有其他语句。单独这个语句的时间应该在10us左右。上面16*16位运算单语句估计只要1us左右。16*16速度快很多。这是添加了硬件库后的结果。
half_cmd = ((int32_t)SWING_HW * M_q15) >> 15;
ercircle
发表于 2025-9-3 11:36:54
水水水木木木 发表于 2025-9-3 11:20
实测了。还是10us多。可能是因为需要保留32位数据长度导致没有使用硬件乘法。比寄存器操作还慢1us。是不 ...
我测试手册例程16位乘以16位取32位结果只需要3.75us@11.0592MHz,可以发下您的测试程序吗?
#include <STC8H.H>
#include <def.H>
#include <stdio.H>
void Delay10us(void) //@11.0592MHz
{
unsigned char data i;
i = 35;
while (--i);
}
void main()
{
////////////////////////////////////////////////////////////////////////////////
//16 位乘 16 位
////////////////////////////////////////////////////////////////////////////////
unsigned long res;
unsigned int dat1, dat2;
P_SW2 |= 0x80;
P2M1 = 0; P2M0 = 0; //设置为准双向口
P20 = 1;
Delay10us();
P20 = 0;
Delay10us();
P20 = 1;
//访问扩展寄存器 xsfr
MD1 = dat1;
//dat1 用户给定
MD5 = dat2;
//dat2 用户给定
ARCON = 4 << 5;
//16 位*16 位,乘法模式
OPCON = 1;
//启动计算
while((OPCON & 1) != 0);
//等待计算完成
res = MD3;
P20 = 0;
//32 位结果
//////////////////////////////////////////////////////////////////////////////////
////32 位除以 16 位
//////////////////////////////////////////////////////////////////////////////////
//unsigned long res;
//unsigned long dat1;
//unsigned int dat2;
////访问扩展寄存器 xsfr
//MD3U32 = dat1;
////dat1 用户给定
//MD5U16 = data2;
////dat2 用户给定
//ARCON = 6 << 5;
////32 位/16 位,除法模式
//OPCON = 1;
////启动计算
//while((OPCON & 1) != 0);
////等待计算完成
//res = MD3U32;
////32 位商,16 位余数在 MD5U16 中
//////////////////////////////////////////////////////////////////////////////////
////左移或右移:
//////////////////////////////////////////////////////////////////////////////////
//unsigned long res;
//unsigned long dat1;
//unsigned char num;
////移位的位数, 用户给定
//MD3U32 = dat1;
////dat1 用户给定
//ARCON = (2 << 5) + num;
////32 位左移模式
////ARCON = (1 << 5) + num;
////32 位右移模式
//OPCON = 1;
////启动计算
//while((OPCON & 1) != 0);
////等待计算完成
//res = MD3U32;
////32 位结果
while(1);
}
ercircle
发表于 2025-9-3 11:38:59
水水水木木木 发表于 2025-9-3 11:36
我将int32去掉了,实测是4.5us。确实快了很多。代码如下。
half_cmd = (SWING_HW * M_q15) >> 15;
我再将 ...
注意keil选项里编译等级也会影响这个速度
水水水木木木
发表于 2025-9-3 11:41:50
ercircle 发表于 2025-9-3 10:46
官网下载最新版本:
https://www.stcaimcu.com/data/download/Library/STC8_MDU16.LIB
所以是不是要换支持MDU32的单片机?支持MDU32的单片机型号不多,最强大的应该是STC32G和AI8051U了吧?为了兼容32位和8位,显然AI8051U最好?
水水水木木木
发表于 2025-9-3 11:45:00
ercircle 发表于 2025-9-3 11:38
注意keil选项里编译等级也会影响这个速度
8051还能优化啊。这我第一次知道。这个等级一般建议多少?7级吗?我是默认的0级测试的。你用我的语句测试,用硬件库这种。
half_cmd = ((int32_t)SWING_HW * (uint16_t)M_q15) >> 15;