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
的变化,代码逻辑清晰,易于调试和扩展