2026 ADI机器控制设计竞赛 - 基于ADMT4000实现多层电梯升降控制系统
该项目使用了ADMT4000、TMC5160,实现了电梯升降控制的设计,它的主要功能为:精准控制电梯升降,掉电不丢失位置,并可以自动对齐。
标签
嵌入式系统
STM32
Rust
ADMT4000
justbe
更新2026-05-11
10
KiCad文件
全屏

效果演示请进入原视频地址观看。

一、项目概述

1.1 项目目标

本项目旨在开发一个基于STM32U545微控制器的智能电梯控制系统,使用Rust语言和Embassy异步框架实现。系统具备以下核心功能:

  • 多楼层电梯运动控制(支持6层楼)
  • 步进电机精确位置控制(TMC5160驱动)
  • 绝对位置编码器反馈(ADMT4000磁编码器)
  • 人机交互界面(键盘输入、OLED显示、LED指示、蜂鸣器反馈)
  • 自动校准与对齐功能
  • 状态机驱动的电梯逻辑控制

1.2 技术特点

  • 嵌入式Rust开发:使用#![no_std]裸机环境,保证内存安全和高性能
  • 异步并发架构:基于Embassy框架实现多任务并发执行
  • 状态机设计:使用smlang库实现电梯主控状态机
  • 实时通信:通过Signal和Watch机制实现任务间高效通信
  • 参数持久化:校准数据存储在Flash中,断电不丢失

二、系统架构

2.1 硬件平台

  • 主控芯片:STM32U545RE(ARM Cortex-M33)
  • 步进电机驱动:TMC5160(SPI接口,256微步)
  • 位置传感器:ADMT4000磁编码器(SPI接口,绝对位置)
  • 人机接口
    • I2C键盘(VK36N16I,地址0x65)
    • I2C OLED显示屏(SSD1306,128x64,地址0x3C)
    • WS2812 LED灯带(30颗灯珠)
    • PWM蜂鸣器
  • 调试接口:USART1串口CLI

2.1.1 电源框图

image.png

2.1.2 信号连接

image.png

2.1.3 硬件总览

image.png

2.1.4 PCB设计

image.png

背面补充了蜂鸣器的保护二极管(正面封装不好焊);如红圈所示,ws2812信号脚使用电阻上拉至5v,如紫圈所示

image.png

2.1.5 组装整体图

功能展示 - frame at 0m0s.jpg


2.2 软件架构

┌─────────────────────────────────────────────────────────┐
│ Embassy Executor │
(异步任务调度器)
└─────────────────────────────────────────────────────────┘

┌──────────────────┼──────────────────┐
│ │ │
┌───────▼────────┐ ┌──────▼──────┐ ┌────────▼────────┐
│ 输入任务层 │ │ 控制任务层 │ │ 输出任务层 │
├────────────────┤ ├─────────────┤ ├─────────────────┤
│ task_input │ │task_main │ │ task_oled │
│ task_cli │ │task_actuator│ │ task_led │
│ │ │ │ │ task_buzzer │
└────────────────┘ └─────────────┘ └─────────────────┘
│ │ │
└───────────────────┼─────────────────┘

┌───────────▼───────────┐
全局通信层 (global)
│ Signal / Watch │
└───────────────────────┘

2.3 核心模块

驱动层(driver/)

  • tmc5160.rs:步进电机驱动器控制
  • admt4000.rs:磁编码器读取
  • keyboard.rs:I2C键盘扫描

任务层(task/)

  • status.rs:主状态机(电梯逻辑控制)
  • actuator.rs:执行器任务(电机+编码器协同)
  • input.rs:键盘输入处理
  • oled.rs:OLED显示更新
  • led.rs:WS2812 LED控制
  • buzzer.rs:蜂鸣器音效
  • cli.rs:串口调试命令行

配置层

  • config.rs:系统参数配置
  • global.rs:全局通信信号定义

三、关键技术实现

3.1 状态机设计

电梯主控状态机包含7个状态:

UnInit    → 未初始化(启动状态)
Correct → 校准模式(手动标定各楼层位置)
Align → 对齐模式(自动寻找初始楼层)
Idle → 空闲状态(等待指令)
Open → 开门状态(5秒自动关门)
MoveUp → 上行运动
MoveDown → 下行运动

状态转换逻辑

  • 启动时根据Flash中是否有校准数据决定进入Correct或Align状态
  • Correct状态下,用户按数字键选择楼层,按确认键标定当前位置
  • Idle状态下,按数字键设置目标楼层,自动判断上行/下行
  • Open状态下,5秒倒计时自动关门,可按关门键提前关闭
  • 运动中可继续输入目标楼层,系统会自动排队处理

image.png

校准状态(白色为当前楼层,其余楼层为未校准):

image.png

1楼已校准:

image.png

上电后的自动找平状态:

image.png

到达楼层为绿色(开门状态),待去楼层是蓝绿色:

image.png

关门空闲状态:

image.png

运动状态:

image.png



3.2 电机控制算法

TMC5160配置

  • 微步分辨率:256微步/步
  • 每圈步数:51200微步(200步 × 256微分)
  • 最大速度:51200 微步/秒
  • 加速度:12800 微步/秒²
  • 启动速度:10 微步/秒

位置控制流程

1. 读取ADMT4000编码器当前角度
2. 根据校准数据计算目标位置(微步数)
3. 发送位置指令到TMC5160
4. 轮询vactual寄存器判断是否到达
5. 到达后读取编码器验证位置精度

3.3 校准数据管理

数据结构

struct CorrectData([isize; 6]);  // 存储6个楼层的编码器读数

存储位置:Flash偏移地址0x00040000(256KB处)

校准流程

  1. 用户手动移动电梯到第1层,按"1"+"确认"标定
  2. 依次标定2-6层
  3. 全部标定完成后,数据写入Flash,进入idle状态

位置计算公式

position = (encoder - encoder[0]) * 50
// 编码器分辨率:1024计数/圈
// 转换系数:1024/200/256 ≈ 1/50

3.4 任务间通信机制

使用Embassy的Signal和Watch实现:

Signal(单次触发)

INPUT_SIGNAL: Signal<InputEvent>           // 键盘事件
ACTUATOR_CMD: Signal<ActuatorInstruction> // 执行器指令
ACTUATOR_RESPONSE: Signal<MainEvents> // 执行器响应

Watch(状态广播)

CURRENT: Watch<usize>      // 当前楼层(0-5)
TARGET: Watch<usize> // 目标楼层掩码(bit0-5)
STATUS: Watch<MainStates> // 电梯状态

多个任务可同时监听Watch变化,实现状态同步更新。

image.png

3.5 WS2812 LED驱动

编码原理

  • 使用PWM的DMA波形输出模拟WS2812时序
  • 逻辑1:高电平0.8μs,低电平0.45μs
  • 逻辑0:高电平0.4μs,低电平0.85μs
  • PWM频率:800kHz(周期1.25μs)

显示逻辑

  • 校准模式:红色/蓝色
  • 对齐模式:橙色
  • 当前楼层:白色
  • 目标楼层:蓝绿色
  • 开门状态:绿色

3.6 OLED显示设计

布局

┌──────────────────────────┐
│ ┌────┐ │
│ │ 3 │ 状态图标 │ ← 左侧:七段数码管显示当前楼层
│ └────┘ │ ← 右侧:状态图标(箭头/圆圈等)
└──────────────────────────┘

状态图标

  • Idle:左右箭头向内(▶◀)
  • Open:左右箭头向外(◀▶)
  • MoveUp:向上箭头(▲)
  • MoveDown:向下箭头(▼)
  • Correct:未校准○、已校准✓
  • Align:横线—

image.png

四、代码流程分析

4.1 主程序启动流程

main() {
1. 初始化STM32外设(80MHz时钟)
2. 创建I2C总线(共享给键盘和OLED
3. 创建SPI总线(共享给TMC5160ADMT4000
4. 启动7个异步任务:
- task_cli:串口调试
- task_buzzer:蜂鸣器控制
- task_led:LED灯带
- task_input:键盘扫描
- task_oled:OLED刷新
- task_actuator:电机控制
- task_main:主状态机
5. 进入Embassy调度器循环
}

4.2 键盘输入处理流程

task_input() {
loop {
1. 扫描I2C键盘(50ms周期)
2. 检测按键按下事件(防抖处理)
3. 将按键码转换为InputEvent枚举
4. 通过INPUT_SIGNAL发送给主状态机
5. 触发蜂鸣器按键音效
}
}

4.3 主状态机运行流程

task_main() {
loop {
1. 等待三种事件之一:
- ACTUATOR_RESPONSE(电机完成动作)
- INPUT_SIGNAL(用户按键)
- Timer1秒定时器,用于开门倒计时)

2. 将事件转换为MainEvents

3. 调用状态机处理:fsm.process_event(event)

4. 处理副作用事件(effect)

5. 广播当前状态到STATUS
}
}

关键状态转换示例

// 空闲状态下按数字键
Idle + Number(floor) / idle_input {
if floor > current {
effect = InnerMoveUp(floor) // 触发上行
} else if floor < current {
effect = InnerMoveDown(floor) // 触发下行
}
}

// 上行到达目标楼层
MoveUp + Arrive = Open {
timeout_seconds = AUTO_CLOSE_SECONDS // 开始5秒倒计时
}

4.4 执行器任务流程

task_actuator() {
1. 初始化TMC5160ADMT4000
2.Flash读取校准数据
3. 判断是否需要校准(NeedCorrect/NeedAlign

loop {
match ACTUATOR_CMD.wait() {
Correct => {
// 校准模式
loop {
读取编码器 → 更新CURRENT
等待用户标定各楼层
全部完成后写入Flash
}
}
MoveTo(floor) => {
// 运动控制
读取当前编码器位置
校正TMC5160内部位置
计算目标位置
发送运动指令
等待到达(轮询vactual寄存器)
验证位置精度
发送Arrive响应
}
}
}
}

4.5 显示更新流程

task_oled() {
loop {
1. 清空显示缓冲区
2. 获取当前状态(current, target, status)
3. 绘制七段数码管(当前楼层)
4. 绘制状态图标
5. 刷新到OLED硬件
6. 等待任一状态变化(select3)
}
}

task_led() {
loop {
1. 根据状态更新LED颜色数组
2. 转换为WS2812波形数据
3. 通过PWM DMA发送
4. 等待状态变化
}
}

五、关键代码片段

5.1 TMC5160初始化

async fn init(&mut self) {
// CHOPCONF: spreadCycle模式
self.write_register(0x6c, 0x000100C3).await;

// IHOLD_IRUN: 保持电流3, 运行电流10
let i = 6 << 16 + 10 << 8 + 3;
self.write_register(0x10, i).await;

// 使能StealthChop静音模式
self.write_register(0x00, 0x00000004).await;

// 运动参数配置
self.write_register(0x23, 10).await; // vstart
self.write_register(0x26, TMC5160_MAX_MSPS / 4).await; // amax
self.write_register(0x27, TMC5160_MAX_MSPS).await; // vmax
self.write_register(0x28, TMC5160_MAX_MSPS / 4).await; // dmax
}

5.2 ADMT4000 CRC校验

fn calc_crc(input: u32) -> u8 {
let mut shft = [1u8, 1, 1, 1, 1];

for i in (5..=30).rev() {
let data_bit = ((input >> i) & 1) as u8;
let xor_0 = data_bit ^ shft[4];

shft[4] = shft[3];
shft[3] = shft[2];
shft[2] = shft[1] ^ xor_0;
shft[1] = shft[0];
shft[0] = xor_0;
}

let mut crc5 = 0u8;
for i in 0..5 {
crc5 |= shft[i] << i;
}
crc5
}

5.3 状态机定义(smlang宏)

smlang::statemachine! {
transitions: {
*UnInit + NeedCorrect = Correct,
UnInit + NeedAlign = Align,

Correct + Number(usize) / correct_select = Correct,
Correct + KeyConfirm / correct_active = Correct,
Correct + CorrectFinish / correct_clear = Idle,

Idle + Number(usize) / idle_input = Idle,
Idle + InnerMoveUp(usize) / move_up = MoveUp,
Idle + InnerMoveDown(usize) / move_down = MoveDown,

Open + Second / open_on_second = Open,
Open + InnerTimeOut = Idle,

MoveUp + Arrive = Open,
MoveDown + Arrive = Open,
}
}

六、系统特性

6.1 安全性设计

  • 位置验证:每次运动后读取编码器验证实际位置
  • CRC校验:ADMT4000通信使用CRC5校验
  • 边界保护:校准数据检查编码器读数合法性
  • Flash保护:写入前擦除,确保数据完整性

6.2 用户体验优化

  • 音效反馈:按键、到达、错误三种音效
  • 视觉反馈:OLED实时显示状态,LED指示目标楼层
  • 自动关门:开门5秒后自动关闭
  • 运动中输入:运行时可继续输入目标楼层

6.3 调试功能

  • 串口CLI:支持手动设置current/target/status
  • defmt日志:通过SWD输出详细调试信息
  • 状态查询:实时查看状态机状态和事件

七、性能指标

指标

数值

主频

160 MHz

位置分辨率

51200 微步/圈

最大速度

51200 微步/秒

加速度

12800 微步/秒²

键盘扫描周期

50 ms

LED刷新率

10 Hz

OLED刷新

事件驱动

编码器精度

1024 计数/圈

八、项目依赖

核心依赖

  • embassy-executor:异步任务执行器
  • embassy-stm32:STM32 HAL库
  • embassy-sync:同步原语(Signal/Watch)
  • embassy-time:时间管理

外设驱动

  • ssd1306:OLED显示驱动
  • embedded-graphics:图形绘制库
  • eg-seven-segment:七段数码管

工具库

  • smlang:状态机宏
  • embedded-cli:命令行解析
  • defmt:格式化日志
  • static_cell:静态内存分配

九、总结

本项目成功实现了一个功能完整的嵌入式电梯控制系统,展示了Rust在嵌入式领域的强大能力:

技术亮点

  1. 使用异步编程模型简化多任务并发
  2. 状态机驱动的清晰控制逻辑
  3. 类型安全的硬件抽象层
  4. 零成本抽象的高性能实现

实用价值

  • 可作为电梯控制系统的原型验证
  • 演示了步进电机闭环控制方案
  • 提供了完整的人机交互参考设计

改进方向

  • 增加故障检测与恢复机制
  • 实现多电梯调度算法
  • 添加网络通信功能(如Modbus/CAN)
  • 优化运动曲线(S型加减速)

项目信息

  • 开发语言:Rust (edition 2024)
  • 目标平台:STM32U545RE
  • 开发框架:Embassy
  • 代码规模:约2000行


附件下载
adi_design_src.zip
团队介绍
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号