1. LVGL 与 MQTT 基础连接状态显示

LVGL 与 MQTT 基础连接状态显示 学习卡片

任务目标

创建一个LVGL图形界面,包含一个MQTT连接状态指示标签。界面启动时显示“DISCONNECTED”,当收到MQTT消息(例如发布到主题status的内容为connected)时,标签更新为“CONNECTED”并改变颜色。本案例聚焦于LVGL标签控件的基本使用与MQTT回调到UI更新的最小闭环。

环境依赖

需要LVGL v8.x库及MQTT客户端库(如paho.mqtt.c)。以下代码假设LVGL已初始化且显示器/触摸驱动已就绪,MQTT客户端已连接至Broker。UI更新需在LVGL的线程上下文中执行,因此MQTT回调中仅记录状态,通过lv_timer周期性检查并更新UI。

关键完整代码

#include "lvgl.h"
#include "MQTTClient.h"

// MQTT配置
#define BROKER_ADDR "tcp://broker.emqx.io:1883"
#define CLIENT_ID "lvgl_demo_client"
#define TOPIC_STATUS "demo/status"

// 全局状态
static volatile int mqtt_connected_flag = 0;  // 0=断开, 1=已连接
static lv_obj_t *status_label;

// MQTT消息到达回调(在MQTT线程中执行)
static void msg_arrived(void *context, char *topicName, int topicLen, 
                        MQTTClient_message *message) {
    if (strcmp(topicName, TOPIC_STATUS) == 0) {
        if (strncmp(message->payload, "connected", 9) == 0) {
            mqtt_connected_flag = 1;
        } else {
            mqtt_connected_flag = 0;
        }
    }
    MQTTClient_freeMessage(&message);
    MQTTClient_free(topicName);
}

// LVGL定时器:周期性检查MQTT状态并更新UI
static void ui_update_timer_cb(lv_timer_t *timer) {
    if (mqtt_connected_flag) {
        lv_label_set_text(status_label, "CONNECTED");
        lv_obj_set_style_text_color(status_label, lv_color_hex(0x00FF00), 0);
    } else {
        lv_label_set_text(status_label, "DISCONNECTED");
        lv_obj_set_style_text_color(status_label, lv_color_hex(0xFF0000), 0);
    }
}

// 创建UI界面
static void ui_create(void) {
    status_label = lv_label_create(lv_scr_act());
    lv_obj_center(status_label);
    lv_label_set_text(status_label, "DISCONNECTED");
    lv_obj_set_style_text_color(status_label, lv_color_hex(0xFF0000), 0);
    lv_obj_set_style_text_font(status_label, &lv_font_montserrat_24, 0);
}

// MQTT初始化与连接
static void mqtt_init(void) {
    MQTTClient client;
    MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
    MQTTClient_willOptions will_opts = MQTTClient_willOptions_initializer;
    int rc;

    MQTTClient_create(&client, BROKER_ADDR, CLIENT_ID, 
                      MQTTCLIENT_PERSISTENCE_NONE, NULL);
    conn_opts.keepAliveInterval = 20;
    conn_opts.cleansession = 1;

    MQTTClient_setCallbacks(client, NULL, NULL, msg_arrived, NULL);
    if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) {
        printf("MQTT连接失败,错误码: %d\n", rc);
        return;
    }
    MQTTClient_subscribe(client, TOPIC_STATUS, 1);
}

// 主函数
int main(void) {
    lv_init();
    // ... 显示器/触摸初始化代码 ...

    ui_create();
    mqtt_init();

    // 创建LVGL定时器,每200ms检查一次状态
    lv_timer_create(ui_update_timer_cb, 200, NULL);

    while (1) {
        lv_timer_handler();
        lv_delay_ms(5);
    }
}

运行与验证

  1. 编译:链接LVGL、MQTT库及必要的系统库,例如:
    gcc -o mqtt_ui_demo main.c -llvgl -lpaho-mqtt3c -lm -lpthread
  2. 运行:执行./mqtt_ui_demo,屏幕中央应显示红色“DISCONNECTED”。
  3. 验证步骤:
    • 使用MQTT客户端(如MQTTX)连接同一Broker,向主题demo/status发布消息connected。
    • 观察屏幕标签应在200ms内变为绿色“CONNECTED”。
    • 发布任意其他内容(如disconnected),标签应恢复为红色“DISCONNECTED”。
  4. 通过条件:标签颜色与文本能随MQTT消息正确切换,且程序无崩溃或内存泄漏。

关键说明

  • MQTT回调运行在MQTT客户端线程,不能直接调用LVGL API,因此使用volatile标志位传递状态,由LVGL定时器轮询更新。
  • 若需实时性更高的响应,可使用lv_async_call,但定时器方案更简单且足以满足状态指示场景。
  • 本案例仅演示状态文本更新,实际项目中可扩展为图标、动画等更丰富的视觉反馈。