这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【2026 Let's do 第1期】静音步进电机控制实践成果帖 -- 迷你桌面

共1条 1/1 1 跳转至

【2026 Let's do 第1期】静音步进电机控制实践成果帖 -- 迷你桌面滑台控制系统

助工
2026-06-21 16:45:15     打赏

功能概览

  • 通过步数实现简单位置管理,即将长度映射到具体的步数(总长度分为N个位置),可以准确指定移动到准确的位置

  • 支持以下控制功能:回到原点、移动到指定位置、设定移动距离(移动相对位置)

  • 实现平滑加减速控制,避免电机突然启动或停止

  • 回零操作


硬件介绍

  • NUCLEO-G474RE 开发板 1 块:作为系统核心控制器,负责数据采集、逻辑处理、阈值修改及模式切换功能。

  • Grove - 0.96英寸黄蓝双色OLED显示屏 1 个:显示实时电流、阈值、工作模式及状态信息,采用I²C通信。

  • TMC2209 SilentStepStick 模块 1 个

  • 面包板 1 块

  • 杜邦线 若干

按下图所示,将各模块连接起来,组成本次项目的演示电路。

静音步进电机控制_bb.png

设计思路

系统架构设计

         本系统采用经典的三层架构设计模式,自底向上依次为硬件抽象层、业务逻辑层和应用接口层。硬件抽象层负责初始化和操作各类外设接口,包括GPIO引脚配置、TMC2209驱动通信、OLED显示驱动等。业务逻辑层实现了电机运动控制、位置管理、加减速算法等核心功能。应用接口层提供了串口命令解析、按键事件处理等用户交互接口。

        在任务划分方面,将系统功能拆分为三个独立任务:电机控制任务负责步进脉冲生成和位置计数,是系统中最关键、对实时性要求最高的任务;显示任务负责定期刷新OLED屏幕内容,由于OLED更新速度较慢且对实时性要求不高,分配较低优先级;串口任务负责接收和解析上位机命令,命令处理结果通过队列传递给电机任务执行。

任务调度设计

         FreeRTOS的任务调度采用基于优先级的抢占式调度策略。本系统配置三个任务优先级:电机控制任务优先级为3(最高),显示任务优先级为2,串口任务优先级为2。相同优先级的任务采用时间片轮转调度算法,确保各任务能够公平地获得CPU时间片。

        电机控制任务采用事件驱动模式,平常处于阻塞状态等待命令队列消息。当串口任务解析到有效命令后,通过队列向电机任务发送控制指令,电机任务被唤醒后执行相应的运动控制操作。这种设计避免了轮询方式带来的CPU资源浪费,同时保证了命令响应的及时性。

        显示任务采用周期性模式,以100毫秒为周期定时唤醒执行。每次唤醒后,任务首先获取显示互斥信号量,然后读取系统状态并更新OLED屏幕显示内容,最后释放信号量并再次进入延时等待。

        串口任务同样采用周期性模式,以50毫秒为周期扫描串口缓冲区。当检测到有数据到达时,任务读取一行命令字符串并进行解析,根据命令类型执行相应操作。对于需要电机执行的控制命令,任务构建命令结构体并通过队列发送给电机任务;对于查询类命令,任务直接读取系统状态并通过串口返回结果。

功能实现

软件架构

mermaid-diagram-2026-06-20-205920.png


核心代码实现

全局变量定义

// 调试串口定义 - 用于与上位机通信和调试信息输出
#define SERIAL_DEBUG Serial

// TMC2209步进电机驱动串口定义 - 用于与TMC2209芯片进行UART通信
#define SERIAL_TMC Serial1

// TMC2209器件从机地址定义 - 二进制00地址 (TMC2209默认地址)
#define TMC2209_SLAVE_ADDR 0b00

// TMC2209寄存器地址定义 - 用于UART通信配置
#define TMC2209_REG_SLAVE_CONF 0x00    // 从机配置寄存器
#define TMC2209_REG_SLAVE_STATUS 0x01  // 从机状态寄存器

// TMC2209控制引脚配置 - 连接到SilentStepStick模块
const uint8_t TMC2209_EN_PIN = D3;    // 使能引脚 - 低电平使能电机输出
const uint8_t TMC2209_STEP_PIN = D4;  // 步进脉冲引脚 - 每脉冲触发一步
const uint8_t TMC2209_DIR_PIN = D5;    // 方向控制引脚 - 高低电平控制旋转方向
const uint8_t TMC2209_UART_RX = D2;   // UART接收引脚 (预留)
const uint8_t TMC2209_UART_TX = D1;   // UART发送引脚 (预留)

// OLED显示屏配置 - Grove 0.96英寸黄蓝双色OLED
const uint8_t OLED_I2C_ADDR = 0x3C;   // OLED的I2C从机地址
const uint8_t OLED_SDA_PIN = D11;     // I2C数据线引脚
const uint8_t OLED_SCL_PIN = D13;     // I2C时钟线引脚

步进脉冲生成

// 步进脉冲生成核心逻辑
if (currentTime - lastStepTime >= stepInterval) {
    lastStepTime = currentTime;  // 更新上次步进时间

    // 根据方向更新位置计数器
    if (g_direction) {
        g_systemState.currentPosition++;  // 前进则位置加1
    } else {
        g_systemState.currentPosition--;  // 后退则位置减1
    }

    g_stepTarget--;                      // 剩余步数减1
    g_accelProfile.stepCount++;          // 已执行步数加1

    // 产生步进脉冲 - 拉高至少2微秒
    digitalWrite(TMC2209_STEP_PIN, HIGH);
    delayMicroseconds(2);
    digitalWrite(TMC2209_STEP_PIN, LOW);

    // 检查是否到达目标位置
    if (g_stepTarget <= 0) {
        stopMotor();  // 停止电机
        // 如果是回零操作,到达原点后位置清零
        if (g_systemState.status == STATUS_HOMING) {
            g_systemState.currentPosition = 0;
            g_systemState.status = STATUS_IDLE;
        }
    }
}

FreeRTOS任务创建

// 创建FreeRTOS通信机制
commandQueue = xQueueCreate(10, sizeof(Command));   // 创建命令队列,深度10
stateQueue = xQueueCreate(10, sizeof(SystemState)); // 创建状态队列,深度10
displaySemaphore = xSemaphoreCreateMutex();         // 创建显示互斥信号量

// 创建FreeRTOS任务
xTaskCreate(vMotorTask,      // 任务函数
            "MotorTask",     // 任务名称
            256,            // 堆栈大小
            NULL,           // 参数
            3,              // 优先级
            NULL);          // 任务句柄

xTaskCreate(vDisplayTask,    // 任务函数
            "DisplayTask",   // 任务名称
            256,            // 堆栈大小
            NULL,           // 参数
            2,              // 优先级
            NULL);          // 任务句柄

xTaskCreate(vSerialTask,     // 任务函数
            "SerialTask",    // 任务名称
            256,            // 堆栈大小
            NULL,           // 参数
            2,              // 优先级
            NULL);          // 任务句柄

// 启动FreeRTOS调度器
vTaskStartScheduler();

毫米到步数转换

// 将毫米转换为微步数
float targetMm = param.substring(7).toFloat();
int32_t targetSteps = (int32_t)(targetMm * (STEPS_PER_REV * DEFAULT_MICROSTEPS) / LEAD_SCREW_PITCH_MM);
// 计算: 毫米 × (200步/转 × 8微步) / 2.0mm = 毫米 × 800步/毫米

电机控制任务核心

void vMotorTask(void* pvParameters) {
    Command cmd;
    cmd.type = CMD_NONE;
    cmd.value = 0;

    for (;;) {
        // 非阻塞方式接收命令
        BaseType_t received = xQueueReceive(commandQueue, &cmd, 0);

        if (received == pdTRUE) {
            switch (cmd.type) {
                case CMD_FORWARD:
                    g_systemState.status = STATUS_RUNNING;
                    stepper.setSpeed(DEFAULT_SPEED_STEPS);
                    stepper.move(cmd.value);
                    break;
                case CMD_STOP:
                    stepper.stop();
                    g_systemState.status = STATUS_STOPPED;
                    break;
                // ... 其他命令处理
            }
            cmd.type = CMD_NONE;
        }

        // 频繁调用stepper.run()处理步进脉冲
        for (int i = 0; i < 10; i++) {
            stepper.run();
        }

        vTaskDelay(1);  // 让出CPU给其他任务

        // 更新位置和状态
        g_systemState.currentPosition = stepper.currentPosition();
        if (g_systemState.status == STATUS_RUNNING && !stepper.isRunning()) {
            g_systemState.status = STATUS_IDLE;
        }
    }
}

功能展示

OLED显示内容

OLED屏幕显示布局如下:

--------------------
| Run Current: 50%  |
| Threshold: 1.00A  |
| Mode: DIRECT      |
| Pos: 500/1000     |
| Status: STOPPED   |
--------------------

20260620212934_92_116.jpg

串口命令演示

系统上电后,通过串口调试助手发送命令可实现以下功能:

基本运动控制

  • 发送"F500" → 电机前进500步,响应"OK:MOVE=FORWARD:500"

  • 发送"B200" → 电机后退200步,响应"OK:MOVE=BACKWARD:200"

  • 发送"S" → 立即停止电机,响应"OK:STOPPED"

位置控制

  • 发送"H" → 执行回零操作,响应"OK:HOMING..."

  • 发送"P?" → 查询位置,响应"POS:500:1000:STOPPED"

参数设置

  • 发送"SET:POS=500" → 设置总位置数为500,响应"OK:SET:POS=500"

{% asset_img 2026-06-20-21-33-42.png 【EEPW-2026-Let-s-do-第1期】DigiKey陪你走过春夏秋冬-静音步进电机控制实践 %}

运行特性

在500步/秒默认速度下,系统完成了以下性能测试:加减速过程平滑,无明显冲击振动;位置控制精度达到±1步;响应延迟小于5毫秒;连续运行1小时无异常发热。系统各项功能均正常工作,满足设计要求。


演示视频


传送门

【2026 Let's do 第1期】静音步进电机控制实践开箱帖

【2026 Let's do 第1期】静音步进电机控制实践过程帖


参考资料





关键词: Let's do     DIY     STM32     C/C++         

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]