17454|43

4008

帖子

0

TA的资源

版主

楼主
 

数字接口 stm32F4+l6205 步进电机驱动 [复制链接]

 
本帖最后由 huo_hu 于 2023-3-17 12:53 编辑

此内容由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接定时器的通道管脚受刹车位控制可以迅速切换到无效电平起保护作用。这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灌电流,最好在二极管上并个电阻到地防止发光二极管短路的情况下高压输入到io口烧毁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:通道34也一样设置

5:使能溢出中断

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

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

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

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

附件1:查表输出电机正反转 F407_SMotor_Part1.zip (744.7 KB, 下载次数: 183)

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就执行一次更新,上来清除所有的输出(11N22N)再根据条件设置。每输出完一次表数据即翻转一次所以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),可以保证这一点。

 

视频链接:https://bbs.eeworld.com.cn/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定义的数值。

另外比较新一点的Keil版本支持调试变量动态刷新,设置在这里,在启动调试以后可以勾选。

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

VID_20200531_030819.mp4 (10.45 MB, 下载次数: 509)

VID_20200531_030819.mp4 (10.45 MB, 下载次数: 509)

附件:对称正弦幅值输出

F407_SMotor_Part2.zip (751.06 KB, 下载次数: 125)

F407_SMotor_Part2.zip (751.06 KB, 下载次数: 125)

 

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

     上面那个对称输出的方法也可以适应中等速度运转,但是有个问题无解,就是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系列上运行。
附件:非对称迭代计算 
F407_SMotor_3.zip (753.68 KB, 下载次数: 109)

 

第五部分 调速
  
上面章节的程序的已经可以实现最基本的功能了,改变M1_M可调整输出力矩,通过M1_SettingParm可设定速度,只是每次调用都需要给定细分度和定时器周期值。本章节实现根据指定的加速度累计速度值,并分解速度参数自行设定运行。首先添加一个结构体封装电机的各个参数,参看StepMotor.h里的定义不贴出来了。
  第一个是步值,程序采用了相对记步的方式,通过函数对步值进行设定和获取当前步值
static int32_t Relative_Step=0;
//设定和返回相对记步
void M1_Set_Step(int32_t ss) {
   int32_t tmp=(M1_Step/(SINCYCLE_VALUE/256));

    Relative_Step=tmp-ss;
}
int32_t M1_Get_Step(void) {
    int32_t tmp=M1_Step/(SINCYCLE_VALUE/256);    
    return (tmp-Relative_Step);    
}
  实际上就是实现相对坐标定位,Set函数给定的参数就是当前电机的位置值,此后M1.Step以此为参照点折算成相对步值。另外u64的数据类型显得比较冗余没有必要,因此移位以后转换为u32数据类型24位整步+8位微步的数据。这个Step是带符号的。
  第二个是HZ*100倍为单位的速度值,驱动函数检测此变量的修改,然后按新数值设定电机运行参数。这里有几个要注意的地方设定值和实际运行值有偏差,这个偏差发生在两种情况:第一种是速度值太小不能设置,程序目前参数能支持4的最小速度(即输出0.04HZ正弦波),更小的数值会造成计算溢出,当然你也可以自己通过其它方式实现。第二种偏差情况是细分度过小引起的计算误差,当细分度小于16时偶尔会有+-1的数值误差。速度值也是带符号数,速度为正时步值加,速度为负时步值减。
  第三个是带符号加速度值Acc,因为在驱动函数每10ms调用一次累加速度值,所以单位为 速度单位/10ms即每10ms速度加或减0.01HZ。设定为正数经过一段时间后速度会达到正向最大值,设定为负数经过一段时间会达到反转最大速度。设置为0时保持当前速度不变。
调速部分就是在M1Speed.c中的SpeedDriver函数,这个函数由大循环每10ms调用一次实现速度调整。参看上传的附件比较长,我就不粘贴了。memory_spd缓存当前速度值,每次比较判断M1.Speed的不同时说明外部操作修改了需要重新设置。M1_GetSpeed函数可以返回真实的速度值,但这个值并不是M1.Speed,原因在于调速需要保留之前的调速结果。举个例子说明一下,M1.Speed=0,Acc=1时一次函数调用会将M1.Speed设置为1,即虽然没有成功但目标变化为1,再次调用为2...直到设置为4时电机以最小速度启动。如果不保留123的状态Acc=1时速度值始终无法增加导致无法启动错误,M1.Speed可以理解为上次驱动调用后的结果。关于这个变量说了这么多实际就是速度值精度的问题,如果精度定为0.05HZ那么都不会有问题,原则上也不应当设定比精度更小的数值。
  调速函数接下来根据速度待设定值反算出N细分度和Arr的乘积值,即程序里nc=...的赋值语句,然后判断速度边界然后再根据nc计算细分度的设定值。速度设定分两种情况:无迭代时(N>512)(512是宏指定的迭代数组的大小),此时Arr固定为16384。有迭代时N=512,256,128,...8,4。有迭代的情况N必须是2的整数次幂,尾数由Arr来调整,因为N和Arr的乘积决定转速,所以N缩小一倍同时Arr放大一倍结果不变。实际程序中选取Arr的取值范围为16384~8192之间(即宏ARR_MAX指定的参数值)。
  通过nc计算N值使用二进制移位即可实现,参见while(tmp>=(ARR_MAX*2)) {  ...这段循环。循环结束时nn的值就是待设定的细分度。之后是一段判断条件,最终Arr设定值由nc和设定的细分度运算出来即nc/nn/2。参数计算好以后,通过M1_SettingParm函数做修改,这个函数和前几章节不同之处在于增加了一句
        if (pn<M1_N)  M1_Step &=~((uint64_t)(HALF_SINCYCLE_VALUE/pn)-1);
这句是很有必要的,它的作用时当细分度变小时清除二进制整步值的尾数,这样才能保证每周期从0开始。
  ISR.c里的变量比较重要原则上不该允许其它程序修改,以后不需要调试这些变量以后可以用static来修饰保护。程序下载以后调试环境修改M1.Acc为1或-1即可看到电机的加速过程,运行时要接一个电流表随时调整M1_M的值保持适当的力矩输出。

 

第六部分 力矩查表
    上面调速的过程运行时你会看到当速度增加时L6205输入电流会持续减小,原因是电机运转时线圈中的感生电动势的增加,理论上这个电动势应该和速度成正比。为减少存储占用使用细分度力矩表,相同的细分度区间认为是正比例变化,表项对应细分度值,同时表内包含次细分下的最小速度和最大速度值及最小力矩值和最大力矩值。
typedef struct {
    uint32_t Speed_Low;
    uint32_t Speed_High;    
    uint32_t Momen_Low;    
    uint32_t Momen_High;    
} MomentItem_TypeDef;
差表输出时按比例分配力矩最大值和最小值的差就行了。参见M1Moment.c,设置时再附加一个加速度力矩补偿参数和加速度乘积。表中的数据为匀速运动时测定的数据,当电机加速时应该用更大的力矩输出才能保证不丢步。另外一个情况是电机减速运动减速运动也要输出更大的力矩,这点和直流电机不太一样。加速度已知的情况要补偿多少力矩呢?这个和你电机的负载情况有关,更准确的说和你电机所带负载的转动惯量有关系,你可以想象电机带着一根很长的轻质细杆做加速运动,电机想加速转动却扭不动的情况,这时候必须对加速度进行限制别无它法。力矩补偿值需要根据实际的负载情况做测试以后确定。
  程序里在M1Speed里加入了一句SpeedFlg=9;(2的9次方=512)使得细分度大于512时和等于512的细分标记相同,从而表项即为M1.SpeedFlg的最低5位。M1_Moment.c的前面部分是测试力矩表项,前面的初始化完成以后会将各细分值下力矩表的Speed_Low值和Speed_High值填充,然后速度设为0等待。之后在调试界面手动修改M1_Acc为1等待一段时间电机会停留在下一个力矩表测试点,这时根据电流表读数调整M1_M到合适的电流,当前力矩值自动填充到表。完成这个测试点后再次将M1_Acc置为1加速到下一个测试点。最后完成时复制MomentTable的内容后启用下半部分输出即可。

  关于力矩输出这块儿再说明几点,首先步进电机的输出力矩取决于线圈中的电流,电流越大输出力矩也越大,但是和直流电机不同,过量的电流会无谓的损耗。步进电机的转动完全是靠输出正弦余弦波的相位来控制的(可以参看我另外一篇贴子),步进电机并不会因为输出力矩大而转的更快。
  提高系统能够输出的最大力矩的唯一方法就是提高驱动电路的供电电压,供电电压确定以后我们可以把力矩输出分配到这几部分。
  1.维持匀速运行过程不丢步,电机运行的过程中一定要保证力矩输出值大于当前速度下的最小维持转动力矩,这样才能保证不丢步,低转速下丢步会造成步值计数偏差,高转速下丢步必然会堵转。这个最小维持转动力矩主要取决于电机线圈的电感量或者说是矩频特性。
  2.维持系统做加减速,加速或减速都需要在上面的维持转动力矩的基础上进一步增加力矩来保证加减速的过程不丢步,需要增加的力矩取决于系统的转动惯量。
  3.另外在转速比较高时随着开关频率的增加开关损耗会逐渐增加,进入高速运转时这个不容忽视。
  由上可以看出一个固定的系统最大转速和最大加速度是两个重要指标,和电机特性和负载特性息息相关。不同的电机矩频特性差异很大,主要是线圈匝数影响很大,同时42系列电机也有好几种。这个参数可以用相间电感来测量,电感偏大的电机想高速运动是不现实的,但电感大的电机在低速时同样的电流输出力矩更大。

 

附件:第567章节代码,覆盖相应文件即可  StepMotor_Part567.zip (8.79 KB, 下载次数: 101)

视频:24V 电机17H185H-04AC Acc=2000急速正反转,达到最大速度后加速度符号取反,位置有偏差是反转介入的时间差引起的。

VID_20200614_215415.mp4 (11.41 MB, 下载次数: 185)

 

第七部分 自动运行到指定步值

  前面几部分已经把电机的基本控制都实现了,修改Acc即可按指定的加速度调整电机速度,力矩会根据不同的速度自动设置。最后一部分,想要实现的功能是自动步值到位,就是你告诉我想要去的位置,然后就不用管了,系统自动调整加速度到达位置后停止。系统应该能满足如下需求:
(1)根据指定的速度上限和加速度上限运行,以满足不同的带负载需要。
(2)任何时刻都可以修改目标位置,系统根据目标位置的变化自动调整加减速方向。
(3)最短的时间一次运行到位避免回调。
(4)到位后用状态位表示已经完成。
要实现这样的功能我最初的想法也和大家一样根据目标点位置做逻辑,然后编程序就是一大堆的if else if else...,这样子不行,程序代码乱糟糟越弄越复杂,根本没法儿调试。最后改变思路把逻辑简化了程序就好办了,你可以看到最后实现就几行代码就能完成。
  首先为达到随时可以修改目标位置的功能需要一个全局量缓存当前设定值,然后每10ms执行驱动函数,驱动函数上来先比较设定值和缓存值是否相同,如果不同清除几个标记重新设定,如果相同继续执行下面的程序一直到最后到达目标位置,这部分很好理解就不贴代码了。
  因为状态调整时的速度大小和方向是任意的,所以接下来要回答的一个问题是在当前速度(包括方向)下以最大减速度减速会落在哪里?这个好办,根据公式2aS=Vt*Vt-V0*V0求S就行,因为末速度是0所以S=Vt*Vt/2/a。要正确运用这个公式还要把现在程序里的各个变量的单位和关系梳理以下。
以下凡出现程序变量的地方都表示没有单位的数值。
  步值M1.Step单位是256倍放大的整步单位,这个是由M1_Get_Step函数来定的,返回相对步值时有个运算。一个整步即对应一个正弦半周期,200个正弦半周期电机一转,所以M1.Step从0走到51200电机转一周。
  速度M1.Speed单位是100倍放大的HZ数,1HZ就是每秒一个正弦周期,也就是每秒2个整步,可以写成M1.Speed/100*2 整步/秒,对应成步值单位再*256。
  加速度单位是每10毫秒加减一个速度单位,所以Vt/a上下都约掉一个速度单位就等于M1.Speed/Acc*10毫秒=M1.Speed/Acc*0.01秒。
带入公式
S=Vt/2*(Vt/a)=(M1.Speed/100*2*256)/2*M1.Speed/Acc*0.01单位为和M1.Step一样的步值单位即256放大的整步。
化简以一下=M1.Speed*M1.Speed*256/10000/Acc
  再看一下符号的处理,原本的公式中a是带符号的加速度,而我们这里加速度没有设定方向,加速度方向应该是和速度方向相反才能做减速运动,实际的Acc是不带方向的正数,所求的位移量的方向应该和速度方向一致。换句话说如果是正转减速以后的位移符号为正,如果反转减速以后位移量为负,所以最后计算结果的符号和速度方向相同。再对上面式子进行一次处理变为
abs(M1.Speed)*M1.Speed*256/10000/Acc  (Acc运动控制时能够设置的最大加速度值,无方向的正数)
  这个计算结果再加上当前位置点即为减速以后的落点(包括静止速度为0的情况),再用设定目标点的位置减去这个数即为步差值。说了这么一大堆实际上就是解释底下三行代码的来历,看起来有些复杂,但是单位换算是在编程的过程中是必须弄清楚而且不能错的。AccMax是初始化时设定的运行过程中允许使用的最大加速度的绝对值。
int32_t tmp;
tmp=((int64_t)abs(M1.Speed)*(M1.Speed)*256/10000);
tmp=M1.Step+tmp/(M1.Run_AccMax);
return (CompTargetStep-tmp);
  这个返回值我们起个名字叫步差值可能不是特别准确无所谓了,它的含义是在当前速度状态下如果现在立刻做最大减速运动将会到达的位置点与目标设定点的差值。数值为负说明将会降落在目标点左侧,数值为正将会降落在目标点右侧。这个数怎么用呢?别眨眼最核心的部分来了,如果这个数值的符号和速度的符号相同意味着当前运行状态能够到达目标位置,能够到达换句话说就是可以加速;反之如果符号位不同意味着不能到达目标位置也就是说需要减速。上面那句话就是核心的逻辑,我们再把可以加速用逻辑替换一下就是加速度符号的设置和速度方向一致,需要减速用逻辑替换就是加速度符号和速度方向相反。把这个逻辑展开以后你会发现速度符号只是中间一个过度,最后可以约掉,因此最后化简为下面逻辑语句:
if (步差值<0) {
        setac=-(M1.Run_AccMax);
    } else
        setac=M1.Run_AccMax;
  化简的过程我就不做了,你也能够想象的出来,步差非正即负-再套速度非正即负-再套速度非正即负-再套加速度非正即负,最后结果就是步差符号决定加速度符号。这个逻辑语句就能够完成步值到位的功能,其它部分可以都不要,每驱动执行一次取步差置加速度方向你就会看到最基本的功能,改变目标点的设置,步值跟随目标点变化。变化的过程包括静止状态开始加速(步差值的绝对值极大),持续加速直到速度上限后保持最大速度(步差值的绝对值逐渐变小),在临近减速最小位置开始减速直到指定的目标位置,整个减速过程步差值的绝对值保持在接近于0的水平。即使调速到位的开始状态速度非0仍然是正确的,反正当时调试时看到这个结果能成立我也是惊掉下巴了,原来这么简单撒。
  接下来就是处理最大速度上限,调速程序中其实有速度上限的约束,这里只是想提供给用户临时指定一个比调速中的速度上限更小的数值设定的功能,达到速度上限就不再加速即
if (abs(M1.Speed) >= M1.Run_SpeedMax ) {    M1.Acc=0;return;}
  这样写有个bug就是在速度到达最大速度值以后无法反向减速,因此后面又附加一个能够到达位置的逻辑条件,如果不能到达的情况可以反向设置加速度。
  目前为止的代码完成以后如果调试运行,你会发现有个问题就是M1.Step步值在目标点附近左右摇摆停不下来,探究原因以后得出结论并不是数值精度的问题,根本原因是驱动函数每10ms调用调整一次,这个时间段相对于一个微步的移动时间来说是很大的,不足以控制电机最后精确到达指定位置。另外因为步进时间间隔因为调速的原因是变化的,在中断服务程序外精确控制有个如何同步的问题,会比较麻烦。因此需要对ISR程序加以改动,引入一个微步运行模式,思路就是在中断服务程序里每次释放一个微步的方式前进(或后退)直到最后完成,一个微步就是M1.Step的最小单位。自动运行到位的驱动函数中判断,如果当前位置已经非常接近目标位置了就计算出还差多少个微步可以到达,设定这个数值以后切换到微步进模式就可以精确到位了。程序中还有其它一些细节不一一祥述了,如果有疑问我再作答。
  当前代码能够满足加速度上限为150的情况准确到位值没有回调。如果想做的更好些可以在最后的减速阶段实施pid控制,思路就是根据步差的数值调整加速度,这段以后再改进。
  另外一部分扩展是电机指令控制和串口上位机这个难度不大,网上例子也挺多,相信大家能够搞出来。想提醒大家注意的地方就是keil环境里字符串和变量之间的转换。数值转字符串用sprintf就行,字符串转变量在标准输入输出库里面已经有这个功能,下面这个函数就可以完成根本不用自己编写:
//转换字符为数值,非0:有非法字符
uint8_t ChgStrVal(uint32_t addr,int32_t * ret) {
    char * errch=0;
    *ret = strtol((char *)(addr),&errch,10);
    return *errch;
}
  视频:24V电机17H185H-04AC 每3秒正反转10圈 电流最大130毫安

     VID_20200629_042431.mp4 (22.25 MB, 下载次数: 187)

 

第八部分 补充说明
    与大多数脉冲式步进电机驱动不同,本设计量化了步值、速度和加速度为后续进一步开发提供方便。设计中完全摒弃了几个传统设计概念。首先一个是最小启动频率,这个概念源自于脉冲式步进电机驱动,驱动器上一般有很多拨码开关,选择细分和电流,然后外部控制电路输入一个方波脉冲,这个脉冲的最大频率意为可以在静止状态启动步进电机转动。其实这个指标没有什么科学依据,如果是空载启动频率没有多大意义。再一个是S曲线加速,网上能找到一大把关于S曲线加速的文章,各种花式计算,只是说要减小启停阶段的加速度,反正我是没太明白原理是怎么来的。再一个是spwm的计算器,我也下载过几个,计算结果和本设计中的数值对不上,后来分析是那些计算没有考虑0.5个细分度的相位偏移,也就是第一个三角波的中间点和正弦相位0值相切,所以第一个数据为0,这样计算是不对的。应该是三角波起始点和正弦波起始点是相同的,所以第一个开点数据一定不为0(除非幅值为0)。

  另外一个是关于电流检测,最理想的情况是让一个步进电机的控制系统能够适应所有不同类型的步进电机。你可能会这样想,如果能实时检测到电机线圈里的电流值反馈给控制器就能形成闭环,自动调整线圈里的电流。然而实时检测线圈的电流不是一件容易的事,因为线圈是由pwm的开关输出控制的,运动中的电感线圈在到导通的瞬间电流情况非常复杂,仅检测出一个瞬间值没有多大作用。当然你也可以通过积分和滤波求出有效值或均值,但是实时性又得不到满足,等到几个周期以后再实施调整恐怕已经晚了,一旦发生堵转除了再启动已经没有别的办法了。另外一个情况是电机加速,因为加速动作是由控制器控制产生的,所以第一时间控制器就知道应该增加力矩以推动电机加速,没有必要等到反馈信号再做决定,这部分是闭环电路不能取代的。如果你是一个驱动器的生产商当然会希望驱动器能够适应各种电机的情况做个万能驱动器,然而在没有参数的情况下做优化是不现实的。如果不知道系统负载的情况也就不能准做出力矩补偿,前面说了加速度力矩补偿和转动惯量相关,而转动惯量必须要转动起来以后才能确定。如果不能准确设定系统的最大加速度参数最后一个章节的步值到位功能也就没办法实现了,因为缺少参数。

  最后感谢大家的支持,有不当之处恳请指正。

 

    看到有人问中央对齐的pwm波,这里再展开讨论一下。我们在调制输出正弦波的时候有个重要的操作,就是换向,换向是指从调制正半周输出切换到调制负半周输出。这段代码在定时器中断服务里是这样写的
                TIM1->CCER &= ~(TIM_CCER_CC1E|TIM_CCER_CC1NE|TIM_CCER_CC2E|TIM_CCER_CC2NE);
                 if ....      TIM1->CCER |= TIM_CCER_CC2E;//B+ 
看似是先清0然后再置位,而实际的情况是程序跑得飞快,清0的过程在IO口上反映不出来,如果看波形的话ENA或ENB在半周期的输出过程维持着高或低电平不变。换向的时候ENAB会产生电平翻转,这是个非常重要的时刻。中央对齐的一个优点除了可以输出对称波形以外还有一个优点就是换向和桥打开输出电流不在同一个时间点。正弦半周最后一个输出点和第一个输出点都是占空比最小的pwm,换向发生在最后一个pwm和第一个pwm的中间位置,这个时候pwm输出肯定是关闭的。换向和pwm开关都时有延时的,而且开和关的延时时间不一致。如果不是中央对齐模式就避免不了换向和pwm导通同时进行,调整pwm极性解决不了这个问题,要么是pwm周期前开要么是pwm周期后开。你可以想象这个换向延时还没走完pwm已经导通了,所以不可避免有部分负半周的输出到了正半周。而且糟糕的情况还不止这些,电机是一种感性负载,当电机开始转动以后,即便是pwm关闭输出,线圈里也会存在剩余电流,如果换向没完成的时候,pwm一旦打开输出就会把所有的反向电流全部吸收干净,相当于这边分电流和电源自己消耗了。当然你也可以开启死区控制来缓解,死区的问题是后面调速的时候死区参数不是一个固定的数值调整起来比较麻烦。尽量用中央对齐输出就好了。

 

此帖出自stm32/stm8论坛

最新回复

6666666666666666666666666666666666666666666666666666666   详情 回复 发表于 2024-11-20 22:11
点赞(5) 关注(13)
 

回复
举报

1万

帖子

203

TA的资源

管理员

沙发
 

谢谢楼主分享~~写的清晰明白,受益了!

此帖出自stm32/stm8论坛
加EE小助手好友,
入技术交流群
EE服务号
精彩活动e手掌握
EE订阅号
热门资讯e网打尽
聚焦汽车电子软硬件开发
认真关注技术本身
 
个人签名玩板看这里:
https://bbs.eeworld.com.cn/elecplay.html
EEWorld测评频道众多好板等你来玩,还可以来频道许愿树许愿说说你想要玩的板子,我们都在努力为大家实现!
 

回复

297

帖子

0

TA的资源

一粒金砂(中级)

板凳
 

收藏了!!

此帖出自stm32/stm8论坛
 
 

回复

6

帖子

0

TA的资源

一粒金砂(初级)

4
 

学习了,感谢楼主

此帖出自stm32/stm8论坛
 
 
 

回复

41

帖子

0

TA的资源

一粒金砂(初级)

5
 

感谢楼主分享

此帖出自stm32/stm8论坛
 
 
 

回复

295

帖子

1

TA的资源

版主

6
 

支持,好贴,正在学习

此帖出自stm32/stm8论坛
 
 
 

回复

310

帖子

5

TA的资源

一粒金砂(中级)

7
 

感谢楼主分享,好帖

此帖出自stm32/stm8论坛
 
 
 

回复

6

帖子

0

TA的资源

一粒金砂(初级)

8
 
楼主这个芯片是内部电流环么
此帖出自stm32/stm8论坛

点评

没明白什么意思  详情 回复 发表于 2020-7-6 21:34
 
 
 

回复

4008

帖子

0

TA的资源

版主

9
 
不是吃的 发表于 2020-7-6 11:53 楼主这个芯片是内部电流环么

没明白什么意思

此帖出自stm32/stm8论坛
 
 
 

回复

6

帖子

0

TA的资源

一粒金砂(初级)

10
 
本帖最后由 不是吃的 于 2020-7-7 10:49 编辑
huo_hu 发表于 2020-7-6 21:34 没明白什么意思

就是怎么控制电流的大小的,是用mos管搭建驱动电路,原来是用电流采样,让后用电流合成细分驱动电机

此帖出自stm32/stm8论坛

点评

电流采样是个办法,但是滤波不好弄,电路比较复杂 本例电流是由输出正弦的幅值来控制的,是开环控制。 如果你能做好电流采样改成闭环只是分分钟的事。  详情 回复 发表于 2020-7-7 22:00
 
 
 

回复

4008

帖子

0

TA的资源

版主

11
 
不是吃的 发表于 2020-7-7 10:43 huo_hu 发表于 2020-7-6 21:34 没明白什么意思 就是怎么控制电流的大小的,是用mos管搭建驱动电路,原 ...

电流采样是个办法,但是滤波不好弄,电路比较复杂

本例电流是由输出正弦的幅值来控制的,是开环控制。

如果你能做好电流采样改成闭环只是分分钟的事。

此帖出自stm32/stm8论坛

点评

这个电流采样,太多毛刺了,真心不好弄。  详情 回复 发表于 2020-10-29 09:34
 
 
 

回复

6

帖子

0

TA的资源

一粒金砂(初级)

12
 
huo_hu 发表于 2020-7-7 22:00 电流采样是个办法,但是滤波不好弄,电路比较复杂 本例电流是由输出正弦的幅值来控制的,是开环控制。 ...

大佬可以换个tb67h450芯片试试,带电流硬件可调,感觉性能可以更好

此帖出自stm32/stm8论坛

点评

这种桥驱动模块挺多的,以前用过lmd18200,三洋也有一款lv8548。 你说的这个是单桥驱动,和l9170差不多,l9170以前弄过一下,印象里开关速度不行,做直流电机没问题,因为正转不可能马上切换到反转,但是做步进电  详情 回复 发表于 2020-7-9 23:31
 
 
 

回复

4008

帖子

0

TA的资源

版主

13
 
不是吃的 发表于 2020-7-9 21:15 大佬可以换个tb67h450芯片试试,带电流硬件可调,感觉性能可以更好

这种桥驱动模块挺多的,以前用过lmd18200,三洋也有一款lv8548。

你说的这个是单桥驱动,和l9170差不多,l9170以前弄过一下,印象里开关速度不行,做直流电机没问题,因为正转不可能马上切换到反转,但是做步进电机不行。

此帖出自stm32/stm8论坛
 
 
 

回复

6

帖子

0

TA的资源

一粒金砂(初级)

14
 
huo_hu 发表于 2020-7-9 23:31 这种桥驱动模块挺多的,以前用过lmd18200,三洋也有一款lv8548。 你说的这个是单桥驱动,和l9170差不 ...

这个开关频率在500ns,应该还可以,看别人做过,能起跳急停,大佬这个开关频率达到多少做步进电机驱动才合格

此帖出自stm32/stm8论坛

点评

500ns行不过没用过,行是肯定都行,PWM频率低开关延时长些也无所谓  详情 回复 发表于 2020-7-10 22:16
 
 
 

回复

4008

帖子

0

TA的资源

版主

15
 
不是吃的 发表于 2020-7-10 12:26 这个开关频率在500ns,应该还可以,看别人做过,能起跳急停,大佬这个开关频率达到多少做步进电机驱动才合格 ...

500ns行不过没用过,行是肯定都行,PWM频率低开关延时长些也无所谓

此帖出自stm32/stm8论坛
 
 
 

回复

3

帖子

0

TA的资源

一粒金砂(初级)

16
 
写的很详细,收藏起来慢慢看,感谢楼主分享
此帖出自stm32/stm8论坛
 
 
 

回复

2

帖子

0

TA的资源

一粒金砂(初级)

17
 

载波频率是多少的?

此帖出自stm32/stm8论坛

点评

就是定时器时钟源呗  详情 回复 发表于 2020-9-10 11:52
 
 
 

回复

4008

帖子

0

TA的资源

版主

18
 
jcx0324 发表于 2020-9-10 11:27 载波频率是多少的?

就是定时器时钟源呗

此帖出自stm32/stm8论坛
 
 
 

回复

7608

帖子

2

TA的资源

五彩晶圆(高级)

19
 

很厉害,差点错过好帖。

此帖出自stm32/stm8论坛
 
个人签名

默认摸鱼,再摸鱼。2022、9、28

 
 

回复

2

帖子

0

TA的资源

一粒金砂(初级)

20
 

收藏了

此帖出自stm32/stm8论坛
 
 
 

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

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表