/* * 模块名称:UI Page DC (直流量内容页) * 模块功能:直流量叶子节点(node 4)内容页——2 行动态列表:温度(STM32 片内 ADC 透传码值, * 未标定)+ 直流通道(V0.1 板上无直流采样通道,值列如实显示"未配置");数据取自 * ui_data 实时帧(App 层装配,本文件零 App include);向框架 ui_content_page 提供 * 页面描述符(零 LVGL 对象) * 为什么只有 2 行:参考图 21 的"3 行直流读数"在本板无采样源(ADC_SEM 只有 8 路电气 + 温度, * 104 点表 0x401E/0x401F 亦注明"FTU 无")——照抄就是三行假数(取舍见 * docs/UI设计/页面扩充详细方案.md §3.1.2 方案①,菜单语义与点表保持一致) * 空值口径:温度通道无效时显 "--";码值一律不挂单位(挂上"℃"就是替用户完成了没做的标定) * 适用平台:STM32F407ZGTx / PC 模拟器(两端共用) * 作者:王建锋 * 创建日期:2026-09-09 * 修改记录: * 2026-09-09 王建锋 创建:自 ui_content_page 单体拆出(数据原样迁移,零改动) * v2.0 2026-10-25 王建锋 道E task-15 回炉:3 行 Flash 假数(ZL01/ZL02/Pa1)→ 2 行快照 * 真值;温度取 yc[ADC_SEM_TEMP] 并显式标注是码值 */ /* 头文件包含区 */ #include #include "ui_page_dc.h" #include "ui_data.h" #include "ui_tokens.h" #include "ui_w_editor.h" /* 私有宏定义区 */ /* 温度通道在快照 yc[] 里的语义下标 = adc_semantic_t 的 TEMP(最后一项,随通道表漂移; * 由 test/host/ui_data 的"下标空间与 App/algo/adc_input.h 逐行一致"断言兜住) */ #define DC_YC_TEMP 8u #define DC_ROW_N 2u #define DC_INVALID "--" /* 温度值列前缀:一个"码"字把"这是 12 位原始码、不是温度"写进屏上而不是注释里 */ #define DC_CODE_PREFIX "码" /* 静态变量定义区 */ /* 帧缓存(按发布序号门控,同交流量页) */ static ui_data_rt_t s_rt; static uint32_t s_seq; /* 函数定义区 */ /* * 函数功能:把常量串安全搬进显示缓冲(替代 strcpy,规范 7.5) * 入口参数:a_dst - 目标缓冲(框架 UI_BUF_STRLEN) char * * a_lit - 源字面量(长度由宏用 sizeof 算好) const char * * a_len - 需拷贝字节数(不含 NUL) uint32_t * 返回值:无 * 限定条件:a_dst/a_lit 非 NULL;a_len 超缓冲按缓冲截断 * 函数说明:代码规范 7.5 禁 strcpy;长度来自调用点 sizeof,写串与算长同一处 */ static void dc_put(char *a_dst, const char *a_lit, uint32_t a_len) { if (a_len > ((uint32_t)UI_BUF_STRLEN - 1u)) { a_len = (uint32_t)UI_BUF_STRLEN - 1u; } (void)memcpy(a_dst, a_lit, a_len); a_dst[a_len] = (char)0; } #define DC_PUT(a_dst, a_lit) dc_put((a_dst), (a_lit), (uint32_t)(sizeof(a_lit) - 1u)) /* * 函数功能:取用最新实时帧(只在发布序号变化时整帧拷) * 入口参数:无 * 返回值:1 - 有可用帧;0 - 首帧未到或本帧无效 uint8_t * 限定条件:uiTask 绘制上下文 */ static uint8_t dc_frame_ready(void) { uint32_t now = ui_data_rt_seq(); if (now != s_seq) { s_seq = now; if (ui_data_rt(&s_rt) != 0) { (void)memset(&s_rt, 0, sizeof(s_rt)); return 0u; } } return (s_rt.valid != 0u) ? 1u : 0u; } /* * 函数功能:开页复位缓存(强制重取最新帧) * 入口参数:无 * 返回值:无 */ static void dc_init(void) { s_seq = 0u; (void)memset(&s_rt, 0, sizeof(s_rt)); } /* * 函数功能:逐行取数(第 1 行温度码值、第 2 行直流通道未配置) * 入口参数:a_row - 全局行下标 0..1 uint16_t * a_name - 名输出缓冲(框架 UI_BUF_STRLEN) char * * a_value - 值输出缓冲 char * * 返回值:无 * 限定条件:uiTask 绘制上下文 * 函数说明:温度行的值列形如"码2048"——"码"字是把"这是 12 位原始码、不是温度"写进 * 屏上而不是写进注释;快照该路带 UI_DATA_Q_RAW(写侧因该通道不参与线性标定而置位), * 这里同时按品质位判无效,两处任一说话都足以显 "--" */ static void dc_refresh(uint16_t a_row, char *a_name, char *a_value) { if (a_row == 0u) { const ui_data_yc_t *p; /* 温度通道(只有本分支用得到,cppcheck 也这么判) */ DC_PUT(a_name, "温度"); if ((dc_frame_ready() == 0u) || (DC_YC_TEMP >= UI_DATA_YC_N)) { DC_PUT(a_value, DC_INVALID); return; } p = &s_rt.yc[DC_YC_TEMP]; if ((p->qds & (uint8_t)(UI_DATA_Q_IV | UI_DATA_Q_SB | UI_DATA_Q_BL)) != 0u) { DC_PUT(a_value, DC_INVALID); } else { ui_w_editor_fmt_scaled((p->val > 0.0f) ? (int32_t)(p->val + 0.5f) : 0, 0u, a_value, (uint32_t)UI_BUF_STRLEN); /* 前缀"码":单位由品质位说话,不靠读的人猜(长度取 sizeof,改字不脱节) */ (void)memmove(a_value + (sizeof(DC_CODE_PREFIX) - 1u), a_value, strlen(a_value) + 1u); (void)memcpy(a_value, DC_CODE_PREFIX, sizeof(DC_CODE_PREFIX) - 1u); } return; } DC_PUT(a_name, "直流通道"); DC_PUT(a_value, "未配置"); } /* * 页面描述符(外部链接:生成物 ui_page_registry.c 按菜单树 #page=dc 绑定引用): * 2 行单页列表页;band_h 必须 >0(选中行黑字需白带,同交流量页约定) */ const content_page_def_t ui_page_dc_desc = { .id = "dc", .title = "直流量", .selectable = 1u, .top_y = UI_LIST_TOP, .pitch = UI_ROW_PITCH, .band_h = UI_ROW_BAND_H, .text_dy = 0, .left_x = UI_LIST_LEFT_X, .right_x = UI_LIST_RIGHT_X, .rows_per_page = UI_LIST_ROWS, .row_count = DC_ROW_N, .rows = NULL, .init_cb = dc_init, .refresh = dc_refresh, };