obj/ 目录是车载仪表盘的“大脑”,它负责处理所有非 UI 的业务逻辑。这部分代码采用了 “数据模型驱动 UI” 的设计思想,将车辆的实时状态(数据模型)与界面的视觉表现完全分离,实现了高度的解耦和可维护性。

其核心职责可以分为两大部分:

  1. 输入与状态更新 callback.c:接收外部指令(如控制台输入),并更新内部的车辆状态数据模型。
  2. 状态渲染 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(): 创建一个每秒触发的定时器,用于更新屏幕上的时间显示。

核心数据流

本项目的逻辑遵循一个清晰的单向数据流,极大地简化了状态管理:

  1. 输入 (Input): 用户在控制台输入指令,例如 速度 80
  2. 处理 (Process): handle_console_input() 捕获输入,process_command() 解析指令。
  3. 更新模型 (Update Model): process_command() 修改全局数据模型 g_vehicle_state.speed 的值为 80
  4. 渲染 (Render): LVGL 的主循环定时器触发 update_ui_from_state()
  5. 同步 UI (Sync UI): update_ui_from_state() 函数读取到 g_vehicle_state.speed 的新值 80,计算出对应的指针角度,并调用 LVGL 的动画函数,使速度指针平滑地指向 80km/h 的位置。

这个流程确保了 UI 的任何变化都源于 g_vehicle_state 的变化,代码逻辑清晰,易于调试和扩展