ESP-01S+STM32F103C8T6 连接One net 二
·
上一期介绍了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上显示(设备接入管理-设备管理-详情-属性)

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



所有评论(0)