STM32从零到量产开发:四路继电器工业控制模块开发 - 系统应用层(system_app)设计说明
·
STM32从零到量产开发:四路继电器工业控制模块开发 - 系统应用层(system_app)设计说明
1. 模块概述
本模块为工业控制模块的系统应用层,负责运行时间统计、复位计数、看门狗喂狗等系统级服务。向上为 Modbus 协议层和 RS232 Shell 提供统一的系统状态读数接口,向下封装 HAL 层与 Flash 参数模块的依赖,实现关注点分离。
核心功能:
- 运行时间统计:本次上电运行秒数(16 位回绕,对应输入寄存器 0x0000)
- 累计运行秒/小时:跨重启连续累计,掉电不丢失,用于设备寿命评估(#4 设备履历)
- 累计复位次数:对应输入寄存器 0x0001,由 FlashParam 模块上电自动 +1
- 看门狗喂狗:封装 HAL_IWDG_Refresh,主循环单圈调用防止 IWDG 超时复位(6.5 秒超时)
设计约束:
- 文件名使用
system_app避免与 CubeMX 生成的system_stm32f1xx.c冲突 - 板载看门狗 IWDG 超时配置为 6.5 秒
2. 数据流
| 数据源 | 接口函数 | 目标/用途 |
|---|---|---|
| HAL_GetTick() | SystemApp_GetUptime() | 本次上电运行秒(16 位回绕) |
| flash_param | SystemApp_GetRunSeconds() | 跨重启累计运行秒(#4 设备履历) |
| flash_param | SystemApp_GetRunHours() | 累计运行小时(秒 / 3600) |
| flash_param | SystemApp_GetResetCount() | 累计复位次数(低 16 位) |
| 主循环 | SystemApp_FeedWatchdog() | 刷新 IWDG 防止超时复位 |
3. 存储架构
3.1 与 flash_param 的依赖关系
本模块不自行维护任何静态变量,所有累计数据实时向 flash_param 模块获取:
SystemApp_GetRunSeconds() → FlashParam_GetRunSeconds()
├─ run_sec_base(掉电保存基准)
└─ 本次上电 HAL_GetTick()/1000(增量)
SystemApp_GetResetCount() → FlashParam_Get()->reset_count(低16位)
解耦说明:
- 本层不自行维护任何静态变量,全部读数实时向 HAL / flash_param 取,不存在缓存与真实值不一致的风险
- 累计运行时间统一走 FlashParam_GetRunSeconds(),上层无需感知"Flash 保存基准 + 本次上电增量"的拼接细节
- 看门狗句柄 hiwdg 的依赖收敛在本文件,上层业务不直接接触 HAL IWDG 接口
4. 对外公共接口
| 函数 | 返回值类型 | 说明 |
|---|---|---|
| SystemApp_Init() | void | 系统应用层初始化(在所有外设初始化后调用) |
| SystemApp_Tick1ms() | void | 系统 1ms 心跳(预留扩展点,当前为空实现) |
| SystemApp_GetUptime() | uint16_t | 获取运行时间(秒,16 位回绕,约 18.2 小时回绕,对应输入寄存器 0x0000) |
| SystemApp_GetRunSeconds() | uint32_t | 获取累计运行秒数(掉电保存基准 + 本次上电增量,#4 设备履历) |
| SystemApp_GetRunHours() | uint32_t | 获取累计运行小时数(运行秒数 / 3600,#4 设备履历) |
| SystemApp_GetResetCount() | uint16_t | 获取累计复位次数(低 16 位,对应输入寄存器 0x0001) |
| SystemApp_FeedWatchdog() | void | 喂看门狗(封装 HAL_IWDG_Refresh,主循环单圈调用) |
5. 关键设计亮点
5.1 零静态变量设计
本模块不维护任何静态变量,所有读数实时从 HAL 层或 FlashParam 模块获取:
- Uptime:直接调用 HAL_GetTick() / 1000,无缓存
- RunSeconds / RunHours:委托 FlashParam_GetRunSeconds() 计算,避免直接读 run_sec_base 漏掉本次上电增量
- ResetCount:从 FlashParam_Get()->reset_count 读取,由 FlashParam_Init 在每次上电 +1
优势:不存在缓存与真实值不一致的风险,代码简洁且可维护性高。
5.2 运行秒跨重启连续累计
run_sec_base由 flash_param 模块在 Flash 中掉电保存- 每次上电后,FlashParam_GetRunSeconds() = run_sec_base + HAL_GetTick()/1000
- SystemApp_GetRunHours() = SystemApp_GetRunSeconds() / 3600
- 确保设备运行时间统计准确且断电不丢失,用于设备寿命评估
5.3 16 位回绕处理
- Uptime 返回 uint16_t,约 18.2 小时回绕一次(65535 秒),符合规格书 4.3 定义
- ResetCount 返回 uint16_t(低 16 位),内部 reset_count 为 uint32_t,取低 16 位对应输入寄存器
5.4 看门狗喂狗封装
- 封装 HAL_IWDG_Refresh(&hiwdg),统一管理系统看门狗
- 板载看门狗 IWDG 超时 6.5 秒,主循环每圈调用一次 SystemApp_FeedWatchdog() 防止超时复位
- 上层业务不直接接触 HAL IWDG 接口,依赖收敛在本文件
5.5 1ms 心跳预留扩展点
- SystemApp_Tick1ms() 当前为空实现,预留了 1ms 心跳扩展能力
- 如需扩展软件定时器调度等 1ms 级任务,可在此实现,无需修改上层调用逻辑
6. 与 Modbus 协议协作
| 输入寄存器地址 | 对应接口 | 数据来源 |
|---|---|---|
| 0x0000 | SystemApp_GetUptime() | HAL_GetTick() / 1000(本次上电秒,16 位回绕) |
| 0x0001 | SystemApp_GetResetCount() | FlashParam_Get()->reset_count(低 16 位) |
| 0x0002 | SystemApp_GetRunSeconds() | FlashParam_GetRunSeconds()(跨重启累计秒) |
| 0x0003 | SystemApp_GetRunHours() | SystemApp_GetRunSeconds() / 3600(累计小时) |
7. 依赖关系
| 依赖模块 | 依赖方式 | 说明 |
|---|---|---|
| main.h | #include | HAL 层基础定义 |
| app_main.h | #include | 应用层公共定义 |
| bsp_storage.h | #include | FlashParam 接口(flash_param 模块) |
| iwdg.h | #include | IWDG 句柄 hiwdg 定义 |
| HAL 库 | 函数调用 | HAL_GetTick()、HAL_IWDG_Refresh() |
8. 设计总结
| 设计维度 | 具体措施 |
|---|---|
| 数据完整性 | 零静态变量,实时从 HAL/FlashParam 获取,无缓存不一致风险 |
| 运行统计 | 跨重启连续累计(秒 + 小时),掉电不丢失,用于设备寿命评估 |
| 看门狗管理 | 封装喂狗接口,主循环单圈调用,IWDG 超时 6.5 秒 |
| 关注点分离 | 上层不直接接触 HAL IWDG,依赖收敛在本文件 |
| 可扩展性 | 1ms 心跳预留扩展点,便于后续添加软件定时器调度 |
| 协议对接 | 与 Modbus 输入寄存器 0x0000~0x0003 一一对应 |
该模块设计遵循"零静态变量"原则,所有读数实时从底层获取,消除了缓存与真实值不一致的风险。运行统计功能通过委托 flash_param 模块实现跨重启连续累计,看门狗喂狗封装统一了系统级看门狗管理,整体架构清晰、解耦充分,符合工业控制软件的可靠性设计要求。
/**
******************************************************************************
* @file system_app.h
* @brief 系统应用层 - 运行时间统计、复位计数、看门狗喂狗等
*
* 对应规格书:
* - 4.3 输入寄存器: Uptime / ResetCount / FrameCount / CRCErrorCount
* - 2. 板载看门狗 IWDG 超时 6.5 秒
*
* 注: 文件名使用 system_app 避免与 CubeMX 生成的 system_stm32f1xx.c 冲突
******************************************************************************
*/
#ifndef __SYSTEM_APP_H
#define __SYSTEM_APP_H
#ifdef __cplusplus
extern "C" {
#endif
#include "main.h"
/**
* @brief 系统应用层初始化 (在所有外设初始化后调用)
*/
void SystemApp_Init(void);
/**
* @brief 系统 1ms 心跳 (在 SysTick 中断或主循环调用)
* @note 累计运行秒数 (Uptime, 16位回绕)
*/
void SystemApp_Tick1ms(void);
/**
* @brief 获取运行时间 (秒, 16位回绕, 对应输入寄存器 0x0000)
*/
uint16_t SystemApp_GetUptime(void);
/**
* @brief 获取累计运行秒数 (掉电保存基准 + 本次上电秒数, #4)
* @note 运行秒数 = Flash 中保存的 run_sec_base(掉电不丢) + 本次上电 HAL_GetTick()/1000
* 该值跨重启连续累计, 用于计算运行小时/设备寿命评估。
*/
uint32_t SystemApp_GetRunSeconds(void);
/**
* @brief 获取累计运行小时数 (#4 设备履历)
* @note 运行小时 = 累计运行秒数 / 3600, 掉电保存、跨重启连续。
*/
uint32_t SystemApp_GetRunHours(void);
/**
* @brief 获取累计复位次数 (对应输入寄存器 0x0001)
*/
uint16_t SystemApp_GetResetCount(void);
/**
* @brief 喂看门狗
* @note 封装 HAL_IWDG_Refresh, 便于统一管理
*/
void SystemApp_FeedWatchdog(void);
#ifdef __cplusplus
}
#endif
#endif /* __SYSTEM_APP_H */
/**
******************************************************************************
* @file system_app.c
* @brief 系统应用层实现(运行时间统计、复位计数、看门狗喂狗)
*
* 模块功能:
* 封装与产品规格书对应的运行履历接口,向上为 Modbus / RS232 Shell 提供统一读数。
* 运行秒 / 小时来自 flash_param(掉电保存基准 + 本次上电增量,#4 运行小时统计)。
*
* 数据流:
* HAL_GetTick() -> SystemApp_GetUptime() 本次上电运行秒 (16 位回绕)
* flash_param -> SystemApp_GetRunSeconds() 跨重启累计运行秒
* -> SystemApp_GetRunHours() 累计运行小时 (秒 / 3600)
* flash_param -> SystemApp_GetResetCount() 累计复位次数
* 主循环 -> SystemApp_FeedWatchdog() 刷新 IWDG 防止超时复位
*
* 解耦说明:
* 1. 本层不自行维护任何静态变量,全部读数实时向 HAL / flash_param 取,
* 不存在缓存与真实值不一致的风险。
* 2. 累计运行时间统一走 FlashParam_GetRunSeconds(),上层无需感知
* "Flash 保存基准 + 本次上电增量" 的拼接细节。
* 3. 看门狗句柄 hiwdg 的依赖收敛在本文件,上层业务不直接接触 HAL IWDG 接口。
******************************************************************************
*/
#include "app_main.h"
#include "bsp_storage.h"
#include "iwdg.h"
/* -------------------------- API 快速导航 --------------------------
* void SystemApp_Init(void); 系统应用层初始化 (外设初始化后调用)
* uint16_t SystemApp_GetUptime(void); 本次上电运行秒数 (16 位回绕)
* uint32_t SystemApp_GetRunSeconds(void); 跨重启累计运行秒数 (#4)
* uint32_t SystemApp_GetRunHours(void); 跨重启累计运行小时数 (#4)
* uint16_t SystemApp_GetResetCount(void); 累计复位次数 (低 16 位)
* void SystemApp_FeedWatchdog(void); 喂看门狗, 主循环单圈调用
* void SystemApp_Tick1ms(void); 1ms 心跳扩展点 (当前为空实现)
* ------------------------------------------------------------------ */
/* -------------------------- 区块 4:对外公共业务 API -------------------------- */
/**
* @brief 系统应用层初始化(在所有外设初始化后调用)
* @retval 无
* @note 运行时间基于 HAL_GetTick() 系统毫秒时基,无需额外变量初始化
*/
void SystemApp_Init(void)
{
/* 运行时间基于 HAL_GetTick(), 无需额外初始化 */
}
/**
* @brief 获取运行时间(秒,16位回绕,对应输入寄存器 0x0000)
* @retval 上电后累计秒数(约18.2小时回绕,符合规格书 4.3)
* @note HAL_GetTick() 返回 ms, /1000 得到秒, 取低16位
* @note 本值仅表示本次上电时长;需要跨重启累计值请用 SystemApp_GetRunSeconds()
*/
uint16_t SystemApp_GetUptime(void)
{
/* HAL_GetTick() 返回 ms, /1000 得到秒, 取低16位 (约18.2小时回绕, 符合规格书 4.3) */
return (uint16_t)(HAL_GetTick() / 1000u);
}
/**
* @brief 获取累计运行秒数 (#4 设备履历)
* @retval 自设备首次运行以来的累计秒数(掉电保存基准 + 本次上电增量)
* @note 【关联指引】直接委托 flash_param 的 FlashParam_GetRunSeconds() 计算,
* 避免直接读 run_sec_base 漏掉本次上电增量,保证实时准确且断电不丢失
*/
uint32_t SystemApp_GetRunSeconds(void)
{
/* #4 累计运行秒数委托 flash_param 计算 (已保存基准 + 本次上电增量),
* 实时准确且断电不丢失。直接读取 run_sec_base 会漏掉本次上电增量,
* 故统一走 FlashParam_GetRunSeconds()。 */
return FlashParam_GetRunSeconds();
}
/**
* @brief 获取累计运行小时数 (#4 设备履历)
* @retval 累计运行小时(运行秒数 / 3600)
* @note 【关联指引】依赖 SystemApp_GetRunSeconds(),跨重启连续累计,用于设备寿命评估
*/
uint32_t SystemApp_GetRunHours(void)
{
/* #4 运行小时 = 累计秒数 / 3600 */
return SystemApp_GetRunSeconds() / 3600u;
}
/**
* @brief 获取累计复位次数(对应输入寄存器 0x0001)
* @retval 上电累计复位次数(低16位)
* @note 【关联指引】数据来自 FlashParam_Get()->reset_count,由 FlashParam_Init 在每次上电 +1
*/
uint16_t SystemApp_GetResetCount(void)
{
/* 从 Flash 参数获取累计复位次数 (低16位) */
return (uint16_t)(FlashParam_Get()->reset_count & 0xFFFFu);
}
/**
* @brief 喂看门狗
* @retval 无
* @note 封装 HAL_IWDG_Refresh,便于统一管理;主循环单圈调用防止 IWDG 超时复位
*/
void SystemApp_FeedWatchdog(void)
{
HAL_IWDG_Refresh(&hiwdg);
}
/**
* @brief 系统 1ms 心跳(预留扩展点)
* @retval 无
* @note 当前实现直接基于 HAL_GetTick 计算 uptime,此函数为空;
* 如需扩展 1ms 心跳任务(如软件定时器调度),可在此实现
*/
void SystemApp_Tick1ms(void)
{
/* 预留: 当前实现直接基于 HAL_GetTick 计算 uptime, 此函数为空 */
/* 如需扩展 1ms 心跳任务 (如软件定时器调度), 可在此实现 */
}
更多推荐


所有评论(0)