结果左对齐,可以看到,结果输出明显大了很多。
2、定时器模块的学习和测试 在开始学习和测试MDU模块之前,先来学习一下定时器模块,便于后面测试MDU指令执行的时间,这里以TIM3定时器为例来学习和研究。
TIM3和TIM4定时器可以作为输出和输入定时器使用,我们这里考虑到用来计数或计时使用,所以就是用了定时器最基本的功能。选择TIM3是因为它在作为输入捕获定时器使用的时候支持48MHz的计数频率,应该感觉比较准。
1) 定时器的初始化
我们就用来计时,所以采用最快的48MHz计数,所有不必要的中断全部关闭。
/*---------------------------------------------------------------------------*/
/* Name : void Timer3_Init(void)
/* Input : NO
/* Output : NO
/* Description: Timer3的参数设置
/*---------------------------------------------------------------------------*/
void Timer3_Init(void)
{
SetBit(PH_SEL, T3SEL); //Timer3端口使能
ClrBit(PH_SEL1, T3CT); //默认端口为P11,功能转移后为P01,需TIMER4转移到P00
//TIM3 输入timer模式,111对应48MHz
SetBit(TIM3_CR0, T3PSC2); //计数器时钟分频选择
SetBit(TIM3_CR0, T3PSC1); //000-->24M 001-->12M 010-->6M 011-->3M
SetBit(TIM3_CR0, T3PSC0); //100-->1.5M 101-->750K 110-->375K 111-->187.5K
ClrBit(TIM3_CR0, T3OCM);
ClrBit(TIM3_CR0, T3IRE); //比较匹配中断/脉宽检测中断0-->Disable 1-->Enable
ClrBit(TIM3_CR0, T3OPM); //0-->计数器不停止 1-->单次模式
//这里只取计数器的计数值,所以不需要中断了
ClrBit(TIM3_CR1, T3IPE); //输入Timer PWM周期检测中断使能 0-->Disable 1-->Enable
ClrBit(TIM3_CR1, T3IFE); //计数器上溢中断使能 0-->Disable 1-->Enable
ClrBit(TIM3_CR1, T3NM1); //输入噪声脉宽选择
ClrBit(TIM3_CR1, T3NM0); //00-->不滤波 01-->4cycles 10-->8cycles 11-->16cycles
ClrBit(TIM3_CR0, T3MOD); //0-->Timer模式 1-->输出模式
//手册中规定,定时器的计数值需要在停止计数时读取,否则低位无法读取
// SetBit(TIM3_CR1, T3EN); //TIM3使能 0-->Disable 1-->Enable
}
2) 计时方式
oldt = newt ;
//使能计数
SetBit(TIM3_CR1, T3EN); //TIM3使能 0-->Disable 1-->Enable
//被测试部分代码
。。。。。
//禁止计数
ClrBit(TIM3_CR1, T3EN); //TIM3使能 0-->Disable 1-->Enable
newt = TIM3__CNTR;
//计算实际的计数差,确定执行时间
if(newt >= oldt)
IntToHex(str,newt-oldt);
else
IntToHex(str,65536-oldt+newt);
//打印到串口终端
put_string("tim3=");
put_string(str);
put_string("nr");
通过测定两次计时器的计数值来准确计算代码执行部分使用的时间。这里面应该会包含禁止计数器计数指令所包含的时间,这个时间误差可以考虑通过不同方式的多次测量来消除误差。
3) 试验验证
第一次, 被测部分代码为:
GP44 = 0;
for(PowerUpCnt = 0; PowerUpCnt < 10; PowerUpCnt++) ;
file:///C:UsersADMINI~1AppDataLocalTempmsohtmlclip1\01clip_image012.jpg
计数差为0x013B,计算时间为0x013B/48M = 6.5625*10e-6 = 6.5625微妙
第二次,我们改变被测部分
GP44 = 0;
for (PowerUpCnt = 0;PowerUpCnt < 5; PowerUpCnt++) ;
file:///C:UsersADMINI~1AppDataLocalTempmsohtmlclip1\01clip_image014.jpg
计数差为0x00A5,计算时间为0x00A5/48M = 3.4375*10e-6 =3.4375微妙
3、MDU模块的学习和测试1)概述
官方文件中是这样描述MDU模块的,MDU 是一个计算协处理单元,主要协助单片机完成大数据量的复杂运算。MDU 除了提供乘除法运算外,还提供三角函数和低通滤波器的运算。在实际使用中,MDU 模块可以在中断程序和主程序调用而计算结果互不干扰。 通过这段描述,我们可以知道,厂家为了实现基于51内核的电机控制,特定的设置这样一个硬件加速器,完成乘除法运算、三角函数运算和低通滤波运算。
MDU的特性:
⚫ 支持中断嵌套调用
⚫ 硬件加速,减少 CPU负担
⚫ 支持以下运算模式
- 16位有符号乘法
- 16位有符号乘法(左移1 位)
- 16位无符号乘法
- 32位/16位的无符号除法
- 低通滤波器(LPF)
- 坐标转换(sin/cos)
- 反正切(Atan)
2)操作方式
手册中描述,一个完整的MDU 操作流程应包含如下步骤:
1. MDU_CR的启动 MDU 运算 (MDURUN)位置 1
2. 配置MUD_MD寄存器,选择 MDU的运算模式
3. 写入数据到 MDU_A、MDU_B、MDU_C、MDU_D,当 MDU 检测到 MDU_C[7:0]被写入数据时开始运算
4. 等待 MDU_CR 的MDU繁忙(MDUBUSY) 位置0
5. MDU_CR的终止 MDU 运算(MDUDONE) 位置1
3) 下面测试MDU提供的几种数学运算的使用和执行时间
我了保证执行时间的准确性,我们采取循环多次取平均的方式反映实际的运算时间。
1. 16位有符号乘法
/*-------------------------------------------------------------------------------
有符号乘法 -- MuiltS_MDU
------------------------------------------------------------------------------*/
for (PowerUpCnt = 0; PowerUpCnt < 10; PowerUpCnt++)
MuiltS_MDU(0x4567, 0x4321,INT16_DataH,INT16_DataL);
file:///C:UsersADMINI~1AppDataLocalTempmsohtmlclip1\01clip_image016.jpg
file:///C:UsersADMINI~1AppDataLocalTempmsohtmlclip1\01clip_image018.jpg
计算结果的对比是正确的,时间为0x030F/48MHz/10= 1.63微妙
2. 16位有符号乘法(左移1位)
/*-------------------------------------------------------------------------------
有符号乘法,结果左移一位 -----> MuiltS1_MDU
---------------------------------------------------------------------------*/
for (PowerUpCnt = 0; PowerUpCnt < 10; PowerUpCnt++)
MuiltS1_MDU(31540,425,INT16_DataH,INT16_DataL);
file:///C:UsersADMINI~1AppDataLocalTempmsohtmlclip1\01clip_image020.jpg
file:///C:UsersADMINI~1AppDataLocalTempmsohtmlclip1\01clip_image022.jpg
计算结果的对比是正确的,时间为0x030F/48MHz/10= 1.63微妙
3. 16位无符号乘法
/*-------------------------------------------------------------------------------
无符号乘法 -----> Muilt_MDU
------------------------------------------------------------------------------*/
for (PowerUpCnt = 0; PowerUpCnt < 10; PowerUpCnt++)
Muilt_MDU(0x597,0x4321,INT16_DataH,INT16_DataL);
file:///C:UsersADMINI~1AppDataLocalTempmsohtmlclip1\01clip_image024.jpg
file:///C:UsersADMINI~1AppDataLocalTempmsohtmlclip1\01clip_image026.jpg
计算结果的对比是正确的,时间为0x030F/48MHz/10= 1.63微妙
4. 32位除16位无符号除法
1) 求商运算
/*-------------------------------------------------------------------------------
32Bit/16Bit无符号除法----求商 -----> DivQ_MDU
-------------------------------------------------------------------------------*/
for (PowerUpCnt = 0;PowerUpCnt < 10; PowerUpCnt++)
DivQ_MDU(0x1234,0x5678,0x04,INT16_DataH,INT16_DataL);
file:///C:UsersADMINI~1AppDataLocalTempmsohtmlclip1\01clip_image028.jpg
file:///C:UsersADMINI~1AppDataLocalTempmsohtmlclip1\01clip_image030.jpg
计算结果的对比是正确的,时间为0x0431/48MHz/10= 2.235微妙
2) 求余数运算
/*------------------------------------------------------------------------------
32Bit/16Bit无符号除法----求余数 -----> DivR_MDU
------------------------------------------------------------------------------*/
for (PowerUpCnt = 0; PowerUpCnt < 10;PowerUpCnt++)
DivR_MDU(0x1234,0x5678,0x04,INT16_DataH);
file:///C:UsersADMINI~1AppDataLocalTempmsohtmlclip1\01clip_image032.jpg
经计算余数为了0,时间为0x03B9/48MHz/10= 1.985微妙
5. 坐标转换
/*------------------------------------------------------------------------------
Sin/Cos计算与坐标转换 -----> SinCos_MDU(iCos0,iTheta, iSin0, iCos, iSin)
-------------------------------------------------------------------------------*/
for (PowerUpCnt = 0;PowerUpCnt < 10; PowerUpCnt++)
SinCos_MDU(0x1234,45,0x2134,INT16_DataH,INT16_DataL);
file:///C:UsersADMINI~1AppDataLocalTempmsohtmlclip1\01clip_image034.jpg
坐标变换公式:
file:///C:UsersADMINI~1AppDataLocalTempmsohtmlclip1\01clip_image036.jpg
可以计算得到:
45换算为角度:45/32767*180 = 2.47
Sin0 = 0x1234*sin2.47 +0x2134*cos2.47 = 8692=0x21F4,
Cos0= 0x1234*cos2.47 -0x2134*sin2.47 = 4290=0x10C2,
这个的计算结果有点偏大了,不知道怎么回事。希望批评指正。
时间为0x0431/48MHz/10 = 2.235微妙
6. 反正切
/*----------------------------------------------------------------------------------
角度计算 -----> Atan_MDU
幅值计算 -----> Atan_MDU
------------------------------------------------------------------------------*/
for (PowerUpCnt = 0;PowerUpCnt < 10; PowerUpCnt++)
Atan_MDU(0x1234,0x2134,INT16_DataH,INT16_DataL);
file:///C:UsersADMINI~1AppDataLocalTempmsohtmlclip1\01clip_image038.jpg
幅值的计算公式:
file:///C:UsersADMINI~1AppDataLocalTempmsohtmlclip1\01clip_image040.jpg
可以计算得到iUs = √0x12342+0x21342 = 9693 =0x25DD 计算结果与现实基本相同。
角度计算为
iTheta = tan-1(sin/cos) = tan-1(0x2134/0x1234) = 61.266度
换算为16进制有符号数为
iTheta = 61.266*32767/180 = 11153=0x2B91 计算结果与现实相符。
时间为0x03F5/48MHz/10 = 2.11微妙