润和星闪WS63E的MQTT示例程序存在的潜在问题

发布于:2025-05-28 ⋅ 阅读:(16) ⋅ 点赞:(0)

目录

引言

程序简介

代码结构分析

核心函数分析

MQTT 连接与通信

数据采集与处理

任务管理

问题分析

结构体修改引发线程间通信失效的原因分析

关键问题点

解决方案

1. 调整消息队列最大长度

2. 确保消息读取时缓冲区足够大

3. 动态检查和适应结构体大小

4. 增强错误检查

结语


引言

润和在其星闪开发套件中提供了一个MQTT的示例,该程序可以采集温湿度信息并上传华为云平台,是学习华为云的一个很好的例子。

有个学生想在该示例基础上添加压力传感器信息,在下面的结构体中添加了char pressure[10]:

typedef struct {
    int msg_type;
    char temp[10];
    char humi[10];
    char *receive_payload;
} MQTT_msg;

添加后程序不工作了,两个线程不能正确运行了,没有输出打印信息。今天分享一下程序存在的问题,供大家参考。 

程序简介

先简单的介绍一下这个程序。这是一个基于华为云 IoT 平台的 MQTT 通信应用程序,运行在嵌入式设备上。主要功能是通过 WiFi 连接网络,使用 MQTT 协议与云端通信,采集环境温湿度数据并上报,同时接收云端指令控制设备(如蜂鸣器)。

代码结构分析

程序由多个功能模块组成:

  1. MQTT 通信模块

    • 包含连接、发布、订阅等核心功能
    • 使用回调函数处理消息到达、连接丢失等事件
  2. WiFi 连接模块

    • 负责建立与指定 WiFi 热点的连接
  3. 环境数据采集模块

    • 通过 AHT20 传感器采集温度和湿度数据
  4. JSON 处理模块

    • 实现数据的 JSON 格式编码和解码
  5. PWM 控制模块

    • 控制外设(如蜂鸣器)的 PWM 输出
  6. 任务管理模块

    • 创建和管理多个任务线程

核心函数分析

MQTT 连接与通信

int mqtt_connect(void)
  • 初始化 MQTT 客户端并连接到华为云 IoT 平台
  • 设置连接参数,包括保活间隔、用户名和密码
  • 注册回调函数处理连接丢失、消息到达和消息确认
  • 将环境数据(温度、湿度)封装为 JSON 格式
  • 发布消息到指定主题
int msgArrved(void *context, char *topic_name, int topic_len, MQTTClient_message *message)
  • 消息到达回调函数
  • 将接收到的消息放入消息队列,供后续处理

数据采集与处理

void environment_task_entry(void)
  • 环境数据采集任务
  • 初始化 AHT20 传感器并循环读取温湿度数据
  • 将数据封装为消息结构体并发送到队列

任务管理

static void mqtt_sample_entry(void)
  • 应用入口函数
  • 创建消息队列和两个任务线程:
    • mqtt_task:处理 MQTT 通信
    • environment_task_entry:采集环境数据

问题分析

结构体修改引发线程间通信失效的原因分析

当在MQTT_msg结构体中增加char pressure[10];成员后,线程间通信失效的主要原因是消息队列的消息长度配置与实际消息大小不匹配

关键问题点

  1. 消息队列创建时的固定长度

    #define MSG_MAX_LEN 28
    ret = osal_msg_queue_create("name", MSG_QUEUE_SIZE, &g_msg_queue, 0, MSG_MAX_LEN);
    
     
    • MSG_MAX_LEN被定义为 28 字节,这是原始结构体的大小
    • 增加pressure[10]成员后,结构体大小变为 38 字节,超出了队列的最大长度
  2. 消息队列读写操作

    // 写入消息
    uint32_t ret = osal_msg_queue_write_copy(g_msg_queue, receive_msg, sizeof(MQTT_msg), OSAL_WAIT_FOREVER);
    
    // 读取消息
    uint32_t resize = 32; // 初始大小设置不足
    ret = osal_msg_queue_read_copy(g_msg_queue, report_msg, &resize, OSAL_WAIT_FOREVER);
    
     
    • 写入时使用sizeof(MQTT_msg)(新大小 38 字节)
    • 读取时初始resize为 32 字节,且未正确更新为结构体实际大小

解决方案

1. 调整消息队列最大长度

#define MSG_MAX_LEN 40  // 根据新结构体大小调整

2. 确保消息读取时缓冲区足够大

uint32_t resize = sizeof(MQTT_msg);  // 使用正确的结构体大小
ret = osal_msg_queue_read_copy(g_msg_queue, report_msg, &resize, OSAL_WAIT_FOREVER);

3. 动态检查和适应结构体大小

// 创建队列时使用动态计算的大小
ret = osal_msg_queue_create("name", MSG_QUEUE_SIZE, &g_msg_queue, 0, sizeof(MQTT_msg));

// 读取消息前确认缓冲区大小
MQTT_msg *report_msg = osal_kmalloc(sizeof(MQTT_msg), 0);
uint32_t resize = sizeof(MQTT_msg);

4. 增强错误检查

if (resize < sizeof(MQTT_msg)) {
    printf("Error: Message buffer size is insufficient!\n");
    // 处理错误情况
}

经过以上修改后,现在程序执行正常了。

结语

这个错误比较隐蔽,因为没有啥提示信息。应该说润和的示例程序不太规范,没有考虑程序扩充的问题,部分地方甚至采用了硬编码,而不是完全用宏来定义的。类似这样的问题,值得我们每个人格外小心。


网站公告

今日签到

点亮在社区的每一天
去签到