STM32 蜗轮蜗杆电机控制系统设计

STM32 蜗轮蜗杆电机控制系统设计文档


目录

  1. 系统概述
  2. 硬件接线
  3. 代码架构设计
  4. 调试问题排查
  5. 控制器配置详解

1. 系统概述

本系统以 STM32F103(72MHz) 为主控,运行 FreeRTOS ,接收三路遥控信号源(PPM / SBUS / PX4 MAVLink),经优先级仲裁后驱动 蜗轮蜗杆执行机构

执行机构由 步进电机 + DM860H 驱动器 组成,STM32 通过 TIM1 输出可变频率 PWM 作为 STEP 脉冲,GPIO 控制方向:

复制代码
遥控信号源
  ├── PPM   (PA7 / TIM3 输入捕获)
  ├── SBUS  (PB11 / USART3)
  └── PX4   (PA3 / USART2 MAVLink)
        │
        ▼ 优先级仲裁(wlwg_Tasks)
        │
        ▼
  TurboControl_SetCommandUs(command_us)
        │
   ┌────┴────────────────────┐
   PA9 (TIM1 CH2 STEP 脉冲)  PB15 (DIR 方向)
        │                         │
        └──────────┬──────────────┘
                   ▼
             DM860H 驱动器
                   │
                   ▼
           步进电机 → 蜗杆机构

2. 硬件接线

2.1 引脚总览

引脚 复用功能 方向 连接到
PA7 TIM3_CH2 输入捕获 ← 输入 PPM 接收机信号线
PA9 TIM1_CH2 AF_PP → 输出 DM860H PUL+(STEP 脉冲)
PB15 GPIO 推挽输出 → 输出 DM860H DIR+(方向)
PA2 USART2_TX → 输出 PX4 飞控 RX
PA3 USART2_RX ← 输入 PX4 飞控 TX(MAVLink)
PB11 USART3_RX ← 输入 SBUS 接收机(100k 8E2 反相)

2.2 DM860H 接线

复制代码
STM32                        DM860H
────────────────────────────────────────
PA9  ─── ----------- ──→  PUL+
GND  ──────────────────→  PUL−
PB15 ───-------------──→  DIR+
GND  ──────────────────→  DIR−
(ENA+ / ENA− 可不接,默认使能)

PUL 脉冲宽度需 ≥ 2.5μs,本设计占空比 50%,最低频率 200Hz 时

脉冲宽度 2500μs,最高频率 5kHz 时脉冲宽度 100μs,均满足要求。

2.3 定时器配置

TIM1(STEP 脉冲输出)

参数
时钟源 72MHz APB2
预分频 Prescaler 71(÷72 → 1MHz)
分辨率 1 μs / count
模式 PWM1,CH2,AF_PP
ARR(初始) 999(运行时动态修改)
占空比 50%(CCR = (ARR+1)/2)

TIM3(PPM 输入捕获)

参数
预分频 71(→ 1MHz)
捕获极性 下降沿
计数上限 65535

3. 代码架构设计

3.4 涡轮涡杆 完整控制流(设计目标)

当前代码使用硬编码测试值 TurboControl_SetCommandUs(1200U),完整实现应为:

c 复制代码
void Start_wlwg_Tasks(void *argument)
{
    for (;;) {
        uint32_t now_ms = HAL_GetTick();

        /* 仲裁选源 */
        osMutexAcquire(g_controlMutexHandle, osWaitForever);
        select_active_channels_locked(now_ms);
        osMutexRelease(g_controlMutexHandle);

        /* CH2(油门通道)→ 蜗杆执行机构 */
        TurboControl_SetCommandUs(g_active_channels[2]);

        osDelay(10);
    }
}

4. 调试问题排查

问题一:CLion 监视窗口报 "No symbol in current context"

现象 :监视 calculated_freq_hzcalculated_period_uslast_command_us 报错。

原因 :这三个名字是结构体 g_turbo_dbg 的成员,不是独立全局变量,GDB 无法直接按裸名查找。

解决:在 CLion Watches 中改用完整路径:

复制代码
# 错误
calculated_freq_hz

# 正确
g_turbo_dbg.calculated_freq_hz
g_turbo_dbg.calculated_period_us
g_turbo_dbg.last_command_us
g_turbo_dbg.update_count
g_turbo_dbg.pwm_running
g_turbo_dbg.direction

问题二:wlwg_Tasks 从未运行------FreeRTOS 堆溢出

现象

复制代码
g_turbo_dbg.update_count   = 0   ← TurboControl_SetCommandUs 从未被调用
g_turbo_dbg.last_command_us = 1000 ← 停在 Init 初始值,从未变为 1200
s_working_channels[]        正常跳变(PPM 任务在运行)

update_count = 0 直接证明 wlwg_Tasks 从未被调度器运行过,

原因是任务在创建阶段就已失败(osThreadNew 返回 NULL)。

根本原因:堆空间不足

c 复制代码
// FreeRTOSConfig.h 原值
#define configTOTAL_HEAP_SIZE  ((size_t)3072)   // 仅 3KB

FreeRTOS 使用 heap_4 动态分配,每次 osThreadNew 从堆申请:

申请项 大小(估算)
任务 TCB(含 Trace / Mutex 字段) ~96 字节
任务栈(128 words × 4) 512 字节
heap_4 块头 × 2 16 字节
每个任务小计 ~624 字节
复制代码
5 个用户任务:5 × 624 = 3120 字节
1 个 Mutex  :          ~88 字节
─────────────────────────────────
合计需求:             ~3208 字节  >  3072 字节(超出!)

wlwg_Tasks 是第 5 个被创建的任务,堆在此之前已耗尽,
osThreadNew 返回 NULL,任务句柄无效,调度器永远不调度它。

Idle Task 和 Timer Task 因 configSUPPORT_STATIC_ALLOCATION = 1

使用静态内存,不占堆,但五个用户任务和 mutex 均为动态分配。

修复

c 复制代码
// FreeRTOSConfig.h 修改后
#define configTOTAL_HEAP_SIZE  ((size_t)8192)   // 8KB,剩余 SRAM 仍有 12KB

预防方法:任务全部创建完毕后在调试器控制台执行:

复制代码
p xPortGetFreeHeapSize()

返回 0 说明堆已耗尽;建议保留至少 512 字节裕量。

每次增加任务时的估算公式

复制代码
新增需求 = sizeof(TCB_t) + 栈字数 × 4 + 16
         ≈ 96 + stack_words × 4 + 16

增加一个 128 words 栈的任务 ≈ 624 字节

wlwg 调试变量快速检查清单

在 CLion Live Watch 中添加以下表达式,可实时判断控制器状态:

监视表达式 正常值 异常说明
g_turbo_dbg.update_count 持续递增 为 0 → 任务未运行(堆溢出)
g_turbo_dbg.last_command_us 950~2000 停在 1000 → 从未被调用
g_turbo_dbg.pwm_running 0 或 1 长时间为 0 → 命令在死区内
g_turbo_dbg.calculated_freq_hz 200~5000 为 0 → 停止状态
g_turbo_dbg.calculated_period_us 200~5000 为 0 → 停止状态
g_turbo_dbg.direction +1 或 -1 0 → 停止

5. 控制器配置详解

5.1 DM860H 拨码开关设置

DM860H 通过 SW1~SW8 配置电流和细分:

电流设置(SW1~SW3):根据步进电机额定电流选择,常用设置:

SW1 SW2 SW3 峰值电流
ON ON ON 2.4A
OFF ON ON 2.7A
ON OFF ON 3.0A
OFF OFF ON 3.7A
ON ON OFF 4.3A
OFF ON OFF 5.0A
ON OFF OFF 6.0A
OFF OFF OFF 7.2A

细分设置(SW5~SW8):细分越高转动越平滑但最高转速越低:

SW5 SW6 SW7 SW8 细分数 步/转(1.8°电机)
ON ON ON ON 1 200
OFF ON ON ON 2 400
ON OFF ON ON 4 800
OFF OFF ON ON 8 1600
ON ON OFF ON 16 3200
OFF ON OFF ON 32 6400
ON OFF OFF ON 64 12800
OFF OFF OFF ON 128 25600

推荐从 8 细分(SW5=OFF SW6=OFF SW7=ON SW8=ON)开始调试,

此时最高频率 5kHz 对应 5000/1600 = 3.125 转/秒 = 187.5 RPM。

SW4:静止时电流(ON = 半流,OFF = 全流)。推荐 ON(半流锁轴,减少发热)。


5.2 频率映射与速度计算

控制量 command_us(1000 为中位)经过如下变换得到 PWM 频率:

复制代码
step 1:提取偏移量
  centered = command_us - 1000
  delta    = |centered|,限制在 [50, 1000]

step 2:线性映射到频率
  freq_hz = 200 + (delta - 50) × 4800 / 950

  delta=50   → freq_hz = 200  Hz(最慢)
  delta=1000 → freq_hz = 5000 Hz(最快)

step 3:计算周期
  period_us = 1_000_000 / freq_hz
  限制范围:[200μs, 5000μs]

step 4:写入定时器
  ARR = period_us - 1
  CCR = (ARR + 1) / 2    (50% 占空比)

实际转速换算(以 8 细分、1.8° 步进电机为例):

复制代码
转速(RPM) = freq_hz × 60 / steps_per_rev
          = freq_hz × 60 / 1600

200  Hz → 7.5  RPM
1000 Hz → 37.5 RPM
3000 Hz → 112  RPM
5000 Hz → 187  RPM

5.3 死区与方向逻辑

复制代码
command_us
    │
    ├─ 950 ~ 1050 ──→ 死区
    │                  HAL_TIM_PWM_Stop()
    │                  PWM 停止,电机锁轴
    │
    ├─ > 1050 ────→ 正转
    │                  DIR = PB15 HIGH(GPIO_PIN_SET)
    │                  delta = command_us - 1000
    │
    └─ < 950 ─────→ 反转
                       DIR = PB15 LOW(GPIO_PIN_RESET)
                       delta = 1000 - command_us

换向保护 :检测到方向改变时先停 PWM,延时 2ms 再重启,

防止步进电机在高速时反向冲击损坏蜗杆机构:

c 复制代码
if (direction != s_last_direction && s_pwm_running) {
    HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_2);
    HAL_Delay(2);   // 等待电机惯性消耗
    s_pwm_running = 0;
}
HAL_GPIO_WritePin(turbo_dir_GPIO_Port, turbo_dir_Pin, dir_pin);
// 方向稳定后再启动 PWM

5.4 调试变量结构体说明

c 复制代码
// turbo_control.h
typedef struct {
    volatile uint32_t last_command_us;      // 最后输入的 command_us
    volatile uint32_t calculated_period_us; // 实际写入 ARR 的周期(μs)
    volatile uint32_t calculated_freq_hz;   // 对应频率(Hz)
    volatile int32_t  direction;            // +1=正转  -1=反转  0=停止
    volatile uint32_t pwm_running;          // TIM1 CH2 是否在输出
    volatile uint32_t last_update_ms;       // 最后一次调用的时间戳(ms)
    volatile uint32_t update_count;         // 调用总次数(任务活跃性指标)
    volatile uint32_t error_count;          // 保留,暂未使用
} turbo_control_debug_t;

extern volatile turbo_control_debug_t g_turbo_dbg;

在 CLion 的 Watches 窗口直接添加 g_turbo_dbg

展开结构体即可实时查看所有字段,无需逐个添加成员。


5.5 参数调整指南

调整目标 修改位置 参数
最高转速 turbo_control.c TurboControl_MapToPeriod() freq_hz 上限(当前 5000)
最低转速 同上 freq_hz 下限(当前 200)
死区范围 turbo_control.c TurboControl_SetCommandUs() 950U / 1050U
换向延时 同上 HAL_Delay(2U)
通道映射 freertos.c Start_wlwg_Tasks() g_active_channels[2](当前油门通道)
FreeRTOS 堆 FreeRTOSConfig.h configTOTAL_HEAP_SIZE(当前 8192)
任务栈大小 freertos.c wlwg_Tasks_attributes .stack_size = 128 * 4
相关推荐
foundbug9992 小时前
STM32 上实现 Modbus-RTU
stm32·单片机·嵌入式硬件
飞睿科技2 小时前
飞睿智能5.8G毫米波雷达智能猫砂盆检测方案
嵌入式硬件·物联网·雷达·智能猫砂盆·宠物用品
小叮当⇔3 小时前
TI电源管理芯片——TPS65251RHAR手册
单片机·嵌入式硬件
leo__5203 小时前
51单片机实现读写U盘
嵌入式硬件·mongodb·51单片机
项目題供诗3 小时前
STM32-GPIO输入(四)
stm32·单片机·嵌入式硬件
我在人间贩卖青春3 小时前
ADC采集
stm32·adc
西城微科方案开发4 小时前
华润微(SEMICO)高速度低功耗的8位MCU——CS98P171 SOP8
单片机·嵌入式硬件
青鱼295 小时前
SysTick_Handler在裸机和RTOS中的区别
单片机·嵌入式硬件·rtos·systick_handler
我在人间贩卖青春5 小时前
SPI总线
stm32·spi