【嵌入式Linux应用开发】设计温湿度采集MCU子系统

1. 概述

​ 本篇主要是使用百问网的100ASK_STM32F103_PRO开发板加上ESP8266和DHT11设计一个采集环境温湿度的子系统,将温湿度数据上云,让阿里云服务器转发给订阅了该温湿度数据主体的MQTT客户端,也就是之前做的基于STM32MP157开发板的温湿度监控系统。

温湿度监控系统应用开发所有文章

  1. 【嵌入式Linux应用开发】移植LVGL到Linux开发板
  2. 【嵌入式Linux应用开发】初步移植MQTT到Ubuntu和Linux开发板
  3. 【嵌入式Linux应用开发】SquareLine Studio与LVGL模拟器
  4. 【嵌入式Linux应用开发】温湿度监控系统——绘制温湿度折线图
  5. 【嵌入式Linux应用开发】温湿度监控系统——学习paho mqtt的基本操作
  6. 【嵌入式Linux应用开发】温湿度监控系统——多线程与温湿度的获取显示
  7. 【嵌入式Linux应用开发】设计温湿度采集MCU子系统

适用开发板

​ 适用于百问网的100ASK_STM32F103_PRO开发板。

2. 软件平台

​ 这个温湿度采集子系统是基于RT-Thread操作系统,使用的ide是RTT的studio,因为可以用它的生态软件包快速实现我们的需求。

3. 配置软件包

​ 新建rt-thread studio的STM32F103的工程就不介绍了,依照官方文档做很简单的,下面开始添加和配置软件包。

3.1 配置DHT11

​ 如果再RT-Thread Settings的软件包里面搜索不到DHT11的软件包的话,可以去官网的软件包中查看一下分类,然后再去软件包中设置:

【嵌入式Linux应用开发】设计温湿度采集MCU子系统_第1张图片

【嵌入式Linux应用开发】设计温湿度采集MCU子系统_第2张图片

在这里面找到DHT11的软件包:

【嵌入式Linux应用开发】设计温湿度采集MCU子系统_第3张图片

这里油两种,都可以使用,如果不清楚使用的引脚序号是多少的话可以暂时不设置。

3.2 配置MQTT

​ mqtt在RT-Thread Settings软件包的IoT-物联网中的:

【嵌入式Linux应用开发】设计温湿度采集MCU子系统_第4张图片

这里选择的是其中一种,也是前面几篇文章用的mqtt库paho mqtt,使能了示例。

3.3 配置AT设备

​ 因为我们的方案是使用的ESP8266连接WiFi入网然后再去和阿里云服务器建立连接的,因而就需要使用到ESP8266的库,在RT-Thread Settings里面ESP8266的应用是在AT设备里面设置的,而AT设备也是在IoT-物联网里面的:

【嵌入式Linux应用开发】设计温湿度采集MCU子系统_第5张图片

我们需要设置连接的WiFi名称和密码,然后和ESP8266连接的串口是哪个也需要指定。

​ 当DHT11、MQTT、AT设备都配置到之后就选择保存,将配置生效生成代码到工程里面去。

4. 温湿度数据上云

4.1 修改DHT11示例代码

​ 在DHT11的示例代码中,使用的引脚是用引脚序号来定义的,如果不熟悉这种用法可以将源码注释掉,改成使用GET_PIN宏函数来选择GPIO:

// 源代码
#include 
#include 
#include 
#include "dhtxx.h"

#define DATA_PIN                 PKG_USING_DHTXX_SAMPLE_PIN

修改后的代码:

【嵌入式Linux应用开发】设计温湿度采集MCU子系统_第6张图片

可以看到这里添加了一个驱动层的头文件,这是因为GET_PIN是在里面宏定义的,通过此函数可以方便的指定我们用的是哪一组GPIO的哪一个引脚。

​ DHT的源码是将读取数据的app注册放到了终端去输入指令调用的,我们期望的是每隔固定周期自动读取,因而可以自己创建一个线程:


static void dht_thread_entry(void *parameter)
{
    dht_device_t sensor = dht_create(DATA_PIN);
    while(1)
    {
        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);
        }
        else
        {
            rt_kprintf("Read dht sensor failed.\n");
        }
        rt_thread_delay(5000);
    }

    dht_delete(sensor);
}

static int dht_thread_init(void)
{
    rt_thread_t dht_t = rt_thread_create("DHT", \
                                         dht_thread_entry, \
                                         RT_NULL, \
                                         512, \
                                         RT_THREAD_PRIORITY_MAX>>1, \
                                         10);
    if(dht_t == RT_NULL)
    {
        rt_kprintf("Failed to create dht thread.\n\r");
        return -1;
    }

    rt_thread_startup(dht_t);

    return 0;
}

INIT_APP_EXPORT(dht_thread_init);

这样F103就会每隔大约5s的时间读取一次温湿度数据:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dAKCcSwu-1657613242193)(LinuxApp-7-TempHumiSubSystem/image-20220706103704730.png)]

可以看到数据是放大了10倍的,如果没有精度需求的哈,可以只保留整数位也就是将数据除以10:

rt_int32_t temp = dht_get_temperature(sensor)/10;
rt_int32_t humi = dht_get_humidity(sensor)/10;

4.2 添加MQTT线程

​ MQTT使用的AT设备是使用UART3连接的ESP8266,但是我们的源码里面是没有使能和定义UART3及其引脚的,因而我们需要去board.h里面将UART3的设置定义出来:

【嵌入式Linux应用开发】设计温湿度采集MCU子系统_第7张图片

然后再去MQTT的示例里面修改登录服务器的地址、客户端ID等信息:

【嵌入式Linux应用开发】设计温湿度采集MCU子系统_第8张图片

接着定义一个静态全局变量is_connect来表明客户端和服务器是断开还是连接状态,这个标志在paho mqtt的连接成功回调函数和连接断开回调函数中改变:

在这里插入图片描述

【嵌入式Linux应用开发】设计温湿度采集MCU子系统_第9张图片

  • 1-连接状态
  • -1断开状态

随后去mqtt_start中将客户端ID的赋值改成我们宏定义的值,且保活时间周期设置为60s:

【嵌入式Linux应用开发】设计温湿度采集MCU子系统_第10张图片

最后创建线程,等待DHT线程传来数据,线程传输数据我们使用rtt的消息队列,我们在mqtt的线程中初始化一个消息队列,mqtt的线程读取队列,dht的线程发送队列,所以这个消息队列应该没定义成一个全局变量,好让两个不同的源文件调用:

rt_mq_t pmq;
static void mqtt_thread_entry(void *parameter)
{
    // 如果没有开启mqtt客户端,先开启
    if(is_started != 1) mqtt_start(1, NULL);

    // 创建一个消息队列
    pmq = rt_mq_create("TempHumi mq", sizeof(rt_uint16_t), 4, RT_IPC_FLAG_FIFO);
    if(pmq ==RT_NULL)
    {
        rt_kprintf("Failed to create data message queue.\r\n");
        return;
    }

    while(1)
    {
        // 只有在mqtt客户端连接上了服务器之后才能坐后面的事情
        if(is_connect == 1)
        {
            rt_uint16_t value = 0;
            int ret = rt_mq_recv(pmq, &value, sizeof(value), 10);
            if(ret==RT_EOK)
            {
                rt_kprintf("Success to receive message queue data:%d°C-%dRH.\r\n", (value>>8)&0xFF, value&0xFF);
                char buf[8] = {0};
                rt_sprintf(buf, "%d", value);
                // 调用发布API
                int rc = paho_mqtt_publish(&client, QOS1, MQTT_PUBTOPIC, buf);
                if(rc != PAHO_SUCCESS)
                {
                    rt_kprintf("Failed to publish message.\r\n");
                }
            }
        }
        else
        {
            rt_thread_delay(1);
        }
    }
}

static int mqtt_thread_init(void)
{
    rt_thread_t mqtt_t = rt_thread_create("mqtt thread", \
                                           mqtt_thread_entry, \
                                           RT_NULL, \
                                           1024, \
                                           RT_THREAD_PRIORITY_MAX>>1, \
                                           10);
    if(mqtt_t == RT_NULL)
    {
        rt_kprintf("Failed to create mqtt thread.\r\n");
        return -1;
    }

    rt_thread_startup(mqtt_t);

    return 0;
}

INIT_APP_EXPORT(mqtt_thread_init);

4.3 dht线程发送消息队列

​ 将在mqtt示例源码中定义的消息队列放到dht示例源码中声明,然后在线程中使用:

extern rt_mq_t pmq;
static void dht_thread_entry(void *parameter)
{
    dht_device_t sensor = dht_create(DATA_PIN);
    while(1)
    {
        if(dht_read(sensor))
        {
            rt_int32_t temp = dht_get_temperature(sensor)/10;
            rt_int32_t humi = dht_get_humidity(sensor)/10;
            if(pmq != RT_NULL)
            {
                rt_uint16_t value = (temp<<8) + humi;
                int ret = rt_mq_send(pmq, &value, sizeof(value));
                if(ret != RT_EOK)
                {
                    rt_kprintf("Failed to send message.\r\n");
                }
            }
//            rt_kprintf("Temp: %d, Humi: %d\n", temp, humi);
        }
        else
        {
            rt_kprintf("Read dht sensor failed.\n");
        }
        rt_thread_delay(5000);
    }

    dht_delete(sensor);
}

5. 编译烧写运行

​ 将程序改好之后直接编译,然后使用ST-Link烧录到板子里面运行,然后让STM32MP157开发板也运行前面编译好的那个demo,就可以看到温湿度数据在Linux开发板上的屏幕上,显示出来了。

【嵌入式Linux应用开发】设计温湿度采集MCU子系统_第11张图片

你可能感兴趣的:(嵌入式Linux高级案例,linux,mcu,单片机)