GD32VW553-IoT V2 获取温湿度数据并 MQTT 上报
分享作者:Mr_Fang
作者昵称:Mr_Fang
评测品牌:萤火工场
评测型号:GD32VW553-IOT-V2
发布时间:2025-10-24 10:44:50
1
前言
本项目将使用 DHT11 获取环境温湿度数据并显示在 OLED 屏幕上,连接 WIFI 后可使用 MQTT 上报数据
开源口碑分享内容

搭建 MQTT 服务器

此部分参考此文章:GD32VW55x MQTT 控制 GPIO 输出

OLED 驱动移植

此部分参考此文章:GD32VW553-IoT V2 利用 Wi-Fi 在OLED屏幕上播放视频

使用 DHT11 读取温湿度数据

DHT11 数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器,内部由一个 8 位单片机控制一个电阻式感湿元件和一个 NTC 测温元件。DHT11 虽然也是采用单总线协议,但是该协议与 DS18B20 的单总线协议稍微有些不同之处。相比于 DS18B20 只能测量温度,DHT11 既能检测温度又能检测湿度,不过 DHT11 的精度和测量范围都要低于 DS18B20,其温度测量范围为 090%RH,误差在±5%RH

dht11.c

#include "dht11.h"

// DHT11 IO
#define GPIO_DATA GPIO_PIN_3

// 复位DHT11
void DHT11_Rst(void)       
{
    DHT11_IO_OUT();                        //SET OUTPUT
    gpio_bit_reset(GPIOA, GPIO_DATA);    //拉低DQ
    sys_us_delay(20000);                //拉低至少18ms
    gpio_bit_set(GPIOA, GPIO_DATA);        //DQ=1
    sys_us_delay(30);                    //主机拉高20~40us
}

// 等待DHT11的回应
// 返回1: 未检测到DHT11的存在
// 返回0: 存在
uint8_t DHT11_Check(void)
{   
    uint8_t retry=0;
    DHT11_IO_IN();//SET INPUT     
    while (gpio_input_bit_get(GPIOA, GPIO_DATA)&&retry<100)//DHT11会拉低40~80us
    {
        retry++;
        sys_us_delay(1);
    };     
    if(retry>=100)return 1;
    else retry=0;
    while (!gpio_input_bit_get(GPIOA, GPIO_DATA)&&retry<100)//DHT11拉低后会再次拉高40~80us
    {
        retry++;
        sys_us_delay(1);
    };
    if(retry>=100)return 1;
    return 0;
}

// 从DHT11读取一个位
uint8_t DHT11_Read_Bit(void)
{
     uint8_t retry=0;
    while(gpio_input_bit_get(GPIOA, GPIO_DATA)&&retry<100)//等待变为低电平
    {
        retry++;
        sys_us_delay(1);
    }
    retry=0;
    while(!gpio_input_bit_get(GPIOA, GPIO_DATA)&&retry<100)//等待变高电平
    {
        retry++;
        sys_us_delay(1);
    }
    sys_us_delay(40);//等待40us
    if(gpio_input_bit_get(GPIOA, GPIO_DATA))return 1;
    else return 0;           
}

// 从DHT11读取一个字节
uint8_t DHT11_Read_Byte(void)
{
    uint8_t i,dat;
    dat=0;
    for (i=0;i<8;i++) 
    {
        dat<<=1; 
        dat|=DHT11_Read_Bit();
    }
    return dat;
}

// 从DHT11读取一次数据
// temp: 温度值(范围:0~50°)
// humi: 湿度值(范围:20%~90%)
// 返回: 0, 正常; 1, 读取失败
uint8_t DHT11_Read_Data(uint8_t *temp,uint8_t *humi)
{
    uint8_t buf[5];
    uint8_t i;
    DHT11_Rst();
    if(DHT11_Check()==0)
    {
        for(i=0;i<5;i++)//读取40位数据
        {
            buf[i]=DHT11_Read_Byte();
        }
        if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
        {
            *humi=buf[0];
            *temp=buf[2];
        }
    }
    else return 1;
    return 0;
}

// 初始化DHT11, 同时检测DHT11的存在
// 返回1: 不存在
// 返回0: 存在
uint8_t DHT11_Init(void)
{
    rcu_periph_clock_enable(RCU_GPIOA);
    gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_3);

    DHT11_Rst();  //复位DHT11
    return DHT11_Check();//等待DHT11的回应
} 

dht11.h

#ifndef DHT11_H
#define DHT11_H

#include "gd32vw55x.h"
#include "sys.h"

// DHT11 IO
#define GPIO_DATA GPIO_PIN_3

#define DHT11_IO_IN()    {gpio_mode_set(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_DATA);}
#define DHT11_IO_OUT()    {gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_DATA);}

uint8_t DHT11_Init(void);
uint8_t DHT11_Read_Data(uint8_t *temp,uint8_t *humi);
uint8_t DHT11_Read_Byte(void);
uint8_t DHT11_Read_Bit(void);
uint8_t DHT11_Check(void);
void DHT11_Rst(void);

#endif

使用 MQTT 上报数据

打开 MDK MQTT Demo 的 /main/mqtt_client_main.c,可以直接在这里编写代码(可以直接删除内容)

引入头文件和定义常量、全局变量

#include <stdint.h>
#include <stdio.h>
#include "app_cfg.h"
#include "gd32vw55x_platform.h"
#include "wifi_management.h"
#include "wifi_init.h"

#include "lwip/apps/mqtt.h"
#include "lwip/apps/mqtt5.h"
#include "lwip/apps/mqtt_priv.h"

#include "mqtt5_client_config.c"

#include "oled.h"
#include "dht11.h"

#define SSID        "SSID"
#define PASSWORD    "PASSWORD"

#define SERVER_PORT 1883
ip_addr_t sever_ip_addr = IPADDR4_INIT_BYTES(192,168,0,2);

static char client_id[] = {'G', 'i', 'g', 'a', 'D', 'e', 'v', 'i', 'c', 'e', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
struct mqtt_connect_client_info_t client_info = {
    .client_id = client_id,
    .client_user = NULL,
    .client_pass = NULL,
    .keep_alive = 120,
    .will_topic = NULL,
    .will_topic = NULL,
    .will_qos = 0,
    .will_retain = 0
};

char* topic_pub  = "dht11/topic";

static mqtt_client_t *mqtt_client = NULL;
int16_t connect_fail_reason = -1;

uint8_t temp;
uint8_t humi;

MQTT 任务相关函数

struct mqtt_connect_client_info_t* get_client_param_data_get(void)
{
    return &client_info;
}

// 断开并释放MQTT连接
void mqtt_connect_free(void)
{
    connect_fail_reason = -1;
    if (mqtt_client == NULL)
        return;

    mqtt5_disconnect(mqtt_client);
    mqtt5_param_delete(mqtt_client);
    mqtt_client_free(mqtt_client);
    mqtt_client = NULL;
}

// 断开连接或连接异常回调函数
void mqtt_connect_callback(mqtt_client_t *client, void *arg, mqtt_connection_status_t status)
{
    char *prefix = NULL;
    char *reason = NULL;

    if ((status == MQTT_CONNECT_ACCEPTED) ||
        (status == MQTT_CONNECT_REFUSED_PROTOCOL_VERSION)) {
        return;;
    }

    prefix = "MQTT: client will be closed, reason is ";
    switch (status) {
    case MQTT_CONNECT_DISCONNECTED:
        reason = "remote has closed connection";
        break;
    case MQTT_CONNECT_TIMEOUT:
        reason = "connect attempt to server timed out";
        break;
    default:
        reason = "others";
        break;
    }

    printf("%s%s, id is %d.\r\n", prefix, reason, status);
}

// 解析错误码
void mqtt_fail_reason_display(mqtt_connect_return_res_t fail_reason)
{
    char *prefix = "MQTT mqtt_client: connection refused reason is ";
    char *reason = NULL;

    switch(fail_reason) {
    case MQTT_CONNECTION_REFUSE_PROTOCOL:
        reason = "Bad protocol";
        break;
    case MQTT_CONNECTION_REFUSE_ID_REJECTED:
        reason = "ID rejected";
        break;
    case MQTT_CONNECTION_REFUSE_SERVER_UNAVAILABLE:
        reason = "Server unavailable";
        break;
    case MQTT_CONNECTION_REFUSE_BAD_USERNAME:
        reason = "Bad username or password";
        break;
    case MQTT_CONNECTION_REFUSE_NOT_AUTHORIZED:
        reason = "Not authorized";
        break;

    default:
        reason = "Unknown reason";
        break;
    }
    printf("%s%s, id is %d.\r\n", prefix, reason, fail_reason);

    return;
}

// 与服务器建立连接
static int client_connect(void)
{
    err_t ret = ERR_OK;
    uint32_t connect_time = 0;

    mqtt_client = mqtt_client_new();

    printf("MQTT: start link server...\r\n");

    if (mqtt5_param_cfg(mqtt_client)) {
        printf("MQTT: Configuration MQTT parameters failed, stop connection.\r\n");
        return -2;
    }

    connect_time = sys_current_time_get();
    ret = mqtt5_client_connect(mqtt_client, &sever_ip_addr, SERVER_PORT, mqtt_connect_callback, NULL, &client_info,
            &(mqtt_client->mqtt5_config->connect_property_info),
            &(mqtt_client->mqtt5_config->will_property_info));
    if (ret != ERR_OK) {
        printf("MQTT mqtt_client: connect to server failed.\r\n");
        return ret;
    }

    // 等待连接成功
    while (mqtt_client_is_connected(mqtt_client) == false) {
        // 超时
        if ((sys_current_time_get() - connect_time) > 5000) {
            printf("MQTT mqtt_client: connect to server timeout.\r\n");
            return -3;
        }
        // 异常
        if (connect_fail_reason == MQTT_CONNECTION_REFUSE_PROTOCOL) {
            mqtt5_disconnect(mqtt_client);
            mqtt5_param_delete(mqtt_client);
            printf("MQTT: The server does not support version 5.0, now switch to version 3.1.1.\r\n");
            connect_fail_reason = -1;
            break;
        } else if (connect_fail_reason > 0) {
            mqtt5_fail_reason_display((mqtt5_connect_return_res_t)connect_fail_reason);
            return connect_fail_reason;
        }
        sys_yield();
    }

    printf("MQTT: Successfully connected to server.\r\n");

    return 0;
}

// 发布回调函数
void mqtt_pub_cb(void *arg, err_t status)
{
    switch (status) {
    case ERR_OK:
        printf("topic publish success.\r\n");
        break;
    case ERR_TIMEOUT:
        printf("topic publish time out.\r\n");
        break;
    default:
        printf("topic publish failed.\r\n");
        break;
    }

    return;
}

// 发布
static int client_publish(char *topic, char *context, uint16_t length)
{
    err_t ret = ERR_OK;

    ret = mqtt5_msg_publish(mqtt_client, topic, context, length, 1, 1, mqtt_pub_cb, NULL, mqtt_client->mqtt5_config->publish_property_info,
            mqtt_client->mqtt5_config->server_resp_property_info.response_info);
    return ret;
}

// MQTT主函数
static void mqtt_client_demo(void)
{
    if (client_connect() != 0) {
        printf("MQTT connect server failed.\r\n");
        goto exit;
    }

    while(1) {
        sys_msleep(5000);
        char context[256] = {'\0'};

        DHT11_Read_Data(&temp,&humi);

        OLED_ShowNum(64, 6, temp, 2, 16, 1);
        OLED_ShowNum(64, 26, humi, 2, 16, 1);
        OLED_Refresh();

        int len = snprintf(context, sizeof(context), "{\"temp\": %d, \"humi\": %d}", temp, humi);
        if(client_publish(topic_pub, context, len) == ERR_OK) {
            printf("topic: %s\r\npayload: %s\r\n", topic_pub, context);
        }
    }

exit:
    printf("MQTT: close mqtt connection.\r\n");
    mqtt_connect_free();

    return;
}

// 任务函数
static void mqtt_client_task(void *param)
{
    int status = 0;
    char *ssid = SSID;
    char *password = PASSWORD;
    struct mac_scan_result candidate;

    if (ssid == NULL) {
        printf("ssid can not be NULL!\r\n");
        goto exit;
    }

    /*
    * 1. Start Wi-Fi scan
    */
    printf("Start Wi-Fi scan.\r\n");
    status = wifi_management_scan(1, ssid);
    if (status != 0) {
        printf("Wi-Fi scan failed.\r\n");
        goto exit;
    }
    sys_memset(&candidate, 0, sizeof(struct mac_scan_result));
    status = wifi_netlink_candidate_ap_find(WIFI_VIF_INDEX_DEFAULT, NULL, ssid, &candidate);
    if (status != 0) {
        goto exit;
    }

    /*
    * 2. Start Wi-Fi connection
    */
    printf("Start Wi-Fi connection.\r\n");
    if (wifi_management_connect(ssid, password, 1) != 0) {
        printf("Wi-Fi connection failed\r\n");
        goto exit;
    }

    /*
    * 3. Start MQTT client
    */
    printf("Start MQTT client.\r\n");
    mqtt_client_demo();

    /*
    * 4. Stop Wi-Fi connection
    */
    printf("Stop Wi-Fi connection.\r\n");
    wifi_management_disconnect();

exit:
    printf("The test has ended.\r\n");
    sys_task_delete(NULL);
}

主函数

int main(void)
{
    platform_init();

    // 初始化 OLED
    OLED_Init();
    OLED_ColorTurn(0);
    OLED_DisplayTurn(0);

    OLED_ShowString(6, 6, (uint8_t *)"Temp:", 16, 1);
    OLED_ShowString(6, 26, (uint8_t *)"Humi:", 16, 1);
    OLED_Refresh();

    if (wifi_init()) {
        printf("wifi init failed.\r\n");
    }

    while(DHT11_Init())
    {
        printf("DHT11 Error \r\n");
        sys_us_delay(1000000);
    }

    sys_task_create_dynamic((const uint8_t *)"MQTT Client", 4096, OS_TASK_PRIORITY(0), mqtt_client_task, NULL);

    sys_os_start();

    for ( ; ; );
}

烧录程序

使用 Type-C 数据线将 GD32VW553-IoT V2 开发板连接到电脑,拨动拨码开关“1”到“ON”侧,按下按钮 K1 进入下载模式

打开 GD32 All In One Programmer 软件,按照下图配置后即可直接烧录

GD32 All In One Programmer 中勾选 Jump to run the App program 烧录程序后即可自动运行

使用 MQTT 客户端订阅消息获取数据

可以参考此文章:GD32VW55x MQTT 控制 GPIO 输出,使用 MQTT 客户端测试章节配置 MQTTBox 软件订阅 dht11/topic 消息

全部评论
暂无评论
0/144