理论

stm32步进电机控制程序系统(步进电机控制程序编写)(1)stm32步进电机控制程序系统(步进电机控制程序编写)(2)

为了实现步进电机的平缓启停以及避免转高转速时不失步停转。在步进电机启动、停止过程中,需要采用加减速的算法对启动过程进行控制。S曲线是加减速控制最理想的方案。但是S曲线的公式以及控制过程都比较复杂。基于单片机实现这一算法需要有深厚的数学以及单片机软件设计能力。

本视频从浅入深介绍S曲线加减数的理论、编程与实践。

将S曲线离散化,在整个加减速过程中,以一定的时间间隔更新频率,总的更新次数为2*N,i表示为第i次的更新,则第i次更新的频率f(i)表示为:

stm32步进电机控制程序系统(步进电机控制程序编写)(3)

其中fb为开始的频率,fr是最终运行的频率,α是曲线的伸缩系数,一般可以取3-5之间的常数。

比如,启动加速,开始频率为400Hz,运行频率为5KHz。

停止减速,开始频率为5KHz,停止频率为400Hz,

加减速的时间均为1s,按10ms的时间间隔更新频率,总共更新100次,α取5。

则可以绘制以下的加减速曲线:

stm32步进电机控制程序系统(步进电机控制程序编写)(4)

编程

通过以下步骤实现实现步进电机的S曲线的加减速控制:

整个加减速控制过程的难点在于:

为了解决S曲线的运算时间问题,基于STM32F103,我采用了查表法,具体步骤如下:

1. 将α值定义5,

stm32步进电机控制程序系统(步进电机控制程序编写)(5)

的取值范围为-5~5之间。

2. 在整个加减速过程中,表达式

stm32步进电机控制程序系统(步进电机控制程序编写)(6)

在取值范围-5~5内均匀取1024个数值,得到数值表。

3. 定义一个unsigned short型有1024个元素的const类型的数组,用于存储数值表。

4. Const数组存储在内部的flash,数值表共占用2048字节。

STM32F103RTC6共256K,程序组和设置参数占用48K,bootloader程序占用了8K,远程升级空间占用了100K,目前应用程序只用到40K左右。

剩余60K左右的空间,腾出2K的空间来存储数值表,有空间,就是这么任性。

5. 在中断程序中,根据总的更新次数以及当前的更新计数值,计算

stm32步进电机控制程序系统(步进电机控制程序编写)(7)

值,再映射到0-1023的数值有的索引值,通过索引获取数值。

6. 需要注意的是stm32f103不支持浮点数的运算,所以对于浮点数的运算,需要换算成乘以一个数再除以另一个数,比如*α,需要转变为*65535/13107。

下面一段代码是根据更新的计数值获取频率的函数:

U16 fnMC_GetFreq(U16 n, U16 halftn, U16 alpha, U16 minfreq, U16 maxfreq){//alpha=alpha * 4096 signed int udataA; signed short uiDataA; U16 uiRes; U32 uwData; udataA = (signed int)alpha * (signed int)n; udataA = (signed int)udataA / halftn; if(udataA > 32767){  udataA = 32767; } uiDataA = (signed short)alpha - (signed short)udataA; uiDataA = (signed short)4 * 4096 - uiDataA; if(uiDataA < 0){ uiDataA = 0; } uiRes = (U16)uiDataA;  uiRes = uiRes / 32;//*1023/8/4096 if(uiRes > 1023){ uiRes = 1023; } udataA = (signed int)(maxfreq - minfreq) * g_mc_uchExp[uiRes]; udataA = udataA / 65535; uiDataA = (signed int)udataA; uiDataA += minfreq; if(uiDataA < 200){ uiDataA = 200; } return(uiDataA); }

下面一段代码是产生步进电机控制信号的PWM周期中断程序:

 int data;	 U16 freq;	 STRMotorRegs *motor;	 motor = &g_motor_regs[0]; MOTOR_A_CLEARINT();	 motor->steps ++;	 data = (int)MOTOR_A_STEPS_GET();	 if(motor->direction == 0)	 {	 	data = data + 1;	 		 }	 else	 {	 	data = data - 1;	 }	 MOTOR_A_STEPS_SET(data);	 freq = motor->runfrequency;	 if(motor->runstate == MOTOR_RUN_STATE_INC){		if(motor->runtimer >= motor->starttime){			motor->runstate = MOTOR_RUN_STATE_IDLE;		}else{			freq = fnMC_GetFreq(motor->runtimer, motor->halfstarttime, motor->alpha, motor->startfreq, motor->runfrequency);//U16 n,U16 halftn,U16 alpha,U16 maxfreq,U16 minfreq)		}		motor->runsnapfreq = freq;	 }else if(motor->runstate == MOTOR_RUN_STATE_IDLE){		if(motor->totalstep <= (motor->steps + motor->stopremainstep)){			motor->runstate = MOTOR_RUN_STATE_DEC;			motor->runtimer = 0;					}		motor->runsnapfreq = freq;	 }else{	 	if(motor->runtimer >= motor->stoptime){			freq = motor->stopfreq;		}else{			freq = fnMC_GetFreq(motor->runtimer, motor->halfstoptime, motor->alpha, motor->runsnapfreq, motor->stopfreq);//U16 n,U16 halftn,U16 alpha,U16 maxfreq,U16 minfreq)		}	 }	 	 if(motor->steps >= motor->totalstep)	 {	 	 motor->starting = FALSE;	 }	 	 if(FALSE == motor->starting)	 {	 	MOTOR_A_DISABLE();	 }else{	 	motor->curfrequency = freq;	 	fnMT_Cal_MotorA_TimeConf();	 }

实践

下面是生成S曲线数值表、控制步进电机启动、停止的视频,从视频上可以明显看到启动时慢加速->快加速->慢加速的过程,以及停止时慢减速->快减速->慢减速的过程。