【增强版ESP32C3无线串口&电台实战开发】
增强版ESP32C3无线485串口&电台实战开发
ESP32接入国产大模型之腾讯混元
前言
随着物联网技术的快速发展,ESP32系列芯片因其强大的性能和丰富的功能,成为了物联网开发的热门选择。而ESPNOW作为ESP32的一种高速无线通信协议,无需WiFi网络即可实现设备间的点对点通讯,非常适合传感器数据传输、远程控制等场景。
本文将详细介绍如何利用Trae开发环境结合豆包大模型,现在都直接用trae进行esp32的开发,完全可以代替arduino和vs code,编译下载全代码AI,快速实现ESP32C3之间的ESPNOW无线串口&电台系统。Trae作为新一代AI辅助开发工具,能大幅提升开发效率,让代码编写更加智能高效。
🔧 **
https://www.trae.cn/**:使用豆包大模型辅助开发,让ESP32开发事半功倍!
请大家点击豆包火山注册地址,不注册是不能完成下面的实验哦:https://t.vncps.com/5LOve
谢谢啦大家的支持💖💖💖

一、豆包大模型与Trae开发环境
1.1 豆包大模型在ESP32开发中的应用
豆包大模型可以帮助我们:
- 快速生成代码:根据需求描述自动生成ESP32相关代码
- 解决技术问题:解答开发过程中遇到的技术难题
- 优化代码结构:提供代码优化建议,提高代码质量
- 学习新技术:快速了解ESP32的新功能和使用方法
1.2 Trae开发环境优势
Trae作为新一代AI辅助开发工具,相比传统VSCode+PlatformIO有以下优势:
- AI智能补全:基于豆包大模型的智能代码补全,大幅提升编码效率
- 上下文理解:能够理解整个项目的上下文,提供更准确的开发建议
- 无缝集成:内置PlatformIO支持,无需额外配置
- 实时协作:支持多人实时协作开发
- 云端同步:代码自动云端备份,安全可靠
1.3 注册火山引擎并使用Trae
- 访问火山引擎注册地址:
https://t.vncps.com/5LOve - 完成注册并登录
- 订阅火山CodePlan,畅享Trae中所有模型
请大家点击豆包火山注册地址:https://t.vncps.com/5LOve
方舟 Coding Plan 支持 Doubao、GLM、DeepSeek、Kimi 等模型,工具不限,现在订阅折上9折,低至8.9元,订阅越多越划算!立即订阅:https://volcengine.com/L/2p_L1OTLQZw/ 邀请码:TVGNH4JT
访问火山方舟 Coding Plan 新用户特惠活动,按需订阅套餐。套餐介绍参见套餐概览https://www.volcengine.com/docs/82379/1925114?lang=zh。
在开通管理页面https://console.volcengine.com/ark/region:ark+cn-beijing/openManagement?LLM=%7B%7D&advancedActiveKey=subscribe选择或切换目标模型,无需在工具中额外变更模型配置。
-
下载并安装Trae客户端
官网地址:https://www.trae.cn/
-
在Trae中Platformio创建ESP32项目

二、项目概述
本项目实现了一个基于ESP32C3的ESPNOW无线串口&电台系统,具有以下功能:
- 设备自动配对与连接管理
- 双向数据透明传输
- 配置信息持久化存储
- AT指令配置界面
- 连接状态实时监测
2.1 系统框架图
2.2 配置流程图
三、硬件准备
3.1 所需零件
- ESP32C3开发板(2块)

【下单链接】[https://s.click.taobao.com/y793qHn](https://s.click.taobao.com/y793qHn,一定要安装天线测试
【下单链接】https://s.click.taobao.com/FUJ3xfn,ESP32C3 PRO MINI开发板板载ESP32-C3FH4芯片模块wifi 蓝牙开发板也是可以的,我采用这个小巧模块自带陶瓷天线
- WIN10/WIN11电脑:编写代码调试功能
- USB数据线x2:用于烧录代码和串口通信。
- 天线(推荐使用外置天线,增强通信距离)
- USB数据线(2条)
- 面包板及杜邦线(可选,用于扩展)
3.2 硬件连接
- LED指示灯:连接到GPIO8(ESP32C3)
- 天线:连接到开发板的天线接口
- 串口连接:
- Serial:USB口,用于配置和调试
- MySerial0:普通串口,用于数据传输
- MySerial1:485口,用于工业设备通信
原理图
PCB板图
我用solidworks2024设计了一个外壳
然后发给拓竹H3D打印切片
PCB通过嘉立创生产后得到了屎黄色黄色板子🤣🤣🤣
人工手动贴片两块
这里我们为了提高esp32c3的天线信号增益,手动调整PCB的板载天线改为外置棒杆天线
修改完毕后,我们就将3D外壳、PCB、杜邦线还有天线一起组装后,大约需要1天反复调整后得到小巧的数传电台啦
这里我把我常用的电台都放在这里,给大家欣赏一下

突然发现我的小电台超好看😘😘😘
四、软件配置
首先需要VScode安装Platformio,然后Trae安装Platformio插件调用即可
! https://i-blog.csdnimg.cn/direct/6ccc36df04704e4cbb9ad4becfc23c9a.png
全程交给Trae进行编程外加写博客
! https://i-blog.csdnimg.cn/direct/55a8a6f8d5094860888ec14d42316cfd.png
4.1 PlatformIO配置(platformio.ini)
下面是esp32c3配置代码:
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
; [env:seeed-xiao-esp32-c6]
; platform = Seeed Studio
; board = seeed-xiao-esp32-c6
[env:seeed-xiao-esp32-c3]
platform = Seeed Studio
board = seeed-xiao-esp32-c3
framework = arduino
; 监视器波特率
monitor_speed = 115200
monitor_filters = esp32_exception_decoder
lib_deps =
SPIFFS
board_build.partitions = partitions.csv
build_flags = -std=gnu++17
upload_protocol = esptool
upload_resetmethod = nodemcu
配置说明:
- 支持ESP32C3开发板
- 使用Arduino框架开发
- 依赖库包括SPIFFS(文件系统)
- 自定义分区表配置
- 启用C++17标准
4.2 分区表配置(partitions.csv)
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x140000,
app1, app, ota_1, 0x150000,0x140000,
spiffs, data, spiffs, 0x290000,0x160000,
coredump, data, coredump,0x3F0000,0x10000,
分区说明:
nvs:用于存储非易失性数据otadata:OTA更新数据app0/app1:应用程序分区(支持OTA双分区)spiffs:SPIFFS文件系统分区,用于存储配置文件coredump:崩溃转储分区
五、核心代码分析
5.1 主程序结构(main.cpp)
#include <Arduino.h>
#include <WiFi.h>
#include <esp_now.h>
#include <esp_wifi.h>
#include <string.h>
#include <SPIFFS.h> // 添加SPIFFS支持
#include <HardwareSerial.h>
#define LED_PIN 8 // esp32c3 GPIO8 连接到LED,esp32c6 GPIO15
// #define LED_signal 9
#define LED_connect 10
#define C485 2
// 使用更安全的GPIO引脚(避免使用GPIO0/2等有特殊功能的引脚)
// const int RX_PIN = 1; // 推荐使用的RX引脚
// const int TX_PIN = 0; // 推荐使用的TX引脚
// SoftwareSerial MySerial1(RX_PIN, TX_PIN); // RX, TX
HardwareSerial MySerial0(0);
HardwareSerial MySerial1(1);
// #define LED_PIN 15 //esp32c3 GPIO8 连接到LED,esp32c6 GPIO15
#define CONFIG_FILE "/espnow_config.json" // SPIFFS配置文件路径
#define CURRENT_VERSION "1.0" // 当前版本号
// 默认波特率
#define DEFAULT_BAUD_RATE 115200
static uint8_t selfMac[6];
static uint8_t peerMac[6];
static bool isPaired = false;
static bool isConnected = false;
static bool configMode = false;
String serialBuffer = ""; // 用于接收串口数据的缓冲区
esp_now_peer_info_t peer;
const unsigned long CONNECTION_TIMEOUT = 10000; // 增加超时时间
unsigned long lastBlink = 0;
unsigned long lastSent = 0;
unsigned long lastReceived = 0;
bool data = false;
// 波特率设置
int baudRate = DEFAULT_BAUD_RATE; // 当前波特率
// 连接状态更新时间
unsigned long lastConnectionUpdate = 0;
// 格式化 MAC 地址
String formatMac(const uint8_t *mac)
{
char buf[18];
snprintf(buf, sizeof(buf), "%02X:%02X:%02X:%02X:%02X:%02X",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
return String(buf);
}
void print(String s)
{
Serial.println(s);
MySerial1.println(s);
}
// ================== SPIFFS ==================
// 保存配对MAC地址和版本信息到SPIFFS
bool saveConfig()
{
if (!SPIFFS.begin(true))
{
print("❌ An error occurred while mounting SPIFFS");
return false;
}
File configFile = SPIFFS.open(CONFIG_FILE, "w");
if (!configFile)
{
print("❌ Failed to open config file for writing");
return false;
}
// 创建JSON格式的数据 - 包含波特率配置
String configJson = "{";
configJson += "\"version\":\"" + String(CURRENT_VERSION) + "\",";
configJson += "\"peer_mac\":\"" + formatMac(peerMac) + "\",";
configJson += "\"baud_rate\":" + String(baudRate);
configJson += "}";
configFile.print(configJson);
configFile.close();
print("✅ Config saved to SPIFFS");
return true;
}
bool parseMacAddress(const String &input, uint8_t *outMac)
{
String clean = input;
clean.replace(":", "");
clean.replace("-", "");
clean.replace(" ", "");
if (clean.length() != 12)
return false;
for (int i = 0; i < 6; i++)
{
String byteStr = clean.substring(i * 2, i * 2 + 2);
outMac[i] = (uint8_t)strtol(byteStr.c_str(), NULL, 16);
}
return true;
}
// 从SPIFFS加载配对MAC地址和版本信息
bool loadConfig()
{
if (!SPIFFS.begin(true))
{
print("❌ An error occurred while mounting SPIFFS");
return false;
}
File configFile = SPIFFS.open(CONFIG_FILE, "r");
if (!configFile)
{
print("❌ Failed to open config file for reading");
return false;
}
String json = configFile.readString();
configFile.close();
// 解析JSON数据 - 包括波特率
int versionStart = json.indexOf("\"version\":\"") + 11;
int versionEnd = json.indexOf("\"", versionStart);
int macStart = json.indexOf("\"peer_mac\":\"") + 12;
int macEnd = json.indexOf("\"", macStart);
int baudStart = json.indexOf("\"baud_rate\":") + 12;
int baudEnd = json.indexOf(",", baudStart);
if (baudStart > 12) { // 检查是否有波特率配置
String baudStr = json.substring(baudStart, baudEnd);
baudRate = baudStr.toInt();
// 验证波特率是否为支持的值
if (baudRate != 9600 && baudRate != 38400 && baudRate != 115200) {
baudRate = DEFAULT_BAUD_RATE; // 使用默认值
}
} else {
baudRate = DEFAULT_BAUD_RATE; // 没有保存的波特率配置时使用默认值
}
if (versionStart > 11 && macStart > 12) // 检查是否找到字段
{
String loadedVersion = json.substring(versionStart, versionEnd);
String macStr = json.substring(macStart, macEnd);
print("Loaded version: " + loadedVersion);
print("Loaded MAC: " + macStr);
print("Loaded baud rate: " + String(baudRate));
// 尝试解析MAC地址
return parseMacAddress(macStr, peerMac);
}
return false;
}
// 清除SPIFFS中的配置
void clearConfig()
{
if (!SPIFFS.begin(true))
{
print("❌ An error occurred while mounting SPIFFS");
return;
}
if (SPIFFS.exists(CONFIG_FILE))
{
SPIFFS.remove(CONFIG_FILE);
print("✅ Config file cleared from SPIFFS");
baudRate = DEFAULT_BAUD_RATE; // 重置为默认波特率
}
}
// ========================================
bool attemptPairWith(const uint8_t *targetMac)
{
memset(&peer, 0, sizeof(peer));
memcpy(peer.peer_addr, targetMac, 6);
peer.channel = 0;
peer.encrypt = false;
if (esp_now_add_peer(&peer) != ESP_OK)
return false;
const char *testMsg = "CONN";
return (esp_now_send(targetMac, (uint8_t *)testMsg, strlen(testMsg)) == ESP_OK);
}
// 连接检测任务
void connectionCheckTask(void *pvParameters)
{
while (1)
{
if (attemptPairWith(peerMac))
{
isConnected = true;
lastConnectionUpdate = millis(); // 更新连接时间
print("✅ Reconnected!");
digitalWrite(LED_PIN, LOW); // 点亮
}
else
{
isConnected = false; // 修正:断开连接时更新状态
lastConnectionUpdate = millis(); // 更新连接时间
// print("❌ Connection lost!");
digitalWrite(LED_PIN, HIGH); // 熄灭
}
vTaskDelay(pdMS_TO_TICKS(CONNECTION_TIMEOUT)); // 增加检测间隔到5秒
}
}
void printhelp()
{
print("\nESP32-C3 ESP-NOW Enhanced (with Debug Log)");
print("Enter config mode with '+++', then use AT commands:");
print(" AT+HELP Show this help");
print(" AT+PAIR=<MAC> Pair with device");
print(" AT+CLEAR Clear paired device");
print(" AT+MAC Get own MAC");
print(" AT+FRIEND Get paired device MAC");
print(" AT+TEST Test communication");
print(" AT+RESTART Restart device");
print(" AT+BAUD=<rate> Set baud rate (9600/38400/115200)");
print(" AT+GETBAUD Get current baud rate");
print(" AT+SYSINFO Print system parameters");
print(" ATO Exit config mode");
}
// 打印系统参数
void printSystemInfo()
{
// 更新连接状态 - 基于配对状态和最后接收数据时间
unsigned long now = millis();
print("=== ESP32c3 Radio System Parameters by @2345vor ===");
print("Firmware Version: " + String(CURRENT_VERSION));
print("My MAC Address: " + formatMac(selfMac));
if (isPaired) {
print("Peer MAC Address: " + formatMac(peerMac));
} else {
print("Peer MAC Address: Not Paired");
}
print("Current Baud Rate: " + String(baudRate));
print("Connection Status: " + String(isConnected ? "Connected" : "Disconnected"));
print("Pairing Status: " + String(isPaired ? "Paired" : "Not Paired"));
print("Last Received: " + String((now - lastReceived) / 1000.0) + "s ago");
print("Last Connection Update: " + String((now - lastConnectionUpdate) / 1000.0) + "s ago");
print("=========================");
}
// 处理AT指令
void handleATCommand(const String &command)
{
if (command.equalsIgnoreCase("AT+TEST"))
{
if (isPaired)
{
String testMsgStr = formatMac(selfMac) + " send message to " + formatMac(peerMac) + ":TEST";
const char *testMsg = testMsgStr.c_str();
if (esp_now_send(peerMac, (uint8_t *)testMsg, strlen(testMsg)) == ESP_OK)
{
print("TEST OK");
}
else
{
print("TEST FAIL");
}
}
else
{
print("ERROR: Not paired");
}
}
else if (command.startsWith("AT+PAIR="))
{
String macStr = command.substring(8);
if (parseMacAddress(macStr, peerMac))
{
if (attemptPairWith(peerMac))
{
saveConfig(); // 使用新的SPIFFS保存函数
print("SaveConfig OK");
}
else
{
print("ERROR: Pair failed");
}
}
else
{
print("ERROR: Invalid MAC");
}
}
else if (command.equalsIgnoreCase("AT+CLEAR"))
{
clearConfig(); // 使用新的SPIFFS清除函数
print("ClearConfig OK");
}
else if (command.equalsIgnoreCase("AT+MAC"))
{
print(formatMac(selfMac));
}
else if (command.equalsIgnoreCase("AT+FRIEND"))
{
if (isPaired)
{
print(formatMac(peerMac));
}
else
{
print("ERROR: Not paired device");
}
}
else if (command.equalsIgnoreCase("AT+RESTART"))
{
print("Restarting...");
delay(100);
ESP.restart();
}
else if (command.equalsIgnoreCase("AT+HELP"))
{
printhelp();
}
else if (command.startsWith("AT+BAUD="))
{
String baudStr = command.substring(8);
int newBaud = baudStr.toInt();
// 检查是否是支持的波特率
if (newBaud == 9600 || newBaud == 38400 || newBaud == 115200) {
baudRate = newBaud;
// 重新初始化串口
MySerial0.updateBaudRate(baudRate);
MySerial1.updateBaudRate(baudRate);
saveConfig(); // 保存新波特率到配置文件
print("Baud rate set to: " + String(baudRate));
} else {
print("ERROR: Unsupported baud rate. Use 9600, 38400, or 115200");
}
}
else if (command.equalsIgnoreCase("AT+GETBAUD"))
{
print("Current baud rate: " + String(baudRate));
}
else if (command.equalsIgnoreCase("AT+SYSINFO"))
{
printSystemInfo();
}
else if (command.equalsIgnoreCase("ATO"))
{
// 退出配置模式
configMode = false;
print("Exit config mode");
}
else
{
print("ERROR: Invalid command");
}
}
// 接收回调:带调试打印
void onDataRecv(const esp_now_recv_info_t *esp_now_info, const uint8_t *data, int len)
{
const uint8_t *mac = esp_now_info->src_addr; // 获取发送方的MAC地址
lastReceived = millis(); // 更新最后接收时间
// 检查是否来自配对设备
if (memcmp(mac, peerMac, 6) == 0)
{
isConnected = true; // 确认连接状态
lastConnectionUpdate = millis(); // 更新连接状态时间
isPaired = true; // 设置配对标志
// 特殊处理 CONN 消息,只用于连接测试,不转发
if (len == 4 && memcmp(data, "CONN", 4) == 0) {
// 这是一个连接测试请求,不需要转发
return;
}
}
// 直接转发数据到两个串口,保持原始数据完整性
Serial.write(data, len);
MySerial0.write(data, len);
MySerial1.write(data, len);
}
void setup()
{
pinMode(LED_PIN, OUTPUT);
// pinMode(LED_signal, OUTPUT);
pinMode(LED_connect, OUTPUT);
pinMode(C485, OUTPUT);
digitalWrite(C485, HIGH); // 初始灭灯
digitalWrite(LED_PIN, HIGH); // 初始灭灯
// digitalWrite(LED_signal, HIGH); // 初始灭灯
digitalWrite(LED_connect, HIGH); // 初始灭灯
Serial.begin(DEFAULT_BAUD_RATE); // 使用默认波特率初始化
MySerial0.begin(DEFAULT_BAUD_RATE, SERIAL_8N1, 20, 21);
// And configure MySerial1 on pins RX=D9, TX=D0
MySerial1.begin(DEFAULT_BAUD_RATE, SERIAL_8N1, 1, 0);
print("Initializing SPIFFS...");
// 初始化SPIFFS
if (!SPIFFS.begin(true))
{
print("❌ An error occurred while mounting SPIFFS");
// 如果SPIFFS挂载失败,尝试格式化
if (SPIFFS.format())
{
print("✅ SPIFFS formatted successfully");
if (!SPIFFS.begin(false))
{
print("❌ Failed to mount SPIFFS after formatting");
}
}
else
{
print("❌ Failed to format SPIFFS");
}
}
else
{
print("✅ SPIFFS mounted successfully");
}
printhelp();
WiFi.mode(WIFI_STA);
esp_wifi_set_promiscuous(true);
esp_wifi_set_channel(1, WIFI_SECOND_CHAN_NONE);
esp_wifi_set_promiscuous(false);
if (esp_now_init() != ESP_OK)
{
print("❌ ESP-NOW init failed!");
return;
}
esp_now_register_recv_cb(onDataRecv);
WiFi.macAddress(selfMac); // 使用WiFi库获取MAC地址
print(">>> MY MAC: " + formatMac(selfMac) + " <<<");
if (loadConfig()) // 使用新的SPIFFS加载函数
{
print("💾 Loaded peer: " + formatMac(peerMac));
if (attemptPairWith(peerMac))
{
isPaired = true; // 设置配对标志
isConnected = true; // 设置连接标志
lastReceived = millis(); // 记录最后接收时间
lastConnectionUpdate = millis(); // 记录连接更新时间
print("✅ Resumed pairing!");
}
else
{
print("❌ Resume failed");
clearConfig(); // 使用新的SPIFFS清除函数
}
}
// 创建连接检测任务
xTaskCreate(
connectionCheckTask,
"connectionCheckTask",
2048,
NULL,
5,
NULL);
print("🟢 Connection check task started");
// digitalWrite(LED_signal, LOW); // 初始灭灯
digitalWrite(LED_connect, LOW); // 初始灭灯
// 重新初始化串口使用加载的波特率
if (baudRate != DEFAULT_BAUD_RATE) {
Serial.begin(baudRate);
MySerial0.updateBaudRate(baudRate);
MySerial1.updateBaudRate(baudRate);
}
// 启动时打印系统参数
printSystemInfo();
}
void loop()
{
delayMicroseconds(10); // 使用微秒延迟,1000等同于1毫秒
// 处理软件串口(串口0)- 仅数传
if (MySerial0.available())
{
while (MySerial0.available())
{
char c = MySerial0.read();
serialBuffer += c;
if (c == '\n' || c == '\r')
{
if (isPaired && serialBuffer.length() > 0)
{
digitalWrite(LED_PIN, LOW);
esp_now_send(peerMac, (uint8_t *)serialBuffer.c_str(), serialBuffer.length());
lastSent = millis();
digitalWrite(LED_PIN, HIGH);
serialBuffer = "";
}
else if (!isPaired)
{
MySerial0.println("❌ Not paired with any device");
serialBuffer = "";
}
}
}
data = true;
}
// 处理软件串口(串口1)- 仅数传
if (MySerial1.available())
{
while (MySerial1.available())
{
char c = MySerial1.read();
serialBuffer += c;
if (c == '\n' || c == '\r')
{
if (isPaired && serialBuffer.length() > 0)
{
digitalWrite(LED_PIN, LOW);
esp_now_send(peerMac, (uint8_t *)serialBuffer.c_str(), serialBuffer.length());
lastSent = millis();
digitalWrite(LED_PIN, HIGH);
serialBuffer = "";
}
else if (!isPaired)
{
MySerial1.println("❌ Not paired with any device");
serialBuffer = "";
}
}
}
data = true;
}
// 处理硬件串口(串口0)- 配置+数传
if (!data && Serial.available())
{
// 逐字节读取,避免数据粘连
while (Serial.available())
{
char c = Serial.read();
serialBuffer += c;
// 检测"+++"序列
if (serialBuffer.length() >= 3 &&
serialBuffer.endsWith("+++"))
{
// 移除"+++"前的部分,保留可能的其他字符
int plusIndex = serialBuffer.lastIndexOf("+++", serialBuffer.length() - 3);
if (plusIndex >= 0)
{
serialBuffer = serialBuffer.substring(plusIndex);
// 进入配置模式
configMode = true;
Serial.println("AT OK");
printhelp();
serialBuffer = ""; // 清空缓冲区
break; // 跳出while循环
}
}
}
if (!configMode)
{
// 数传模式:发送数据到对端
if (isPaired && serialBuffer.length() > 0) // 只要配对就可以发送数据
{
digitalWrite(LED_PIN, LOW); // 点亮
esp_now_send(peerMac, (uint8_t *)serialBuffer.c_str(), serialBuffer.length());
lastSent = millis(); // 更新最后发送时间
digitalWrite(LED_PIN, HIGH); // 熄灭
serialBuffer = ""; // 发送后清空缓冲区
}
else if (!isPaired)
{
print("❌ Not paired with any device");
serialBuffer = ""; // 清空缓冲区
}
}
else
{
// 检查是否退出配置模式命令
if (serialBuffer.endsWith("\n") || serialBuffer.endsWith("\r"))
{
// 配置模式:处理AT指令
serialBuffer.trim();
if (!serialBuffer.isEmpty())
{
// 处理AT指令
handleATCommand(serialBuffer);
serialBuffer = ""; // 处理完后清空
}
}
}
}
data = false;
}
5.2 串口功能分配
本项目使用了三个串口,各自功能如下:
-
Serial:USB口,用于配置和调试
- 连接到电脑的USB接口
- 用于发送AT指令进行设备配置
- 用于查看系统状态和调试信息
-
MySerial0:普通串口,用于数据传输
- 连接到GPIO20和GPIO21
- 用于与普通串口设备通信
- 支持透明数据传输
-
MySerial1:485口,用于工业设备通信
- 连接到GPIO1和GPIO0
- 用于与RS-485工业设备通信
- 通过C485引脚(GPIO2)控制485芯片的收发状态
5.3 核心功能模块
-
设备配对与连接管理
- 通过AT+PAIR=指令配对目标设备
- 自动重连机制确保连接稳定
- 连接状态实时监测与LED指示
-
数据传输
- 支持双向透明数据传输
- 三个串口的数据都可以通过ESPNOW无线传输
- 数据传输时LED指示灯闪烁提示
-
配置管理
- 通过SPIFFS文件系统持久化存储配置
- 支持波特率配置(9600/38400/115200)
- 配置自动加载与验证
-
AT指令系统
- 丰富的AT指令集,支持设备配置和状态查询
- 配置模式与数传模式无缝切换
- 详细的帮助信息和错误提示
六、使用方法
6.1 设备配对
- 连接两个ESP32C3开发板到电脑
- 打开串口监视器,波特率设置为115200
- 在串口输入
+++进入配置模式 - 输入
AT+MAC获取本机MAC地址 - 在另一个设备上输入
AT+PAIR=<MAC>,其中<MAC>为第一个设备的MAC地址 - 配对成功后,设备会自动保存配置并进入数传模式
6.2 数据传输
- 从电脑发送数据:通过Serial(USB口)发送数据,会自动通过ESPNOW传输到配对设备
- 从普通串口发送数据:通过MySerial0发送数据,会自动通过ESPNOW传输到配对设备
- 从485口发送数据:通过MySerial1发送数据,会自动通过ESPNOW传输到配对设备
- 接收数据:ESPNOW接收到的数据会同时转发到三个串口
6.3 配置命令
| 命令 | 功能 | 示例 |
|---|---|---|
| AT+HELP | 显示帮助信息 | AT+HELP |
| AT+PAIR= | 配对目标设备 | AT+PAIR=9C:13:9E:CC:3B:88 |
| AT+CLEAR | 清除配对信息 | AT+CLEAR |
| AT+MAC | 获取本机MAC地址 | AT+MAC |
| AT+FRIEND | 获取配对设备MAC | AT+FRIEND |
| AT+TEST | 测试通信 | AT+TEST |
| AT+RESTART | 重启设备 | AT+RESTART |
| AT+BAUD= | 设置波特率9600/38400/115200 | AT+BAUD=115200 |
| AT+GETBAUD | 获取当前波特率 | AT+GETBAUD |
| AT+SYSINFO | 打印系统参数 | AT+SYSINFO |
| ATO | 退出配置模式 | ATO |
七、测试与调试
7.1 测试步骤
- 准备两个ESP32C3开发板,烧录相同的代码
- 按照6.1节的步骤进行设备配对
- 验证LED指示灯状态:配对成功后LED常亮
- 测试数据传输:从一个设备的任意串口发送数据,在另一个设备的所有串口查看是否接收到数据
- 测试连接稳定性:断开一个设备的电源,重新上电后观察是否自动重连
7.1.1 USB互发测试

可以正常收发数据2345vor和123
7.1.2 串口互发测试
记得手动添加\r或\n结束符哦👌👌👌

这里的串口0和串口1 485接口都已测试通过
7.2 常见问题与解决方案
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 配对失败 | MAC地址格式错误 | 确保MAC地址格式正确,不含空格或其他字符 |
| 连接不稳定 | 距离过远或干扰严重 | 靠近设备或减少干扰源,使用外置天线 |
| 数据传输失败 | 未配对或连接断开 | 重新配对设备,确保连接状态正常 |
| 串口无响应 | 波特率设置错误 | 使用AT+GETBAUD查看当前波特率,确保与串口监视器设置一致 |
八、总结
本项目成功实现了基于ESP32C3的增强版无线串口&电台系统,具有以下特点:
-
多串口支持:明确区分了三个串口的功能,Serial作为USB口用于配置和调试,MySerial0作为普通串口用于数据传输,MySerial1作为485口用于工业设备通信。
-
稳定可靠:采用ESPNOW协议实现高速无线通信,配合自动重连机制,确保连接稳定可靠。
-
易于配置:通过AT指令系统,用户可以方便地进行设备配对、波特率设置等操作。
-
灵活扩展:系统架构清晰,易于扩展其他功能,如传感器数据采集、远程控制等。
-
AI辅助开发:使用Trae结合豆包大模型,大幅提升了开发效率,让代码编写更加智能高效。
通过本项目,我们展示了如何利用ESP32C3和ESPNOW协议构建一个功能强大的无线串口&电台系统,为物联网设备间的通信提供了一种高效、可靠的解决方案。
🔧 **
https://www.trae.cn/**:使用豆包大模型辅助开发,让ESP32开发事半功倍!
请大家点击豆包火山注册地址,不注册是不能完成下面的实验哦:https://t.vncps.com/5LOve
谢谢啦大家的支持💖💖💖
九、扩展与展望
-
增加传感器支持:可以扩展系统,添加温湿度、光照等传感器,实现无线传感器网络。
-
实现OTA更新:通过ESPNOW实现设备固件的无线更新,方便系统维护和功能升级。
-
增加加密功能:对传输数据进行加密,提高系统安全性。
-
支持多设备网络:扩展为星型或 mesh 网络,支持更多设备的通信。
-
优化功耗:通过深度睡眠等技术,降低系统功耗,延长电池寿命。
通过不断完善和扩展,本系统可以应用于更多场景,如工业自动化、智能家居、环境监测等领域,为物联网应用提供更加灵活、可靠的通信解决方案。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)