《lvgl基础学习 —— 分层架构》
1.为什么一定要分层
如果这样写代码:
static void slider_cb(lv_event_t *e) { int val = lv_slider_get_value(slider); ioctl(fd, ISP_SET_EXPOSURE, val); // ❌ }
短期没问题,长期会变成:
-
UI 改 → 硬件逻辑跟着改
-
没法单元测试
-
没法做 PC 仿真
-
换平台(RK → Ambarella)几乎重写
这就是“UI 直接操硬件”的灾难
2.正确的三层架构
┌──────────────┐ │ UI │ ← LVGL(button / slider / switch) │ 只关心交互 │ └──────▲───────┘ │ 消息 / 调用 ┌──────┴───────┐ │ Service │ ← 业务逻辑(状态 / 策略 / 校验) │ 不碰 LVGL │ └──────▲───────┘ │ 抽象接口 ┌──────┴───────┐ │ Driver │ ← ioctl / sysfs / i2c / spi │ 不知道 UI │ └──────────────┘
总之就是:
UI不知道硬件
Driver不知道UI
Service做中间人
3.每一层”只干什么,不干什么“
1️⃣ UI 层(LVGL)
✔ 可以做
-
创建控件
-
响应点击 / 拖动
-
显示状态
❌ 绝对不做
-
ioctl
-
open("/dev/xxx")
-
sleep
-
复杂逻辑
📌 UI = 纯交互层
2️⃣ Service 层(业务层,最重要)
✔ 可以做
-
参数合法性判断
-
状态保存
-
模式切换
-
异步处理
❌ 不做
-
直接操作 LVGL
-
直接画 UI
📌 Service = 大脑
3️⃣ Driver 层(驱动 / 设备访问)
✔ 只做
-
和设备打交道
-
提供最底层接口
int driver_set_exposure(int val);
❌ 不做
-
判断 UI 状态
-
知道按钮 / slider
📌 Driver = 手脚
4.数据流是怎么走的?
用户拖动 Slider 的完整链路:
用户拖 slider
↓
UI slider_cb()
↓
service_set_exposure(val)
↓
driver_set_exposure(val)
↓
硬件
反方向(硬件状态变化)
硬件变化
↓
driver_get_exposure()
↓
service_update_state()
↓
UI 刷新 label
demo:Slider 调节“亮度”,Label 显示当前值, UI 不知道硬件,Driver 不知道 LVGL
Driver 层(driver_brightness.c)
// driver_brightness.c #include <stdio.h> static int g_brightness = 50; int driver_set_brightness(int val) { if(val < 0 || val > 100) return -1; g_brightness = val; printf("[DRIVER] brightness = %d\n", g_brightness); return 0; } int driver_get_brightness(void) { return g_brightness; }
Service 层(service_brightness.c)
浙公网安备 33010602011771号