2. 系统总体架构设计:硬件架构、软件架构与通信协议
好,咱们进入第二章。这一章是整个系统的骨架,说白了就是「怎么搭积木」。我个人习惯,做任何嵌入式项目之前,一定先把架构图画清楚。你想想看,如果连主控和语音芯片怎么连都没想好,后面写代码肯定要返工。
我在项目中遇到过不少同学,上来就写代码,写到一半发现引脚不够用,或者通信协议选错了。嗯,那滋味可不好受。所以这一章,咱们把硬件、软件、通信协议这三块掰开揉碎了讲清楚。
2.1 硬件架构设计
硬件架构,说白了就是选芯片、定接口。咱们这个电梯语音播报系统,核心模块就四个:主控、语音、显示、传感。我建议你画个框图,把每个模块的电源、地、通信接口标清楚。
2.1.1 主控模块
主控是大脑。我个人偏爱 STM32 系列,特别是 STM32F103C8T6,性价比高,资料多。为什么选它?
- 性能够用:72MHz 主频,处理语音播报和传感器数据绰绰有余。
- 外设丰富:I2C、SPI、UART 都有,方便接各种模块。
- 成本低:淘宝几块钱一片,学生党也能玩得起。
2.1.2 语音模块
语音播报,我推荐用 SYN6288 或者 JQ8900。这两个芯片都支持 TTS(文本转语音),直接发串口指令就能播报。
| 模块型号 | 接口 | 特点 | 适用场景 |
|---|---|---|---|
| SYN6288 | UART | 中文语音合成,音质好 | 需要播报楼层、提示语 |
| JQ8900 | UART / I2C | 支持 MP3 播放,可预存音频 | 需要播放固定提示音 |
我个人习惯用 SYN6288,因为它可以直接发中文文本,比如发 "3楼到了",它就能播出来。JQ8900 适合播放预录好的音频文件,比如 "叮咚" 声。
2.1.3 显示模块
显示模块,我建议用 OLED 128x64,I2C 接口。为什么?
- 省引脚:I2C 只需要两根线(SCL、SDA)。
- 显示清晰:可以显示中文、数字、图标。
- 功耗低:适合长时间运行。
我在项目中遇到过一个问题:OLED 的 I2C 地址默认是 0x3C,但有些模块是 0x3D。你买回来一定要先确认地址,不然死活驱动不起来。
2.1.4 传感模块
传感模块,这里指的是楼层检测。最简单的方案是用霍尔传感器 + 磁铁。电梯每层装一个磁铁,轿厢上的霍尔传感器检测到磁铁,就知道到哪一层了。
当然,如果你做模拟,也可以用按键模拟楼层信号。我建议初学者先用按键,等系统跑通了再换真实传感器。
2.2 软件架构设计
软件架构,我习惯用 RTOS(实时操作系统)。为什么?因为电梯系统有多个任务:播报、显示、检测楼层、处理按键。如果用裸机写,一个 while 循环里塞一堆 if,代码会乱成一锅粥。
2.2.1 RTOS 任务划分
我建议用 FreeRTOS,轻量、免费、资料多。任务划分如下:
任务1:楼层检测任务(优先级最高)
- 读取传感器状态
- 判断当前楼层
- 发送楼层变化消息
任务2:语音播报任务(优先级中)
- 接收楼层变化消息
- 调用语音模块播报
任务3:显示更新任务(优先级低)
- 更新 OLED 显示内容
- 显示当前楼层、方向
任务4:按键处理任务(优先级中)
- 检测按键输入
- 模拟楼层呼叫
你想想看,如果不用 RTOS,楼层检测和语音播报混在一起,万一播报卡住了,楼层检测也会受影响。用 RTOS 后,每个任务独立运行,互不干扰。
2.2.2 状态机设计
电梯系统,说白了就是一个状态机。我习惯用有限状态机(FSM)来设计。
| 状态 | 描述 | 触发条件 | 动作 |
|---|---|---|---|
| IDLE | 空闲状态 | 无楼层请求 | 显示当前楼层 |
| MOVING_UP | 上行状态 | 检测到上行请求 | 播报 "上行",更新显示 |
| MOVING_DOWN | 下行状态 | 检测到下行请求 | 播报 "下行",更新显示 |
| ARRIVED | 到达状态 | 检测到目标楼层 | 播报 "X楼到了" |
嗯,这里要注意:状态切换一定要加防抖处理。我曾经因为没加防抖,电梯在两层之间来回跳,播报也跟着乱叫。
2.3 通信协议选择
通信协议,说白了就是模块之间怎么说话。咱们这个系统,主要涉及三种协议:
2.3.1 UART(串口)
语音模块用 UART。波特率我建议用 9600 或 115200。SYN6288 默认是 9600,JQ8900 可以配置。
// 发送语音播报指令示例
// 假设用 SYN6288,播报 "3楼到了"
uint8_t cmd[] = {0xFD, 0x00, 0x0B, 0x01, 0x03, '3', '\xC2', '\xA5', '\xB5', '\xBD', '\xC1', '\xCB'};
// 0xFD: 帧头
// 0x00 0x0B: 数据长度
// 0x01: 命令字
// 0x03: 文本编码(GBK)
// 后面是 "3楼到了" 的 GBK 编码
HAL_UART_Transmit(&huart1, cmd, sizeof(cmd), 1000);
2.3.2 I2C
OLED 显示模块用 I2C。I2C 的好处是只用两根线,可以挂多个设备。比如你以后想加温湿度传感器,也可以挂在同一根 I2C 总线上。
// OLED 初始化示例
// 地址 0x3C
uint8_t init_cmd[] = {0xAE, 0x20, 0x10, 0xB0, 0xC8, 0x00, 0x10, 0x40, 0x81, 0xFF, 0xA1, 0xA6, 0xA8, 0x3F, 0xA4, 0xD3, 0x00, 0xD5, 0xF0, 0xD9, 0x22, 0xDA, 0x12, 0xDB, 0x20, 0x8D, 0x14, 0xAF};
HAL_I2C_Master_Transmit(&hi2c1, 0x3C << 1, init_cmd, sizeof(init_cmd), 1000);
2.3.3 GPIO(通用输入输出)
传感器和按键用 GPIO。霍尔传感器输出高低电平,直接接到 STM32 的 GPIO 引脚,配置成输入模式即可。
我个人习惯,所有 GPIO 都加上拉或下拉电阻,防止浮空。你想想看,如果引脚浮空,传感器没触发时电平乱跳,系统会误判楼层。