通过Arduino烧录8266固件
cpp
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
static WiFiClient espClient;
PubSubClient mqttClient(espClient);
// ONENET MQTT 连接参数
const char* MQTT_SERVER = "183.230.40.96";
const int MQTT_PORT = 1883;
String PRODUCT_ID = ""; // 产品ID
String DEVICE_NAME = ""; // 设备名称
String USERNAME = ""; // MQTT用户名
String PASSWORD = ""; // MQTT密码(Token)
bool paramsReceived = false;
#define WIFI_SSID "LCDZ"
#define WIFI_PASSWD "LCDZlcdz"
// #define WIFI_SSID "12345678"
// #define WIFI_PASSWD "12345678"
String serialInput = ""; // 缓存串口输入
String lcCommandInput = ""; // 缓存 LC 指令输入
// ONENET MQTT 订阅/发布主题
String getTopicPropertySet() {
return "$sys/" + PRODUCT_ID + "/" + DEVICE_NAME + "/thing/property/set";
} // 属性设置主题
String getTopicPropertyPost() {
return "$sys/" + PRODUCT_ID + "/" + DEVICE_NAME + "/thing/property/post";
} // 属性上报主题
// 物模型属性存储(简易键值)
#define MAX_PROPERTIES 20 // 最大属性数
struct PropertyData {
String name;
String value;
bool hasValue;
};
PropertyData propertyStore[MAX_PROPERTIES]; // 已接收的属性列表
// 已绑定的物模型属性
String boundProperties[MAX_PROPERTIES]; // 已绑定属性名
int boundCount = 0; // 已绑定数量
// 解析串口参数(LC+Connect)
void parseSerialParams(String input) {
// 检查是否以 "LC+Connect:" 开头
if (input.startsWith("LC+Connect:")) {
// 去掉前缀
String params = input.substring(11);
params.trim(); // 去掉首尾空格
// 解析逗号分隔的参数(去掉引号)
int startPos = 0;
int paramIndex = 0;
bool inQuotes = false;
for (int i = 0; i <= params.length(); i++) {
if (i == params.length() || (!inQuotes && params.charAt(i) == ',')) {
String param = params.substring(startPos, i);
param.trim();
// 去掉首尾引号
if (param.startsWith("\"") && param.endsWith("\"")) {
param = param.substring(1, param.length() - 1);
}
// 按索引写入
if (param.length() > 0) {
switch (paramIndex) {
case 0: PRODUCT_ID = param; break;
case 1: DEVICE_NAME = param; break;
case 2: USERNAME = param; break;
case 3: PASSWORD = param; break;
}
paramIndex++;
}
startPos = i + 1;
} else if (params.charAt(i) == '"') {
inQuotes = !inQuotes;
}
}
if (paramIndex >= 4) {
paramsReceived = true;
Serial.println("Parameter:OK");
// Serial.print("PRODUCT_ID: "); Serial.println(PRODUCT_ID);
// Serial.print("DEVICE_NAME: "); Serial.println(DEVICE_NAME);
// Serial.print("USERNAME: "); Serial.println(USERNAME);
// Serial.print("PASSWORD: "); Serial.println(PASSWORD);
} else {
Serial.println("Parameter:error");
}
}
}
// 解析并执行 LC+Send 指令
// 格式: LC+Send:"物模型名称":数据
// 数据可为整数/浮点/字符串
void parseLCSendCommand(String input) {
// 检查是否以 "LC+Send:" 开头
if (input.startsWith("LC+Send:")) {
// 去掉前缀
String params = input.substring(8);
params.trim();
// 提取模型名和数据,格式: "模型名":数据
int quoteStart = params.indexOf('"');
int quoteEnd = params.indexOf('"', quoteStart + 1);
int colonPos = params.indexOf(':', quoteEnd + 1);
if (quoteStart >= 0 && quoteEnd > quoteStart && colonPos > quoteEnd) {
// 模型名(去引号)
String modelName = params.substring(quoteStart + 1, quoteEnd);
// 数据部分
String data = params.substring(colonPos + 1);
data.trim();
// 尝试按数值或字符串发送
if (modelName.length() > 0 && data.length() > 0) {
// 判断是否数字
bool isNumber = false;
bool isFloat = false;
// 浮点或整数
if (data.indexOf('.') >= 0) {
// 浮点数校验
float testFloat = data.toFloat();
if (testFloat != 0.0 || data == "0.0" || data == "0" || data.startsWith("0.")) {
isNumber = true;
isFloat = true;
}
} else {
// 整数校验
long testLong = data.toInt();
if (testLong != 0 || data == "0") {
// 确认每位都是数字
bool allDigits = true;
int startIdx = 0;
if (data.charAt(0) == '-' || data.charAt(0) == '+') startIdx = 1; // 允许符号位
for (int i = startIdx; i < data.length(); i++) {
if (!isDigit(data.charAt(i))) {
allDigits = false;
break;
}
}
if (allDigits && data.length() > startIdx) {
isNumber = true;
isFloat = false;
}
}
}
if (isNumber) {
if (isFloat) {
// 发送浮点
float floatValue = data.toFloat();
sendToONENET(modelName.c_str(), floatValue);
// Serial.print("LC+Send OK(float): ");
// Serial.print(modelName);
// Serial.print(" = ");
// Serial.println(floatValue, 6); // 显示 6 位小数
} else {
// 发送整数
long longValue = data.toInt();
// 若超出 int,转换为 float 发送
sendToONENET(modelName.c_str(), (float)longValue);
// Serial.print("LC+Send OK(int): ");
// Serial.print(modelName);
// Serial.print(" = ");
// Serial.println(longValue);
}
} else {
// 鍙戦€佸瓧绗︿覆
sendToONENET(modelName.c_str(), data.c_str());
// Serial.print("LC+Send OK(string): ");
// Serial.print(modelName);
// Serial.print(" = \"");
// Serial.print(data);
// Serial.println("\"");
}
}
}
}
}
// MQTT 消息回调
void mqttCallback(char* topic, byte* payload, unsigned int length) {
// 将 payload 转成字符串
String message = "";
for (unsigned int i = 0; i < length; i++) {
message += (char)payload[i];
}
Serial.print("Message received [");
Serial.print(topic);
Serial.print("]: ");
Serial.println(message);
// 解析 JSON
StaticJsonDocument<200> doc;
DeserializationError error = deserializeJson(doc, message);
if (error) {
Serial.print("JSON parse failed: ");
Serial.println(error.c_str());
return;
}
// 根据 topic 处理不同消息
String topicStr = String(topic);
if (topicStr == getTopicPropertySet()) {
// 处理属性下发
// Serial.println("Property set command received");
// 可在此解析具体属性,如 doc["params"]["xxx"]
// 按 OneNET 物模型要求回复 set_reply,避免"设备响应超时"
String msgId = doc["id"] | "0";
StaticJsonDocument<128> rsp;
rsp["id"] = msgId;
rsp["code"] = 200;
rsp["msg"] = "success";
char rspBuf[128];
size_t rspLen = serializeJson(rsp, rspBuf);
String replyTopic = "$sys/" + PRODUCT_ID + "/" + DEVICE_NAME + "/thing/property/set_reply";
bool pubOk = mqttClient.publish(replyTopic.c_str(), (uint8_t*)rspBuf, rspLen);
// Serial.print("set_reply publish "); Serial.println(pubOk ? "ok" : "fail");
} else if (topicStr == getTopicPropertyPost()) {
// 处理属性上报应答
// Serial.println("Property post response received");
}
}
// ONENET MQTT 连接
bool connectToONENET() {
mqttClient.setServer(MQTT_SERVER, MQTT_PORT);
mqttClient.setCallback(mqttCallback); // 设置回调
// clientId 直接用设备名称
String clientId = DEVICE_NAME;
// 打印连接参数用于调试
// Serial.println("=== ONENET MQTT Connection Info ===");
// Serial.print("Server: "); Serial.println(MQTT_SERVER);
// Serial.print("Port: "); Serial.println(MQTT_PORT);
// Serial.print("ClientID: "); Serial.println(clientId);
// Serial.print("Username: "); Serial.println(USERNAME);
// Serial.print("Password: "); Serial.println(PASSWORD);
// Serial.println("===================================");
// 尝试连接
if (mqttClient.connect(clientId.c_str(), USERNAME.c_str(), PASSWORD.c_str())) {
Serial.println("ONENET MQTT Connected");
// 订阅 ONENET 相关主题
String topicSet = getTopicPropertySet();
String topicPost = getTopicPropertyPost();
if (mqttClient.subscribe(topicSet.c_str())) {
// Serial.print("Subscribed to: ");
// Serial.println(topicSet);
} else {
// Serial.print("Failed to subscribe to: ");
// Serial.println(topicSet);
}
if (mqttClient.subscribe(topicPost.c_str())) {
// Serial.print("Subscribed to: ");
// Serial.println(topicPost);
} else {
// Serial.print("Failed to subscribe to: ");
// Serial.println(topicPost);
}
return true;
} else {
Serial.print("ONENET MQTT Connect failed, rc=");
int state = mqttClient.state();
Serial.println(state);
// 错误原因
switch(state) {
// case -4: Serial.println("Connection timeout"); break;
// case -3: Serial.println("Connection lost"); break;
// case -2: Serial.println("Connect failed"); break;
// case -1: Serial.println("Disconnected"); break;
// case 1: Serial.println("Bad protocol version"); break;
// case 2: Serial.println("Bad client ID"); break;
// case 3: Serial.println("Unavailable"); break;
// case 4: Serial.println("Bad credentials (Username/Password)"); break;
// case 5: Serial.println("Unauthorized"); break;
}
return false;
}
}
// 发送数据到 ONENET(数值)
void sendToONENET(const char* propertyName, float value) {
Serial.println("=== sendToONENET called ===");
Serial.print("Property: "); Serial.println(propertyName);
Serial.print("Value: "); Serial.println(value);
if (!mqttClient.connected()) {
Serial.println("MQTT not connected, reconnecting...");
if (!connectToONENET()) {
Serial.println("ERROR: Failed to connect!");
return;
}
} else {
Serial.println("MQTT connected OK");
}
// ONENET 物模型上报格式: {"id":"消息ID","params":{"属性":{"value":值}}}
StaticJsonDocument<300> doc;
char idStr[20];
sprintf(idStr, "%lu", millis()); // 使用时间戳作为消息ID
doc["id"] = idStr;
JsonObject params = doc.createNestedObject("params");
JsonObject property = params.createNestedObject(propertyName);
property["value"] = value; // 按 ONENET 要求嵌套 value
char jsonBuffer[300];
serializeJson(doc, jsonBuffer);
// 打印 JSON 调试
// Serial.print("JSON: "); Serial.println(jsonBuffer);
String topicPost = getTopicPropertyPost();
// Serial.print("Topic: "); Serial.println(topicPost);
// Serial.print("Topic length: "); Serial.println(topicPost.length());
// Serial.print("JSON length: "); Serial.println(strlen(jsonBuffer));
// 保证 MQTT loop 被调用
mqttClient.loop();
delay(10); // 让 MQTT loop 运行一次
// 发布
bool publishResult = mqttClient.publish(topicPost.c_str(), jsonBuffer);
// Serial.print("Publish result: "); Serial.println(publishResult ? "true" : "false");
// 再执行几次 loop 确认发送
mqttClient.loop();
delay(50); // 稍等以保证发送完成
mqttClient.loop();
if (publishResult) {
// Serial.println("SUCCESS: Published!");
// Serial.print("Topic: "); Serial.println(topicPost);
// Serial.print("Data: "); Serial.println(jsonBuffer);
} else {
// Serial.println("ERROR: Publish failed!");
// Serial.print("MQTT state: "); Serial.println(mqttClient.state());
// Serial.print("MQTT connected: "); Serial.println(mqttClient.connected() ? "yes" : "no");
}
// Serial.println("========================");
}
// 发送数据到 ONENET(字符串)
void sendToONENET(const char* propertyName, const char* value) {
Serial.println("=== sendToONENET (string) called ===");
Serial.print("Property: "); Serial.println(propertyName);
Serial.print("Value: "); Serial.println(value);
if (!mqttClient.connected()) {
Serial.println("MQTT not connected, reconnecting...");
if (!connectToONENET()) {
Serial.println("ERROR: Failed to connect!");
return;
}
} else {
Serial.println("MQTT connected OK");
}
// ONENET 物模型上报格式: {"id":"消息ID","params":{"属性":{"value":值}}}
StaticJsonDocument<300> doc;
char idStr[20];
sprintf(idStr, "%lu", millis()); // 使用时间戳作为消息ID
doc["id"] = idStr;
JsonObject params = doc.createNestedObject("params");
JsonObject property = params.createNestedObject(propertyName);
property["value"] = value; // 按 ONENET 要求嵌套 value
char jsonBuffer[300];
serializeJson(doc, jsonBuffer);
// 打印 JSON 调试
Serial.print("JSON: "); Serial.println(jsonBuffer);
String topicPost = getTopicPropertyPost();
// Serial.print("Topic: "); Serial.println(topicPost);
// Serial.print("Topic length: "); Serial.println(topicPost.length());
// Serial.print("JSON length: "); Serial.println(strlen(jsonBuffer));
// 保证 MQTT loop 被调用
mqttClient.loop();
delay(10); // 让 MQTT loop 运行一次
// 发布
bool publishResult = mqttClient.publish(topicPost.c_str(), jsonBuffer);
Serial.print("Publish result: "); Serial.println(publishResult ? "true" : "false");
// 再执行几次 loop 确认发送
mqttClient.loop();
delay(50); // 稍等以保证发送完成
mqttClient.loop();
if (publishResult) {
// Serial.println("SUCCESS: Published!");
// Serial.print("Topic: "); Serial.println(topicPost);
// Serial.print("Data: "); Serial.println(jsonBuffer);
} else {
// Serial.println("ERROR: Publish failed!");
// Serial.print("MQTT state: "); Serial.println(mqttClient.state());
// Serial.print("MQTT connected: "); Serial.println(mqttClient.connected() ? "yes" : "no");
}
// Serial.println("========================");
}
void sendToCloud(const char* modelName, float value) {
sendToONENET(modelName, value);
// Serial.print("LC+Send OK: ");
// Serial.print(modelName);
// Serial.print(" = ");
// Serial.println(value);
}
void sendToCloud(const char* modelName, const char* value) {
sendToONENET(modelName, value);
// Serial.print("LC+Send OK: ");
// Serial.print(modelName);
// Serial.print(" = ");
// Serial.println(value);
}
void setup() {
Serial.begin(115200);
delay(1000); // 等待串口稳定
// 一直等待串口收到 LC+Connect: 参数
// Serial.println("=== ONENET MQTT Device Starting ===");
// Serial.println("Waiting for LC+Connect command...");
// Serial.println("Format: LC+Connect:\"产品ID\",\"设备名称\",\"用户名\",\"密码\"");
// Serial.println("===================================");
while (!paramsReceived) {
if (Serial.available() > 0) {
char c = Serial.read();
if (c == '\n' || c == '\r') {
if (serialInput.length() > 0) {
parseSerialParams(serialInput);
serialInput = "";
}
} else {
serialInput += c;
}
}
}
// 初始化 WiFi
wifiInit(WIFI_SSID, WIFI_PASSWD);
// 连接 ONENET MQTT
if (connectToONENET()) {
Serial.println("ONENET initialized successfully");
} else {
Serial.println("ONENET initialization failed");
}
}
void loop() {
// 保持 MQTT 连接
if (!mqttClient.connected()) {
connectToONENET();
}
mqttClient.loop();
// 处理串口输入
if (Serial.available() > 0) {
char c = Serial.read();
// 判断是否 LC 指令(以 LC+ 开头)
if (lcCommandInput.length() == 0 && (c == 'L' || c == 'l')) {
lcCommandInput += c;
} else if (lcCommandInput.length() > 0) {
// 继续接收 LC 指令
lcCommandInput += c;
if (c == '\n' || c == '\r') {
if (lcCommandInput.length() > 0) {
if (lcCommandInput.startsWith("LC+Send:")) {
parseLCSendCommand(lcCommandInput);
}
lcCommandInput = "";
}
}
// 防止缓存溢出
if (lcCommandInput.length() > 200) {
lcCommandInput = "";
}
}
}
}
// 初始化 WiFi
void wifiInit(const char *ssid, const char *passphrase) {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, passphrase);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("wifi error");
}
Serial.println("wifi ok");
}
此固件只需要更改wifi 账号密码 其他参数可以通过指令传进去
#define WIFI_SSID ""
#define WIFI_PASSWD ""
ONENET云平台配置
1.创建产品

说明:红框里面必须一样其他随便
2.创建物模型



标志符就是物模型名称
3.创建设备

选择对应的产品名称
4.生成密钥

python
import base64
import hmac
from urllib.parse import quote
import time
# 中国移动官方文档给出的核心秘钥计算算法
def token(id,access_key):
version = '2018-10-31'
res = 'products/%s' % id # 通过产品ID访问产品API
# 用户自定义token过期时间
et = str(int(time.time()) + 63072000) # 设置为2年有效时间
# 签名方法,支持md5、sha1、sha256
method = 'sha1'
# 对access_key进行decode
key = base64.b64decode(access_key)
# 计算sign
org = et + '\n' + method + '\n' + res + '\n' + version
sign_b = hmac.new(key=key, msg=org.encode(), digestmod=method)
sign = base64.b64encode(sign_b.digest()).decode()
# value 部分进行url编码,method/res/version值较为简单无需编码
sign = quote(sign, safe='')
res = quote(res, safe='')
# token参数拼接
token = 'version=%s&res=%s&et=%s&method=%s&sign=%s' % (version, res, et, method, sign)
return token
username = "5af2tgcpsX" # 产品ID
accesskey = "" # 密钥
password = token(username, accesskey)
print(password)
5.ESP8266连接测试
指令
完整命令列表
- 连接命令(LC+Connect)
格式:
LC+Connect:"产品ID","设备名称","用户名","密码"
根据您的配置:
LC+Connect:"5af2tgcpsX","0001","5af2tgcpsX","密码"
- 发送数据命令(LC+Send)
发送到 dome1 物模型:
发送整数:
LC+Send:"wd":25LC+Send:"dome1":100LC+Send:"dome1":0LC+Send:"dome1":-10
发送浮点数:
LC+Send:"dome1":25.5LC+Send:"dome1":65.8LC+Send:"dome1":0.0LC+Send:"dome1":-10.3
发送字符串:
LC+Send:"dome1":"hello"LC+Send:"dome1":"status_ok"LC+Send:"dome1":"online"
发送到 dome2 物模型:
发送整数:
LC+Send:"dome2":50LC+Send:"dome2":200LC+Send:"dome2":0LC+Send:"dome2":-20
发送浮点数:
LC+Send:"dome2":50.5LC+Send:"dome2":75.8LC+Send:"dome2":0.0LC+Send:"dome2":-20.5
发送字符串:
LC+Send:"dome2":"world"LC+Send:"dome2":"status_error"LC+Send:"dome2":"offline
5.1连接上云



stm32连接上云
ESP8266.H
cpp
#ifndef __ESP8266_H
#define __ESP8266_H
#include "sys.h"
void ESP8266_Init(uint32_t BaudRate);
void Esp8266Cont(void);
void Serial_SendString(char *String);
void SendToCloud(const char *model_name, int value);
void SendToCloudFloat(const char *model_name, float value);
void SendToCloudString(const char *model_name, const char *str_value);
#endif
ESP8266.C
cpp
#include "esp8266.h"
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "lcd.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h> // 增加math.h头文件
#include <ctype.h> // 增加math.h头文件
#include <limits.h> // 增加math.h头文件
// 兼容嵌入式环境的NAN定义(如果编译器不支持)
#ifndef NAN
#define NAN (0.0/0.0)
#endif
// 函数声明
uint8_t CheckStringInBuffer(uint8_t *buffer, uint16_t len, const char *str);
int ParseMQTTParameterInt(uint8_t *buffer, uint16_t len, const char *param_name);
float ParseMQTTParameterFloat(uint8_t *buffer, uint16_t len, const char *param_name);
int IsFloatNaN(float value); // 新增NaN判断函数
void SendToCloud(const char *model_name, int value);
void SendToCloudFloat(const char *model_name, float value);
void SendToCloudString(const char *model_name, const char *str_value);
//数组
#define USART_RX_BUFFER_SIZE 1024
uint8_t Uart_GetRxFlag = 0;
uint8_t usart_rxbuffer[USART_RX_BUFFER_SIZE]; //接收的数据
uint16_t usart_rxlen = 0;
uint8_t usart_txbuffer[USART_RX_BUFFER_SIZE]; //发送数据
extern u8 maxMq2,maxMq135,maxWd,maxSd;
u8 ktd_value = 0; // 新增ktd参数存储变量
//硬件定义
// USART1 时钟源在 APB2,总线使能要用 RCC_APB2Periph_USART1
#define USARTClock RCC_APB2Periph_USART1 //串口时钟
#define PINClock RCC_APB2Periph_GPIOA //管脚时钟
#define DMAClock RCC_AHBPeriph_DMA1 //DMA时钟
#define TX GPIO_Pin_9
#define RX GPIO_Pin_10
#define PIN GPIOA
#define USART USART1
#define USARTIRQ USART1_IRQn
//注意8266设置成115200
// ONENET MQTT连接参数设置
// 产品ID
static const char *product_ID = "5af2tgcpsX";
// 设备名称
static const char *CLIENT_ID = "0001";
// MQTT用户名
static const char *USERNAME = "5af2tgcpsX";
// MQTT密码(Token)
static const char *PASSWORD = "";
void ESP8266_Init(uint32_t BaudRate)
{
/*开启时钟*/
// USART1 位于 APB2,总线时钟必须用 APB2 使能,否则串口会假死
RCC_APB2PeriphClockCmd(USARTClock, ENABLE); // 开启 USART1 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
RCC_AHBPeriphClockCmd(DMAClock, ENABLE); // 使能 DMA1 时钟
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = TX;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(PIN, &GPIO_InitStructure); //将PA2引脚初始化为复用推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = RX;
GPIO_Init(PIN, &GPIO_InitStructure); //将PA3引脚初始化为上拉输入
/*USART初始化*/
USART_InitTypeDef USART_InitStructure; //定义结构体变量
USART_InitStructure.USART_BaudRate = BaudRate; //波特率
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //硬件流控制,不需要
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; //模式,发送模式和接收模式均选择
USART_InitStructure.USART_Parity = USART_Parity_No; //奇偶校验,不需要
USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位,选择1位
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长,选择8位
USART_Init(USART, &USART_InitStructure); //将结构体变量交给USART_Init,配置USART2
/*中断输出配置*/
USART_ITConfig(USART, USART_IT_IDLE, ENABLE); //开启串口空闲中断
// RX DMA1 通道5 (USART1_RX 对应 DMA1 Channel5)
DMA_InitTypeDef DMA_InitStructure; //定义结构体变量
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART->DR; //外设基地址,给定形参AddrA
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设数据宽度,选择字节,对应8为的USART数据寄存器
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址自增,选择失能,始终以USART数据寄存器为源
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)usart_rxbuffer; //存储器基地址,给定存放USART数据寄存器的全局数组
DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte; //存储器数据宽度,选择字节,与源数据宽度对应
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器地址自增,选择使能,每次转运后,数组移到下一个位置
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //数据传输方向,选择由外设到存储器
DMA_InitStructure.DMA_BufferSize = USART_RX_BUFFER_SIZE; //转运的数据大小(转运次数)
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //模式,选择正常模式(非循环)
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //非存储器到存储器模式
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //优先级,选择中等
DMA_Init(DMA1_Channel5, &DMA_InitStructure); //将结构体变量交给DMA_Init,配置DMA1的通道5
/*使能USART2的DMA接收*/
USART_DMACmd(USART, USART_DMAReq_Rx, ENABLE);
/*启动DMA接收*/
DMA_Cmd(DMA1_Channel5, ENABLE);
/*NVIC配置*/
NVIC_InitTypeDef NVIC_InitStructure; //定义结构体变量
NVIC_InitStructure.NVIC_IRQChannel = USARTIRQ; //选择配置NVIC
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //指定NVIC线路使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //指定NVIC线路的抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //指定NVIC线路的响应优先级为1
NVIC_Init(&NVIC_InitStructure); //将结构体变量交给NVIC_Init,配置NVIC外设
/*USART使能*/
USART_Cmd(USART, ENABLE); //使能USART2,串口开始运行
}
void USART1_IRQHandler(void)
{
if (USART_GetITStatus(USART, USART_IT_IDLE) == SET) //判断是否是USART2的接收事件触发的中断
{
/* 清除空闲中断标志 */
volatile uint32_t temp;
temp = USART->SR; // 读取状态寄存器
temp = USART->DR; // 读取数据寄存器
(void)temp;
/* 计算接收到的数据长度 */
usart_rxlen = USART_RX_BUFFER_SIZE - DMA_GetCurrDataCounter(DMA1_Channel5);
/* 设置接收完成标志 */
if (usart_rxlen > 0)
{
Uart_GetRxFlag = 1;
}
/* 重新启动DMA接收 */
DMA_Cmd(DMA1_Channel5, DISABLE); // 关闭DMA
DMA_SetCurrDataCounter(DMA1_Channel5, USART_RX_BUFFER_SIZE); // 重新设置传输数量
DMA_Cmd(DMA1_Channel5, ENABLE); // 重新开启DMA
}
}
void serialPortForwarding(uint8_t *Array, uint16_t Length)
{
uint16_t i;
for (i = 0; i < Length; i ++) //遍历数组
{
USART_SendData(USART, Array[i]); //将字节数据写入数据寄存器
while (USART_GetFlagStatus(USART, USART_FLAG_TXE) == RESET); //等待发送完成
}
}
u8 step;
void Serialportparsing(){
if(Uart_GetRxFlag){
//串口一转运方便调试
serialPortForwarding(usart_rxbuffer, usart_rxlen);
// 检查接收到的数据并更新状态机
if(CheckStringInBuffer(usart_rxbuffer, usart_rxlen, "Parameter:OK"))
{
if(step < 1) step = 1;
}
if(CheckStringInBuffer(usart_rxbuffer, usart_rxlen, "wifi ok"))
{
if(step < 2) step = 2;
}
if(CheckStringInBuffer(usart_rxbuffer, usart_rxlen, "ONENET MQTT Connected") ||
CheckStringInBuffer(usart_rxbuffer, usart_rxlen, "MQTT Connected!"))
{
step = 3;
}
// 检查是否是MQTT下行控制指令
if(CheckStringInBuffer(usart_rxbuffer, usart_rxlen, "\"method\":\"control\"") &&
CheckStringInBuffer(usart_rxbuffer, usart_rxlen, "\"params\""))
{
step = 3;
OLED_ShowCH(0,0,"1");
// 解析ktd参数(新增)
int temp_val = ParseMQTTParameterInt(usart_rxbuffer, usart_rxlen, "ktd");
if(temp_val >= 0)
{
ktd_value = (u8)temp_val;
}
}
else if(step == 3)
{
// 兼容旧格式解析
int temp_val = ParseMQTTParameterInt(usart_rxbuffer, usart_rxlen, "maxqt");
if(temp_val >= 0) maxMq135 = (u8)temp_val;
temp_val = ParseMQTTParameterInt(usart_rxbuffer, usart_rxlen, "maxyw");
if(temp_val >= 0) maxMq2 = (u8)temp_val;
temp_val = ParseMQTTParameterInt(usart_rxbuffer, usart_rxlen, "maxwd");
if(temp_val >= 0) maxWd = (u8)temp_val;
temp_val = ParseMQTTParameterInt(usart_rxbuffer, usart_rxlen, "maxsd");
if(temp_val >= 0) maxSd = (u8)temp_val;
}
// 清空接收缓冲区
memset(usart_rxbuffer, 0, usart_rxlen);
usart_rxlen = 0;
Uart_GetRxFlag = 0;
}
}
void Serial_SendByte(uint8_t Byte)
{
USART_SendData(USART, Byte);
while (USART_GetFlagStatus(USART, USART_FLAG_TXE) == RESET);
}
void Serial_SendArray(uint8_t *Array, uint16_t Length)
{
uint16_t i;
for (i = 0; i < Length; i ++)
{
Serial_SendByte(Array[i]);
}
}
void Serial_SendString(char *String)
{
uint8_t i;
for (i = 0; String[i] != '\0'; i ++)
{
Serial_SendByte(String[i]);
}
}
u8 step = 0;
// 检查接收缓冲区中是否包含指定字符串
uint8_t CheckStringInBuffer(uint8_t *buffer, uint16_t len, const char *str)
{
uint16_t str_len = strlen(str);
if(str_len == 0 || len < str_len) return 0;
for(uint16_t i = 0; i <= len - str_len; i++)
{
if(memcmp(&buffer[i], str, str_len) == 0)
{
return 1;
}
}
return 0;
}
/**
* 解析MQTT JSON中的整数参数
* 支持格式:{"method":"control","params":{"ktd":3}}
* @param buffer: 接收缓冲区
* @param len: 数据长度
* @param param_name: 要解析的参数名
* @return: 解析到的整数值,-1表示解析失败
*/
int ParseMQTTParameterInt(uint8_t *buffer, uint16_t len, const char *param_name)
{
// 安全检查
if(buffer == NULL || param_name == NULL || len == 0) return -1;
// 将缓冲区转为字符串(添加结束符)
char temp_buf[USART_RX_BUFFER_SIZE + 1];
memcpy(temp_buf, buffer, len);
temp_buf[len] = '\0';
// 查找params对象起始位置
char *params_start = strstr(temp_buf, "\"params\":{");
if(params_start == NULL) return -1;
// 移动到params对象内部
params_start += 9; // 跳过 "\"params\":{"
// 查找参数名
char param_pattern[32];
snprintf(param_pattern, sizeof(param_pattern), "\"%s\":", param_name);
char *param_pos = strstr(params_start, param_pattern);
if(param_pos == NULL) return -1;
// 移动到参数值位置
param_pos += strlen(param_pattern);
// 跳过空格/制表符/换行符
while(*param_pos == ' ' || *param_pos == '\t' || *param_pos == '\n' || *param_pos == '\r')
{
param_pos++;
if(param_pos >= temp_buf + len) return -1;
}
// 检查是否是数字(支持负数)
if(!isdigit(*param_pos) && *param_pos != '-') return -1;
// 解析整数
char *end_ptr;
long value = strtol(param_pos, &end_ptr, 10);
// 验证解析结果
if(end_ptr == param_pos || value > INT_MAX || value < INT_MIN) return -1;
return (int)value;
}
/**
* 解析MQTT JSON中的浮点参数
* @param buffer: 接收缓冲区
* @param len: 数据长度
* @param param_name: 要解析的参数名
* @return: 解析到的浮点数值,NAN表示解析失败
*/
float ParseMQTTParameterFloat(uint8_t *buffer, uint16_t len, const char *param_name)
{
// 安全检查
if(buffer == NULL || param_name == NULL || len == 0) return NAN;
// 将缓冲区转为字符串(添加结束符)
char temp_buf[USART_RX_BUFFER_SIZE + 1];
memcpy(temp_buf, buffer, len);
temp_buf[len] = '\0';
// 查找params对象起始位置
char *params_start = strstr(temp_buf, "\"params\":{");
if(params_start == NULL) return NAN;
// 移动到params对象内部
params_start += 9;
// 查找参数名
char param_pattern[32];
snprintf(param_pattern, sizeof(param_pattern), "\"%s\":", param_name);
char *param_pos = strstr(params_start, param_pattern);
if(param_pos == NULL) return NAN;
// 移动到参数值位置
param_pos += strlen(param_pattern);
// 跳过空格/制表符/换行符
while(*param_pos == ' ' || *param_pos == '\t' || *param_pos == '\n' || *param_pos == '\r')
{
param_pos++;
if(param_pos >= temp_buf + len) return NAN;
}
// 检查是否是数字(支持负数和小数点)
if(!isdigit(*param_pos) && *param_pos != '-' && *param_pos != '.') return NAN;
// 解析浮点数
char *end_ptr;
float value = strtof(param_pos, &end_ptr);
// 验证解析结果
if(end_ptr == param_pos) return NAN;
return value;
}
/**
* 判断浮点数是否为NAN(兼容嵌入式环境)
* @param value: 要判断的浮点值
* @return: 1表示是NAN,0表示不是
*/
int IsFloatNaN(float value)
{
// NAN的特性:不等于自身
return (value != value) ? 1 : 0;
}
// 发送整数数据到云端
void SendToCloud(const char *model_name, int value)
{
char send_cmd[128];
sprintf(send_cmd, "LC+Send:\"%s\":%d\r\n", model_name, value);
Serial_SendString(send_cmd);
}
// 发送浮点数数据到云端
void SendToCloudFloat(const char *model_name, float value)
{
// 检查是否为无效值
if(IsFloatNaN(value)) return;
char send_cmd[128];
sprintf(send_cmd, "LC+Send:\"%s\":%.2f\r\n", model_name, value);
Serial_SendString(send_cmd);
}
// 发送字符串数据到云端
void SendToCloudString(const char *model_name, const char *str_value)
{
if(str_value == NULL) return;
char send_cmd[128];
sprintf(send_cmd, "LC+Send:\"%s\":\"%s\"\r\n", model_name, str_value);
Serial_SendString(send_cmd);
}
//连接8266
u8 step0_sent = 0;
u8 isShow=1;
u8 lin=6;
void Esp8266Cont(){
switch(step){
case 0:
if(step0_sent == 0)
{
char connect_cmd[512];
snprintf(connect_cmd, sizeof(connect_cmd),
"LC+Connect:\"%s\",\"%s\",\"%s\",\"%s\"\r\n",
product_ID, CLIENT_ID, USERNAME, PASSWORD);
Serial_SendString(connect_cmd);
step0_sent = 1;
}
isShow?OLED_ShowCH(0,lin,"Parameter"):OLED_ShowCH(0,lin,"");
break;
case 1:
isShow?OLED_ShowCH(0,lin,"await WIFI"):OLED_ShowCH(0,lin,"");
break;
case 2:
isShow?OLED_ShowCH(0,lin,"await MQTT"):OLED_ShowCH(0,lin,"");
break;
case 3:
isShow?OLED_ShowCH(0,lin,"MQTT ONLINE"):OLED_ShowCH(0,lin,"");
break;
}
Serialportparsing();
}
说明:更改对应的头文件
static const char *product_ID = "5af2tgcpsX";
// 设备名称
static const char *CLIENT_ID = "0001";
// MQTT用户名
static const char *USERNAME = "5af2tgcpsX";
// MQTT密码(Token)
static const char *PASSWORD = "";
反向控制部分
在ParseMQTTParameterInt修改物体模型名称即可
main
cpp
ESP8266_Init(115200); //初始化
void oneNet(){
if(time_count>=200){
Esp8266Cont();
maxMq2=maxMq2;
maxSd=maxSd;
maxMq135=maxMq135;
maxMq2=maxMq2;
// Serialportparsing();
time_count=0;
// BEEP=!BEEP;
if(step>=3){
SendToCloud("hw",HW);
delay_ms(1);
SendToCloud("qt",mq135);
delay_ms(1);
SendToCloud("sd",humi);
delay_ms(1);
SendToCloud("wd",temp);
delay_ms(1);
SendToCloud("yw",mq2);
delay_ms(1);
// SendToCloud("qt",mq135);
// delay_ms(1);
// SendToCloud("sd",humi);
// delay_ms(1);
// SendToCloud("wd",temp);
// delay_ms(1);
// SendToCloud("yw",mq2);
delay_ms(1);
}
}
}