开发板STM32三轴联动插补加减速源码(基于STM32F1和STM32F4,带中文注释版)

张开发
2026/4/12 17:15:35 15 分钟阅读

分享文章

开发板STM32三轴联动插补加减速源码(基于STM32F1和STM32F4,带中文注释版)
开发板STM32 三轴联动 带插补 加减速 源代码 MDK 源码 分别基于STM32F1和STM32F4两套的三轴联动插补(直线圆弧两种带)加减速的源码基于国外写的脱机简易雕刻机源码的项目修改添加了大量的中文注释可以很好帮助大家学习这个源码。最近在捣鼓三轴运动控制系统发现网上有个基于STM32的脱机雕刻机项目挺有意思。原版代码是国外开发者写的但咱们团队把它扒拉过来魔改了一波——不仅移植到F1和F4两个平台还往源码里怼了上万字的中文注释现在连刚入门的小白都能看明白那些骚操作。先看工程结构项目里最带劲的是这个运动控制核心// 三轴联动主控函数F4版本用DSP库加速 void Motion_Core_Update(void) { // 实时计算剩余步数 int32_t steps_remaining max(max(x_steps, y_steps), z_steps); // 动态调整脉冲频率核心加速算法 if (steps_remaining 200) { current_freq max_freq; // 全速飙车模式 } else { current_freq sqrt(2 * accel * steps_remaining); // 减速曲线计算 } TIM_SetAutoreload(STEP_TIMER, SystemCoreClock / current_freq / 2); }这段代码里藏着速度变化的灵魂。当剩余步数足够多时直接满速跑接近终点时用平方根函数做平滑减速实测效果比某些商用驱动器还丝滑。直线插补的实现比想象中简单粗暴void Line_Interp(int32_t target[], float feedrate) { // 计算各轴总步数 x_steps labs(target[X] - current_pos[X]); y_steps labs(target[Y] - current_pos[Y]); z_steps labs(target[Z] - current_pos[Z]); // 取最大步数作为基准 step_count max(x_steps, max(y_steps, z_steps)); // 步进增量计算避免浮点运算 x_inc (target[X] - current_pos[X]) 16 / step_count; y_inc (target[Y] - current_pos[Y]) 16 / step_count; z_inc (target[Z] - current_pos[Z]) 16 / step_count; // 启动加减速调度器 Accel_Engine_Start(step_count); }这里用定点数运算替代浮点F1版本直接硬算F4版则用Q格式处理。看到那个16操作没这其实是用65536作为定点数精度既保证计算速度又不会溢出。开发板STM32 三轴联动 带插补 加减速 源代码 MDK 源码 分别基于STM32F1和STM32F4两套的三轴联动插补(直线圆弧两种带)加减速的源码基于国外写的脱机简易雕刻机源码的项目修改添加了大量的中文注释可以很好帮助大家学习这个源码。圆弧插补就有点东西了核心算法改编自Bresenham圆算法// 圆弧插补状态机 typedef struct { int32_t x, y; int32_t d; uint8_t quadrant; uint16_t over90_flag; } Arc_State; void Arc_Interp(Arc_State *arc) { while(arc-d 0) { step_X(); // 输出X轴脉冲 arc-d 2 * arc-x 1; arc-x; if(arc-d 0) { step_Y(); // 输出Y轴脉冲 arc-d 2 * (arc-y - arc-x) 1; arc-y--; } // 处理象限切换 if(arc-x arc-y !arc-over90_flag) { arc-quadrant; arc-over90_flag 1; } } }这状态机跑起来跟贪吃蛇似的通过误差项d的正负决定移动方向。代码里藏了个象限切换的骚操作处理超过90度的圆弧时自动跳转实测画圆精度能控制在±2个脉冲内。F1和F4两套代码最大的区别在定时器配置上。F1用标准库操作TIM3// F1的定时器初始化72MHz主频 void STEP_TIM_Init(void) { TIM_TimeBaseInitTypeDef timer; timer.TIM_Prescaler 0; // 不分频 timer.TIM_CounterMode TIM_CounterMode_Up; timer.TIM_Period 7200; // 初始10kHz TIM_TimeBaseInit(TIM3, timer); TIM_Cmd(TIM3, ENABLE); }而F4用HAL库HALTIMOCStartDMA玩起了高级操作// F4的DMA脉冲发射168MHz主频 void STEP_DMA_Start(void) { HAL_TIM_PWM_Start(htim1, TIM_CHANNEL_1); HAL_TIM_OC_Start_DMA(htim1, TIM_CHANNEL_2, (uint32_t*)pulse_buffer, PULSE_BUF_SIZE); }F4的DMA传输配合预装载缓冲实测脉冲频率能飚到200kHz不带丢步的。不过要注意用DMA时GPIO必须配置为复用推挽模式否则输出波形会变方波它二舅——方不起来。源码里最实用的其实是这个加速度曲线生成器// 梯形加减速参数生成 void Accel_Engine_Calc(int32_t total_steps) { // 计算加速段步数 uint32_t accel_steps (max_freq * max_freq) / (2 * accel); if(total_steps 2 * accel_steps) { // 完整梯形加速-匀速-减速 cruise_steps total_steps - 2 * accel_steps; } else { // 三角波模式只有加减速 accel_steps total_steps / 2; cruise_steps 0; } // 生成速度曲线表 for(int i0; iaccel_steps; i){ speed_table[i] sqrt(2 * accel * i); // 加速段 } }这个算法妙在自动识别运动距离是否够跑完加速匀速减速三个阶段。当总步数太少时自动切换成三角波模式实测在小距离移动时明显比固定梯形加速流畅。想跑起来这套代码记得改这几个地方在motor_pin.h里配置实际使用的GPIO引脚根据机械结构调整stepspermm参数F4版本需要开启FPU和DSP库定时器中断优先级要设为最高最后说个坑原版代码的圆弧插补只支持XY平面要搞三维螺旋插补得自己改插补算法。不过拿这个做基础来魔改比从头写至少省两个月咖啡钱。源码包里带了激光雕刻和CNC两种配置示例拿烙铁的时候小心别把开发板烫出烤肉味就行。

更多文章