1 开发板介绍该开发板的主控芯片型号为CY8C624A,是一个具有 Cortex-M4F 和 Cortex-M0+ 的 双核CPU,该主控芯片的功能框图如下所示:开发板两侧留有供调试和外接其他模块的排针接口,如下图所示。从图中可以看出预留出了串口、IIC、SPI、ADC和PWM等常见的外设和总线接口。2 设计简介2.1 功能简介本次设计基于 RT-Thread 物联网操作系统和 Infineon 开发板,使用 RT-Studio 作为开发工具,使用 ESP8266-WIFI 模块作为物联网的通讯介质,使用腾讯云服务器作为MQTT服务器,使用腾讯连连作为人机交互端,整体的功能框图如下所示:2.2 ESP8266 简介本次使用的 ESP8266 模块如下图所示,ESP8266 是一款强大的 WIFI 模块,支持 AT 指令开发,SDK 开发、Lua 开发、Arduino 开发、Lua 开发等开发方式,本次为了方便和主控板通讯采用 AT 指令的方式进行开发。3 开发步骤本次开发使用 AT 组件和 MQTT 通讯协议进行设备和服务器之间的通讯,所以需要在配置中配置相应的组件。3.1 AT 组件RT-Thread 官方支持了丰富的 AT 设备,本次所用的 ESP8266 模块的配置如下所示,需要开启相应的组件并配置路由的信息和AT设备的串口。3.2 MQTT 组件RT-Thread 官方支持了多种 MQTT 组件,本次使用 PahoMQTT 组件进行开发,配置如下所示:3.3 CJson 组件为了方便和腾讯云服务器进行通讯,在设计通讯格式时采用物模型的方式进行通讯,需要用到 Json 数据格式,在嵌入式设备中通常使用 CJSOn 库对 Json 数据进行解析,CJson 的配置如下:配制好的组件如下图所示:3.4 腾讯云服务器的配置腾讯云物联网开发平台作为本项目的云平台进行数据的转发。4 关键代码编写MQTT任务的代码如下,主要写了登录,退出,发布消息的代码,订阅回调函数。#include #include #include #include #include "rtdevice.h" #define DBG_TAG "mqtt_task.c" #define DBG_LVL DBG_LOG #include #include "paho_mqtt.h" #include "infineon_esp8266.h" #include "json_parse.h" #include "led.h" #include "cJSON.h" //#include "cJSON_util.h" /**MQTT URI farmat:domain modetcp://iot.eclipse.org:1883ipv4 modetcp://192.168.10.1:1883ssl://192.168.10.1:1884ipv6 modetcp://[fe80::20c:29ff:fe9a:a07e]:1883ssl://[fe80::20c:29ff:fe9a:a07e]:1884/ #define MQTT_URI "tcp://T0FR66L94D.iotcloud.tencentdevices.com:1883" #define MQTT_CLIENT_ID "T0FR66L94Dinfineon_esp8266" #define MQTT_USERNAME "T0FR66L94Dinfineon_esp8266;12010126;AVBVT;1647450202" #define MQTT_PASSWORD "68dab4c81b227f841ef86b6223711975106a4a4cfe6556f77504b606430eeae0;hmacsha256" #define MQTT_SUBTOPIC "$thing/down/property/T0FR66L94D/infineon_esp8266" #define MQTT_PUBTOPIC "$thing/up/property/T0FR66L94D/infineon_esp8266" #define MQTT_WILLMSG "Goodbye!" / define MQTT client context / static MQTTClient client; static int is_started = 0; / *@brief MQTT 订阅回调函数@param c 客户端标识@param msg_data 收到的数据@return 无 */ static void infineon_mqtt_sub_callback(MQTTClient *c, MessageData *msg_data) { *((char *) msg_data->message->payload + msg_data->message->payloadlen) = '�'; LOG_D("mqtt sub callback: %.s", //msg_data->topicName->lenstring.len, //msg_data->topicName->lenstring.data, msg_data->message->payloadlen, (char * )msg_data->message->payload); parse_msg(msg_data->message->payloadlen, (char ) msg_data->message->payload); // 解析收到的数据 } /@brief MQTT 默认的订阅回调函数@param c 客户端标识@param msg_data 收到的数据@return 无 */ static void infineon_mqtt_sub_default_callback(MQTTClient *c, MessageData *msg_data) { *((char *) msg_data->message->payload + msg_data->message->payloadlen) = '�'; LOG_D("mqtt sub default callback: %.s %.s", msg_data->topicName->lenstring.len, msg_data->topicName->lenstring.data, msg_data->message->payloadlen, (char * )msg_data->message->payload); } /@brief MQTT 连接的回调函数@param c 客户端标识@return 无/ static void infineon_mqtt_connect_callback(MQTTClient c) { LOG_D("enter mqtt_connect_callback!"); } / @brief MQTT 上线的回调函数 @param c 客户端标识 @return 无/ static void infineon_mqtt_online_callback(MQTTClient c) { LOG_D("enter mqtt_online_callback!"); } / @brief MQTT 掉线的回调函数 @param c 客户端标识 @return 无/ static void infineon_mqtt_offline_callback(MQTTClient c) { LOG_D("enter mqtt_offline_callback!"); } /@brief MQTT 启动@param 无@return 成功返回0,失败返回-1/ int infineon_mqtt_start(void) { / init condata param by using MQTTPacket_connectData_initializer / MQTTPacket_connectData condata = MQTTPacket_connectData_initializer; static char cid[20] = { 0 }; if (is_started) { LOG_E("mqtt client is already connected."); return -1; } / config MQTT context param / { client.isconnected = 0; client.uri = MQTT_URI; / generate the random client ID / rt_snprintf(cid, sizeof(cid), "rtthread%d", rt_tick_get()); / config connect param / memcpy(&client.condata, &condata, sizeof(condata)); client.condata.clientID.cstring = MQTT_CLIENT_ID; client.condata.keepAliveInterval = 30; client.condata.cleansession = 1; client.condata.username.cstring = MQTT_USERNAME; client.condata.password.cstring = MQTT_PASSWORD; / config MQTT will param. / client.condata.willFlag = 1; client.condata.will.qos = 1; client.condata.will.retained = 0; client.condata.will.topicName.cstring = MQTT_PUBTOPIC; client.condata.will.message.cstring = MQTT_WILLMSG; / malloc buffer. / client.buf_size = client.readbuf_size = 1024; client.buf = rt_calloc(1, client.buf_size); client.readbuf = rt_calloc(1, client.readbuf_size); if (!(client.buf && client.readbuf)) { LOG_E("no memory for MQTT client buffer!"); return -1; } / set event callback function / client.connect_callback = infineon_mqtt_connect_callback; client.online_callback = infineon_mqtt_online_callback; client.offline_callback = infineon_mqtt_offline_callback; / set subscribe table and event callback / client.messageHandlers[0].topicFilter = rt_strdup(MQTT_SUBTOPIC); client.messageHandlers[0].callback = infineon_mqtt_sub_callback; client.messageHandlers[0].qos = QOS1; / set default subscribe event callback / client.defaultMessageHandler = infineon_mqtt_sub_default_callback; } / run mqtt client / paho_mqtt_start(&client); is_started = 1; return 0; } / * @brief MQTT 停止 @param 无 @return 成功返回0,失败返回-1/ int infineon_mqtt_stop(void) { if (is_started == 1) { is_started = 0; return paho_mqtt_stop(&client); } } / * @brief MQTT 发布消息 @param send_buff 要发布的消息的内容 @return 成功返回0,失败返回-1/ int infineon_mqtt_publish(char send_buff) { if (is_started == 0) { LOG_E("mqtt client is not connected."); return -1; } paho_mqtt_publish(&client, QOS1, MQTT_PUBTOPIC, send_buff); return 0; } / @brief MQTT 新订阅的回调函数 @param client 客户端标识 @param msg_data 收到的数据 @return 无 */ void infineon_mqtt_new_sub_callback(MQTTClient *client, MessageData *msg_data) { *((char *) msg_data->message->payload + msg_data->message->payloadlen) = '�'; LOG_D("mqtt new subscribe callback: %.s %.s", msg_data->topicName->lenstring.len, msg_data->topicName->lenstring.data, msg_data->message->payloadlen, (char * )msg_data->message->payload); } / @brief MQTT 订阅 @param topic 要订阅的主题的名字 @return 成功返回0,失败返回-1/ int infineon_mqtt_subscribe(char topic) { if (is_started == 0) { LOG_E("mqtt client is not connected."); return -1; } return paho_mqtt_subscribe(&client, QOS1, topic, infineon_mqtt_new_sub_callback); } / @brief MQTT 取消订阅 @param topic 要取消订阅的主题的名字 @return 成功返回0,失败返回-1 */ int infineon_mqtt_unsubscribe(char topic) { if (is_started == 0) { LOG_E("mqtt client is not connected."); return -1; } return paho_mqtt_unsubscribe(&client, topic); } / json数据格式 {"method":"report", // report 表示设备属性上报
"clientToken":"123", // 用于上下行消息配对标识
"timestamp":1628646783, // 属性上报的时间,格式为 UNIX 系统时间戳,不填写该字段表示默认为当前系统时间。单位为毫秒
"params":{ // JSON 结构内为设备上报的属性值
"led":1,
"fan":1
}
}/ / * @brief MQTT 处理线程 @param parameter 线程的入参 @return 无 */ void mqtt_thread_entry(void *parameter) { while (1) { if (get_esp8266_link_status() == 0) // 等到 ESP8266 连接成功后才能连接腾讯云 { break; } else { rt_thread_mdelay(1000); } } infineon_mqtt_start(); // 启动mqtt,连接服务器 cJSON *root = NULL; cJSON params = NULL; char send_str = NULL; while (1) { rt_thread_mdelay(5000); // publish 间隔 root = cJSON_CreateObject(); / 创建一个cJSON对象,要用 cJSON_Delete 释放内存 / if (root != NULL) { cJSON_AddStringToObject(root, "method", "report"); cJSON_AddStringToObject(root, "clientToken", "123"); params = cJSON_CreateObject(); / 创建子对象 / if (params != NULL) { cJSON_AddItemToObject(root, "params", params); cJSON_AddNumberToObject(params, "led", get_led_status()); // 添加 LED 状态 cJSON_AddNumberToObject(params, "fan", get_fan_status()); // 风扇状态 send_str = cJSON_Print(root); if (send_str != NULL) { LOG_D("send msg: %sn", send_str); infineon_mqtt_publish(send_str); } } } if (send_str != NULL) // 释放空间 { cJSON_free(send_str); send_str = NULL; } if (root != NULL) { cJSON_Delete(root); // 防止内存泄露,会把下面所有的子节点都释放 } } } / @brief 启动 MQTT 处理线程 @param 无 @return 无/ int start_mqtt_thread(void) { / 创建 MTQTT 处理线程 */ rt_thread_t thread = rt_thread_create("mqtt_thread", mqtt_thread_entry, RT_NULL, 2048, 10, 20); if (thread != RT_NULL) { rt_thread_startup(thread); // 创建成功则启动线程 } else { LOG_E("create mqtt thread failed"); return (-RT_ERROR); } return RT_EOK; }