使用RT-Thread通过MQTT连接华为物联网平台实验
硬件环境:
(1)开发板:ST官方的stm32wb55-st-nucleo开发板
(2)wifi模块:esp8266
(3)温湿度传感器:DHT22
(4)单色oled屏:主控ssd1306,分辨率126x64
软件环境:
(1)开发环境:Keil MDK v5.29
(2)RTOS:RT-Thread 4.0.3
实现目标:将温度、湿度数据上报到华为云物联网平台。
一、准备工作
(1)安装ENV工具,参见官方文档《Env 用户手册》:
https://www.rt-thread.org/document/site/#
(2)安装git下载最新的rt-thread源码,可到github或码云gitee上下载:
git clone https://gitee.com/rtthread/rt-thread.git
(3)查看rt-thread源码的bsp文件夹内已经适配了stm32wb55-st-nucleo开发板,进入“...\rt-thread\bsp\stm32\stm32wb55-st-nucleo”,打开env运行scons --dist将工程抽离成独立工程(看个人习惯,喜欢一个项目一个工程文件夹就抽离一下)。
(4)先对工程文件进行编译,看看有没有错误,理论上官方默认状态是无错误的。打开env再运行:
pkgs --upgrade
pkgs --update
scons --target=mdk5
然后用keil打开工程,编译0错误,0警告。准备工作完成。
二、获取需要的软件包
rt-thread提供非常多的软件包,主要任务就是怎么把软件包利用起来。本次操作需要的软件包:DHT22驱动、ESP8266驱动、MQTT软件包、json软件包,另外把oled屏驱动添加到工程。
1. 添加DHT22驱动
(1)DHT22与开发板连接,电源、地、数据就三根线,数据线我连接到开发板的GPIOB 9引脚上,需要查找一下GPIOB 9在rt-thread系统内对应的引脚号(打开drv_gpio.c文件,看到引脚列表pins[]可见对应编号为25),后面需要配置到menuconfig内。(注意:新版驱动去掉了pins[]列表,暂时不知道去哪里查找引脚对应的编号,可能需要在代码内使用GET_PIN(B,9)获取了)
(2)添加DHTxx驱动软件包,工程目录内打开env,执行menuconfig,开启软件包和例程,版本选择最新,引脚号配置为25:
2. 添加oled显示屏驱动
(1)在工程目录内建立user_add_files文件夹,将后期用户代码都放在这个文件夹内。并在user_add_files文件夹内新建SConscript文件,内容如下(目的是scons时自动添加文件夹内的所有文件到工程):
-
import os
-
from building import *
-
objs = []
-
cwd = GetCurrentDir()
-
list = os.listdir(cwd)
-
-
for item in list:
-
if os.path.isfile(os.path.join(cwd, item, 'SConscript')):
-
objs = objs + SConscript(os.path.join(item, 'SConscript'))
-
Return('objs')
(2)在user_add_files文件夹内新建oled_ssd1306_drv文件夹并新建对应的SConscript文件, oled驱动文件放到oled_ssd1306_drv文件夹:
SConscript文件内容:
-
from building import *
-
cwd = GetCurrentDir()
-
src = Glob('*.c')
-
CPPPATH = [cwd]
-
group = DefineGroup('oled_ssd1306_drv', src, depend = [''], CPPPATH = CPPPATH)
-
Return('group')
(3)使用scons --target=mdk5重新构建工程,发现oled驱动已添加到工程:
(4)在main.c中添加测试代码:
-
-
-
-
-
-
/* defined the LED1 pin: PB5 */
-
-
-
-
int main(void)
-
{
-
/* set LED0 pin mode to output */
-
rt_pin_write(LED_R_PIN, PIN_LOW);
-
rt_pin_write(LED_G_PIN, PIN_LOW);
-
rt_pin_write(LED_B_PIN, PIN_LOW);
-
rt_pin_mode(LED_R_PIN, PIN_MODE_OUTPUT);
-
rt_pin_mode(LED_G_PIN, PIN_MODE_OUTPUT);
-
rt_pin_mode(LED_B_PIN, PIN_MODE_OUTPUT);
-
dht_device_t sensor = dht_create(PKG_USING_DHTXX_SAMPLE_PIN);
-
oled_dev.display_on();
-
char disp_str[50];
-
for(;;)
-
{
-
rt_thread_mdelay(3000);
-
if(dht_read(sensor))
-
{
-
rt_int32_t temp = dht_get_temperature(sensor);
-
rt_int32_t humi = dht_get_humidity(sensor);
-
rt_kprintf("Temp: %d, Humi: %d\n", temp, humi);
-
rt_sprintf(disp_str,"Humi: %d.%d %%",humi/10,humi%10);
-
oled_dev.show_string(0,4,(unsigned char *)disp_str,16,1);
-
rt_sprintf(disp_str,"Temp: %d.%d C",temp/10,temp%10);
-
oled_dev.show_string(0,24,(unsigned char *)disp_str,16,1);
-
oled_dev.refresh();
-
}
-
else
-
{
-
rt_kprintf("Read dht sensor failed.\n");
-
rt_pin_write(LED_R_PIN, PIN_HIGH);
-
}
-
}
-
return RT_EOK;
-
}
编译烧录运行:
3. 添加ESP8266 WIFI模块驱动
(1)stm32wb55芯片有两个串口(lpuart1和uart1,正好一个做控制台、一个连接wifi模块,配置时注意区分,我将lpuart1作为控制台,uart1连接wifi),在menuconfig下面路径找到esp8266,开启并根据实际情况配置wifi密码和串口号:
(2)保存 --> pkgs --update --> scons --target=mdk5
(3)keil打开工程 --> 编译 --> 烧录 --> 运行,打开串口工具,查看信息,已经可以发现wifi正常连接上了。
4. 添加MQTT软件包,当时有4个MQTT软件包可选,哪个好用不了解,暂时选择my mqtt。
利用软件包自带的sample进行测试,直接编译烧录,控制台输入mqtt_start:
根据打印信息,可以看出已与服务器连接;之后发布一个消息试试,内容为hello!,由于例程已订阅的默认主题和发布的默认主题相同,所以如果MQTT运行正常则发布的内容会被原样接收到,测试如下,说明my mqtt软件包初步运行正常。
5.因为需要使用json串传输数据,所以添加json软件包。
三、在华为物联网平台上创建产品
注册华为云账号,在华为物联网平台上创建产品、建立产品模型、创建设备,具体过程及传输的json字符串格式参见官方指导文件《MQTT设备快速接入》文档:
(https://support.huaweicloud.com/qs-iothub/iot_05_0006.html)
我的产品截图:
模型定义截图(只添加温度和湿度两个属性):
四、上传温度和湿度数据到华为云
(1)根据my_mqtt软件包自带的sample例程的函数,稍作调整,用于上报数据,mqtt_start函数采用rtthread上电自动运行方式INIT_APP_EXPORT(mqtt_start)。
编写数据上报函数(JSON串格式参见上面华为MQTT设备快速接入文档):
-
/*
-
* 函数名称:user_humiture_send_to_server
-
* 输入参数:temp 温度数据,单位0.1C
-
* humi 湿度数据,单位0.1%
-
* 返回数据:-1 发送失败
-
* 0 发送成功
-
*/
-
int8_t user_humiture_send_to_server(int temp,int humi)
-
{
-
cJSON *root_prop;
-
cJSON *root_serv;
-
cJSON *array_serv;
-
cJSON *root;
-
char *cjson_str = NULL;
-
//检查mqtt连接状态
-
if(paho_mqtt_is_connected(&client) == 0) return -1;
-
//生成json字符串
-
root_prop = cJSON_CreateObject();
-
cJSON_AddNumberToObject(root_prop, "humidity", (humi/10) + 0.1 * (humi%10));
-
cJSON_AddNumberToObject(root_prop, "temperature", (temp/10) + 0.1 * (temp%10));
-
//
-
root_serv = cJSON_CreateObject();
-
cJSON_AddStringToObject(root_serv, "service_id", "humiture");
-
cJSON_AddItemToObject(root_serv, "properties", root_prop);
-
cJSON_AddStringToObject(root_serv, "event_time", "NULL"); //"20201207T002920Z"
-
//
-
array_serv = cJSON_CreateArray();
-
cJSON_AddItemToArray(array_serv,root_serv);
-
//
-
root = cJSON_CreateObject();
-
cJSON_AddItemToObject(root, "services", array_serv);
-
//发布数据
-
cjson_str = cJSON_PrintUnformatted(root);
-
mqtt_publish(cjson_str);
-
//释放内存
-
cJSON_Delete(root);
-
cJSON_free(cjson_str);
-
return 0;
-
}
(2)在main函数内调用数据上报函数,具体见后面我的实验工程代码,编译烧写运行程序;登录华为云查看设备状态为在线,可见云端已收到数据:
(3)数据上报华为云初步测试成功,我的测试工程代码:
链接:https://pan.baidu.com/s/10I-BtE3UVGmxp7F2TpNxHA
提取码:38sr