ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

STM32步进电机搅拌机控制:定时器PWM实现多档调速与正反转

STM32步进电机搅拌机控制:定时器PWM实现多档调速与正反转 做搅拌机控制大多数人的第一反应是用直流减速电机加一个调压模块。这样做不仅转速会随负载波动正反转切换、定时停机也要额外搭不少电路。而换成 STM32 控制步进电机之后整个问题会变得非常干净转速就是脉冲频率角度就是脉冲个数。不需要测速编码器不需要复杂的速度环只要单片机把脉冲数发准电机就会按照预期转。本文要做一个基于 STM32F103 的步进电机搅拌机控制系统。项目不追求复杂目标是跑通一条完整链路按键启停、正反转切换、多档调速、连续搅拌。实现上采用 HAL 库加定时器 PWM 输出步进驱动器选常见的 A4988 或 DRV8825既有教学意义也贴近实际工程里“定时器发脉冲”的核心思路。读完这篇文章你能得到三样东西一套可以直接编译下载的 STM32 步进电机控制代码代码不依赖额外库一张完整的硬件接线图和 CubeMX 配置步骤照着做就能点亮电机一份针对“电机不转、抖动、丢步、复位”的排查清单遇到问题不用瞎猜。1. 这篇文章真正要解决的问题很多单片机初学者学过 GPIO、定时器、中断但不知道它们组合起来能做成一台完整设备。搅拌机控制就是一个典型练习它既有维度适中的交互逻辑又有真实电机驱动还涉及供电和抗干扰做完之后对 STM32 的理解会上一个台阶。这个项目的核心需求如下需求说明启停控制按键按下后电机开始搅拌再次按下停止方向控制支持正转、反转切换模拟搅拌时的正反向混合速度调节至少 3 档转速正常搅拌、快搅、慢搅连续运行搅拌过程是长时间连续转动不是精确转多少圈状态指示用 LED 显示运行状态和方向从控制原理上看步进电机由驱动器接收 STEP 脉冲每个脉冲走一步。所以软件要做的核心工作有两件产生频率可变的脉冲统计已经发送的脉冲个数。这两件事用定时器 PWM 加中断计数来完成是最合理的方案也是实际工程中最常采用的做法。这件事对三类人最有价值正在做课程设计或毕业设计需要“STM32 步进电机 按键/显示”的完整案例学过 51 单片机想转到 STM32 但不知道从哪个项目切入的初学者做小家电原型验证需要快速实现搅拌、混合、送料类功能的嵌入式工程师。这里真正容易踩坑的地方是很多人用 HAL_Delay 做延时在主循环里翻转 GPIO 去模拟脉冲。这样写代码很简单但电机一旦跑起来整个 MCU 都被延时占住按键响应全是问题。所以本文直接采用定时器 PWM 更新中断计数方案电机脉冲由硬件生成CPU 只需要响应按键和状态切换。2. 步进电机基础两相四线混合式步进电机与控制原理2.1 为什么搅拌机要选步进电机直流减速电机结构简单、扭矩大但它的转速会随负载变化。当搅拌物变稠时电机转速明显下降如果没有测速编码器很难做出稳定的匀速搅拌。步进电机是开环控制脉冲频率和转速严格对应。只要驱动器收到频率稳定的脉冲电机转速就稳定不受负载小范围波动影响。这在搅拌、送料、混合类设备中非常实用。2.2 两相四线混合式步进电机的结构常见的两相四线混合式步进电机有四根引出线分别对应两相绕组A、A-、B、B-。定子由软磁材料加工成多个磁极转子是永磁体加上软铁齿。通电顺序决定了旋转方向通电频率决定了转速。用万用表电阻挡可以轻松判断引线关系测量方式结果同相两根线之间电阻较小通常在几欧姆到几十欧姆之间不同相两根线之间电阻无穷大或非常大例如常见的 42 步进电机步距角为 1.8 度转一圈需要 200 个完整脉冲也就是 200 步/圈。2.3 步进电机驱动模块的作用STM32 的 GPIO 无法直接驱动电机绕组必须经过驱动模块。常见的驱动方案有驱动方案适用电机特点A4988 / DRV8825两相四线混合式步进电机支持细分、电流可调、使用广泛ULN200324BYJ48 四相五线步进电机便宜但驱动能力弱适合小扭矩演示L298N大电流步进或直流电机压降大效率低现在工程中较少用本项目使用 A4988因为 STM32 输出 STEP、DIR、EN 三个信号就可以控制电机。即使后续换成 DRV8825代码逻辑也完全一样只需注意使能引脚极性和驱动板电流设置。2.4 步进电机控制的两个基本公式设步距角为 1.8 度即 200 步/圈。目标转速为 RPM转/分钟时每秒需要的脉冲数为脉冲频率 RPM × 200 / 60如果想控制电机精确转动一定角度需要的脉冲数为脉冲数 目标角度 / 步距角例如目标转速 60 RPM则脉冲频率为 200 Hz目标角度 90 度则脉冲数为 50 个。理解这两个公式后面所有代码都能对上号。3. 系统方案与硬件接线3.1 系统整体方案系统由四部分组成STM32F103C8T6 最小系统板负责按键读取、逻辑判断、PWM 输出A4988 步进驱动板接收 STM32 的 STEP 脉冲输出到步进电机绕组两相四线步进电机执行转动电源、按键、LED提供动力和交互。运行逻辑是用户按下按键STM32 设置 TIM2 PWM 的频率和脉冲计数目标然后启动 PWM 输出。A4988 每收到一个 PWM 上升沿就驱动电机走一步。到达目标步数后定时器更新中断里自动停止 PWM。3.2 引脚分配表STM32 引脚功能说明PA0STEPTIM2_CH1 PWM 输出到 A4988 STEPPA1DIR方向控制高电平正转低电平反转PA2EN驱动使能低电平有效PB0KEY1启动/停止搅拌PB1KEY2切换方向PB10KEY3切换速度档位PC13LED1运行指示灯板载 LEDPB12LED2方向指示灯接线时注意两点必须共地A4988 的逻辑 GND 与 STM32 的 GND 要连在一起否则 STEP 信号没有参考地电机不转电机电源独立电机电源不要从 STM32 开发板的 3.3V 取电直接从 12V/24V 电源给 A4988 供电。3.3 A4988 与 STM32 接线STM32 A4988 3.3V - VDD GND - GND PA0/STEP - STEP PA1/DIR - DIR PA2/EN - ENABLE电机电源部分12V 电源正极 - A4988 VMOT 12V 电源负极 - A4988 GND A4988 1A、1B - 电机 A 相两根线 A4988 2A、2B - 电机 B 相两根线A4988 的 MS1、MS2、MS3 引脚悬空时细分为 1也就是整步模式。如果想降低振动和噪声可以将 MS1、MS2、MS3 接到高电平设置为 16 细分。后面代码里的MICRO_STEP宏需要与硬件设置保持一致。4. 开发环境准备4.1 软件工具项目使用标准 HAL 库配套工具如下工具用途Keil MDK代码编译和下载调试STM32CubeMX图形化配置芯片引脚、时钟、定时器STM32 ST-LINK Utility备用烧录工具也可以用 Keil 直接下载工具版本请以实际安装为准本文重点演示通用配置流程。如果电脑里已经有 Keil MDK 和 CubeMX可以直接开始。4.2 新建工程前需要注意的事在 CubeMX 中新建工程时芯片选择STM32F103C8T6。F103C8T6 是 64 KB Flash、20 KB RAM 的 M3 内核芯片跑本项目绰绰有余。时钟配置为外部 8 MHz 晶振倍频到 72 MHz这是 F103 系列最常见的主频设置。如果板子上没有外部晶振也可以选择内部 HSI 时钟但需要注意后续定时器计算公式中时钟源不同。5. STM32CubeMX 配置与工程生成5.1 基本配置步骤打开 STM32CubeMX新建工程并选择 STM32F103C8T6然后按以下步骤配置。RCC 配置在System Core - RCC中将 HSE 设置为Crystal/Ceramic Resonator。SYS 配置在System Core - SYS中将 Debug 设置为Serial Wire这样可以保留 SWD 下载调试接口。时钟树配置进入Clock Configuration将 HCLK 设置为 72 MHz系统会自动计算其他分频值。关键分频结果是 APB1 定时器时钟为 72 MHzTIM2 挂在 APB1 上。5.2 GPIO 配置在引脚图上点击对应的引脚选择功能引脚功能模式说明PB0GPIO_Input上拉输入PB1GPIO_Input上拉输入PB10GPIO_Input上拉输入PC13GPIO_Output运行指示 LEDPB12GPIO_Output方向指示 LEDPA1GPIO_OutputDIR 控制PA2GPIO_OutputEN 控制PA0TIM2_CH1复用功能TIM2 通道 1 PWM 输出PB0、PB1、PB10 作为按键输入在 GPIO 设置中配置为 Internal Pull-Up。按键另一端接地按下时读到低电平。5.3 TIM2 PWM 配置在Timers - TIM2中Clock Source : Internal Clock Channel1 : PWM Generation CH1 Prescaler : 71 Counter Period : 100 Auto Reload Preload : Enable Pulse : 50这样 TIM2 通道 1 的 PWM 频率初始值为PWM频率 72MHz / ((71 1) × (100 1)) ≈ 10 kHz但这只是初始值实际转速会在代码里动态修改 ARR 寄存器所以初始值只需要合理即可。在NVIC Settings中勾选TIM2 global interrupt这是脉冲计数的关键。5.4 生成工程点击Project Manager设置工程名称和路径Toolchain 选择MDK-ARM。在Code Generator中勾选Generate peripheral initialization as a pair of .c/.h files per peripheral方便按外设管理代码。生成后使用 Keil 打开工程编译一次确认没有基础错误后再写应用代码。6. 代码实现PWM 精确控制步进电机6.1 代码文件规划CubeMX 生成工程后用户代码主要写在main.c、stepper.c、stepper.h中。stepper.c负责步进电机控制main.c负责按键逻辑和系统状态管理。6.2 新建 stepper.h在Core/Inc目录下新建头文件// 文件路径Core/Inc/stepper.h #ifndef __STEPPER_H #define __STEPPER_H #include main.h void Stepper_Start(float rpm, uint32_t steps, uint8_t dir); void Stepper_Stop(void); void Stepper_SetSpeed(float rpm); extern volatile uint32_t gStepCount; extern volatile uint32_t gTargetSteps; extern volatile uint8_t gStepperBusy; #endif6.3 新建 stepper.c在Core/Src目录下新建源文件// 文件路径Core/Src/stepper.c #include stepper.h #include tim.h #define STEPS_PER_REV 200 #define MICRO_STEP 1 volatile uint32_t gStepCount 0; volatile uint32_t gTargetSteps 0; volatile uint8_t gStepperBusy 0; static void Step_SetDir(uint8_t dir) { // 正向定义为 DIR 引脚高电平 HAL_GPIO_WritePin(DIR_GPIO_Port, DIR_Pin, dir ? GPIO_PIN_SET : GPIO_PIN_RESET); } static void Step_Enable(uint8_t en) { // A4988 的 EN 为低电平有效 HAL_GPIO_WritePin(EN_GPIO_Port, EN_Pin, en ? GPIO_PIN_RESET : GPIO_PIN_SET); } void Stepper_Stop(void) { HAL_TIM_PWM_Stop(htim2, TIM_CHANNEL_1); gStepperBusy 0; gStepCount 0; Step_Enable(0); } void Stepper_SetSpeed(float rpm) { uint32_t f_pulse 0; uint32_t arr 0; if (rpm 0.0f) { return; } // 每秒脉冲数 转速 * 每圈步数 / 60 f_pulse (uint32_t)(rpm * STEPS_PER_REV * MICRO_STEP / 60.0f); if (f_pulse 0) { f_pulse 1; } if (f_pulse 100000) { f_pulse 100000; } // PSC71 时定时器时钟 72MHz / 72 1MHz // ARR 1MHz / 脉冲频率 - 1 arr 1000000U / f_pulse - 1U; __HAL_TIM_SET_AUTORELOAD(htim2, arr); __HAL_TIM_SET_COMPARE(htim2, TIM_CHANNEL_1, arr / 2U); } void Stepper_Start(float rpm, uint32_t steps, uint8_t dir) { if (gStepperBusy) { Stepper_Stop(); } Step_SetDir(dir); Step_Enable(1); Stepper_SetSpeed(rpm); gStepCount 0; gTargetSteps steps; gStepperBusy 1; __HAL_TIM_SET_COUNTER(htim2, 0); HAL_TIM_PWM_Start(htim2, TIM_CHANNEL_1); } // 定时器更新中断回调 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim-Instance TIM2) { if (gStepperBusy) { gStepCount; if (gStepCount gTargetSteps) { HAL_TIM_PWM_Stop(htim2, TIM_CHANNEL_1); gStepperBusy 0; gStepCount 0; Step_Enable(0); } } } }代码的关键逻辑是Stepper_SetSpeed根据目标转速计算 ARRPWM 频率等于脉冲频率Stepper_Start设置方向、使能驱动、启动 PWM 输出在HAL_TIM_PeriodElapsedCallback中每产生一个 PWM 周期步进电机就走一步计数加一到达目标步数后自动停止 PWM并释放驱动使能。这个方案的精髓在于PWM 波形完全由硬件产生中断只做计数。CPU 不需要在脉冲间隙等待按键响应非常顺滑。6.4 编写 main.c 主逻辑在main.c的用户代码区添加以下逻辑。定义全局状态#define SPEED_LEVELS 3 #define CONTINUOUS_STEPS 0xFFFFFFFF static const float speed_table[SPEED_LEVELS] {30.0f, 60.0f, 120.0f}; static uint8_t speed_index 1; static uint8_t current_dir 0; static uint8_t running 0;编写按键扫描函数这里使用最简单实用的消抖方式uint8_t Key_Scan(void) { if (HAL
返回列表