上一期介绍了ESP-01S如何通过CH340连接并使用串口工具配置与发送消息,这次介绍ESP-01S+STM32F103C8T6,直接通过给开发板编译的方式连接onenet,并讲dht11的数据上报云端。注意,一切连接操作需要在已经烧录ESP-01S关于MQTT(1471)的基础上进行。

1、使用到的元器件:

dht11、ESP-01S、STM32F103C8T6最小开发板

2、主要元件线路连接:

ESP-01S STM32F103C8T6 dht11
3V3 3V3 3V3
EN 3V3
TX RX(PA10)
RX TX(PA9)
GND GND GND
PA0

3、主要代码(使用Keil+STlink)

ESP-01S.c:

#include "esp01s.h"
#include "delay.h"
#include <string.h>
#include <stdio.h>

// ==================== 接收缓冲区 ====================
static char rx_buffer[512];
static uint16_t rx_index = 0;

// ==================== USART1 中断服务函数 ====================
void USART1_IRQHandler(void) {
    if (USART_GetITStatus(ESP01S_USART, USART_IT_RXNE) != RESET) {
        char c = USART_ReceiveData(ESP01S_USART);
        if (rx_index < sizeof(rx_buffer) - 1) {
            rx_buffer[rx_index++] = c;
        }
    }
}

// ==================== 初始化 ESP-01S 串口 ====================
void ESP01S_Init(uint32_t baudrate) {
    GPIO_InitTypeDef GPIO_InitStruct;
    USART_InitTypeDef USART_InitStruct;

    RCC_APB2PeriphClockCmd(ESP01S_GPIO_CLK | ESP01S_USART_CLK, ENABLE);

    GPIO_InitStruct.GPIO_Pin = ESP01S_TX_PIN;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(ESP01S_GPIO_PORT, &GPIO_InitStruct);

    GPIO_InitStruct.GPIO_Pin = ESP01S_RX_PIN;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(ESP01S_GPIO_PORT, &GPIO_InitStruct);

    USART_InitStruct.USART_BaudRate = baudrate;
    USART_InitStruct.USART_WordLength = USART_WordLength_8b;
    USART_InitStruct.USART_StopBits = USART_StopBits_1;
    USART_InitStruct.USART_Parity = USART_Parity_No;
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(ESP01S_USART, &USART_InitStruct);

    USART_ITConfig(ESP01S_USART, USART_IT_RXNE, ENABLE);
    NVIC_EnableIRQ(USART1_IRQn);

    USART_Cmd(ESP01S_USART, ENABLE);

    memset(rx_buffer, 0, sizeof(rx_buffer));
    rx_index = 0;

    Delay_ms(1500);
}

// ==================== 发送 AT 指令(自动添加 \r\n) ====================
void ESP01S_SendCmd(const char *cmd) {
    while (*cmd) {
        USART_SendData(ESP01S_USART, *cmd++);
        while (USART_GetFlagStatus(ESP01S_USART, USART_FLAG_TXE) == RESET);
    }
    USART_SendData(ESP01S_USART, '\r');
    while (USART_GetFlagStatus(ESP01S_USART, USART_FLAG_TXE) == RESET);
    USART_SendData(ESP01S_USART, '\n');
    while (USART_GetFlagStatus(ESP01S_USART, USART_FLAG_TXE) == RESET);
}

// ==================== 发送原始数据(不自动添加 \r\n,用于 Payload) ====================
void ESP01S_SendRawData(const char *data, uint16_t len) {
    for (uint16_t i = 0; i < len; i++) {
        USART_SendData(ESP01S_USART, data[i]);
        while (USART_GetFlagStatus(ESP01S_USART, USART_FLAG_TXE) == RESET);
    }
    // 发送结束标志(\r\n),绝大多数固件要求
    USART_SendData(ESP01S_USART, '\r');
    while (USART_GetFlagStatus(ESP01S_USART, USART_FLAG_TXE) == RESET);
    USART_SendData(ESP01S_USART, '\n');
    while (USART_GetFlagStatus(ESP01S_USART, USART_FLAG_TXE) == RESET);
}

// ==================== 等待响应(匹配字符串) ====================
uint8_t ESP01S_WaitResponse(const char *expected, uint32_t timeout_ms) {
    uint32_t time = 0;
    rx_index = 0;
    memset(rx_buffer, 0, sizeof(rx_buffer));

    while (time < timeout_ms) {
        if (strstr(rx_buffer, expected) != NULL) {
            return 1;
        }
        Delay_ms(1);
        time++;
    }
    return 0;
}

// ==================== 连接 WiFi ====================
uint8_t ESP01S_ConnectWiFi(const char *ssid, const char *password) {
    char cmd[128];

    ESP01S_SendCmd("AT+RST");
    Delay_ms(3000);

    ESP01S_SendCmd("AT+CWMODE=1");
    if (!ESP01S_WaitResponse("OK", ESP01S_TIMEOUT_MS)) return 0;

    sprintf(cmd, "AT+CWJAP=\"%s\",\"%s\"", ssid, password);
    ESP01S_SendCmd(cmd);
    if (!ESP01S_WaitResponse("OK", ESP01S_WIFI_TIMEOUT)) return 0;

    ESP01S_SendCmd("AT+CIFSR");
    Delay_ms(500);
    return 1;
}

// ==================== 连接 OneNET MQTT ====================
uint8_t ESP01S_ConnectOneNET(const char *productId, const char *deviceName, const char *token) {
    char cmd[256];
    char clientId[128];
    char username[128];

    sprintf(clientId, "%s", deviceName);
    sprintf(username, "%s", productId);
    sprintf(cmd, "AT+MQTTUSERCFG=0,1,\"%s\",\"%s\",\"%s\",0,0,\"\"",
            clientId, username, token);
    ESP01S_SendCmd(cmd);
    if (!ESP01S_WaitResponse("OK", ESP01S_TIMEOUT_MS)) return 0;

    sprintf(cmd, "AT+MQTTCLIENTID=0,\"%s\"", clientId);
    ESP01S_SendCmd(cmd);
    if (!ESP01S_WaitResponse("OK", ESP01S_TIMEOUT_MS)) return 0;

    sprintf(cmd, "AT+MQTTCONN=0,\"%s\",%d,1", ONENET_BROKER, ONENET_PORT);
    ESP01S_SendCmd(cmd);
    if (!ESP01S_WaitResponse("OK", ESP01S_TIMEOUT_MS)) return 0;

    return 1;
}

// ==================== 发布数据(适配 OneNET 物模型) ====================
uint8_t ESP01S_PublishOneNET(const char *productId, const char *deviceName, uint8_t temp, uint8_t humi) {
    char cmd[200];
    char topic[100];
    char json_payload[160];
    uint16_t payload_len;

    // 1. 构造符合 OneNET 物模型的 JSON
    sprintf(json_payload, "{\"id\":\"1\",\"version\":\"1.0\",\"params\":{\"temperature\":{\"value\":%d},\"humidity\":{\"value\":%d}}}", temp, humi);
    payload_len = strlen(json_payload);

    // 2. 构造发布主题(属性上报)
    sprintf(topic, "$sys/%s/%s/thing/property/post", productId, deviceName);

    // 3. 发送 AT+MQTTPUBRAW 指令(不带 Payload)
    sprintf(cmd, "AT+MQTTPUBRAW=0,\"%s\",%d,0,0", topic, payload_len);
    ESP01S_SendCmd(cmd);

    // 4. 等待模块返回 '>' 提示符
    uint32_t timeout = 0;
    rx_index = 0;
    memset(rx_buffer, 0, sizeof(rx_buffer));
    while (timeout < 3000) {
        if (strstr(rx_buffer, ">") != NULL) {
            break;
        }
        Delay_ms(1);
        timeout++;
    }
    if (timeout >= 3000) {
        return 0;  // 未收到 '>'
    }

    // 5. 发送 JSON Payload
    ESP01S_SendRawData(json_payload, payload_len);

    // 6. 等待发布完成应答
    if (ESP01S_WaitResponse("OK", 5000)) {
        return 1;
    } else {
        return 0;
    }
}

// ==================== 订阅 Topic(可选) ====================
uint8_t ESP01S_SubscribeOneNET(const char *productId, const char *deviceName, const char *subTopic) {
    char cmd[256];
    char topic[128];

    sprintf(topic, "$sys/%s/%s/%s", productId, deviceName, subTopic);
    sprintf(cmd, "AT+MQTTSUB=0,\"%s\",1", topic);
    ESP01S_SendCmd(cmd);
    if (!ESP01S_WaitResponse("OK", ESP01S_TIMEOUT_MS)) return 0;
    return 1;
}

// ==================== 断开 MQTT ====================
uint8_t ESP01S_MQTT_Disconnect(void) {
    ESP01S_SendCmd("AT+MQTTCLEAN=0");
    if (!ESP01S_WaitResponse("OK", ESP01S_TIMEOUT_MS)) return 0;
    return 1;
}


// 通用发布:直接发送完整的 JSON 字符串,topic 由调用者构造
uint8_t ESP01S_PublishRaw(const char *topic, const char *json_payload) {
    char cmd[200];
    uint16_t payload_len = strlen(json_payload);

    // 发送 AT 指令,指定长度
    sprintf(cmd, "AT+MQTTPUBRAW=0,\"%s\",%d,0,0", topic, payload_len);
    ESP01S_SendCmd(cmd);

    // 等待 '>' 提示符
    uint32_t timeout = 0;
    rx_index = 0;
    memset(rx_buffer, 0, sizeof(rx_buffer));
    while (timeout < 3000) {
        if (strstr(rx_buffer, ">") != NULL) break;
        Delay_ms(1);
        timeout++;
    }
    if (timeout >= 3000) return 0;

    // 发送 JSON 数据(不含 \r\n,SendRawData 会自动添加)
    ESP01S_SendRawData(json_payload, payload_len);

    // 等待发布完成
    return ESP01S_WaitResponse("OK", 5000);
}

ESP-01S.h:

#ifndef __ESP01S_H
#define __ESP01S_H

#include "stm32f10x.h"
#include <string.h>
#include <stdio.h>

// ==================== 硬件引脚配置 ====================
#define ESP01S_USART          USART1
#define ESP01S_USART_CLK      RCC_APB2Periph_USART1
#define ESP01S_GPIO_CLK       RCC_APB2Periph_GPIOA
#define ESP01S_TX_PIN         GPIO_Pin_9
#define ESP01S_RX_PIN         GPIO_Pin_10
#define ESP01S_GPIO_PORT      GPIOA

// ==================== 超时配置 ====================
#define ESP01S_TIMEOUT_MS     5000
#define ESP01S_WIFI_TIMEOUT   15000

// ==================== OneNET 平台固定参数 ====================
#define ONENET_BROKER         "mqtts.heclouds.com"
#define ONENET_PORT           1883

// ==================== 函数声明 ====================
void ESP01S_Init(uint32_t baudrate);
void ESP01S_SendCmd(const char *cmd);
void ESP01S_SendRawData(const char *data, uint16_t len);          // 新增
uint8_t ESP01S_WaitResponse(const char *expected, uint32_t timeout_ms);

// WiFi 连接
uint8_t ESP01S_ConnectWiFi(const char *ssid, const char *password);

// OneNET 专用接口(修改原型,直接传温湿度值)
uint8_t ESP01S_ConnectOneNET(const char *productId, const char *deviceName, const char *token);
uint8_t ESP01S_PublishOneNET(const char *productId, const char *deviceName, uint8_t temp, uint8_t humi);
uint8_t ESP01S_SubscribeOneNET(const char *productId, const char *deviceName, const char *subTopic);

// 通用 MQTT 接口(备用)
uint8_t ESP01S_MQTT_Disconnect(void);

// 通用发布:直接发送完整的 JSON 字符串,topic 由调用者构造
uint8_t ESP01S_PublishRaw(const char *topic, const char *json_payload);

#endif

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "OLED_Font.h"
#include "Dht11.h"
#include "esp01s.h"
#include <stdio.h>

// ==================== 用户配置区 ====================
#define ONENET_PRODUCT_ID   "你的产品ID"
#define ONENET_DEVICE_NAME  "你的设备名称"
#define ONENET_TOKEN        "你所生成的token"
#define WIFI_SSID           "所连接的WIFI名称"
#define WIFI_PASSWORD       "所连接的WIFI密码"

int main(void) {
    uint8_t temp, humi;

    OLED_Init();
    DHT11_Init();
    ESP01S_Init(115200);

    OLED_Clear();
    OLED_ShowString(1, 1, "System Init OK");

    OLED_ShowString(2, 1, "Connecting WiFi...");
    if (ESP01S_ConnectWiFi(WIFI_SSID, WIFI_PASSWORD)) {
        OLED_ShowString(2, 1, "WiFi Connected  ");
    } else {
        OLED_ShowString(2, 1, "WiFi Failed!    ");
        while (1) Delay_ms(500);
    }

    OLED_ShowString(3, 1, "Connecting OneNET");
    if (ESP01S_ConnectOneNET(ONENET_PRODUCT_ID, ONENET_DEVICE_NAME, ONENET_TOKEN)) {
        OLED_ShowString(3, 1, "OneNET OK      ");
    } else {
        OLED_ShowString(3, 1, "OneNET Failed! ");
        while (1) Delay_ms(500);
    }

    Delay_ms(1000);
    OLED_Clear();
    OLED_ShowString(1, 1, "Temp:    C");
    OLED_ShowString(2, 1, "Humi:    %");
    OLED_ShowString(4, 1, "Upload: Waiting");

    while (1) {
    if (DHT11_Read_Data(&temp, &humi) == 0) {
        OLED_ShowNum(1, 7, temp, 2);
        OLED_ShowNum(2, 7, humi, 2);

        // ---------- 1. 构造 JSON 数据(按 OneNET 物模型格式) ----------
        char json_payload[160];      // 根据需要调整大小,当前两个字段足够
        sprintf(json_payload,
            "{\"id\":\"1\",\"version\":\"1.0\",\"params\":{"
            "\"temperature\":{\"value\":%d},"
            "\"humidity\":{\"value\":%d}"
            "}}",
            temp, humi);

        // ---------- 2. 构造发布主题 ----------
        char topic[100];
        sprintf(topic, "$sys/%s/%s/thing/property/post", ONENET_PRODUCT_ID, ONENET_DEVICE_NAME);

        // ---------- 3. 调用通用发布函数 ----------
        if (ESP01S_PublishRaw(topic, json_payload)) {
            OLED_ShowString(4, 1, "Upload OK      ");
        } else {
            OLED_ShowString(4, 1, "Upload Failed! ");
            // 尝试重连(同时重连 MQTT)
            ESP01S_ConnectOneNET(ONENET_PRODUCT_ID, ONENET_DEVICE_NAME, ONENET_TOKEN);
        }
    } else {
        OLED_ShowString(3, 1, "DHT11 Error!   ");
    }
    Delay_ms(5000);
}
}

dht11和OLED的文件我并未贴出,可以自行编辑使用。当你需要上传除温湿度外的其他数据时,在main中根据你云上所加物模型,链接你的数据接口即可。

char json_payload[160];      
        sprintf(json_payload,
            "{\"id\":\"1\",\"version\":\"1.0\",\"params\":{"
            "\"temperature\":{\"value\":%d},"
            "\"humidity\":{\"value\":%d}"
            "}}",
            temp, humi);

在烧录后,等待其连接,正常后,最终的数据就会在onenet上显示(设备接入管理-设备管理-详情-属性)

博主也是边学习边分享,若有不正确的地方,请大家告知以便继续学习改正。感谢江协科技相关教程与开源基础代码的支持。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐