diesel_generator.h
GENSET_RUN_TABLE_T 字段与量纲Query_DG_E 枚举成员3. 函数清单4. 核心逻辑解析4.1 寄存器映射约定(非标准 Modbus 用法)4.2 时序参数4.3 数据模型(三层结构体)4.4 与 uCOS-II 的配合4.5 通信协议帧格式4.6 未防御的取值点5. 对外接口导出(供外部调用)使用的外部符号(本文件自身依赖)6. 依赖关系7. 备注与风险点源文件路径:
midware/meter/diesel_generator.h所属模块:midware/meter(电表/油机中间件) 代码行数:88
1. 文件职责
这是油机(柴油发电机组)控制器 Modbus 采集模块的对外头文件。它把三类信息集中在一处:寄存器映射常量(Page 4/5/7/154 的起始寄存器号与寄存器个数)、查询时序常量(500ms 轮询节拍、15s 通讯丢失门限)、以及油机运行数据与节拍控制表的结构体定义。
在数据流中,它定义的数据模型是 EMS 对油机的"唯一视图":midware/meter/diesel_generator.c 按 500ms 节拍填充 g_t_diesel_gen,net/ems.c 读取该表组装 CMD_SEND_GENSET_DATA 报文上报云端。头文件同时用 extern 把 g_t_diesel_gen 暴露给网络层。
logic/ 层不 include 本文件——油机数据只做监视上报,不参与能量调度。
2. 关键数据结构与宏
| 名称 | 类型 | 说明 |
|---|---|---|
__DIESEL_GENERATOR_H__ | 宏 | 头文件防重复包含保护 |
GENSET_DEBUG_INFO | 宏 | 0,调试打印开关;diesel_generator.c 用 #if GENSET_DEBUG_INFO 包裹全部 printf |
GENSET_ADDR | 宏 | 99,油机控制器的 Modbus 从站地址 |
DG_PAGE_4_A0_33_REG_ADDR | 宏 | 4*256 = 1024 (0x0400),Page 4 "Basic Instrumentation" 起始寄存器(A0) |
DG_PAGE_5_A10_11_REG_ADDR | 宏 | 5*256+10 = 1290 (0x050A),Page 5 "Extended Instrumentation" 的 A10 |
DG_PAGE_7_A6_9_REG_ADDR | 宏 | 7*256+6 = 1798 (0x0706),Page 7 "Accumulated Instrumentation" 的 A6 |
DG_PAGE_154_ALARM_REG_ADDR | 宏 | 154*256 = 39424 (0x9A00),Page 154 "Alarm Conditions" 起始寄存器 |
DG_PAGE_4_A0_33_REG_NUM | 宏 | 34,Page 4 一次读 34 个寄存器 |
DG_PAGE_5_A10_11_REG_NUM | 宏 | 2,Page 5 一次读 2 个寄存器 |
DG_PAGE_7_A6_9_REG_NUM | 宏 | 4,Page 7 一次读 4 个寄存器 |
DG_PAGE_154_ALARM_REG_NUM | 宏 | 9,Page 154 一次读 9 个寄存器(8 个告警字 + 1 个被跳过的字) |
DG_QUERY_SPEED_VALUE | 宏 | 500,两次查询之间的最小间隔 500ms |
DG_COMM_LOST_VALUE | 宏 | 1000*15 = 15000ms,15 秒无有效响应判通讯丢失 |
Query_DG_E | 枚举 | 页轮询序号:PAGE_4_BASIC_E=1、PAGE_5_EXTEND_E=2、PAGE_7_ACCUMULATED_E=3、PAGE_154_ALARM_E=4、PAGE_N_MAX_E=5 |
GENSET_RUN_TABLE_T | 结构体 | 油机运行数据表(最后一个成员是 u16_alarm[8] 告警字数组) |
GENSET_CONTROL_CMD_TABLE_T | 结构体 | 时序控制表:u32_get_data_last_time、u32_dg_query_tick |
DIESEL_GENERATOR_TABLE_T | 结构体 | 汇总结构体:t_dg_run_data + t_dg_ctrl_cmd |
g_t_diesel_gen | extern 变量 | DIESEL_GENERATOR_TABLE_T 的全局唯一实例,定义在 diesel_generator.c:20 |
genset_comm_handle | 函数声明 | 油机采集入口,由 task_meter() 每轮调用 |
GENSET_RUN_TABLE_T 字段与量纲
| 字段 | 类型 | 量纲 | 来源页(注释标注) |
|---|---|---|---|
u16_dg_fuel_level | u16 | 1% | p4 |
u16_dg_engine_bat_volt | u16 | 0.1V | p4 |
u32_dg_fuel_consumption | u32 | 0.01 L/h | p5 |
u32_dg_volt_a/b/c | u32 | 0.1V | p4 |
u32_dg_cur_a/b/c | u32 | 0.1A | p4 |
s32_dg_actpower_a/b/c | s32 | 1W | p4(唯一有符号字段) |
u32_dg_positive_energy | u32 | 0.1kWh | p7 |
u16_dg_freq | u16 | 0.1Hz | p4 |
u32_dg_engine_run_time | u32 | 1s | p7 |
u16_alarm[8] | u16[8] | 位域 | p154 |
Query_DG_E 枚举成员
| 成员 | 值 | 说明 |
|---|---|---|
PAGE_4_BASIC_E | 1 | 基础仪表页(电气量、油位) |
PAGE_5_EXTEND_E | 2 | 扩展仪表页(油耗) |
PAGE_7_ACCUMULATED_E | 3 | 累积仪表页(运行时长、发电量) |
PAGE_154_ALARM_E | 4 | 告警页 |
PAGE_N_MAX_E | 5 | 非真实页,仅作"回到起点"的哨兵值;同时也是静态游标的初值,使首次调用立即从 Page 4 开始 |
3. 函数清单
本文件为纯头文件,不包含任何函数定义,仅在 :86 声明了 1 个由 diesel_generator.c 实现的导出函数:
| 函数名 | 作用域 | 说明 |
|---|---|---|
void genset_comm_handle(void) | 全局(外部实现) | 油机数据轮询入口:判断使能、按 500ms 节拍轮流查询 4 个寄存器页、15s 无响应时清零数据 |
4. 核心逻辑解析
本文件无运行逻辑。以下说明它约定的寄存器映射、时序参数与数据模型如何被实现文件使用。
4.1 寄存器映射约定(非标准 Modbus 用法)
四组宏都用 page*256 + offset 的形式编码一个 16 位的 Modbus 寄存器号:
寄存器号 = (页号 << 8) | 页内寄存器号
- 这是油机控制器厂商自定义的"分页寄存器"约定,而非标准 Modbus"线圈/输入/保持寄存器各区各 10000 号段"的约定。在标准 0x03 功能码下,主机实际发出的就是该 16 位值(例如 Page 5 A10 发的是
0x050A)。 - 因此
0x0400、0x050A、0x0706、0x9A00都要原样填入请求帧的起始地址域(大端),响应数据再按页内寄存器序号(A0、A1、…)确定字节偏移。 DG_PAGE_154_ALARM_REG_ADDR的页号 154(0x9A)已超出常规的 0x0000–0x00FF 页范围,属于厂商扩展页。
4.2 时序参数
| 参数 | 值 | 作用 |
|---|---|---|
DG_QUERY_SPEED_VALUE | 500ms | 相邻两次查询(不同页)的最小间隔 |
DG_COMM_LOST_VALUE | 15000ms | 无任何有效响应即判丢失;等于 30 个查询周期(4 页轮换时约 7.5 个完整循环) |
由于四页轮询 + 500ms 节拍,实现文件中一个完整数据刷新周期约 2 秒;15 秒门限相当于连续约 7 轮无响应才清零,对偶发丢帧有较好容忍度。
4.3 数据模型(三层结构体)
DIESEL_GENERATOR_TABLE_T g_t_diesel_gen
├── GENSET_RUN_TABLE_T t_dg_run_data ← 上报给云端的全部量测值
└── GENSET_CONTROL_CMD_TABLE_T t_dg_ctrl_cmd ← 纯内部时序状态,不上报
- 层次清楚:把"量测数据"与"内部时序"分开,
net/ems.c只读t_dg_run_data,t_dg_ctrl_cmd完全由diesel_generator.c自用。 - 两个子结构体都没有全局实例,只有外层
g_t_diesel_gen一个全局,因此外部无法单独取时序字段而绕过完整性约束。
4.4 与 uCOS-II 的配合
头文件不涉及任务、信号量或消息邮箱。约定为单写单读的共享全局数据:
- 写方:
task_meter()(midware/meter/meter.c:5876调genset_comm_handle())。 - 读方:网络发送任务(
net/ems.c组装STATUS_SEND_GENSET_DATA)。 - 无任何互斥保护。32 位字段(
u32_dg_volt_a等)在 32 位 ARM 上单次访问是原子的,但多字段之间的一致性没有保证——上报时可能拿到"上一次查询的电压 + 这一次查询的电流"。实际影响小(量测上报允许跨周期),但属未定义行为。
4.5 通信协议帧格式
头文件不定义帧格式。帧格式全部在 diesel_generator.c 中以硬编码下标实现:请求 8 字节(地址 + 0x03 + 起始寄存器大端 + 数量大端 + CRC16/Modbus 小端),响应为标准 0x03 响应(地址 + 功能码 + 字节数 + 寄存器数据大端 + CRC)。头文件只提供了寄存器地址与数量这两类组帧参数。
4.6 未防御的取值点
DG_PAGE_154_ALARM_REG_NUM 定义为 9,而 GENSET_RUN_TABLE_T.u16_alarm[8] 长度为 8——实现文件正是靠"响应有 9 个寄存器、只取后 8 个"来对应的(跳过第一个寄存器)。这个 9 vs 8 的差值在头文件里没有任何注释说明,仅靠 diesel_generator.c 的偏移量隐含表达,是本文件最容易误读的地方。
5. 对外接口
导出(供外部调用)
| 名称 | 说明 |
|---|---|
extern DIESEL_GENERATOR_TABLE_T g_t_diesel_gen | 全局油机数据表,net/ems.c:1585-1617 读取上报 |
void genset_comm_handle(void) | 油机采集入口,midware/meter/meter.c:5876 调用 |
GENSET_ADDR、DG_PAGE_*_REG_ADDR、DG_PAGE_*_REG_NUM | 寄存器映射宏(当前仅实现文件使用,未见其他文件引用) |
DG_QUERY_SPEED_VALUE、DG_COMM_LOST_VALUE | 时序宏(当前仅实现文件使用) |
Query_DG_E、GENSET_RUN_TABLE_T、GENSET_CONTROL_CMD_TABLE_T、DIESEL_GENERATOR_TABLE_T | 类型定义 |
使用的外部符号(本文件自身依赖)
| 名称 | 来源 |
|---|---|
u16 / u32 / s32 | chip.h(:16 include);随 includes.h 或 MDK 器件头提供基本类型 |
TRUE | 仅在 diesel_generator.c 使用,本头文件未直接使用 |
6. 依赖关系
- 依赖:仅
#include "chip.h"(:16)。注意这是本目录下唯一用chip.h而非<includes.h>的电表相关头文件;实际能编译通过依赖于diesel_generator.c:14紧接着又 include 了includes.h,以及包含顺序上chip.h已能提供u16/u32/s32定义。 - 被依赖:
midware/meter/diesel_generator.c(唯一实现者)midware/meter/meter.c:5876(调genset_comm_handle();meter.c通过meter.h间接可见)net/ems.c:1585-1617(读g_t_diesel_gen)hmi/key.c、midware/interface/modbus/modbus.c、net/server.c仅涉及u8_genset_enable_flag(该宏/字段属于meter.h,不是本文件)
7. 备注与风险点
DG_PAGE_154_ALARM_REG_NUM = 9与u16_alarm[8]的数量差没有注释——实际语义是"Page 154 的 A0 不是告警字",但这层映射只存在于实现文件的字节偏移里,头文件读者无法从9与8的差异推断出究竟哪个寄存器被丢弃。- 最后一次成员
u16_alarm[8]是位域而不是位数组——云端上报时把 8 个 16bit 字逐个展开为Alarm1..Alarm8(net/ems.c:1611-1614),语义是"每字 16 个告警位",但结构体里没有位域定义,位与告警项的对应关系完全依赖上游解析,EMS 侧不做展开。 s32_dg_actpower_a/b/c是全表唯一有符号字段——其余同名"测量值"都用u32。同时u32_dg_volt_*/u32_dg_cur_*在报文中被当作无符号传给fmt_fixed(),而s32_dg_actpower_*用%d直接格式化,类型约定在net/ems.c消费端也必须对齐,容易出错。chip.h与工程统一公共头的混用——本目录其他头文件(如bb_update.h、meter_upgrade.h)都用#include <includes.h>,meter.h亦同。本文件单独用chip.h属于风格不一致;一旦包含顺序变化(例如某 .c 先 include 本头文件再 include 别的),u16/u32的可用性依赖chip.h是否已定义这些别名。- 无统一量纲辅助宏——
0.1V、0.01L/h、0.1kWh等缩放因子只写在行尾注释里,net/ems.c分别用fmt_fixed(x, 10)/fmt_fixed(x, 100)硬编码对应缩放,两边靠人工对齐,无编译期约束。 GENSET_ADDR硬编码 99——油机从站地址不可配置。若现场油机地址不是 0x63,整条采集链路静默失效(只表现为 15s 后数据清零,无显式配置项)。对比meter.h中电网/PV 电表地址都有成组宏,此处缺少可配置性。DG_PAGE_4_A0_33_REG_ADDR等宏名把"页内寄存器号"写进名字,但表达式为page*256——Page 5 的宏名带了+10却把常量写在表达式里(5*256+10),命名与实现一致,可读性尚可;但DG_PAGE_4_A0_33_REG_ADDR的4*256与名字中的 "A0" 对应关系需要读者自行体会。- 时序宏未与底层总线超时联动——
DG_QUERY_SPEED_VALUE(500ms) 远小于usart1_send_data()的超时(1000ms,见meter.c:57)。若串口发送真的阻塞满 1 秒,则轮询节拍会被拉长,但代码没有做补偿;这是一个隐含的时序耦合,本文件未记录。 extern变量无volatile、无访问函数收口——g_t_diesel_gen直接暴露给net/层,字段级约束(如告警0x1111表示无效)无法在头文件层面表达,只能靠约定。