幸运时时彩平台

干货

数字接口 开环 stm32F4+l6205步进电机驱动(待续)

分类名:经验日期:2020-05-23作者:huo_hu 阅读原文

本帖最后由 huo_hu 于 2020-6-11 12:56 编辑

此内容由EEWORLD论坛网友huo_hu原创,如需转载或用于商业用途需征得作者同意并注明出处

本教程制作一款stm32f4驱动的l6205步进电机程序,带有变细分控制;自动力矩调整;速度实时更新;加速度力矩补偿;掉电芯片保护;自动步值到位等功能。L6205具有体积小电路简单的优点,并且有插装的型号很适合学习用。设计倾向于针对特定的电机进行优化,性能和可扩展性比一般驱动器强很多。本次从0开始一步一步给大家详细介绍和讲解,不当之处欢迎指正,文章所设计的文字和代码请勿用于商业目的。

 

第一部分 硬件

幸运时时彩平台本设计用到的是stm32f407的最小系统板,其它f4的系统板应该都可以,需要定时器1的6个通道管脚,和一个刹车管脚,原理图如下图

原理图可以参照l6205的手册,需要说明几点:

幸运时时彩平台1.和stm32管脚连接部分,INA1和2接高级定时器1的通道1 C1和C1N,INB1和2接C2和C2N,ENA和ENB接C3,C4,ENAB之所以接通道管脚有这么两个原因,一个是电机运行到高速时切换到EN输出效果比较好,另外定时器的通道管脚受刹车位控制可以迅速切换到无效电平起保护作用。这7条线加个限流电阻再送stm32更好些,接高级定时器8也可以软件上稍不同。

2.右边部分是一个倍压升压电路,D1 D2为1N4148的快速二极管,如果芯片正常L6205上电以后会从VCP管脚输出一个幅值11V左右200KHz的方波,经过C1电容隔离和C2滤波以后在VBOOT管脚会有一个比VCC高10V左右的直流电压(二极管有压降),判断芯片是否正常可以先测量这个电压是否满足要求。这个电压是给H桥的上桥臂的两个mos管门级供电的。

3.CF1和CF2是储能电容,视工作电流而定,尽量大一点效果好。D3为整流二级管防止倒灌,D4为发光二极管蓝色或绿色比较好,作用是利用正向压降将VCC降低到stm32的逻辑电压,也可用2.5V的稳压二极管(要反接),R2根据VCC的实际值计算,尽量大些防止往stm32灌电流,最好在二极管上并个电阻到地防止二极管损坏高压烧毁stm32。这部分电路目的是提供一个掉电保护电平送到定时器的刹车输入端。一个极端的情况会烧坏l6205芯片就是在电机运转时(ENA和B处于使能的状态)突然切断电源供电,这时储能电容不足以提供给电机运转导致VCC迅速下降,而VBOOT的电压基本维持不变造成上桥臂的过压烧毁。正常上电工作后T1_BreakIn为高电平,在切断电源供电时T1_BreakIn第一时间会呈现低电平,再通过stm32定时器的配置失能ENAB的输出就可以起到保护芯片的作用。

4.布线时地接入端尽量靠近芯片,手册上有提到。

5.另外在后面制做力矩表时有个电流检测,我用的是max4080用消耗电流估算电机力矩值,有兴趣的可以加上,max4080的输出接stm32的adc输入口就行了。

 

第二部分 配置tim1查表法运行

当前版本cbue 5.6.1fw 1.25.0 keil 5。24 建立最小系统,过程...

注意这里最好使用外置晶振HSE,内步HSI抖动很厉害,效果不好。

 

1:定时器1内部时钟,通道1 1N 2 2N 3 4 pwm输出,使能Break(用其它管脚也可以)

2:中央对齐模式

3:通道pwm模式2,关闭预装载,通道极性低电平

4:通道3,4也一样设置

5:使能溢出中断

6:关闭默认的中断服务,自己编写中断服务程序

7:定时器用到的管脚全部下拉,TIM1GPIO Settings里操作也可以

8:定时器使用LL库,hal库也行,冗余的东西有点多,因为大多数地方都用的寄存器操作,所以hal库意义不大。

9:点GENERATE CODE建立keil v5工程,添加目录(后面所有涉及的程序代码都在这个目录下),添加组添加代码,main.c里加头文件,调初始化函数。具体参看一下附件1,不截图了。

附件1:查表输出电机正反转

10:取消stepmotor.h里的最后一行注释,编译下载,用示波器验证一下以下内容

第一个程序会从PE8,PE9C1C1N) PE10,PE11C2C2N) 轮流输出32个变化占空比的pwm波,C1输出完切换到C1N输出。

PE13PE14输出高电平。

PE15悬空或接低电平正常输出,PE15接高电平以后所有通道均输出低电平。

验证没有问题后注释掉stepmotor.h里的最后一行

//#define BREAK_POLARITY_FORDEBUG

编译,接通VCC电源和电机(安全起见推荐12V我这边是42的电机),下载运行,应该会看到电机转动,测一下电流电机空载几十毫安就可以正常转动。

 

再说明几点:

首先是关于刹车控制位,正常情况输入的是高电平,低电平为故障状态,附件1的程序对刹车位置反以允许L6205不上电输出pwm波做调试,调试完后再恢复之前的设置。

刹车位设置好极性以后会在低电平到来的第一时间切断所有通道的输出状态,此后不管通道值如何设置所有输出都是低电平,这部分是硬件触发的,不需要软件参与,所以也没有再开刹车中断操作。之后的运行因为考虑到电机已经失去控制,步值和速度状态已经不对了,应该将之前的所有设置和状态都清除,不再做改变只等待再次开机指令。这部分清除工作放在poweroff函数里以后添加现在是空的。

DBTR寄存器的MOE位是控制所有通道输出的,置位后开始输出,当Breakin管脚低电平时自动清除即关闭输出,此后当Breakin高电平时通过软件置位MOE并且才能再次开启输出,如果不满足条件置位不会成功。DBTR寄存器里有个AOEauto output)位,意指MOE位的置位跟随Breakin输入管脚,即Breakin高电平后即自动置位MOE开启通道的pwm输出,这个AOE位置1可以实现跟随Breakin状态自动输出,但是后面做指令强制关机时要注意关机时清除AOE否则又再次开机输出了。

还有一个是poweron 函数,这里考虑到系统上电初期的初始化动作会比较复杂,可能需要根据实际情况添加部分代码。比如一个滑台控制系统,刚上电时并不知道电机的初始位置在哪里,通常滑台都有行程开关,上电后开始向固定方向运动以触发行程开关的信号,此后电机的真实位置才能确定,这部分操作需要自己编写代码实现,因此单独的构建一个poweron函数完成这部分功能。另外Poweron函数应该能保证不复位的情况下关机以后再次开机,以实现指令开关机,所以置通道34输出高电平,开始输出力矩,初始化位置等都放在这个函数里。

关于软件最重要的就是定时器的溢出中断服务,我全贴上来

uint32_t M1_Step=0;

const uint16_t SPWM_Table[64] = { //M=1 N=32 C=16384 锯齿波数据共64

412,1236,2056,2870,3678,4476,5262,6034,6792,7531,8251,8950,9626,10278,10903,11500,12068,

12606,13112,13585,14023,14427,14794,15125,15418,15673,15890,16068,16206,16305,16364,16384,

16364,16305,16207,16071,15896,15683,15434,15148,14827,14471,14082,13660,13206,12722,12208,

11667,11099,10505,9888,9248,8587,7906,7208,6493,5764,5022,4269,3506,2735,1958,1176,392

};

 

#define N_SIZE 64 //

void TIM1_UP_TIM10_IRQHandler(void) {

LL_TIM_ClearFlag_UPDATE(TIM1);

if (TIM1->CR1 & TIM_CR1_DIR) {//关点输出完毕,开始输出开点

/*设置极性*/

TIM1->CCER &= ~(TIM_CCER_CC1E|TIM_CCER_CC1NE|TIM_CCER_CC2E|TIM_CCER_CC2NE);

if (M1_Step & N_SIZE) {

TIM1->CCER |= TIM_CCER_CC1E;//A+

if ((uint32_t)M1_Step & N_SIZE/2)

TIM1->CCER |= TIM_CCER_CC2E;//B+

else

TIM1->CCER |= TIM_CCER_CC2NE;//B-

} else {

TIM1->CCER |= TIM_CCER_CC1NE;//A-

if (M1_Step & N_SIZE/2)

TIM1->CCER |= TIM_CCER_CC2NE;//B-

else

TIM1->CCER |= TIM_CCER_CC2E;//B+

}//设置极性end

//输出开点pwm

M1_Step++;

TIM1->CCR1=SPWM_Table[~M1_Step&(N_SIZE-1)]/2;

TIM1->CCR2=SPWM_Table[(~M1_Step+(N_SIZE/2))&(N_SIZE-1)]/2;

} else {

//输出关点pwm

TIM1->CCR1=SPWM_Table[M1_Step&(N_SIZE-1)]/2; //2是半力矩输出

TIM1->CCR2=SPWM_Table[(M1_Step+(N_SIZE/2))&(N_SIZE-1)]/2; }

}

 

因为定时器设置成中央对齐模式,所以这个溢出update包括上溢和下溢,用TIM1->CR1  TIM_CR1_DIR 位来区分,关于计数值的变化stm32手册上有说明。上面的示波器看到每半个正弦周期输出的是32pwm波实际上是64次溢出更新通道值的结果。

中断服务程序里分为三大块:输出极性(即选择11N  22N输出),步值前进,查表输出。

查表里面有几个逻辑运算得到表地址,赋值最后的/2是输出正弦满幅值的一半,目的是怕电流太大起个保护作用,&(N_SIZE-1)即与63保证在数据表内,开点和关点的区别是从前往后还是从后往前,所以有个~操作,A相输出即CCR1B相输出即CCR2的差别是相差半个表所以+32,列出AB开关的序列就清楚了。

Step  0  1  2  ...  31  32  33  ...  61  62  63  0

A开   63    62    61     。。。          33       32       31      。。。         2          1         0        63

B开   31   30     29     。。。         1          0         63      。。。          34      33       32       31

A关   0      1       2       ...         31       32       33      ...          61      62        63       0

B关   32   33     34     。。。          63      0          1       。。。           29     30        31       32

  步值前进就一句M1_Step++;如果改成M1_Step--;其它部分都不动你就会看到电机朝相反的方向转。--就是步值后退喽。如果改成M1_Step+=2;你会看到转速加倍。

  再有就是极性输出,因为我们不设定每次步值前进的位数,所以每次输出完关点的pwm就执行一次更新,上来清除所有的输出(11N,22N)再根据条件设置。每输出完一次表数据即翻转一次所以M1_Step&64A相的输出极性,A极性正就从C1输出,A极性负就从C1N输出即可以写成

if (M1_Step & N_SIZE) {

TIM1->CCER |= TIM_CCER_CC1E;//A+

} else {

TIM1->CCER |= TIM_CCER_CC1NE;//A

然后是B相的极性,B的极性落后A半周所以用(M1_Step & N_SIZE/2)来确定,根据A的正负再取一次反即上面程序的写法。A B极性的真值表列出来就好理解了,B的极性就是两个位的异或。

Step   00  01  10  11

 A+   + + - -

 A-   - - + +

 B+   + - - +

 B-   - + + -

最后是这三大部分的逻辑关系,细心的读者可能会有疑问,先出极性再步进的顺序不对啊,这里我仔细验证过,极性设置是带缓冲的,要到下一个周期溢出时才会更新,所以没问题。另外说一下定时器设置时关闭了预装载是个条件,如果开启预装载pwm输出会再延后一个周期,程序要改。

这个查表程序完全围绕着一个M1_Step变量展开,这个变量是程序的核心,之所以叫M1是打算以后用Tim8再控制一个电机叫M2。

这个程序之后我们计算一下当前的转速,后面会用到:

和转速有关的变量有这么几个:

定时器的时钟源频率T=168M

当前细分度N=32,即半个正弦周期的三角波数量也就是半周期pwm波个数(表内数据64个数据是锯齿波,2个锯齿波拼凑一个三角波);

定时器溢出回0周期ARR=16384

如果用正弦频率做单位算式为SPEED=T/2/ARR/N=T/2/(ARR*N)实际应用时HZ单位太大精度不够,再放大100倍用宏函数表示为

#define TIME_CLK 168 //定时器时钟频率MHZ

#define GET_TIMECYCLE(vv) (((uint64_t)TIME_CLK*1000*1000/2*100)/vv)

如果参数vv=ARR*N的值,则运算出正弦频率HZ*100,如果参数vv=正弦频率HZ*100则运算出ARR*N的值;用64位数据运算保证精度,vv可以是32位数据类型。

计算结果程序当前正弦频率=168000000/2*100/16384/32=16024=160.24HZ

因为200步电机走完100个周期电机转一圈,所以160.24HZ/100=1.6024/秒;1.6024*60=96.144/分钟。(HZ单位*100/60即换算成转/分钟)

这部分为后面做个铺垫。

 

最后再做一个扩充(和电机控制没有关系),实际上上面的程序步进值可以是任意值,每次步进的大小就是转速。我们稍加改动就可以做一个码盘同步的控制器,转动编码器时电机跟着转并保持固定的比例(1:1)。用另外一个定时器工作在编码器模式,此后这个定时器的CNT直接和位置相关,这部分有逻辑控制不需要软件参与。然后把这个CNT按一定的比例赋值给T1_Step就可以实现随动功能。理论上只要每次赋值的步差值不超过一个细分度就不会丢步,定时器的溢出速度足够快(约5.1K),可以保证这一点。

 

视频链接:http://bbs.sonata9.com/forum.php?mod=attachment&aid=MzE2MTMyfDVmMzNjMWVifDE1OTEwNzUxODh8MzYyNDE2fDU0ODUzNQ%3D%3D

效果和这个一样,没有再从新录制

 

首先编码器的A B相输出接定时器的通道12,编码器需要供电3.3V和地,需要看编码器手册确认一下,有的不支持3.3V但基本都是开漏输出。Cube配置定时器工作在编码器模式,这里选用定时器4,滤波功能既然有设一下不浪费,用cube设置成编码器模式非常简单:

管脚输入上拉。

定时器同样使用LL库,略

 

StepMotor_Init函数最后加一句启动定时器4

SET_BIT(TIM4->CR1, TIM_CR1_CEN);

码盘同步算式:码盘一圈计数8000; 正弦100个周期对应电机转动一圈step计数值增加100*64*2;

中断服务里用这句替换M1_Step++;

M1_Step=(uint32_t)TIM4->CNT*(32*2)/80;

下载运行...这里的最后说明一下当码盘转动过快时可能有丢步的现象,原因不是stm32反应不及时,而是电机高速转动时输出一半的力矩不足造成的(大力矩时静止状态损耗偏大)。

最后结束第二部分时提醒大家一下,电机的工作电流除了和L6205的驱动电压有关系以外和电机的相电阻有关系,电机的转动起来以后力矩会下降,下降的程度和相电感有关系,在实验时最好串个电流表观测电流,不要长时间大电流工作。L6205有过热保护,电流超过200ma最好加散热片。

 

第三部分 按正弦幅值对称输

  因为用到正弦运算,所以keil 里添加dsp库:

然后点OK

ISR.c中添加头文件:

#define ARM_MATH_DSP //ARM_MATH_CM4

#include "arm_math.h"

#include "stdlib.h"

老版本宏名称为ARM_MATH_CM4stdlib.h包含了绝对值函数。

接下来要规划几个变量:

M1_Step同样是电机1的记步变量,用int64_t 定义即带符号的64位数据,另外宏定义#define HALF_SINCYCLE_VALUE 0x40000000u即一个正弦周期对应的幺1值为0x80000000uM1_Step每加或减一个此数值调制输出走完一个正弦周期。相对应的AB相极性判断条件修改为(uint32_t)M1_Step & HALF_SINCYCLE_VALUE (uint32_t)M1_Step & HALF_SINCYCLE_VALUE/2

与之对应的是步进量int32_t M1_HalfStepAcc,设定转速时有

M1_HalfStepAcc=(int32_t)dir*(HALF_SINCYCLE_VALUE/n/2);dir是方向1正转-1反转,步值前进时M1_Step+=(int64_t)M1_HalfStepAcc *2就行了。

M1_M为输出正弦波的幅值,约定65536为满幅值1,数值越大电机输出力矩越大。

M1_N为电机的细分度,即半个正弦周期三角波的个数。

M1_Arr为定时器的计数周期值,每次溢出中断里更新TIM1->ARR = (M1_Arr-1);此数值应该小于65535并且不能太小,太小的周期值设定会造成中断无法响应。占空比计算及速度设定和此数值相关,理论上通道占空比的设定值不应大于此数值,实际情况大于时输出有效电平。

现在需要计算每个步值的占空比:

图为一个正弦周期中的第n个三角波,紫色线为正弦波,我们假设细分度足够大,此时正弦线可以近似为直线,所以左右对称。前面约定了半个周期数值则细分度为N时一个pwm周期为0x40000000/N这个数也是一次步进的数值StepAcc。第n个三角波的X点坐标(图中P点)为(n+0.5*StepAcc n=0,1,2,3....),线段Y点坐标为sin((n+0。5*StepAcc)。图中可以看出线段L在幅值中所占的比例和待求值与ARR的比例相等,所以Y点坐标*ARR的数值即为占空比数值。

sin((n+0.5*StepAcc*M1_Arr

程序中使用了整数正弦运算arm_sin_q31,函数参数0~0x40000000对应0~π(实际是0~0x80000000对应0~2π),返回值0~0x80000000对应正弦计算结果0~1

arm_sin_q31((int32_t)M1_Step);   M1_Setp变量舍去高32位视为X值即半周期的相位值进行运算。返回值/0x80000000对应正弦计算结果0~1,再乘M1_M/65536为设定的正弦幅值(约定M1_M=65536代表幅值1),再乘定时器周期值M1_Arr即为占空比数值。整数运算如果先除就除成0了,所以调整运算顺序先做乘法,最后变成下面语句:

si=arm_sin_q31((int32_t)M1_Step);

si=(uint64_t)(abs(si))*M1_M/65536*M1_Arr/0x80000000;

M1_CalDat函数每次前进半个步值,然后计算,计算后再前进半个步值。半个步值就是上面式中的0.5StepAcc

上述是步进电机A相的占空比计算,B相和A相相差90度相位,所以可以用余弦的绝对值来计算即上面语句正弦替换为余弦就是B相占空比数值。再进一步dsp中有一个正弦余弦同时运算的函数arm_sin_cos_q31,所不同的是参数里有两个指针,计算后指针内容即结果。

程序里添加了对细分值修改的函数,调试界面手动修改M1_ReSetting_N即可看到转速变化,负数即反转。

实际运行时小力矩低转速有步值位移量不均匀的情况,经过分析是mos管开关有延时造成的,过短的pwm不能开启mos管做输出。所以每个占空比加增加一个补偿量即可达到很好的效果,补偿量就是在。h#define SWITCH_DELAY定义的数值。

视频细分度=50000,每分钟0。064米外激光笔运动情况:

附件:对称正弦幅值输出

 

第四部分 非对称的迭代运算

     上面那个对称输出的方法也可以适应中等速度运转,但是有个问题无解,就是A相数据和B相数据不完全相同,这种差异是运算误差造成的,根本原因是N偏小时整数运算精度不够即

    M1_HalfStepAcc=(int32_t)pdir*(HALF_SINCYCLE_VALUE/pn/2);pn为细分度设置
这句做整数运算时舍弃掉了一部分数据,细分度越小偏差越大。虽然可以在软件中加入代码修正每个周期的偏差,但是当细分度变化时情况会比较复杂不容易处理,百分之百的按理论值输出是不可能的。用迭代计算求解也不能解决这个问题,唯一的办法是对算法进行改进,需要对细分度的设置做出限定:N=2的整数次幂,此时计算是没有误差的。我们先做出这个约定,在下一部分“调速”里再用软件来实现。
  接下来看迭代计算,所谓迭代就是反复求sin(x)=y 再通过直线方程用这个y求x,如此循环。实际上一章节的计算方法和迭代计算方法只差一步之遥,上一章节sin运算的参数是 P点(上图)的相位值,迭代sin计算是参数是P点相位值附加一个参数,这个参数就是上图中“待求值”的相位值(这里不贴图了,和上面的图一样)。运算中需要一个数组存放计算结果,这里选择存储y值。计算分2步:
1.从数组中取出y值,折算成对应的x值,这个折算过程就是乘以三角波的直线斜率,选取适当的幺1值以后斜率就可以用1/M1_N来代替,左斜线是1/M1_N右斜就是-1/M1_N,再附加P点相位值。
这一步就是程序中这一句 tmp=phase+M1_CalDataBuffer[cadd]/M1_N*64;
如果是计算关点进行+运算,如果是计算开点用-运算。+-可以认为是斜率的符号,也可以认为关点在P点右边比P点大所以加,开点在P点左边比P小所以减。
2.用sin(X)*M1_M计算得到y值,再放回到数组里即
M1_CalDataBuffer[cadd]=((uint64_t)abs(arm_sin_q31(tmp))*M1_M)>>(16+8);
如果是电机的A相数据运算用sin,如果是电机B相数据运算用cos。后面部分*64 和右移24位是乘除法数值对应调整,此数值和幺1值及精度保留有关,同时放大缩小不影响结果,不再细致讨论了。


  上面两句执行一次就迭代一次,若干次以后结果就是最终数据,这个计算过程在中断服务里调用,每次调用后的计算结果即y点坐标再用来折算成输出pwm的占空比值,这个过程就是将y值按M1_Arr周期值的比例输出:占空比设定值=((uint64_t)M1_CalDataBuffer[cadd]*M1_Arr)>>(15+8);

迭代数组里存放的是y坐标,而不是占空比的计算结果,这样做有一个优点就是迭代运算的结果与定时器周期值无关。因为后面做速度调整时需要不断修改定时器周期值,当周期值变化时迭代数据区的数值不会改变,从而加速代码的效率。迭代数据区的数据变化的情况只发生在M1_M即输出正弦波幅值变化的时候和M1_N细分度发生变化的时候。
  另外每次步进时需要计算四个数据,A点开,B点开,A点关,B点关,理论上应该有四个数组来存放并且分别运算。如果你把这四个数组的值列出来会发现其实它们的值都是一样的,只是位置不同而已。A开的数据倒序就是A关的数据,同理B开倒序就是B关;A开的数据从折半的中间位置开始顺序就是B开。四个数据区分别运算出同样的结果不划算,本程序经过优化以后这四个数组合并为一个,只是迭代的数组存放地址运算一下即可。代码里计算前对变量oadd和cadd的赋值就是这部分内容。
    cadd=((uint32_t)M1_Step&(HALF_SINCYCLE_VALUE-1))/(HALF_SINCYCLE_VALUE/CALDATABUFFERSIZE);
    //关点迭代存储地址
    oadd =((uint32_t)(-M1_Step-2*M1_HalfStepAcc)&(HALF_SINCYCLE_VALUE-1))/(HALF_SINCYCLE_VALUE/CALDATABUFFERSIZE);
举个例子就能看出来结果,假设细分度N=64,程序中的计算缓冲区大小为512个单元,则每步的cadd分别为:0,8,16...,488,496,504 ;同时oadd=504,496,488,...,16,8,0;
512/64=8,所以每次步进8个单元,当步值穿越中心点后开点和关点重叠到同一个地址上。同样的方法处理A相和B相的地址(用的异或运算)可以让AB相数据也重叠。这样当步值步进到四分之一个正弦半周期时数据区的所有数据都迭代计算一遍,从而提高了运行效率。你可以试一下四个计算注释掉任意三个都能得到相同得结果。
  再说明一点,这样安排有个优点就是N变化时迭代有初值。迭代计算需要计算几次以后才能得到真实的结果,因此有比较接近结果的初值会减少计算量。举个例子:当N=64时迭代计算的地址为0,8,16,24,32...,之后因为速度调整(加速)将N值修改为32后迭代计算地址变为0,16,32...,跳过了第8地址单元故之前的第8地址单元数据保持不变,后面又做减速调整时N值恢复为64,则在第8单元从新开始计算,只要固定的速度对应的幅值基本接近迭代数据就基本不变,所以很快就能得到第8单元的结果。实际上迭代的2~3次以后就接近%90了,无初值也没有那么严重。
  另外程序允许M值超1调整再说明一下。理论上正弦波幅值=1即M1_M=65536时输出完整的正弦波,此时力矩最大。当转速比较高时正弦的完整性对电机影响不大,高转速时总是希望更大的力矩值。M1_M允许赋值为大于65536的幅值,此时正弦波退化为消顶的梯形波,占空比值大于M1_Arr的情况全都=M1_Arr即输出高电平,这里主要是防止占空比大于65535。防止运算超范围也是M1_CalDataBuffer[cadd]=((uint64_t)abs(arm_sin_q31(tmp))*M1_M)>>(16+8);需要做64位整数运算的原因。
  程序中迭代计算部分用宏定义给出方便修改,函数原型复制了一份在ISR_Bak.c中供参考。计算中用到stm32f4的dsp库的就只有正弦余弦函数,如果三角函数用查表运算则完全可以在没有浮点库的芯片stm32f1系列上运行。
附件:非对称迭代计算 

 

调速

力矩表和加速补偿

自动运行到指定步值

 

 

 

 

 

 

 

 

关键字:步进电机'、'stm32F4'、'l6205
阅读原文 浏览量:2197 收藏:4
此内容由EEWORLD论坛网友 huo_hu 原创,如需转载或用于商业用途需征 得作者同意并注明出处

上一篇: ESP32-S2开发之坑(5)--利用USB-CDC模拟触摸游标控制littlevgl
下一篇: [10月DIY]编写个超简单的CPU

评论

登录 | 注册 需要登陆才可发布评论    
评论加载中......
电子工程世界版权所有 京ICP证060456号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright ? 2005-2017 sonata9.com, Inc. All rights reserved
安徽快3 小米彩票平台 北京pk10 亿信彩票开奖直播网 北京pk10 幸运时时彩开奖结果 上海11选5 幸运时时彩 幸运时时彩平台 江苏快三跨度走势图