跳转到内容
新建笔记

项目1:单片机程序审查,控制系统项目结构分析报告

  • 项目名称: 老虎机控制系统 (TigerControl)
  • 硬件平台: STM32F103RET6 微控制器
  • 操作系统: FreeRTOS V10.x
  • 通信协议: Modbus RTU (主站和从站)
  • 主要功能: 工业动平衡机的伺服控制和IO管理
  • 替代传统PLC,实现高精度动平衡机控制
  • 通过Modbus协议与上位机和伺服驱动器通信
  • 提供安全的按钮控制和紧急停止功能
  • 实现智能的工件夹紧控制
┌─────────────────────────────────────────────────────────────┐
│ STM32F103RET6 主控制器 │
├─────────────────┬───────────────┬───────────────────────────┤
│ FreeRTOS 任务 │ 通信协议栈 │ 硬件抽象层 │
│ │ │ │
│ ┌─defaultTask │ ┌─Modbus主站 │ ┌─GPIO控制 │
│ │ ┌─modbusTask │ │ ┌─Modbus从站 │ │ ┌─UART通信 │
│ │ │ ┌─servoTask │ │ │ ┌─地址透传 │ │ │ ┌─定时器 │
│ │ │ │ └─systemTask│ │ │ └─稀疏数组│ │ │ │ └─看门狗 │
│ └─┴─┴─┴─────────┴─┴─┴─┴─────────┴─┴─┴─┴─────────────────────┤
└─────────────────────────────────────────────────────────────┘
│ │ │
┌───────▼───────┐ ┌───────▼───────┐ ┌───────▼───────┐
│ 上位机通信 │ │ 伺服驱动器 │ │ 现场IO设备 │
│ (Modbus从站) │ │ (Modbus主站) │ │ (按钮/阀门) │
└───────────────┘ └───────────────┘ └───────────────┘
FreeRTOS任务调度器
├── defaultTask (优先级: Normal, 栈: 128*4) - 空闲任务
├── modbusTask (优先级: Normal, 栈: 1200*4) - Modbus通信处理
├── servoTask (优先级: High, 栈: 1200*4) - 伺服控制核心
└── systemTask (优先级: Low, 栈: 512*4) - 系统监控和按钮控制

3.1 伺服控制模块 (tigerservo.c/h)

跳转到“3.1 伺服控制模块 (tigerservo.c/h)”
  • 核心功能: 动平衡机伺服电机精确控制
  • 通信方式: Modbus RTU主站模式
  • 控制对象: 台达伺服驱动器(站号1和站号2)
  • 控制精度: 支持32位参数控制
伺服通信状态机流程:
INIT → READ_INOUT_DATA → CHECK_INOUT_DIFF → WRITE_INOUT_DIFF
↓ ↑
CHECK_CTRL_DIFF ← READ_OUTPUT_DATA
↓
WRITE_CTRL_DIFF
typedef struct {
ModbusConfig_t mb; // Modbus通信配置
ServoBalanceInput_t balanceInput; // 动平衡输入参数(21个)
ServoBalanceOutput_t balanceOutput; // 动平衡输出参数(7个)
ServoControllerState_t State; // 伺服控制器状态
// 通信状态管理
ServoCommState_t commState; // 状态机状态
uint8_t commIndex; // 通信索引
uint8_t retryCount; // 重试计数
// 数据缓存机制
uint32_t readInOutDataCache[21]; // 读取缓存
uint32_t writeInOutDataCache[21]; // 写入缓存
uint16_t readCtrlDataCache[2]; // 控制读取缓存
uint16_t writeCtrlDataCache[2]; // 控制写入缓存
} A3ServoController_t;
  • 智能重试策略: 上电初期频繁重试,后期降低频率
  • 通信错误恢复: 超时和错误计数管理
  • 数据一致性检查: 读写缓存差异检测
  • 线程安全保护: 互斥锁保护关键操作

系统同时充当:

  • Modbus主站: 与伺服驱动器通信
  • Modbus从站: 接受上位机控制命令
// 地址映射策略
#define IS_STATION1_ADDR(addr) ((addr) >= 0x0600 && (addr) < 0x0700) // P6组参数
#define IS_STATION2_DATA_ADDR(addr) ((addr) >= 0x5000 && (addr) < 0x6000) // 站2数据
#define IS_STATION2_CTRL_ADDR(addr) ((addr) >= 0xA800 && (addr) < 0xA900) // 站2控制
typedef struct {
uint16_t addr; // Modbus地址
uint16_t value; // 寄存器值
} RegEntry_t;
typedef struct {
RegEntry_t *entries; // 条目数组
uint16_t count; // 当前数量
uint16_t capacity; // 总容量
} RegMap_t;
  • 通信就绪检查: 防止在繁忙状态下写入
  • 数据时效性检查: 超过5秒的数据被标记为过期
  • 设备状态检查: 根据Modbus状态返回相应错误码

3.3 按钮控制模块 (button_control.c/h)

跳转到“3.3 按钮控制模块 (button_control.c/h)”
typedef enum {
BUTTON_TYPE_EMERGENCY_STOP = 0, // 急停按钮 (PB8/IN0)
BUTTON_TYPE_RESET, // 复位按钮 (PB9/IN1)
BUTTON_TYPE_START, // 启动按钮 (PB10/IN2)
} ButtonType_t;
启动按钮流程:
检查系统就绪 → 检查急停状态 → 检查机器运行状态 → 检查气阀状态
↓ ↓ ↓ ↓
失败返回 失败返回 失败返回 智能处理气阀
↓
启动伺服电机
  • 消抖算法: 10ms消抖时间,5ms扫描间隔
  • 事件处理: 按下、释放、长按事件
  • 状态同步: 与伺服控制器状态实时同步

3.4 气阀控制模块 (valveControl.c/h)

跳转到“3.4 气阀控制模块 (valveControl.c/h)”
bool Valve_IsSafeToOperate(void) {
// 1. 急停状态检查
if(g_buttonControl.emergency_stop_active) return true; // 急停时允许开阀
// 2. 伺服运行状态检查
if(!g_servoController.State.bo_zeroSpeed) return false; // 伺服运行中禁止
// 3. 机器运行状态检查
if(g_buttonControl.machine_running) return false; // 机器运行中禁止
// 4. 伺服报警状态检查
if(g_servoController.State.bo_servoAlarmStatus) return false; // 报警时禁止
return true; // 所有检查通过
}
  • 命令处理: 处理上位机的开启/关闭命令
  • 状态反馈: 实时更新气阀状态到Modbus寄存器
  • 错误处理: 安全互锁错误时返回错误状态
时间轴: 0ms ────► 1000ms ────► 3000ms ────► 4000ms ────►
│ │ │ │
HAL初始化 FreeRTOS启动 伺服初始化 正常运行状态
│ │ │ │
├─GPIO初始化 ├─任务创建 ├─Modbus配置 ├─状态机循环
├─UART初始化 ├─互斥锁创建 ├─参数写入 ├─数据同步
├─定时器启动 └─调度器启动 └─连接建立 └─命令处理
└─外设配置
时间片调度 (10ms周期):
servoTask ████████████████████████████████████████████
modbusTask ░░░░████████░░░░████████░░░░████████░░░░████████
systemTask ░░░░░░░░░░░░░░░░░░░░████░░░░░░░░░░░░░░░░░░░░████
defaultTask ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
0ms 10ms 20ms 30ms 40ms 50ms 60ms
主站通信周期 (约100ms):
READ_INOUT → CHECK_DIFF → WRITE_DIFF → READ_OUTPUT → CHECK_CTRL → WRITE_CTRL
↑ ↓
└─────────────────────────── 循环 ────────────────────────────────────┘
从站响应 (<10ms):
接收命令 → 地址验证 → 数据处理 → 响应发送
上位机 ──Modbus从站──► MCU内存 ──状态机──► 伺服驱动器
↑ ↓ ↓
└─ 状态反馈 ←──────── 数据缓存 ←──Modbus主站──┘
↓
按钮控制 → 安全逻辑 → 气阀控制
// 输入参数 (21个32位参数)
struct BalanceInput {
int32_t measureSpeed; // 测量转速
int32_t accelFactor; // 加速系数
int32_t decelFactor; // 减速系数
int32_t measureStopAngle; // 测量停止角度
// ... 其他17个参数
};
// 输出参数 (7个32位参数)
struct BalanceOutput {
int32_t rotorSpeed; // 转子速度
int32_t feedbackPosition; // 回授位置
int32_t currentSlotNum; // 当前槽数
int32_t slipError; // 滑动误差
// ... 其他3个参数
};

问题: 直接处理Modbus输入数据,缺乏范围检查

// 问题代码示例
g_servoController.balanceInput.measureSpeed = (int32_t)value; // 未验证范围

风险: 恶意输入可能导致设备异常 建议: 添加参数范围验证

// 改进建议
if(value >= MIN_SPEED && value <= MAX_SPEED) {
g_servoController.balanceInput.measureSpeed = (int32_t)value;
} else {
return MB_DATA_ERR; // 返回数据错误
}

6.1.2 急停处理不够完善

跳转到“6.1.2 急停处理不够完善”

问题: 急停状态下仍允许某些操作 风险: 可能存在安全隐患 建议: 强化急停状态下的限制

问题: 部分全局变量访问未完全保护

// 潜在竞态条件
g_servoController.isDataDifferent = true; // 多线程访问

建议: 使用原子操作或加强互斥锁保护

问题: 稀疏数组容量固定,可能溢出

if(map->count >= map->capacity) {
return -1; /* 容量已满 */
}

建议: 动态扩容或更大的静态容量

问题: 通信错误恢复较为简单 建议: 实现更智能的错误恢复策略

问题: 看门狗喂狗逻辑可能不够健壮 建议: 增加任务健康检查

当前问题: 伺服任务10ms周期可能过于频繁 建议: 根据实际需求调整任务周期

建议:

  • 批量读写操作减少通信次数
  • 实现通信缓存机制
  • 优化CRC计算
  1. 参数验证框架: 建立统一的参数范围检查机制
  2. 安全状态机: 独立的安全监控状态机
  3. 故障注入测试: 增加故障模式测试
  1. 配置参数化: 将硬编码常量移至配置文件
  2. 日志系统: 增加结构化日志记录
  3. 单元测试: 为关键模块添加单元测试
  1. 远程诊断: 增加远程监控和诊断功能
  2. 数据记录: 历史数据记录和分析
  3. 多语言支持: 支持多种语言界面
  • 架构清晰: 模块化设计,职责分离明确
  • 实时性好: FreeRTOS保证实时响应
  • 通信可靠: 双重Modbus角色设计巧妙
  • 安全考虑: 多层安全互锁机制
  • 输入验证: 缺乏完善的输入数据验证
  • 内存安全: 固定大小数组可能溢出
  • 并发安全: 部分共享数据访问保护不足

该项目展现了良好的嵌入式系统设计理念,但在安全性和健壮性方面还有改进空间。建议在投入生产使用前,重点加强输入验证、错误处理和安全机制。


来源:CSDN 原文,首次发布于 2025-09-11。