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

理论为了实现步进电机的平缓启停,避免高速旋转时的步进停止 。在步进电机的启动和停止过程中,需要采用加减速算法来控制启动过程 。s曲线是最理想的加减速控制方案 。但是S曲线的公式和控制过程比较复杂 。这种算法基于单片机的实现需要单片机深厚的数学和软件设计能力 。
本视频由浅入深的介绍了S曲线加减法的理论、编程和实践 。
S曲线被离散化 。在整个加减速过程中,频率以一定的时间间隔更新 。更新总数为2*N,I为第I次更新 。那么第I次更新的频率f(i)表示为:
其中fb为起始频率,fr为最终运行频率,α为曲线的展开系数,一般可以是3 ~ 5之间的常数 。
比如启动加速,启动频率400Hz,运行频率5KHz 。
减速,启动频率为5KHz,停止频率为400Hz,
加减速时间为1s,频率每隔10ms更新一次,共100次,α为5 。
可以绘制以下加速和减速曲线:
编程 步进电机S曲线的加减速控制通过以下步骤实现:
配置1ms的定时器以及1ms的中断程序 在中断程序中对加减速的频率更新次数i进行计数 配置产生步进电机驱动信号的PWM模块,设置PWM的定时中断以及中断程序 在PWM的定时中断程序中,计算当前更新次数对应的频率,并按出来的频率更新PWM的频率以及占空比 在PWM的定时中断程序中,计算步进电机运行的步数,如果达到设置的步数减去停止的S曲线减速运行所设置的步数,则开始减速运行 。同时检测外部输入,如果有需要停止运行的输入条件,则开始减速运行 。整个加减速控制过程的难度是:
步进电机的计步以及频率更新需要在每一个PWM中断中进行 。步进电机的运行频率最高到40KHz,这种频率下,PWM的定时中断周期达到了25us,PWM定时器中断程序运行总时间尽量小,根据经验至少小于中断周期的30%,即7.5us 。一旦超过这个数值,导致所有中断程序(包括PWM定时中断程序)漏运行,基本主程序无法运行,导致整个控制器假死现象 。根据S曲线的公司是一个复杂的非线性的指数浮点数运算,需要耗费大量的时间,直接调用C语言的库函数计算这一数值可能耗费几十上百毫秒 。为了解决S曲线的运算时间问题,基于STM32F103,我采用了查表法 。具体步骤如下:
1.定义α 5的值,
的取值范围是-5~5 。
2.在整个加速和减速过程中,表达式
在-5~5范围内均匀取1024个值,得到数值表 。
3.定义一个有1024个元素的无符号短数组,用来存储数字表 。
4.Const数组存储在内部flash中,数值表总共占用2048字节 。
STM32F103RTC6总共占用256K,程序组和设置参数占用48K,bootloader程序占用8K,远程升级空占用100K 。目前应用程序只需要40K左右 。
还剩60K 空间左右,预留2K 空间存放数值表 。还有空间,就是这么任性 。
5.在中断程序中,根据总更新次数和当前更新计数值,计算
值,然后映射到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;} udata a =(signed int)(maxfreq-minfreq)* g _ MC _ uch exp[uiRes];udata a = udata a/65535;uid ataa =(signed int)udata a;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 = http://www.laomaozy.com/W-Z/(int)MOTOR_A_STEPS_GET(); if(motor->direction == 0) { data = http://www.laomaozy.com/W-Z/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 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(); } 实践


推荐阅读