发帖
3 0 1

基于Ai-WB2实现使用MQTT完成订阅、发布及点灯功能

云烟
中级会员

6

主题

4

回帖

428

积分

中级会员

积分
428
Ai-WB2系列 898 3 2026-2-3 18:01:01
[i=s] 本帖最后由 云烟 于 2026-2-9 11:08 编辑 [/i]

基于Ai-WB2实现使用MQTT完成订阅、发布及点灯功能


前言

你将学到什么

通过本教程,你将掌握以下核心技能:

  • ✅ 理解 MQTT 协议的核心概念、架构设计及 QoS 质量等级
  • ✅ 在 Ai-WB2 开发板上实现 MQTT 客户端的连接、订阅与发布
  • ✅ 使用 JSON 格式消息控制 RGB LED 的亮灭
  • ✅ 使用 MQTTX 客户端工具进行功能测试与调试

MQTT 协议基础知识

MQTT 是一种基于 发布/订阅(Publish/Subscribe) 模式的轻量级消息传输协议,由 IBM 于 1999 年推出,2014 年成为 OASIS 标准。MQTT 专为资源受限的设备和低带宽、高延迟或不稳定的网络环境设计,是物联网(IoT)领域最流行的通信协议之一。

1️⃣ 核心架构与角色

MQTT 采用 发布/订阅 模式,实现了消息生产者和消费者的解耦:

角色 说明
Publisher(发布者) 消息的发出者,负责将消息发送到指定主题
Subscriber(订阅者) 消息的接收者,订阅感兴趣的主题以接收消息
Broker(代理服务器) 消息中转站,负责接收发布者的消息并转发给订阅者
Topic(主题) 消息的分类标识,使用 / 分隔层级,如 home/bedroom/light

工作流程:发布者将消息发送到 Broker 的某个 Topic → Broker 根据订阅关系将消息转发给所有订阅该 Topic 的订阅者。

2️⃣ MQTT 协议特点

  • 轻量级:协议头最小仅 2 字节,适合资源受限的嵌入式设备
  • 低功耗:保持连接时心跳包开销极小,适合电池供电设备
  • 可靠性:支持三种 QoS(服务质量)等级,满足不同可靠性需求
  • 实时性:支持持久会话,设备断线重连后可接收离线消息
  • 灵活性:主题支持通配符订阅(+ 单层,# 多层)

3️⃣ QoS 消息质量等级

MQTT 定义了三种服务质量等级,用于控制消息传递的可靠性:

QoS 等级 名称 特点 适用场景
QoS 0 最多一次(At most once) 消息只发送一次,不确认、不重试,可能丢失 传感器数据上报、心跳包等允许丢失的数据
QoS 1 至少一次(At least once) 确保消息到达,但可能重复送达 设备状态更新、关键指令等需要确保到达的场景
QoS 2 恰好一次(Exactly once) 四次握手确保消息只到达一次,不丢失不重复 金融交易、支付指令等绝对不允许重复的场景

一、准备工作

📦 硬件与软件清单

分类 项目 数量/版本 说明
硬件 Ai-WB2-12F 开发板 1 核心控制 MCU
Type-C 数据线 1 烧录程序与调试
软件 安信可 Ai-WB2 开源仓库 最新版 Gitee
MQTTX 客户端 最新版 官网下载

⏱️ 预计完成时间

  • 代码配置与编译:约 15 分钟
  • 烧录与调试:约 10 分钟
  • 功能测试:约 10 分钟
  • 总计:约 35 分钟

📋 前置要求

  • 熟悉 GPIO 控制和 FreeRTOS
  • 对 Linux、make、Git 指令有一定的了解
  • 对回调函数、JSON、MQTT 协议有一定了解

二、克隆完整的 Ai-WB2 开源仓库

1️⃣ 克隆仓库

以下指令可直接一键克隆完整 Git 仓库和子模块,也可点击链接跳转直接下载 ZIP 包:

# Gitee
git clone --recursive https://gitee.com/Ai-Thinker-Open/Ai-Thinker-WB2.git

🔴 提示:该仓库包含子模块内容较大(约几百兆),需要耐心等待克隆完成。

2️⃣ 检查仓库完整性

克隆下来的完整文件如图,重点关注图中红框部分的子模块包含内容是否完整无缺失:
01.png

图:Ai-WB2 项目仓库目录结构,红框标注的 toolchain/riscv 子模块应包含 Darwin、Linux、MSYS 三个文件夹且文件夹内应包含有内容。


三、点灯代码配置与编译

1️⃣ 创建 MQTT 测试项目

打开刚克隆的仓库,在 applications → protocols 目录下找到 mqtt 文件夹,将其复制粘贴一份,并重命名为 mqtt_test

02.png

图:将 mqtt 文件夹复制并重命名为 mqtt_test,红色高亮显示选中位置

2️⃣ 配置 WiFi 路由器信息

mqtt_test/tcp 文件夹下找到 main 文件,修改两个宏定义:ROUTER_SSIDROUTER_PWD,填入你的 WiFi 名称和密码:

// 路由器配置信息(需要用户根据实际情况修改)
#define ROUTER_SSID "WIFI"     // 填入你的 WiFi 名称
#define ROUTER_PWD "1234567890" // 填入你的 WiFi 密码

3️⃣ 添加 RGB LED 控制代码

📌 关键配置点:引入头文件与定义引脚

#include "blog.h" 以下添加以下头文件和宏定义:

#include "cJSON.h"    // JSON 解析库
#include <bl_gpio.h>  // GPIO 控制库

// RGB LED 引脚定义(根据实际硬件连接修改)
#define GPIO_LED_RED    14
#define GPIO_LED_GREEN  17
#define GPIO_LED_BLUE   3

📌 关键配置点:LED 状态枚举与任务实现

static void log_error_if_nonzero(const char *message, int error_code) 函数后面添加以下代码:

/* ================= LED 指示灯业务逻辑 ================= */
typedef enum {
    LED_OFF = 0,      // 闲置(全灭)
    LED_BLUE,         // 蓝灯常亮
    LED_GREEN,        // 绿灯常亮
    LED_RED           // 红灯常亮
} led_indicator_state_t;

static volatile led_indicator_state_t g_led_state = LED_OFF;

// 设置 RGB LED 的亮灭状态
static void led_set_level(uint8_t r, uint8_t g, uint8_t b) {
    bl_gpio_output_set(GPIO_LED_RED, r);
    bl_gpio_output_set(GPIO_LED_GREEN, g);
    bl_gpio_output_set(GPIO_LED_BLUE, b);
}

// LED 指示灯任务(FreeRTOS 任务)
static void led_indicator_task(void *pvParameters) {
    // 初始化 GPIO 为输出模式
    bl_gpio_enable_output(GPIO_LED_RED, 0, 0);
    bl_gpio_enable_output(GPIO_LED_GREEN, 0, 0);
    bl_gpio_enable_output(GPIO_LED_BLUE, 0, 0);
    led_set_level(0, 0, 0); // 初始状态:全灭

    while (1) {
        switch (g_led_state) {
            case LED_BLUE: // 蓝灯常亮
                led_set_level(0, 0, 1);
                vTaskDelay(pdMS_TO_TICKS(500)); 
                break;
            case LED_GREEN: // 绿灯常亮
                led_set_level(0, 1, 0);
                vTaskDelay(pdMS_TO_TICKS(500)); 
                break;
            case LED_RED:   // 红灯常亮
                led_set_level(1, 0, 0);
                vTaskDelay(pdMS_TO_TICKS(500));
                break;
            case LED_OFF:   // 全灭
            default:
                led_set_level(0, 0, 0);
                vTaskDelay(pdMS_TO_TICKS(500));
                break;
        }
    }
}

📌 关键配置点:MQTT 客户端参数配置

mqtt_start(void) 函数中配置 MQTT 客户端参数:

/* 
 * 配置 MQTT 客户端参数
 * uri: MQTT 代理服务器地址,使用 mqtt:// 协议(非加密)
 * event_handle: 设置事件回调函数,用于接收连接状态和数据
 */
axk_mqtt_client_config_t mqtt_cfg = {
    .uri = "mqtt://wx.ai-thinker.com:1883",  // Broker 服务器地址与端口
    .client_id = "yunyan_WB2",                // 客户端 ID,必须唯一
    .username = "yunyan",                     // 用户名(可选)
    .event_handle = event_cb,                 // 注册事件回调函数
};

// 创建 LED 控制任务
static TaskHandle_t led_task_handle;
xTaskCreate(led_indicator_task, "led", 512, NULL, 10, &led_task_handle);

📌 关键配置点:MQTT 事件回调函数实现

修改回调函数 event_cb(axk_mqtt_event_handle_t event),实现以下三个关键事件:

/* ==================== MQTT 连接成功事件 ==================== */
case MQTT_EVENT_CONNECTED:
    blog_info("MQTT_EVENT_CONNECTED");
  
    // 订阅主题 "/topic/qos0",QoS 等级 0(最多送达一次,不保证送达)
    msg_id = axk_mqtt_client_subscribe(client, "/topic/qos0", 0);
    blog_info("sent subscribe successful, msg_id=%d", msg_id);

    // 如需取消订阅,取消以下注释
    // msg_id = axk_mqtt_client_unsubscribe(client, "/topic/qos1");
    // blog_info("sent unsubscribe successful, msg_id=%d", msg_id);
    break;
/* ==================== 订阅成功确认事件 ==================== */
case MQTT_EVENT_SUBSCRIBED:
    blog_info("MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
  
    // 订阅成功后,立即向该主题发布一条 QoS 0 的消息 "hello,MQTT!"
    msg_id = axk_mqtt_client_publish(client, "/topic/qos", "hello,MQTT!", 0, 0, 0);
    blog_info("sent publish successful, msg_id=%d", msg_id);
    break;
/* ==================== 收到 MQTT 消息数据事件 ==================== */
case MQTT_EVENT_DATA:
    blog_info("MQTT_EVENT_DATA");

    // 1. 解析 JSON 字符串为 cJSON 对象
    cJSON *root = cJSON_Parse(event->data);
    if (root == NULL) {
        printf("Error parsing JSON!\n");
        break;
    }

    // 2. 获取 LED 字段
    cJSON *LED = cJSON_GetObjectItem(root, "LED");
  
    // 3. 访问值并进行类型检查
    if (LED && LED->type == cJSON_String) {
        if (strcmp(LED->valuestring, "LED_RED") == 0) {
            g_led_state = LED_RED;
            printf("LED_RED_ON");
        }
        else if (strcmp(LED->valuestring, "LED_GREEN") == 0) {
            g_led_state = LED_GREEN;
            printf("LED_GREEN_ON");
        }
        else if (strcmp(LED->valuestring, "LED_BLUE") == 0) {
            g_led_state = LED_BLUE;
            printf("LED_BLUE_ON");
        }
        else if (strcmp(LED->valuestring, "LED_OFF") == 0) {
            g_led_state = LED_OFF;
            printf("LED_OFF");
        }
        else {
            printf("LED ERROR");
        }  
    }

    // 4. 核心:必须手动释放 cJSON 内存!
    cJSON_Delete(root);

    printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
    printf("DATA=%.*s\r\n", event->data_len, event->data);

    break;

4️⃣ 编译与烧录

保存代码后,执行以下命令进行编译与烧录:

make flash p=/dev/ttyUSB0

编译过程如下:04.png

图:编译成功提示,生成 tcp.bin 二进制文件

烧录过程如下:

05.png

图:烧录成功日志,红色标注显示 "[All Success]"

按下复位键重启开发板,打开串口助手,波特率设置为 115200,查看08.png

图:串口日志显示 MQTT 连接成功、订阅成功、发布成功的消息


四、MQTTX 客户端配置与功能测试

1️⃣ 创建 MQTT 连接

打开 MQTTX 客户端,点击"新建"连接,填写以下信息:

06.png

图:MQTTX 连接配置界面,数字标注对应以下配置项

标注 配置项 说明
名称 随便填 连接标识名称
服务器地址 mqtt://wx.ai-thinker.com 与代码中的 URI 保持一致
端口 1883 标准 MQTT 端口(非加密)
Client ID mqttx_xxxxxxxx 确保唯一不重复
用户名 可填可不填 本例为 yunyan
密码 可填可不填 根据实际情况填写

⚠️ 注意:SSL/TLS 选项保持关闭状态,因为本教程使用的是非加密 MQTT 连接。

2️⃣ 添加主题订阅

点击左侧 "+ 添加订阅"按钮,填写订阅信息:
07.png

*图:添加订阅对话框

配置项 说明
Topic /topic/qos0 订阅的主题名称
QoS 0(最多一次) 消息服务质量等级

3️⃣ 发布消息测试

向主题 /topic/qos0 发布 JSON 格式消息,控制 LED 亮灭:

发布红色 LED

{
  "LED": "LED_RED"
}

发布绿色 LED

{
  "LED": "LED_GREEN"
}

发布蓝色 LED

{
  "LED": "LED_BLUE"
}

关闭 LED

{
  "LED": "LED_OFF"
}

发布消息后,可在串口助手中看到相应的打印信息,开发板 RGB 灯也会对应亮起:09.png

图:MQTTX 消息收发界面,显示订阅主题、已发布和已接收的消息
10.png

图:Ai-WB2 开发板 RGB LED 点亮效果(绿色)


五、常见错误排查

🔴 问题 1:WiFi 连接失败

现象:串口日志显示 WiFi 连接超时或认证失败。

排查步骤

  1. 检查 ROUTER_SSIDROUTER_PWD 是否正确填写
  2. 确认 WiFi 路由器工作正常,2.4GHz 频段信号良好(无法连接5G频段)
  3. 检查 WiFi 名称中是否包含特殊字符(建议使用英文和数字)

🔴 问题 2:MQTT 连接失败

现象:串口日志显示 MQTT_EVENT_DISCONNECTED 或连接超时。

排查步骤

  1. 检查 MQTT 服务器地址是否正确:mqtt://wx.ai-thinker.com:1883
  2. 确认网络连接正常,可以访问互联网
  3. 检查 Client ID 是否唯一,避免与其他设备冲突
  4. 查看防火墙设置,确保端口 1883 未被阻止

🔴 问题 3:JSON 解析失败

现象:串口日志输出 Error parsing JSON!,LED 无响应。

排查步骤

  1. 检查发布的 JSON 格式是否正确(注意双引号、大括号配对)
  2. 确认字段名称为 LED(区分大小写)
  3. 验证值是否为以下合法值:LED_REDLED_GREENLED_BLUELED_OFF

🔴 问题 4:LED 不亮

现象:MQTT 消息已接收,但 LED 无反应。

排查步骤

  1. 检查 GPIO 引脚定义是否与实际硬件连接一致(GPIO_LED_REDGPIO_LED_GREENGPIO_LED_BLUE
  2. 使用万用表测量引脚电平是否正常变化
  3. 确认 RGB LED 模块正常工作(可使用简单的 GPIO 测试代码验证)

🔴 问题 5:编译失败

现象:执行 make 命令后出现编译错误。

排查步骤

  1. 确认子模块已完整下载(检查 toolchain/riscv 目录)
  2. 检查是否安装了必要的编译工具链(GCC、Make 等)
  3. 查看编译错误日志,根据提示修改代码或安装依赖库

总结

至此,基于 Ai-WB2 使用 MQTT 协议实现订阅、发布及点灯功能的全部内容已完成!

如有问题或建议,欢迎在评论区留言讨论!


──── 0人觉得很赞 ────

使用道具 举报

赞👍
nice!!
如此详细~
您需要登录后才可以回帖 立即登录
高级模式
返回
统计信息
  • 会员数: 30957 个
  • 话题数: 44900 篇