你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【STM32U3 评测】串口控制步进电机与LabVIEW数据采集

[复制链接]
无垠的广袤 发布时间:2026-6-10 17:30

【STM32U3 评测】串口控制步进电机与LabVIEW数据采集

本文介绍了 NUCLEO-U3C5ZI-Q 开发板结合 TMC2209 驱动器、STM32CubeMX 和 CubeIDE,实现 42 步进电机的串口指令精确控制,设计 LabVIEW 上位机实现数据的自动连续采集的项目设计,包括环境搭建、工程创建、关键代码、流程图、效果演示等。

项目介绍

Nucleo-U3C5ZI-Q 开发板结合 TMC2209 驱动板实现串口和 LabVIEW 上位机控制 42 步进电机旋转。

  • 准备工作:步进电机参数、环境搭建、硬件连接等;
  • 工程测试:工程配置、流程图、关键代码,串口 JSON 指令控制步进电机旋转方向、角度和速度;
  • LabVIEW 设计:前面板、程序面板设计,自动发送 JSON 消息,实现步进电机的自动化控制、数据采集与存储。

42 步进电机

42步进电机(NEMA17)是一种安装尺寸为 42mm×42mm 的两相混合式步进电机,广泛应用于3D打印机、数控机床和自动化控制系统。

42stepper_cover.jpg

42步进电机标准步距角为1.8°,最大输出力矩为0.5Nm,步距精度为5%;其定位精度与步距精度相关,通常采用脉冲信号进行控制。

42步进电机由定子和转子的齿数共同决定,如定子有48齿,分为8组绕组;转子有50齿。绕组分为A、B两相,通过特定的绕线方式,在同一相中,相对的绕组磁极相同,相邻的绕组磁极相反。

42stepper_inside.jpg

42步进电机的参数一般包括相数、步距角、额定电压、相电流、相电阻、相电感、绝缘等级、保持扭矩(静扭矩)、动态扭矩、定位扭矩(失步转矩)、额定转速、响应频率、温升、工作温度等。

详见:【STM32U3 评测】步进电机驱动 .

硬件连接

  • NUCLEO-U3C5ZI-Q 与 TMC2209 驱动板的接线方式如下
TMC2209 NUCLEO-U3C5ZI-Q Note
Dir PB10 Direction
Step PC6 Step pulse
EN PE13 Enable
GND GND Ground
VIO 3V3 Power
  • 使用 Type-C 数据线连接开发板和电脑,结合 ST-LINK 虚拟串口进行通信;
  • TMC2209 与步进电机的接线方式如下
42步进电机 TMC2209 Note
B- 2B B phase
B+ 2A B phase
A+ 1A A phase
A- 1B A phase

stepper_42_diagram.jpg

示意图

connect_diagram_stepper_tmc2209.jpg

实物图

42stepper_connect.jpg

串口打印

从开发板创建工程,串口重定位 printf 并实现字符串打印。

工程创建

  • 打开 STM32CubeMX 软件,选择从开发板创建工程;

cubemx_project_board.jpg

  • 在 Board 标签下搜索并选择 NUCLEO-U3C5ZI-Q 型号开发板;
  • 右下方选中目标开发板,点击右上角 Start Project 按钮,进入 CubeMX 配置界面;

cubemx_u3c5_board.jpg

  • 在引脚配置标签页下,左侧工具目录展开 System Core,选中 GPIO;
  • 在右侧图形引脚下方搜索 PE13 ,将其设置为 GPIO 输出模式,同时配置标签为 EN_PIN
  • 同理,将 PC6 和 PB10 引脚设置为 GPIO 输出模式,配置标签分别为 STEP_PINDIR_PIN

cubemx_gpio_config.jpg

  • 点击上方 Clock 标签配置时钟参数,这里使用默认值;

  • 点击上方 Project Manager 标签,设置工程名称、路径、工具栏等,这里使用 STM32CubeIDE 加载工程;

    cubemx_stepmotor_project_manager.jpg

  • 点击右上角 GENERATE CODE 按钮,生成并打开工程。

    cubemx_open_project.jpg

  • 展开左侧工程文件目录,打开 Core/Src/main.c 文件,点击上方工具栏小锤子按钮,编译工程,无报错;

cubeide_stepper_build.jpg

工程代码

展开左侧工程文件目录,双击打开 Core/Src/main.c 文件,关键代码如下

/* USER CODE BEGIN Includes */
#include <stdio.h>
/* USER CODE END Includes */

/* USER CODE BEGIN 0 */
UART_HandleTypeDef huart1;
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif

PUTCHAR_PROTOTYPE {
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
    return ch;
}
/* USER CODE END 0 */

int main(void)
{
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
      printf("Hello World!\r\n");
      HAL_Delay(500);
  }
  /* USER CODE END 3 */
}

保存代码。

编译上传

  • 右键工程文件夹,选择构建项目,或点击工具栏小锤子按钮;
  • 构建完成后,无报错产生,点击工具栏运行按钮,自动上传固件至开发板并运行;

效果演示

  • 运行串口调试助手软件,配置波特率等参数;
  • 打开串口,接收到开发板连续发送的字符串;

uart_print_hello.jpg

串口中断

通过串口中断实现发送 JSON 消息控制步进电机旋转角度和速度。

工程配置

  • 打开 STM32CubeMX 软件,加载 NUCLEO-U3C5ZI-Q 开发板;
  • 在左侧 BSP 标签页下点击目标开发板,进入配置界面;
  • 取消勾选 VCOM 虚拟串口预设置;

uart1_irq.jpg

  • 点击 USART1 ,进入 NVIC Setting,开启串口 1 全局中断;

usart_irq_enable.jpg

  • 工程命名、设置保存路径、编译器选择 STM32CubeIDE ;
  • 点击右上角 Generate Code 按钮,生成代码并打开工程;

工程代码

展开左侧工程文件目录,双击打开 Core/Src/main.c 文件,添加如下代码

#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stepmotor.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
/* USER CODE END Includes */

UART_HandleTypeDef huart1;

/* USER CODE BEGIN PV */
volatile bool uart_rx_ready = false;
uint8_t uart_rx_buf[256] = {0};
uint32_t uart_rx_len = 0;
uint8_t rx_temp;  // 变量用于串口接收

int target_angle = 0;
uint32_t target_speed = 2;  // 步间延时(ms)
/* USER CODE END PV */

/* Private function prototypes --------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ----------------*/
/* USER CODE BEGIN 0 */
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif

PUTCHAR_PROTOTYPE {
    if (HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY) != HAL_OK) {
        return EOF;
    }
    return ch;
}

// 串口接收中断回调
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1)
    {
        uint8_t ch = rx_temp;
        if(uart_rx_len < sizeof(uart_rx_buf)-1)
        {
            uart_rx_buf[uart_rx_len++] = ch;
        }
        // 收到换行符或大括号(JSON结束)标记接收完成
        if(ch == '\n' || ch == '}')
        {
            uart_rx_buf[uart_rx_len] = '\0';  // 添加字符串结束符
            uart_rx_ready = true;
        }
        // 继续接收下一个字节
        HAL_UART_Receive_IT(&huart1, &rx_temp, 1);
    }
}

// 解析JSON {"angle":90,"speed":2}
static void parse_json_cmd(int *angle, uint32_t *speed)
{
    char *p = (char*)uart_rx_buf;
    // 尝试解析两种格式:带空格和不带空格
    if(sscanf(p, "{\"angle\":%d,\"speed\":%lu}", angle, speed) != 2)
    {
        sscanf(p, "{\"angle\": %d, \"speed\": %lu}", angle, speed);
    }
}

/* USER CODE END 0 */


int main(void)
{
    HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  // 初始化步进电机
  step_motor_init();
  // 启动串口接收中断
  HAL_UART_Receive_IT(&huart1, &rx_temp, 1);
  printf("System Ready!\r\n");
  printf("Waiting for JSON command: {\"angle\":90,\"speed\":2}\r\n");
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
      if(uart_rx_ready){
          // 解析指令
          parse_json_cmd(&target_angle, &target_speed);
          printf("OK: angle=%d, speed=%lu\r\n", target_angle, target_speed);

          // 电机使能 + 转动
          step_motor_enable();
          step_motor_rotate_degrees((float)target_angle, target_speed);
          step_motor_stop();

          // 转动结束  释放扭矩
          step_motor_disable();

          // 清空接收缓冲区
          memset(uart_rx_buf, 0, sizeof(uart_rx_buf));
          uart_rx_len = 0;
          uart_rx_ready = false;
      }
      else
      {
          // 无数据时释放扭矩
          step_motor_disable();
      }

      HAL_Delay(10);
  }
  /* USER CODE END 3 */
}

保存代码。

驱动代码

新建 ./Core/Inc/stepmotor.h 头文件

/*
 * stepmotor.h
 *
 *  Created on: 2026-06-10
 *  Description: TMC2209步进电机驱动封装
 */

#ifndef INC_STEPMOTOR_H_
#define INC_STEPMOTOR_H_

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include <stdbool.h>
#include <stdint.h>

/* 宏定义 --------------------------------------------------------------------*/
// 步进电机参数
#define STEPS_PER_REVOLUTION 1600    // 每圈总步数 = 200步 * 8细分

// 方向定义
#define DIR_CW   GPIO_PIN_SET        // 正转
#define DIR_CCW  GPIO_PIN_RESET      // 反转

/* 函数声明 ------------------------------------------------------------------*/

/**
 * @brief 初始化步进电机
 */
void step_motor_init(void);

/**
 * @brief 使能电机(通电)
 */
void step_motor_enable(void);

/**
 * @brief 失能电机(断电)
 */
void step_motor_disable(void);

/**
 * @brief 旋转指定步数
 * @param steps: 步数(正数正转,负数反转)
 * @param step_delay_ms: 步间延时(毫秒)
 */
void step_motor_rotate_steps(int32_t steps, uint32_t step_delay_ms);

/**
 * @brief 旋转指定角度
 * @param degrees: 角度(度,正数正转,负数反转)
 * @param step_delay_ms: 步间延时(毫秒)
 */
void step_motor_rotate_degrees(float degrees, uint32_t step_delay_ms);

/**
 * @brief 停止电机
 */
void step_motor_stop(void);

/**
 * @brief 测试函数(正反转演示)
 */
void step_motor_test_sequence(void);

#ifdef __cplusplus
}
#endif

#endif /* INC_STEPMOTOR_H_ */

保存代码。

源文件

新建 ./Core/Src/stepmotor.c 源文件,添加如下代码

/*
 * stepmotor.c
 *
 *  Created on: 2026-06-10
 *  Description: TMC2209步进电机驱动实现
 */

#include "stepmotor.h"
#include <stdio.h>
#include <stdlib.h>

// ===================== 函数声明 =====================
static void motor_pulse_send(void);

// ===================== 函数实现 =====================

/**
 * @brief 初始化步进电机
 */
void step_motor_init(void)
{
    // 初始化引脚:EN=高电平(失能),STEP=低,DIR=低
    HAL_GPIO_WritePin(EN_PIN_GPIO_Port, EN_PIN_Pin, GPIO_PIN_SET);
    HAL_GPIO_WritePin(STEP_PIN_GPIO_Port, STEP_PIN_Pin, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(DIR_PIN_GPIO_Port, DIR_PIN_Pin, GPIO_PIN_RESET);

    printf("TMC2209 Stepper Motor Initialized.\r\n");
    printf("Steps per revolution: %lu\r\n", STEPS_PER_REVOLUTION);
}

/**
 * @brief 使能电机(通电)
 */
void step_motor_enable(void)
{
    HAL_GPIO_WritePin(EN_PIN_GPIO_Port, EN_PIN_Pin, GPIO_PIN_RESET);
}

/**
 * @brief 失能电机(断电)
 */
void step_motor_disable(void)
{
    HAL_GPIO_WritePin(EN_PIN_GPIO_Port, EN_PIN_Pin, GPIO_PIN_SET);
}

/**
 * @brief 发送一个步进脉冲(TMC2209 上升沿触发)
 */
static void motor_pulse_send(void)
{
    HAL_GPIO_WritePin(STEP_PIN_GPIO_Port, STEP_PIN_Pin, GPIO_PIN_SET);
    HAL_Delay(1);  // 脉冲宽度1ms(实际应更短,但HAL_Delay最小1ms)
    HAL_GPIO_WritePin(STEP_PIN_GPIO_Port, STEP_PIN_Pin, GPIO_PIN_RESET);
}

/**
 * @brief 旋转指定步数
 */
void step_motor_rotate_steps(int32_t steps, uint32_t step_delay_ms)
{
    if (steps == 0) return;

    int8_t   dir_flag   = (steps > 0) ? 1 : -1;
    uint32_t abs_steps  = (uint32_t)abs(steps);

    // 设置方向
    if (dir_flag > 0)
    {
        HAL_GPIO_WritePin(DIR_PIN_GPIO_Port, DIR_PIN_Pin, DIR_CW);
        printf("Rotating CW, steps: %lu, delay: %lu ms\r\n", abs_steps, step_delay_ms);
    }
    else
    {
        HAL_GPIO_WritePin(DIR_PIN_GPIO_Port, DIR_PIN_Pin, DIR_CCW);
        printf("Rotating CCW, steps: %lu, delay: %lu ms\r\n", abs_steps, step_delay_ms);
    }

    // 使能电机
    step_motor_enable();

    // 发送步数脉冲
    for (uint32_t i = 0; i < abs_steps; i++)
    {
        motor_pulse_send();
        HAL_Delay(step_delay_ms);
    }
}

/**
 * @brief 旋转指定角度
 */
void step_motor_rotate_degrees(float degrees, uint32_t step_delay_ms)
{
    // 角度转步数(四舍五入)
    int32_t steps = (int32_t)(degrees * (STEPS_PER_REVOLUTION / 360.0f) + 0.5f);

    if (steps != 0)
    {
        step_motor_rotate_steps(steps, step_delay_ms);
    }
}

/**
 * @brief 停止电机
 */
void step_motor_stop(void)
{
    // 保持使能,停止发脉冲即可
    HAL_GPIO_WritePin(STEP_PIN_GPIO_Port, STEP_PIN_Pin, GPIO_PIN_RESET);
    printf("Motor stopped\r\n");
}

/**
 * @brief 测试函数(正反转演示)
 */
void step_motor_test_sequence(void)
{
    while (1)
    {
        step_motor_rotate_degrees(180.0f, 2);   // 正转180°
        step_motor_stop();
        HAL_Delay(1000);

        step_motor_rotate_degrees(-90.0f, 2);   // 反转90°
        step_motor_stop();
        HAL_Delay(1000);
    }
}

保存代码。

编译上传

  • 右键工程文件夹,选择构建项目,或点击工具栏小锤子按钮;
  • 构建完成后,无报错产生,点击工具栏运行按钮,自动上传固件至开发板并运行;

效果演示

  • 运行串口调试助手软件,配置波特率等参数;

  • 打开串口,输入 JSON 指令 {"angle": 98, "speed": 2} 并发送;

    uart_stepper_print.jpg

  • 步进电机以目标速度旋转目标角度后释放扭矩,串口回复电机状态;

uart_stepper_run.gif

LabVIEW 上位机

包括前面板和程序面板设计。

前面板

前面板设计包括串口配置、单步测试、连续运行测试、实时演化曲线、数据保存、程序控制等模块。

labview_front_page.jpg

程序面板

程序面板采用模块化设计,将串口指令函数封装,确保单次发送、连续发送任务均准确执行。

labview_block_page.jpg

数据采集

  • 配置目标串口,运行程序;
  • 设置步长、目标角度、延时、存储路径等;
  • 点击 START 按钮,开始运行步进电机并采集数据;

动态演示

  • LabVIEW 程序运行后,步进电机按照设定的步长和延时连续旋转;

    labview_stepper.gif

  • 前面板显示采集数据的实时演化曲线;

labview_run.gif

数据存储

  • 数据采集完成后,串口停止发送消息,数据自动存储至目标路径;
  • 数据保存格式为第一列旋转角度,第二列模拟采集数值;

labview_data_save.jpg

总结

本文介绍了 NUCLEO-U3C5ZI-Q 开发板结合 TMC2209 驱动器、STM32CubeMX 和 CubeIDE,实现 42 步进电机的串口指令精确控制,设计 LabVIEW 上位机实现数据的自动连续采集的项目设计,包括环境搭建、工程创建、关键代码、流程图、效果演示等,为相关产品在工业领域的快速开发和应用设计提供了参考。

收藏 评论0 发布时间:2026-6-10 17:30

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版