本文记录了使用ESP32驱动TK8620 LoRa模块传输温湿度数据的完整过程,重点解决了数据传输中的格式转换和稳定性问题。
概述
在物联网项目中,经常需要将传感器数据通过无线模块传输到远端。本文使用ESP32+TK8620 LoRa模块构建了一个温湿度监测系统,通过实际调试解决了数据传输中的关键问题。
硬件组成
- 主控芯片 :ESP32
- 无线模块 :TK8620 LoRa模块
- 传感器 :SHT系列温湿度传感器
- 通信接口 :UART串口
问题现象:数据异常与传输不稳定
初始代码实现
void sendSensorData() {
Serial1.print("AT+SENDB=010203\r\n");`
float temperature = sht.getTemperature();
float humidity = sht.getHumidity();
Serial1.print("AT+SENDB=");
Serial1.print(temperature, 1);
Serial1.print(",");
Serial1.print(humidity, 1);
Serial1.print("\r\n");
}
遇到的问题
- 数据格式异常 :接收端显示
010203而没有期望的温湿度数据
- 传输不稳定 :频繁出现
AT_ERROR响应
- 数据解析困难 :接收到的数据无法正确解析为原始值
问题分析与解决方案
问题1:数据格式不匹配
根本原因 :ASCII文本格式与十六进制格式混淆
解决方案 :统一使用十六进制格式传输
void sendTemperatureHumidity() {
float temperature = sht.getTemperature();
float humidity = sht.getHumidity();
uint16_t tempInt = (uint16_t)(temperature * 10 + 0.5);
uint16_t humInt = (uint16_t)(humidity * 10 + 0.5);
Serial.print("原始数据 - 温度: ");
Serial.print(temperature, 1);
Serial.print("°C → ");
Serial.print(tempInt);
Serial.print(" (0x");
Serial.print(tempInt, HEX);
Serial.print(")");
char dataHex[9];
snprintf(dataHex, sizeof(dataHex), "%04X%04X", tempInt, humInt);
Serial1.print("AT+SENDB=");
Serial1.print(dataHex);
Serial1.print("\r\n");
}
完整实现代码
发送端完整代码
#include <HardwareSerial.h>
HardwareSerial loraSerial(1);
LORAManager loraManager;
void setup() {
Serial.begin(115200);
loraSerial.begin(115200, SERIAL_8N1, 16, 17);
initLoRaModule();
delay(1000);
}
void initLoRaModule() {
sendATCommand("AT+RST", 2000);
sendATCommand("AT+WORKMODE=21", 1000);
sendATCommand("AT+FREQ=473200000", 1000);
sendATCommand("AT+RATE=6", 1000);
sendATCommand("AT+TXP=15", 1000);
sendATCommand("AT+ADDR=01:02:03:04", 1000);
sendATCommand("AT+DEST=04:03:02:01", 1000);
sendATCommand("AT+ADDRFILTER=1", 1000);
}
String buildSensorDataHex() {
float temperature = sht.getTemperature();
float humidity = sht.getHumidity();
if (isnan(temperature) || isnan(humidity)) {
Serial.println("传感器数据读取失败");
return "";
}
uint16_t tempInt = (uint16_t)(temperature * 10 + 0.5);
uint16_t humInt = (uint16_t)(humidity * 10 + 0.5);
char dataHex[9];
snprintf(dataHex, sizeof(dataHex), "%04X%04X", tempInt, humInt);
Serial.print("传感器数据 - ");
Serial.print("温度: ");
Serial.print(temperature, 1);
Serial.print("°C, 湿度: ");
Serial.print(humidity, 1);
Serial.print("%, 十六进制: ");
Serial.println(dataHex);
return String(dataHex);
}
void loop() {
String hexData = buildSensorDataHex();
if (hexData.length() > 0) {
loraManager.sendData(hexData);
}
if (loraSerial.available()) {
String response = loraSerial.readString();
Serial.print("LoRa响应: ");
Serial.println(response);
loraManager.handleResponse(response);
}
delay(100);
}
void sendATCommand(const String& command, int timeout) {
loraSerial.println(command);
delay(timeout);
while(loraSerial.available()) {
String response = loraSerial.readString();
Serial.println("AT响应: " + response);
}
}
接收端完整代码
#include <HardwareSerial.h>
HardwareSerial loraSerial(1); // 使用UART1
void setup() {
Serial.begin(115200);
loraSerial.begin(115200, SERIAL_8N1, 16, 17);
// 初始化LoRa模块(配置与发送端对应)
initLoRaModule();
Serial.println("接收端就绪,等待数据...");
}
void initLoRaModule() {
sendATCommand("AT+RST", 2000);
sendATCommand("AT+WORKMODE=21", 1000);
sendATCommand("AT+FREQ=473200000", 1000);
sendATCommand("AT+RATE=6", 1000);
sendATCommand("AT+ADDR=04:03:02:01", 1000); // 与发送端DEST对应
sendATCommand("AT+DEST=01:02:03:04", 1000);
sendATCommand("AT+ADDRFILTER=1", 1000);
}
void loop() {
if (loraSerial.available()) {
String response = loraSerial.readString();
if (response.indexOf("+DI:") >= 0) {
processReceivedData(response);
}
}
}
void processReceivedData(const String& data) {
Serial.println("收到数据: " + data);
// 解析数据格式: +DI: LEN 8, SLOT 0, SNR 12, RSSI -60, Data 00FF01C8
int dataIndex = data.indexOf("Data ");
if (dataIndex >= 0) {
String hexData = data.substring(dataIndex + 5);
hexData.trim();
parseSensorData(hexData);
// 显示信号质量
displaySignalQuality(data);
}
}
void parseSensorData(const String& hexData) {
if (hexData.length() == 8) {
String tempHex = hexData.substring(0, 4);
String humHex = hexData.substring(4, 8);
uint16_t tempInt = strtoul(tempHex.c_str(), NULL, 16);
uint16_t humInt = strtoul(humHex.c_str(), NULL, 16);
float temperature = tempInt / 10.0;
float humidity = humInt / 10.0;
Serial.println("=== 传感器数据解析结果 ===");
Serial.print("温度: ");
Serial.print(temperature, 1);
Serial.println("°C");
Serial.print("湿度: ");
Serial.print(humidity, 1);
Serial.println("%");
Serial.println("==========================");
} else {
Serial.println("数据长度错误,无法解析");
}
}
void displaySignalQuality(const String& data) {
// 提取SNR和RSSI值
int snrIndex = data.indexOf("SNR ");
int rssiIndex = data.indexOf("RSSI ");
if (snrIndex >= 0 && rssiIndex >= 0) {
String snrStr = data.substring(snrIndex + 4, data.indexOf(",", snrIndex));
String rssiStr = data.substring(rssiIndex + 5, data.indexOf(",", rssiIndex));
Serial.print("信号质量 - SNR: ");
Serial.print(snrStr);
Serial.print(" dB, RSSI: ");
Serial.print(rssiStr);
Serial.println(" dBm");
}
}
关键调试技巧
1. 数据格式验证
在发送数据前,务必验证数据转换的正确性:
Serial.print("验证转换 - 浮点数: ");
Serial.print(value, 2);
Serial.print(" → 整数: ");
Serial.print(intValue);
Serial.print(" → 十六进制: 0x");
Serial.println(hexValue, HEX);
2. 传输状态监控
实时监控发送状态,避免缓冲区溢出:
loraSerial.println("AT+SENDB?");
delay(50);
while(loraSerial.available()) {
String response = loraSerial.readString();
Serial.println("缓冲区状态: " + response);
}
3. 信号质量评估
根据SNR和RSSI值评估链路质量:
- SNR > 10 dB :优秀
- RSSI > -60 dBm :信号强
- 数据完整性 :检查接收数据是否完整
性能优化建议
根据应用需求调整发送间隔:
- 实时监控 :1-5秒
- 常规监测 :10-60秒
- 节能模式 :1-5分钟
总结
成功解决了TK8620模块数据传输中的关键问题:
- 数据格式统一 :采用十六进制格式确保数据一致性
- 缓冲区管理 :实现状态机避免溢出
- 传输稳定性 :合适的发送间隔和错误处理
- 调试方法 :完善的调试信息输出
这些解决方案不仅适用于温湿度传输,也可以扩展到其他传感器数据的无线传输场景。