十月的皮皮头像
关注
STM32从零到量产开发:四路继电器工业控制模块开发 -上位机 Program.cs 应用程序入口设计说明封面图

STM32从零到量产开发:四路继电器工业控制模块开发 -上位机 Program.cs 应用程序入口设计说明

STM32从零到量产开发:四路继电器工业控制模块开发 -上位机 Program.cs 应用程序入口设计说明

1. 模块概述

本文件是 P02 上位机应用程序的唯一入口点(Program.cs),负责启动引导、命令行参数解析、双模式运行切换及线程模型初始化。

核心功能:

  • 启动引导:初始化 WinForms 应用上下文,创建 MainForm 实例
  • 命令行参数解析:支持 --selftest 参数及可选串口端口号
  • 双模式切换:正常 GUI 交互模式 vs 自测试无头模式(Headless)
  • 跨线程管控:在自测试模式下关闭非法跨线程调用检查,提升测试效率

2. 启动流程

2.1 正常模式(默认)

解析命令行参数 → 初始化 WinForms 样式 → 创建 MainForm → Application.Run(form) → 进入消息循环
  • 不传递 --selftest 参数时,进入标准 WinForms 消息循环
  • 用户通过 GUI 与从机设备交互

2.2 自测试模式(Headless)

解析 --selftest + 端口号 → 初始化 WinForms 样式 → 创建 MainForm → 设置 SelfTest 属性 → 关闭跨线程检查 → 异步执行 RunSelfTest() → 等待完成 → Environment.Exit(0)
  • 传递 --selftest [COM port] 参数时,跳过 GUI 消息循环
  • 直接以无头方式执行 MainForm.RunSelfTest() 异步任务
  • 测试完成后自动退出进程

3. 命令行参数解析

参数说明示例
--selftest启用自测试模式(无头运行)--selftest
--selftest COMx指定自测试使用的串口端口--selftest COM3

解析逻辑:

  • 遍历 args 数组,查找 --selftest 标记
  • --selftest 后紧跟非 -- 开头的参数,则将其作为端口号(如 COM3
  • 端口号默认值为 "COM3"
  • 防御性设计:通过 StartsWith("--") 判断避免将其他参数误识别为端口号

调用示例:

P02HostPC.exe                          # 正常 GUI 模式,默认 COM3
P02HostPC.exe --selftest               # 自测试模式,默认 COM3
P02HostPC.exe --selftest COM5          # 自测试模式,指定 COM5

4. 双模式运行详解

4.1 正常交互模式

项目说明
执行路径Application.Run(form)
GUI 状态正常显示主窗口
跨线程检查启用(CheckForIllegalCrossThreadCalls 默认值)
适用场景日常操作、人工联调

4.2 自测试模式(Headless)

项目说明
执行路径RunSelfTest().GetAwaiter().GetResult() + Environment.Exit(0)
GUI 状态不显示任何窗口(无头运行)
跨线程检查强制关闭(CheckForIllegalCrossThreadCalls = false
端口配置通过命令行参数指定,默认 COM3
适用场景CI/CD 自动化测试、无人值守联调

5. 线程模型

5.1 STA 线程要求

  • 主入口标注 [STAThread],满足 WinForms 对单线程单元(STA)的强制要求
  • 所有 WinForms 控件创建和消息循环必须在 STA 线程上执行

5.2 跨线程调用管控

模式CheckForIllegalCrossThreadCalls说明
正常模式true(默认)捕获 GUI 控件跨线程访问异常,便于开发调试
自测试模式false关闭检查,避免自测试中后台线程更新 UI 时抛出异常中断测试流程

设计说明:自测试模式下关闭跨线程检查是一种务实的工程取舍——测试代码本身应保证线程安全,关闭检查可避免因非关键 UI 更新异常掩盖真正的测试失败。


6. 关键设计亮点

亮点说明
无 GUI 依赖的单元测试入口通过 --selftest 参数实现无头运行,支持自动化测试框架集成
灵活串口配置命令行参数动态指定串口,无需修改代码即可切换测试目标设备
防御性参数解析StartsWith("--") 防止端口号参数被误识别,支持未来扩展更多参数
异步任务安全等待使用 .GetAwaiter().GetResult() 同步等待异步测试完成,避免主线程提前退出
MainForm 协作契约通过 SelfTestModeSelfTestPortSelfTestHeadless 三个属性与 MainForm 通信,解耦入口与业务逻辑
进程可控退出测试完成后调用 Environment.Exit(0) 确保进程干净退出,不残留后台线程

7. 依赖关系

依赖模块依赖方式说明
MainForm直接实例化应用程序主窗口,承载所有业务逻辑
System.Windows.Forms命名空间引用WinForms 框架基础
System.Threading.Tasksusing 引用异步任务(RunSelfTest 返回 Task
IWDG 等 BSP 层间接依赖通过 MainForm 内部调用,Program.cs 不直接接触

8. 设计总结

设计维度具体措施
启动可靠性[STAThread] 确保 STA 线程环境,WinForms 正常初始化
测试友好性--selftest 无头模式 + 端口动态配置,支持 CI/CD 集成
参数安全性防御性解析 + 默认值兜底,避免非法参数导致崩溃
线程安全性正常模式开启跨线程检查,测试模式关闭以保证流程完整
进程管理测试完成后主动 Environment.Exit(0),避免僵尸进程
关注点分离入口层仅负责启动引导,业务逻辑全部委托给 MainForm

该入口设计充分体现了工业上位机软件对"日常交互"与"自动化测试"双场景的兼顾,通过简洁的命令行参数实现模式切换,是 WinForms 应用程序入口的标准实践。
`/**


  • @file modbus_rtu.h
  • @brief Modbus RTU 从站协议栈
  • @details 提供 Modbus RTU 从站接口:初始化、主循环轮询、故障安全检测、从站地址查询、
  •      帧/异常计数与接收中断回调。支持功能码 01/02/03/04/05/06/0F/10/17。
    
  •      字节序:数据/地址大端(MSB 在前),CRC 小端(LSB 在前)。
    
  •      业务关联(参数流向):
    
  •        - 输入:stm32f1xx_it.c HAL_UART_RxCpltCallback → Modbus_RxByte(RS485 字节);
    
  •        - 处理:main.c 主循环调用 Modbus_Poll + Modbus_CheckFailSafe;
    
  •        - 寄存器后端读写 FlashParam_Get/Save、BSP_ADC_*、BSP_DAC_*、BSP_Relay_*、BSP_LED_CommPulse;
    
  •        - 读取:RS232 Shell 经 Modbus_Get* 读取计数/地址。
    

*/

#ifndef __MODBUS_RTU_H
#define __MODBUS_RTU_H

#ifdef __cplusplus
extern “C” {
#endif

#include <stdint.h>
#include “usart.h”

/* ===================== 1. 常量 ===================== /
#define MODBUS_MAX_FRAME_LEN 256u /
最大帧长度(满足 Modbus 标准上限:
读 32 寄存器响应 67B / 写 32 寄存器请求 73B 均不溢出)/
#define MODBUS_MAX_REG_COUNT 32u /
单次最大读写寄存器数 /
#define MODBUS_BROADCAST_ADDR 0u /
广播地址 */

/* ===================== 2. 对外接口 ===================== */

/**

  • @brief 初始化 Modbus RTU 从站
  •     配置 UART1 (RS485) 波特率、启动接收中断
    
  • @param huart: USART1 句柄指针
  • @param slave_addr: 初始从站地址
    */
    void Modbus_Init(UART_HandleTypeDef *huart, uint8_t slave_addr);

/**

  • @brief 轮询处理(在主循环中持续调用)
  •     接收帧 → 解析 → 执行 → 发送响应 → RS485 方向切换
    

*/
void Modbus_Poll(void);

/**

  • @brief 故障安全检测(主循环中调用,与 Modbus_Poll 配合)
  •     连续 fail_safe_sec 无有效帧 → 继电器全断 + FAULT 灯快闪
    
  •     收到任意有效帧 → 自动恢复
    

*/
void Modbus_CheckFailSafe(void);

/**

  • @brief 查询故障安全是否已触发(断线/主站失联进入安全态)
  • @retval 1=已触发(安全态) 0=正常
  • @note 供应用层统一驱动 FAULT LED 使用,避免与报警指示互相覆盖
    */
    uint8_t Modbus_IsFailSafeActive(void);

/**

  • @brief 设置从站地址(运行时修改,不自动保存 Flash)
    */
    void Modbus_SetSlaveAddr(uint8_t addr);

/**

  • @brief 获取当前从站地址
    */
    uint8_t Modbus_GetSlaveAddr(void);

/**

  • @brief 获取有效帧计数(诊断用)
    */
    uint32_t Modbus_GetFrameCount(void);

/**

  • @brief 获取异常码计数(诊断用)
    */
    uint32_t Modbus_GetExceptionCount(void);

/**

  • @brief 接收中断回调 — 由 stm32f1xx_it.c 中 USART1 中断调用
  • @param byte: 收到的单字节
    */
    void Modbus_RxByte(uint8_t byte);

#ifdef __cplusplus
}
#endif

#endif /* __MODBUS_RTU_H */
`

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/2503_92342417/article/details/163617119

文章来源crawl

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--