使用豆包大模型开发ESP32C3的ESPNOW数传电台

前言

随着物联网技术的快速发展,ESP32系列芯片因其强大的性能和丰富的功能,成为了物联网开发的热门选择。而ESPNOW作为ESP32的一种高速无线通信协议,无需WiFi网络即可实现设备间的点对点通讯,非常适合传感器数据传输、智能家居控制等场景。
在这里插入图片描述

现在,我们可以利用豆包大模型的强大能力,更高效地开发ESP32C3的ESPNOW双向通讯功能。本文将详细介绍如何结合豆包大模型,快速实现ESP32C3之间的ESPNOW双向通讯系统。

用ESP32C3实现ESPNOW双向通讯,不仅可以传输传感器数据,还可以实现设备间的实时控制!豆包大模型辅助开发,让代码编写更加高效。😘😘😘💕💕💕

首先声明没有恰饭广告,源代码已经匿名处理,制作细节非常完善,方便大家复刻才会提供快捷的相关链接跳转!!!😘😘😘

本文将重点介绍如何通过豆包大模型辅助开发ESP32C3的ESPNOW双向通讯系统。


1. 豆包大模型

请大家点击豆包火山注册地址,不注册是不能完成下面的实验哦:https://t.vncps.com/5LOve
谢谢啦大家的支持💖💖💖

豆包与火山方舟、火山引擎之间的关系主要体现为技术同源、产品定位互补,三者均隶属于字节跳动旗下。具体联系如下:

🛠️ 1. 火山引擎:底层技术基座
定位:字节跳动推出的企业级云服务平台,提供云计算、大数据、AI 中台、容器服务等基础技术能力。
功能:为火山方舟提供算力支持(GPU集群)、模型训练/推理框架、数据存储等基础设施。
关系:是豆包和火山方舟的技术底层支撑。

🤖 2. 豆包:AI 产品化终端应用
定位:面向公众的AI对话助手(类似ChatGPT),可提供问答、写作、编程等能力。
技术来源:依赖于火山引擎的算力资源及自研大模型(如Skywork天工、Cloud系列模型)。
产品形态:直接向用户提供服务的C端应用(网页/App),如doubao.com。

🔧 3. 火山方舟:AI 模型开发与服务平台
定位:聚焦于企业级AI模型的开发、部署与管理平台(类似百度文心千帆)。
核心功能:

  • 模型接入:支持集成第三方大模型(如百川、MiniMax)。
  • 工具链:提供模型精调(Fine-tuning)、评测、API部署等工具。
  • 场景方案:针对企业需求定制客服、营销等AI解决方案。
    与豆包的联系:
  • 技术同源:共用火山引擎的AI训练框架和推理加速技术。
  • 能力互补:企业可通过火山方舟训练模型,再以SDK/API形式接入自身产品(如集成类似豆包的聊天功能)。
  • 模型共享:豆包的底层模型可能通过火山方舟向企业客户开放定制。

1.1 豆包大模型在ESP32开发中的应用

豆包大模型可以帮助我们:

  1. 快速生成代码:根据需求描述自动生成ESP32相关代码
  2. 解决技术问题:解答开发过程中遇到的技术难题
  3. 优化代码结构:提供代码优化建议,提高代码质量
  4. 学习新技术:快速了解ESP32的新功能和使用方法

1.2 订阅火山codeplan

如果大家订阅火山codeplan
就可以畅享Trae中所有模型,写代码神速,可以理解上下文和代码,我是采用vscode安装Trae插件
在这里插入图片描述
还可以写博客记录下面是我使用的部分记录,对比千问还是强不少,大大减少markdown语法不识别问题
在这里插入图片描述

请大家点击豆包火山注册地址: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选择或切换目标模型,无需在工具中额外变更模型配置。
在这里插入图片描述

2. 环境配置

2.1 开发环境准备

  1. PlatformIO:下载并安装VSCode + PlatformIO插件;
  2. ESP32开发板库:在PlatformIO中添加ESP32支持;
  3. 相关依赖库:根据项目需求添加必要的库文件。

2.2 所需零件

要学习本教程,您需要:
在这里插入图片描述

【下单链接】https://s.click.taobao.com/ViA8xfn,一定要安装天线测试
在这里插入图片描述

【下单链接】https://s.click.taobao.com/FUJ3xfn,ESP32C3 PRO MINI开发板板载ESP32-C3FH4芯片模块wifi 蓝牙开发板也是可以的,我采用这个小巧模块自带陶瓷天线

  1. ESP32C3开发板x2:建议使用Seeed XIAO ESP32C3,体积小巧,功能强大;
  2. WIN10/WIN11电脑:编写代码调试功能
  3. USB数据线x2:用于烧录代码和串口通信。

2.3 硬件连接

  • LED引脚默认在ESP32C3开发板的GPIO8(可在代码中修改);
  • USB供电。

3. 核心代码

3.1 项目配置文件

首先,我们需要配置PlatformIO项目文件:

; 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_esp32c3]
platform = espressif32
board = seeed_xiao_esp32c3
framework = arduino
; 串口上传速度(可选)
; upload_speed = 921600

; 监视器波特率
monitor_speed = 115200

lib_deps = 
    mikalhart/TinyGPSPlus@^1.1.0
    plerup/EspSoftwareSerial@^8.2.0
    SPIFFS

board_build.partitions = partitions.csv
; 启用 C++17(推荐)
build_flags = -std=gnu++17
upload_resetmethod = ck

3.2 主代码实现

下面是ESP32C3的ESPNOW双向通讯核心代码,由豆包大模型辅助开发:

#include <Arduino.h>
#include <WiFi.h>
#include <esp_now.h>
#include <esp_wifi.h>
#include <nvs_flash.h>
#include <nvs.h>
#include <string.h>

#define LED_PIN 8
#define NVS_NAMESPACE "espnow"
#define NVS_KEY_PEER_MAC "peer_mac"

static uint8_t selfMac[6];
static uint8_t peerMac[6];
static bool isPaired = false;
static bool isConnected = false;

const unsigned long BLINK_INTERVAL = 500;
const unsigned long HEARTBEAT_INTERVAL = 1000;
const unsigned long CONNECTION_TIMEOUT = 3000;

unsigned long lastBlink = 0;
unsigned long lastSent = 0;
unsigned long lastReceived = 0;

// 模拟温度
float simulateTemperature() {
    static float temp = 22.0f;
    temp += (random(0, 200) - 100) * 0.01f;
    if (temp < 20.0f) temp = 20.0f;
    if (temp > 35.0f) temp = 35.0f;
    return temp;
}

// 格式化 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);
}

// ================== NVS ==================
bool savePeerMac(const uint8_t* mac) {
    nvs_handle_t handle;
    esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &handle);
    if (err != ESP_OK) return false;
    err = nvs_set_blob(handle, NVS_KEY_PEER_MAC, mac, 6);
    if (err != ESP_OK) { nvs_close(handle); return false; }
    err = nvs_commit(handle);
    nvs_close(handle);
    return (err == ESP_OK);
}

bool loadPeerMac(uint8_t* outMac) {
    nvs_handle_t handle;
    esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READONLY, &handle);
    if (err != ESP_OK) return false;
    size_t size = 6;
    err = nvs_get_blob(handle, NVS_KEY_PEER_MAC, outMac, &size);
    nvs_close(handle);
    return (err == ESP_OK && size == 6);
}

void eraseSavedPeer() {
    nvs_handle_t handle;
    if (nvs_open(NVS_NAMESPACE, NVS_READWRITE, &handle) == ESP_OK) {
        nvs_erase_key(handle, NVS_KEY_PEER_MAC);
        nvs_commit(handle);
        nvs_close(handle);
    }
}
// ========================================

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;
}

bool attemptPairWith(const uint8_t* targetMac) {
    esp_now_peer_info_t peer;
    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 onDataRecv(const uint8_t *mac, const uint8_t *data, int len) {
    // 构造接收到的字符串(确保以 \0 结尾)
    char buffer[len + 1];
    memcpy(buffer, data, len);
    buffer[len] = '\0';

    String senderMac = formatMac(mac);
    Serial.printf("📥 Recv from %s: %s\n", senderMac.c_str(), buffer);

    if (isPaired && memcmp(mac, peerMac, 6) == 0) {
        lastReceived = millis();
        isConnected = true;
    }
}

void setup() {
    pinMode(LED_PIN, OUTPUT);
    digitalWrite(LED_PIN, HIGH); // 初始灭灯

    Serial.begin(115200);
    Serial.println("\nESP32-C3 ESP-NOW Enhanced (with Debug Log)");
    Serial.println("Commands: PAIR xx:xx:..., CLEAR, AT+RESTART, HELP, AT+MAC, AT+FRIEND");

    randomSeed(analogRead(0));

    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        nvs_flash_erase();
        nvs_flash_init();
    }

    WiFi.mode(WIFI_STA);
    esp_wifi_set_channel(1, WIFI_SECOND_CHAN_NONE);

    if (esp_now_init() != ESP_OK) {
        Serial.println("❌ ESP-NOW init failed!");
        return;
    }
    esp_now_register_recv_cb(onDataRecv);

    esp_read_mac(selfMac, ESP_MAC_WIFI_STA);
    Serial.printf("\n>>> MY MAC: %s <<<\n\n", formatMac(selfMac).c_str());

    if (loadPeerMac(peerMac)) {
        Serial.printf("💾 Loaded peer: %s\n", formatMac(peerMac).c_str());
        if (attemptPairWith(peerMac)) {
            isPaired = true;
            isConnected = true;
            lastReceived = millis();
            Serial.println("✅ Resumed pairing!");
        } else {
            Serial.println("❌ Resume failed");
            eraseSavedPeer();
        }
    }
}

String serialBuffer = "";

void loop() {
    while (Serial.available()) {
        char c = Serial.read();
        if (c == '\n' || c == '\r') {
            serialBuffer.trim();
            if (serialBuffer.startsWith("PAIR ") && !isPaired) {
                String macStr = serialBuffer.substring(5);
                if (parseMacAddress(macStr, peerMac)) {
                    if (attemptPairWith(peerMac)) {
                        savePeerMac(peerMac);
                        isPaired = true;
                        isConnected = true;
                        lastReceived = millis();
                        Serial.println("✅ Paired and saved!");
                    } else {
                        Serial.println("❌ Pairing failed");
                    }
                } else {
                    Serial.println("❌ Invalid MAC");
                }
            } else if (serialBuffer.equalsIgnoreCase("CLEAR")) {
                eraseSavedPeer();
                isPaired = false;
                isConnected = false;
                Serial.println("🧹 Cleared");
            } else if (serialBuffer.equalsIgnoreCase("AT+RESTART")) {
                ESP.restart();
            } else if (serialBuffer.equalsIgnoreCase("HELP")) {
                Serial.println("Commands:");
                Serial.println("  PAIR xx:xx:xx:xx:xx:xx");
                Serial.println("  CLEAR");
                Serial.println("  AT+RESTART");
                Serial.println("  AT+MAC");
                Serial.println("  AT+FRIEND");
            } else if (serialBuffer.equalsIgnoreCase("AT+MAC")) {
                Serial.println(formatMac(selfMac));
            } else if (serialBuffer.equalsIgnoreCase("AT+FRIEND")) {
                if (isPaired) {
                    Serial.println(formatMac(peerMac));
                } else {
                    Serial.println("No paired device");
                }
            } else if (!serialBuffer.isEmpty()) {
                Serial.println("❓ Unknown command. Type HELP.");
            }
            serialBuffer = "";
        } else {
            serialBuffer += c;
        }
    }

    unsigned long now = millis();

    // 断连检测
    if (isPaired && (now - lastReceived > CONNECTION_TIMEOUT)) {
        isConnected = false;
    }

    // LED 控制
    if (isConnected) {
        if (now - lastBlink >= BLINK_INTERVAL) {
            digitalWrite(LED_PIN, !digitalRead(LED_PIN));
            lastBlink = now;
        }
    } else {
        digitalWrite(LED_PIN, HIGH); // 熄灭
    }

    // 每秒发送数据(带调试打印)
    if (isPaired && (now - lastSent >= HEARTBEAT_INTERVAL)) {
        float temp = simulateTemperature();
        String payload = formatMac(selfMac) + "," + String(temp, 1);

        esp_now_send(peerMac, (uint8_t*)payload.c_str(), payload.length());
        lastSent = now;

        // 🔽 调试:打印发送内容
        Serial.printf("📤 Sent: %s\n", payload.c_str());
    }

    delay(10);
}

两块开发都上传同样代码,如果出现上传失败

在这里插入图片描述

就按住boot,然后点按reset,松开boot重新烧录即可

烧录成功后按一下reset,选择打开串口助手(插件monitor),回车符LF,发送AT+MAC返回当前地址
在这里插入图片描述
记录MAC地址:0C:4E:A0:68:6A:78

3.3 代码解析

  1. 初始化部分

    • 初始化LED引脚和串口
    • 初始化NVS闪存,用于存储配对信息
    • 初始化WiFi和ESPNOW
    • 注册数据接收回调函数
  2. 配对功能

    • 通过串口命令"PAIR 0C:4E:A0:68:6A:78"进行设备配对
    • 配对成功后将对方MAC地址保存到NVS
    • 设备重启后自动加载配对信息
  3. 数据传输

    • 每秒发送一次模拟温度数据
    • 接收对方发送的数据并更新连接状态
    • 通过LED闪烁指示连接状态
  4. 命令系统

    • PAIR:配对新设备
    • CLEAR:清除配对信息
    • AT+RESTART:重启设备
    • HELP:显示帮助信息
    • AT+MAC:显示本机MAC地址
    • AT+FRIEND:显示配对设备MAC地址

4. 功能测试

4.1 测试步骤

  1. 烧录代码:将代码烧录到两个ESP32C3开发板
  2. 查看MAC地址:通过AT+MAC命令查看两个设备的MAC地址
  3. 配对设备:在一个设备上发送"PAIR xx:xx:xx:xx:xx:xx"命令,其中xx:xx:xx:xx:xx:xx是另一个设备的MAC地址
  4. 观察连接状态:配对成功后,LED会开始闪烁
  5. 查看数据传输:在串口监视器中查看数据发送和接收情况
    在这里插入图片描述

4.2 测试结果

测试项 预期结果 实际结果
设备配对 配对成功后显示"✅ Paired and saved!"
数据发送 每秒发送一次温度数据
数据接收 能接收到对方发送的数据
连接状态 连接时LED闪烁,断开时LED熄灭
自动重连 重启设备后自动加载配对信息
---- 已发送 utf8 编码消息: "AT+RESTART\n" ----
ESP-ROM:esp32c3-api1-20210207
Build:Feb  7 2021
rst:0x3 (RTC_SW_SYS_RST),boot:0xd (SPI_FAST_FLASH_BOOT)
Saved PC:0x40381972
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fcd5810,len:0x438
load:0x403cc710,len:0x90c
load:0x403ce710,len:0x2624
entry 0x403cc710

ESP32-C3 ESP-NOW Enhanced (with Debug Log)
Commands: PAIR xx:xx:..., CLEAR, AT+RESTART, HELP, AT+MAC, AT+FRIEND

>>> MY MAC: 1C:DB:D4:CD:CE:C0 <<<

---- 已发送 utf8 编码消息: "HELP\n" ----
Commands:
  PAIR xx:xx:xx:xx:xx:xx
  CLEAR
  AT+RESTART
  AT+MAC
  AT+FRIEND
---- 已发送 utf8 编码消息: "PAIR 0C:4E:A0:68:6A:78\n" ----
✅ Paired and saved!
📤 Sent: 1C:DB:D4:CD:CE:C0,21.7
📤 Sent: 1C:DB:D4:CD:CE:C0,22.2
📤 Sent: 1C:DB:D4:CD:CE:C0,22.4
📤 Sent: 1C:DB:D4:CD:CE:C0,22.1
📤 Sent: 1C:DB:D4:CD:CE:C0,22.2

正常通讯连接就是两个设备交替闪烁
在这里插入图片描述

数传输出效果,正常100m没有问题,打印效果如下
在这里插入图片描述

5. 豆包大模型辅助开发技巧

5.1 代码生成

当你需要实现某个功能时,可以向豆包大模型描述你的需求,例如:

请帮我生成ESP32C3的ESPNOW双向通讯代码,包含设备配对、数据发送接收、LED状态指示功能。

豆包会根据你的需求生成完整的代码,并提供详细的注释和说明。

5.2 问题解决

在开发过程中遇到问题时,可以向豆包提问,例如:

ESP32C3的ESPNOW连接不稳定,经常断开连接,如何解决?

豆包会分析可能的原因,并提供解决方案。

5.3 代码优化

当你有了初步的代码后,可以向豆包请求代码优化建议,例如:

请帮我优化以下ESP32C3的ESPNOW代码,提高连接稳定性和数据传输效率。

豆包会分析你的代码,并提供具体的优化建议。

6. 总结

通过本文的介绍,我们学习了如何使用豆包大模型辅助开发ESP32C3的ESPNOW双向通讯系统。主要实现了以下功能:

  1. 设备配对:通过串口命令实现两个ESP32C3设备的配对
  2. 数据传输:实现了设备间的双向数据传输
  3. 状态指示:通过LED闪烁指示设备连接状态
  4. 自动重连:设备重启后自动加载配对信息,恢复连接
  5. 调试功能:提供了丰富的调试信息和命令接口

结合豆包大模型的强大能力,我们可以更高效地开发ESP32项目,快速解决遇到的技术问题,提高代码质量和开发效率。

未来,我们可以进一步扩展这个系统,添加更多传感器数据采集、远程控制等功能,实现更复杂的物联网应用场景。


项目源码GitHub仓库链接

参考资料

希望本文对您的ESP32C3开发有所帮助!如果您有任何问题或建议,欢迎在评论区留言。😘😘😘💕💕💕

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐