当前位置:首页 > 工业控制 > 工业控制
[导读]步进电机失步不是“程序发少了脉冲”,而是脉冲频率爬得太快——转子惯性跟不上定子磁场切换。启动频率超过自启动频率、加速度过陡、高速段转矩掉到负载需求以下,都会丢步;急停同理。 工业场景解决方式不是降速将就,而是把速度曲线做成S型:加速度从0平滑升起、再平滑回落,消除梯形曲线在加速段起点/终点的冲击(jerk突变)。


步进电机失步不是“程序发少了脉冲”,而是脉冲频率爬得太快——转子惯性跟不上定子磁场切换。启动频率超过自启动频率、加速度过陡、高速段转矩掉到负载需求以下,都会丢步;急停同理。 工业场景解决方式不是降速将就,而是把速度曲线做成S型:加速度从0平滑升起、再平滑回落,消除梯形曲线在加速段起点/终点的冲击(jerk突变)。

一、脉冲频率由定时器ARR决定

STEP/DIR接口本质就两个问题:发多少脉冲、每个脉冲间隔多久。用定时器PWM输出STEP,ARR决定脉冲周期,改ARR就是改速度:

/* 定时器时钟10MHz,目标脉冲频率freq Hz */

uint16_t arr_of(uint32_t freq){

   if(freq<200) freq=200;          // 限最低启动频率

   return (10000000UL/freq)-1;

}

中断里改ARR,下一个溢出周期才生效,脉冲不会出毛刺。 高频场景建议PWM+DMA搬ARR,别在中断里翻转IO。

二、S型曲线用查表,别运行时算sin

嵌入式端别每步算Sigmoid/三次多项式,预存归一化表即可:

#define SC_N 64

static const uint8_t sc_table[SC_N] = {

0,1,2,4,6,9,12,15,18,22,26,30,34,38,42,46,

50,54,58,62,66,69,73,76,79,82,85,87,89,91,93,94,

95,96,97,97,98,98,99,99,99,99,100,100,100,100,

100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100

};

表里是“当前速度占目标速度百分比”。加速段正向查,减速段镜像查。

三、三段状态机

总步数N,加速段/减速段各分N_acc步,中间匀速:

typedef enum{ACCEL, RUN, DECEL, STOP}st_t;

typedef struct{

   st_t st;

   uint32_t step;        // 已发步数

   uint32_t total;

   uint32_t acc_steps;

   uint32_t dec_steps;

   uint32_t start_f;      // 启动频率,如400Hz

   uint32_t max_f;        // 最高频率,按负载留余量

}sctrl_t;


void stepper_plan(sctrl_t*c, uint32_t steps, uint32_t maxf){

   c->total=steps; c->step=0;

   c->start_f=400; c->max_f=maxf;

   c->acc_steps = steps/4;

   c->dec_steps = steps/4;

   c->st = (steps<=c->acc_steps*2)? ACCEL : ACCEL;

}


uint32_t next_freq(sctrl_t*c){

   if(c->st==RUN) return c->max_f;


   uint32_t idx, ratio;

   if(c->st==ACCEL){

       idx = (c->step*SC_N)/c->acc_steps;

       if(idx>=SC_N) idx=SC_N-1;

       ratio = sc_table[idx];

       return c->start_f + (c->max_f-c->start_f)*ratio/100;

   }

   /* DECEL:从当前往回查 */

   uint32_t left = c->total - c->step;

   idx = (left*SC_N)/c->dec_steps;

   if(idx>=SC_N) idx=SC_N-1;

   ratio = sc_table[SC_N-1-idx];

   return c->start_f + (c->max_f-c->start_f)*ratio/100;

}

每次发完一拍调用一次,算出新频率写ARR。

四、状态切换与减速余量

关键防失步点:减速必须提前进,别等剩最后一步才刹。

void stepper_tick(sctrl_t*c){

   if(c->st==STOP) return;


   if(c->st==ACCEL){

       if(c->step >= c->acc_steps){

           c->st = (c->total-c->step <= c->dec_steps)? DECEL : RUN;

       }

   }else if(c->st==RUN){

       if(c->total - c->step <= c->dec_steps)

           c->st = DECEL;

   }else if(c->st==DECEL){

       if(c->step >= c->total){

           c->st = STOP;

           pwm_stop();

           return;

       }

   }


   uint32_t f = next_freq(c);

   tim_set_arr(arr_of(f));

   emit_step();

   c->step++;

}

短行程(步数少于2倍加速段)直接ACCEL转DECEL,不做匀速段,否则中点速度没起来就进减速。

五、失步保护的几个硬规矩

开环步进“发完脉冲”≠“走到位置”,工业现场要加兜底:

启动频率别贪:空载能起不代表带载能起,从300~500Hz起步最稳

最高频率留余量:标称能跑8kHz,实际按6~7kHz设,高速转矩余量就这点

方向切换在STEP低电平时:DIR在脉冲中间翻会被驱动器当成多一步

加减速步数随负载调:惯量大就把acc_steps提到total/3

驱动器nFAULT接中断:过流/过温立刻停脉冲

关键工位加编码器:定时器编码器接口读实际位置,偏差超阈值报失步

细分别盲加:1/32比1/8脉冲频率翻倍,高频更易丢步

六、落坑清单

直接给8000Hz起步→堵转丢步

梯形曲线急加速→启动冲击响

减速段只剩5步才进→过冲失步

中断里翻转IO发STEP→高频抖动

DIR和STEP同时改→多走一步

最高频率顶着手册上限设→带载就掉

不加nFAULT处理→驱动过温无声停机

开环默认“发完即对”→位置慢慢漂

细分1/32硬上高速→脉冲频率超标

S表运行时算sin→M0/M3卡中断

七、落地顺序

定时器PWM出STEP,先定频跑通不丢步

起频400Hz左右,ARR查表改速

加三段状态机:ACCEL/RUN/DECEL

S曲线归一化表替代梯形

减速段按剩余步数提前切入

短行程合并加速减速

DIR切换时序、nFAULT中断

关键轴接编码器做失步校验

S型加减速的价值不是“曲线好看”,是把加速度突变吃掉——步进电机高速段转矩本来就往下掉,再叠加急加速的惯性冲击,转子必跟不上。 工程上真正稳的做法是:起频低一点、加速段铺长一点、最高频留余量、减速提前进、关键工位补编码器。代码层面用查表法几乎零浮点开销,F103级MCU也跑得动;别在中断里算曲线函数,预存表+ARR映射就够了。



本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
关闭