obj/ 目录是车载仪表盘的“大脑”,它负责处理所有非 UI 的业务逻辑。这部分代码采用了 “数据模型驱动 UI” 的设计思想,将车辆的实时状态(数据模型)与界面的视觉表现完全分离,实现了高度的解耦和可维护性。
其核心职责可以分为两大部分:
- 输入与状态更新
callback.c:接收外部指令(如控制台输入),并更新内部的车辆状态数据模型。 - 状态渲染
control.c:根据数据模型的当前值,周期性地更新 UI 界面,包括指针、数字、报警灯等。
文件功能详解
head.h (公共接口与数据模型)
这个头文件是 obj 模块的“公共 API”,它定义了整个模块的数据核心和对外暴露的接口。
VehicleState结构体: 这是项目中最核心的数据结构,定义了车辆的所有状态,如速度、转速、水温、油量、胎压和里程等。它是整个仪表盘状态的唯一真实来源 (Single Source of Truth)。g_vehicle_state全局变量:VehicleState结构体的一个全局实例,在control.c中定义,并在head.h中通过extern声明,使其可以在整个项目中被访问。- 常量定义: 定义了各种报警阈值,如水温报警 (
WATER_TEMP_WARN)、低油量 (FUEL_LOW) 等,方便集中管理和调整。 - 函数原型: 声明了需要被
main.c调用的主要函数,如handle_console_input(),update_ui_from_state(), 以及各种初始化函数。
control.c (状态-UI 渲染器)
该文件负责将 g_vehicle_state 结构体中的数据“渲染”到 UI 界面上,是连接数据和视觉的桥梁。
update_ui_from_state(lv_timer_t* timer): 这是渲染循环的核心。这个函数使用lvgl 官方建议使用的lv_timer的回调函数,由main.c周期性调用来实现类似多线程的效果。
将以下函数注册到一个定时器中,每隔 50 毫秒执行一次,确保 UI 界面与仪表盘结构体保持同步
它调用的函数如下: 1. 更新指针: 调用update_all_pointers_from_state()。此函数内部使用map_value_to_angle()将速度、转速等物理值映射为指针的旋转角度,然后通过animate_img_angle_to()平滑地将指针以动画形式转到目标角度。 2. 更新胎压: 调用update_tire_pressure_display(),更新四个轮胎的压力读数。如果压力异常,它还会将对应标签的颜色变为红色。 3. 更新里程: 调用update_mileage_labels(),根据当前车速和定时器周期计算并累加行驶里程。 4. 更新报警: 调用check_and_update_warnings(),检查水温、油量等是否达到报警阈值,并相应地显示或隐藏报警图标。
callback.c (输入处理与事件回调)
该文件负责处理所有的外部输入和异步事件,并根据这些输入来修改 g_vehicle_state 结构体。
控制台输入处理:
handle_console_input(): 使用非阻塞的select()系统调用来检查标准输入流。这使得程序可以在不暂停 UI 渲染主循环的情况下,实时接收用户在终端的输入。process_command(): 这是指令解析的核心。它使用sscanf解析用户输入的字符串,支持两种命令:- 开关类命令 (如
左转,远光): 直接切换对应状态。 - 设值类命令 (如
速度 120,胎压 左前 240): 调用parse_and_set_state_value()将字符串数值转换为整数,并更新g_vehicle_state中对应的字段。
- 开关类命令 (如
指示灯控制:
- 提供了多种控制灯光的方法,如通过
LV_STATE_CHECKED(远光灯、安全带)、LV_OBJ_FLAG_HIDDEN(水温报警) 或直接修改透明度 (转向灯闪烁)。 - 转向灯的闪烁效果是通过
lv_timer实现的。control_manual_flashing()函数负责创建和删除这个定时器,从而启动或停止闪烁。
- 提供了多种控制灯光的方法,如通过
初始化与自检:
init_all_lights_test(): 实现开机自检功能,在启动时点亮所有指示灯 2 秒,然后通过一个一次性的lv_timer自动熄灭。init_time_display(): 创建一个每秒触发的定时器,用于更新屏幕上的时间显示。
核心数据流
本项目的逻辑遵循一个清晰的单向数据流,极大地简化了状态管理:
- 输入 (Input): 用户在控制台输入指令,例如
速度 80。 - 处理 (Process):
handle_console_input()捕获输入,process_command()解析指令。 - 更新模型 (Update Model):
process_command()修改全局数据模型g_vehicle_state.speed的值为80。 - 渲染 (Render): LVGL 的主循环定时器触发
update_ui_from_state()。 - 同步 UI (Sync UI):
update_ui_from_state()函数读取到g_vehicle_state.speed的新值80,计算出对应的指针角度,并调用 LVGL 的动画函数,使速度指针平滑地指向 80km/h 的位置。
这个流程确保了 UI 的任何变化都源于 g_vehicle_state 的变化,代码逻辑清晰,易于调试和扩展