STM32F1 嵌入式固件,用于驱动线激光 3D 扫描仪的旋转平台。固件通过串口接收上位机指令,控制步进电机精确步进/移动,并将当前角度回传,实现与上位机扫描软件的协同工作。
- 步进电机非阻塞控制:基于 TIM2 PWM 脉冲计数,
Motor_StartStep/Motor_StartMove立即返回,主循环轮询Motor_IsReady()判断完成 - 双向运动:
CMD_MOVE支持带符号步数(正数逆时针 CCW,负数顺时针 CW) - 高分辨率:3200 步/转(细分驱动),角分辨率 0.1125°/步
- 稳定等待:电机停止后可配置稳定时间(默认 80 ms),避免机械振动干扰图像采集
- 串口 DMA 接收:USART1 + DMA 循环缓冲,零 CPU 开销接收上位机数据帧
- CRC16-CCITT 校验:所有收发帧均附带 CRC,防止数据错误
| 组件 | 规格 |
|---|---|
| 微控制器 | STM32F103(72 MHz,HSE + PLL×9) |
| 步进电机驱动器 | 支持 ENA / DIR / PUL 接口的驱动模块(如 A4988、DM542) |
| 激光模块 | 线激光(由上位机或外部电路控制) |
| 上位机连接 | USB-TTL / USB-串口转换器(USART1,115200 bps) |
| 引脚 | GPIO | 功能 |
|---|---|---|
| MOTOR_DIR | PB0 | 步进电机方向信号 |
| MOTOR_ENA | PB1 | 步进电机使能信号(低电平有效) |
| MOTOR_PUL | PA0 (TIM2_CH1) | 步进脉冲 PWM 输出 |
| USART1_TX | PA9 | 串口发送(至上位机) |
| USART1_RX | PA10 | 串口接收(来自上位机,DMA) |
注意:激光开关命令(
CMD_LASER_ON/CMD_LASER_OFF)已在协议层定义,GPIO 驱动可根据实际硬件在main.c中添加。
+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+
| 0xAA | 0xBB | CMD | DATA (float, 4 bytes, LE) | CRC (2 bytes, BE) | 0xCC | 0xDD |
| Head1 | Head2 | [2] | [3] | [4] | [5] | [6] | [7] | [8] | Tail1 | Tail2 |
+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+
CRC 覆盖范围:字节 [2] ~ [6](CMD + DATA),算法:CRC16-CCITT(初值 0xFFFF,多项式 0x1021)
| CMD 字节 | 宏定义 | DATA 含义 |
|---|---|---|
0x01 |
CMD_STEP |
忽略,步进 1 个脉冲(逆时针) |
0x05 |
CMD_MOVE |
带符号步数(int32_t,正=CCW,负=CW) |
0x03 |
CMD_LASER_ON |
忽略,开启激光(预留) |
0x04 |
CMD_LASER_OFF |
忽略,关闭激光(预留) |
| CMD 字节 | 宏定义 | DATA 含义 |
|---|---|---|
0x81 |
RESP_STEP_DONE |
当前绝对角度(float,度) |
0x82 |
RESP_MOVE_DONE |
当前绝对角度(float,度) |
0xFF |
RESP_ERROR |
0.0f(未知命令) |
.
├── CMakeLists.txt # 顶层 CMake 构建文件
├── cmake/
│ ├── gcc-arm-none-eabi.cmake # ARM GCC 工具链配置
│ ├── starm-clang.cmake # Clang 工具链配置(可选)
│ └── stm32cubemx/
│ └── CMakeLists.txt # STM32CubeMX 自动生成的源文件列表
├── Core/
│ ├── Inc/
│ │ ├── main.h # 系统头文件 & 引脚宏定义
│ │ ├── motor_ctrl.h # 电机控制接口
│ │ ├── scanner_protocol.h # 串口通信协议定义
│ │ ├── tim.h # TIM2 初始化接口
│ │ ├── usart.h # USART1 初始化接口
│ │ ├── dma.h # DMA 初始化接口
│ │ └── gpio.h # GPIO 初始化接口
│ └── Src/
│ ├── main.c # 主程序 & 状态机
│ ├── motor_ctrl.c # 步进电机驱动实现
│ ├── scanner_protocol.c # 帧解析 & 发送实现
│ ├── tim.c # TIM2 HAL 初始化
│ ├── usart.c # USART1 HAL 初始化
│ ├── dma.c # DMA HAL 初始化
│ └── gpio.c # GPIO HAL 初始化
└── Drivers/
├── CMSIS/ # ARM CMSIS 内核文件
└── STM32F1xx_HAL_Driver/ # STM32 HAL 库
- CMake ≥ 3.22
- arm-none-eabi-gcc 工具链
- STM32CubeProgrammer 或 OpenOCD(用于烧录)
# 1. 创建构建目录并生成 Makefile
cmake -S . -B build \
-DCMAKE_TOOLCHAIN_FILE=cmake/gcc-arm-none-eabi.cmake \
-DCMAKE_BUILD_TYPE=Release
# 2. 编译
cmake --build build -j$(nproc)编译成功后,输出文件位于 build/LaserScanner_STM32.elf(及对应的 .bin / .hex)。
openocd -f interface/stlink.cfg \
-f target/stm32f1x.cfg \
-c "program build/LaserScanner_STM32.elf verify reset exit"上电
│
├─ HAL_Init() / SystemClock_Config() 72 MHz HSE PLL
├─ MX_GPIO_Init() / MX_DMA_Init()
├─ MX_USART1_UART_Init() 115200, 8N1
├─ MX_TIM2_Init() PWM 脉冲生成
├─ Motor_Init() 使能驱动器, 角度清零
└─ Proto_Init() 启动 DMA 循环接收
│
▼
┌─────────────────── 主循环 ──────────────────────┐
│ │
│ [SYS_IDLE] 收到帧? │
│ CMD_STEP → Motor_StartStep(1) → STEPPING │
│ CMD_MOVE → Motor_StartMove(n) → MOVING │
│ 其他 → RESP_ERROR │
│ │
│ [STEPPING] Motor_IsReady()? │
│ 是 → Proto_SendResponse(RESP_STEP_DONE, °) │
│ → SYS_IDLE │
│ │
│ [MOVING] Motor_IsReady()? │
│ 是 → Proto_SendResponse(RESP_MOVE_DONE, °) │
│ → SYS_IDLE │
└──────────────────────────────────────────────────┘
本项目的用户代码(Core/Src/motor_ctrl.c、Core/Src/scanner_protocol.c 等)采用 MIT 许可证开放使用。
STM32 HAL 驱动库(Drivers/)版权归 STMicroelectronics 所有,遵循其 BSD 风格许可证。