系统架构设计:硬件架构与软件分层

好,咱们进入第二章。系统架构设计,说白了就是给分拣机画一张「施工蓝图」。我做了这么多年嵌入式,见过太多项目一上来就写代码,写到一半发现引脚不够用、电源带不动、状态机乱成一锅粥。嗯,咱们今天就把这事聊透。

一、硬件架构:五大模块怎么搭

分拣机的硬件,我习惯拆成五个部分:电源、主控、驱动、传感、通信。你想想看,这就像人的身体——电源是心脏,主控是大脑,驱动是肌肉,传感是感官,通信是神经。

1. 电源模块

电源设计,我吃过不少亏。有一次项目里用了便宜的DC-DC模块,结果电机一启动,主控直接复位。后来查了半天,是电源纹波太大。

注意: 分拣机通常需要多路电压:
- 主控:3.3V(数字核心)
- 电机驱动:12V-24V(动力部分)
- 传感器:5V(模拟部分)
- 通信模块:3.3V或1.8V

我个人习惯在电源入口加一个TVS管,再串一个自恢复保险丝。别省这个钱,我曾经因为没加TVS,雷雨天气烧了三块板子。

2. 主控模块

主控选型,我建议看三点:

  • 外设数量:至少2路UART(一路给触摸屏,一路给上位机),3路定时器(PWM输出),1路SPI(给传感器)
  • 处理能力:分拣机不需要跑Linux,STM32F4系列或者国产GD32F4系列足够了
  • 引脚余量:留20%的GPIO做扩展,你永远不知道客户会加什么功能

我最近一个项目用的GD32F407,主频200MHz,跑FreeRTOS,带6个电机和8个传感器,绰绰有余。

3. 驱动模块

电机驱动是分拣机的核心。分拣机一般用步进电机或者直流有刷电机。

电机类型 驱动芯片 控制方式 适用场景
步进电机 DRV8825 / A4988 脉冲+方向 精准定位(分拣臂)
直流有刷 L298N / TB6612 PWM+方向 传送带
无刷电机 ESC(电子调速器) PWM信号 高速旋转(离心分拣)

驱动电路要注意加续流二极管和光耦隔离。我之前偷懒没加光耦,电机启停时主控直接死机——教训啊。

4. 传感模块

分拣机常用的传感器:

  • 光电传感器:检测物体有无,我用E3Z系列的,稳定
  • 颜色传感器:TCS34725,I2C接口,分拣颜色用
  • 称重传感器:HX711+应变片,分拣重量用
  • 限位开关:机械式或者霍尔式,做原点定位

传感器布线要注意屏蔽。我遇到过传感器数据跳变,后来发现是电机线跟信号线走一起了。分开走线,加磁环,问题解决。

5. 通信模块

分拣机一般需要跟PLC或者MES系统通信。常用方案:

  • RS485:工业现场最稳,Modbus协议,距离1000米没问题
  • CAN总线:实时性高,适合多机协同
  • 以太网:数据量大,但成本高
  • WiFi/蓝牙:调试用可以,工业现场不推荐
我的习惯: 主通信用RS485,留一个WiFi模块做调试和日志输出。这样量产时去掉WiFi模块,成本可控。

二、软件架构:三层分离,各司其职

软件架构我坚持分层设计。为什么?因为不分层的代码,三个月后你自己都看不懂。我接手过一个项目,所有逻辑写在一个main.c里,5000行,改一个bug要花三天。

1. 驱动层

驱动层直接操作硬件寄存器。说白了,就是给上层提供API。

// 驱动层示例:步进电机驱动
void stepper_init(void);
void stepper_set_speed(uint16_t rpm);
void stepper_move_steps(int32_t steps);
uint8_t stepper_get_status(void);

驱动层要做的:

  • 初始化外设时钟、GPIO、定时器
  • 提供硬件抽象接口
  • 处理中断服务函数

注意:驱动层不要加业务逻辑。我曾经看到有人在驱动层写分拣算法,那叫一个乱。

2. 中间件层

中间件层是承上启下的。它封装了常用的功能模块:

  • FreeRTOS:任务调度、信号量、消息队列
  • 协议栈:Modbus从站协议、自定义通信协议
  • 算法库:PID控制、滤波算法、颜色识别
  • 日志系统:环形缓冲区、串口打印

中间件层的好处是:换主控芯片时,只需要改驱动层,中间件和应用层基本不动。

3. 应用层

应用层就是业务逻辑。分拣机的应用层包括:

  • 状态机管理(下面细说)
  • 用户交互(按键、触摸屏)
  • 分拣策略(按颜色、按重量、按形状)
  • 异常处理(卡料、缺料、过载)
核心原则: 应用层只调用中间件层的API,不直接操作硬件。这样代码可移植性极强。

三、状态机设计:分拣机的灵魂

状态机,说白了就是分拣机的大脑。它决定了机器在什么条件下做什么事。我见过太多人用一堆if-else来写状态逻辑,结果状态一多,代码就成了一团乱麻。

状态机的基本要素

一个完整的状态机包含:

  • 状态:机器当前处于什么阶段
  • 事件:触发状态切换的条件
  • 动作:进入/退出状态时执行的操作
  • 转移:状态之间的跳转规则

分拣机的典型状态

我设计的分拣机状态机一般包含以下状态:

typedef enum {
    STATE_IDLE,          // 空闲等待
    STATE_DETECT,        // 检测物料
    STATE_CLASSIFY,      // 分类判断
    STATE_SORT,          // 执行分拣
    STATE_ERROR,         // 错误处理
    STATE_CALIBRATE      // 校准模式
} SorterState;

状态转移图

状态转移的逻辑:

  • IDLE → DETECT:传感器检测到物料
  • DETECT → CLASSIFY:物料信息采集完成
  • CLASSIFY → SORT:分类结果确定
  • SORT → IDLE:分拣动作完成
  • 任何状态 → ERROR:出现异常(卡料、超时)
  • ERROR → IDLE:手动复位或自动恢复
避坑指南: 我曾经在状态机里忘了处理「超时」事件。结果有一次物料卡住了,机器一直停在SORT状态,电机堵转烧了。后来我每个状态都加了超时检测,超时自动进ERROR状态。

代码实现示例

void sorter_task(void *param) {
    SorterEvent event;
    while(1) {
        event = get_next_event();  // 从队列获取事件
        switch(current_state) {
            case STATE_IDLE:
                if(event == EVT_DETECT) {
                    motor_start();          // 动作
                    current_state = STATE_DETECT;
                }
                break;
            case STATE_DETECT:
                if(event == EVT_DATA_READY) {
                    classify_material();    // 动作
                    current_state = STATE_CLASSIFY;
                } else if(event == EVT_TIMEOUT) {
                    current_state = STATE_ERROR;
                }
                break;
            // ... 其他状态处理
        }
    }
}

状态机设计要点

  • 状态要正交:每个状态只做一件事,不要一个状态既检测又分拣
  • 事件要明确:事件来源要清晰(传感器、定时器、通信、用户)
  • 要有默认处理:switch语句一定要加default,处理未定义事件
  • 状态机可视化:我习惯先画状态转移图,再写代码。用draw.io或者手画都行
重要提醒: 状态机不要嵌套太深。我见过7层嵌套的状态机,调试时想死的心都有。一般3-5个状态就够了,如果超过8个,考虑拆分成子状态机。

好了,系统架构设计就聊到这儿。硬件架构是骨架,软件分层是肌肉,状态机是灵魂。三者缺一不可。下一章咱们开始讲具体的硬件选型和电路设计,到时候我会把踩过的坑一个一个说给你听。