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 电源框图

2.1.2 信号连接

2.1.3 硬件总览

2.1.4 PCB设计

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

2.1.5 组装整体图

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秒倒计时自动关门,可按关门键提前关闭
- 运动中可继续输入目标楼层,系统会自动排队处理

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

1楼已校准:

上电后的自动找平状态:

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

关门空闲状态:

运动状态:

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"+"确认"标定
- 依次标定2-6层
- 全部标定完成后,数据写入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变化,实现状态同步更新。

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:横线—

四、代码流程分析
4.1 主程序启动流程
main() {
1. 初始化STM32外设(80MHz时钟)
2. 创建I2C总线(共享给键盘和OLED)
3. 创建SPI总线(共享给TMC5160和ADMT4000)
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(用户按键)
- Timer(1秒定时器,用于开门倒计时)
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. 初始化TMC5160和ADMT4000
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在嵌入式领域的强大能力:
技术亮点:
- 使用异步编程模型简化多任务并发
- 状态机驱动的清晰控制逻辑
- 类型安全的硬件抽象层
- 零成本抽象的高性能实现
实用价值:
- 可作为电梯控制系统的原型验证
- 演示了步进电机闭环控制方案
- 提供了完整的人机交互参考设计
改进方向:
- 增加故障检测与恢复机制
- 实现多电梯调度算法
- 添加网络通信功能(如Modbus/CAN)
- 优化运动曲线(S型加减速)
项目信息:
- 开发语言:Rust (edition 2024)
- 目标平台:STM32U545RE
- 开发框架:Embassy
- 代码规模:约2000行
附件下载
adi_design_src.zip
团队介绍
无
评论
0 / 100
查看更多
猜你喜欢
制作FPGA电子琴1. 存储一段音乐,并可以进行音乐播放,
2. 可以自己通过板上的按键进行弹奏,支持两个按键同时按下(和弦)并且声音不能失真,板上的按键只有13个,可以通过有上方的“上“、”下”两个按键对音程进行扩展
john
2497
2026 ADI机器控制设计竞赛 - 基于ADMT4000角度传感器的升降台控制系统该项目使用了ADMT4000,实现了升降台控制的设计,它的主要功能为:定量调整。
Bymyself
3
2026 ADI机器控制设计竞赛 - 用ADMT4000模块实现电梯控制该项目使用了磁转数传感器ADMT4000,实现了多圈绝对位置的多层电梯升降控制系统的设计,它的主要功能为:通过磁转数传感器ADMT4000感知电梯动力系统(舵机),旋转的圈数,控制电梯轿厢位置。。
aramy
9