《lvgl基础学习 —— 消息机制》

1.为什么还要“消息机制”?直接调 Service 不行吗?

  如果直接用service代码可能是这样:

static void slider_cb(lv_event_t *e)
{
    int val = lv_slider_get_value(slider);
    service_set_brightness(val);   // 直接调用
}

在 Demo 阶段 OK,但在真实产品会出问题:

  • Service 里可能:

    • 访问硬件(慢)

    • 等待锁

    • 等待 I/O

  • UI 回调 被阻塞

  • 表现为:

    • UI 卡顿

    • 滑动不顺

    • 点击无响应

  UI 回调必须“非常快”

 

2.消息机制能解决什么问题?

一句话:

UI 只“发消息”,
Service 在自己的上下文里“慢慢处理”。

对比以下两种模型:❌ 同步调用模型

UI 回调
 └── service_set_xxx()
       └── driver_xxx()
            └── 阻塞

 

✅ 消息驱动模型(推荐)

UI 回调
 └── post_message(MSG_SET_XXX)
        ↓
   Service 线程 / 轮询
        ↓
   driver_xxx()

  这样UI就肯定不会卡顿。

 

3.最小可行的”消息模型“

我们需要 3 个东西:

  1. 消息类型

  2. 消息队列

  3. 消息处理循环

1.定义消息类型(enum)

typedef enum {
    MSG_SET_BRIGHTNESS,
    MSG_WIFI_ENABLE,
    MSG_MOTOR_MOVE,
} msg_type_t;

2.定义消息结构体

typedef struct {
    msg_type_t type;
    int value;
} app_msg_t;

3.UI ---> Service:只发消息

app_post_msg(MSG_SET_BRIGHTNESS, val);

4.service集中处理消息

switch(msg.type) {
case MSG_SET_BRIGHTNESS:
    driver_set_brightness(msg.value);
    break;
}

 

4.两种常见的实现方式

方案 A(强烈推荐新手)

👉 环形队列 + 轮询(无多线程)

  • 简单

  • 稳定

  • 适合你现在的 PC / 嵌入式 Linux 学习阶段


方案 B(进阶)

👉 线程 + condition / message queue

  • 更复杂

  • 更强

  • 后期再学

👉 我们现在先用方案 A

 

5.完整”消息队列“最小demo

场景

📌 Slider 改亮度
📌 UI 不直接调 Service
📌 Service 通过消息慢慢处理

1.消息定义(app_msg.h)

#ifndef APP_MSG_H
#define APP_MSG_H

typedef enum {
    MSG_SET_BRIGHTNESS,
} msg_type_t;

typedef struct {
    msg_type_t type;
    int value;
} app_msg_t;

void app_msg_init(void);
int app_msg_post(app_msg_t *msg);
int app_msg_fetch(app_msg_t *msg);

#endif

2.消息队列实现(app_msg.c)

#include "app_msg.h"

#define MSG_QUEUE_SIZE 16

static app_msg_t msg_queue[MSG_QUEUE_SIZE];
static int head = 0;
static int tail = 0;

void app_msg_init(void)
{
    head = tail = 0;
}

int app_msg_post(app_msg_t *msg)
{
    int next = (tail + 1) % MSG_QUEUE_SIZE;
    if(next == head) {
        /* queue full */
        return -1;
    }

    msg_queue[tail] = *msg;
    tail = next;
    return 0;
}

int app_msg_fetch(app_msg_t *msg)
{
    if(head == tail) {
        /* queue empty */
        return -1;
    }

    *msg = msg_queue[head];
    head = (head + 1) % MSG_QUEUE_SIZE;
    return 0;
}

3.Service层(service_task.c)

#include "app_msg.h"
#include "driver_brightness.h"

void service_task_run(void)
{
    app_msg_t msg;

    while(app_msg_fetch(&msg) == 0) {
        switch(msg.type) {
        case MSG_SET_BRIGHTNESS:
            driver_set_brightness(msg.value);
            break;
        default:
            break;
        }
    }
}

4.driver层(driver.c)

#include <stdio.h>

int driver_set_brightness(int val)
{
    printf("[DRIVER] brightness = %d\n", val);
    return 0;
}

5.UI层(ui.c)

#include "lvgl.h"
#include "app_msg.h"

static lv_obj_t *label;

static void slider_cb(lv_event_t *e)
{
    lv_obj_t *slider = lv_event_get_target(e);
    int val = lv_slider_get_value(slider);

    app_msg_t msg = {
        .type = MSG_SET_BRIGHTNESS,
        .value = val,
    };
    app_msg_post(&msg);

    lv_label_set_text_fmt(label, "Brightness: %d", val);
}

void ui_brightness_init(void)
{
    label = lv_label_create(lv_scr_act());
    lv_label_set_text(label, "Brightness: 50");
    lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 20);

    lv_obj_t *slider = lv_slider_create(lv_scr_act());
    lv_obj_set_width(slider, 260);
    lv_obj_center(slider);

    lv_slider_set_range(slider, 0, 100);
    lv_slider_set_value(slider, 50, LV_ANIM_OFF);

    lv_obj_add_event_cb(slider, slider_cb,
                        LV_EVENT_VALUE_CHANGED, NULL);
}

 

main.c

int main(void)
{
    lv_init();
    hal_init();

    app_msg_init();
    ui_brightness_init();

    while(1) {
        lv_timer_handler();
        service_task_run();   // 👈 关键
        usleep(5000);
    }
}

  在实际工程项目中,只要把service_task_run放在一个线程中就好了。

常见坑(一定要避)

❌ UI 回调里 sleep
❌ 消息结构体用指针(生命周期错)
❌ 队列不判满
❌ Service 里调用 LVGL API
❌ 多线程同时操作 LVGL

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2025-12-23 16:43  一个不知道干嘛的小萌新  阅读(3)  评论(0)    收藏  举报