You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

ESP32连接AP后无法接收ESP-NOW数据包的问题求助

问题:ESP32连接路由器时无法接收ESP-NOW数据包

需要实现ESP32连接路由器的同时接收ESP-NOW数据包,已配置双方MAC地址和与路由器一致的WiFi信道,但连接路由器后出现无法接收ESP-NOW数据的问题。

ESP8266发送端代码

#include <ESP8266WiFi.h>
#include <espnow.h>

#define WIFI_CHANNEL 8
uint8_t peer[] = {0x12,0x34,0x56,0x78,0x9A,0xBC}; // ESP32的MAC地址

void onRecv(uint8_t *mac, uint8_t *data, uint8_t len) {
    Serial.print("                                                  in ");
    Serial.println(*data);
}

void onSent(const uint8_t* mac, uint8_t status) {
    Serial.print("send callback status: ");
    Serial.println(status);
}

void setup() {
    Serial.begin(74880);

    WiFi.mode(WIFI_STA);
    WiFi.disconnect();

    wifi_set_channel(WIFI_CHANNEL);

    if (esp_now_init() != 0) {
        return;
    }

    esp_now_set_self_role(ESP_NOW_ROLE_COMBO);
    esp_now_add_peer(peer, ESP_NOW_ROLE_COMBO, 3, NULL, 0);

    esp_now_register_recv_cb(esp_now_recv_cb_t(onRecv));
    esp_now_register_send_cb(esp_now_send_cb_t(onSent));

}

void loop() {
    static uint8_t counter = 0;

    esp_now_send(peer, &counter, sizeof(counter));
    Serial.print("out ");
    Serial.println(counter);

    counter++;

    delay(1000);
}

ESP32接收端代码

#include <WiFi.h>
#include <esp_now.h>
#include "esp_wifi.h"

#define MODE_PASSIVE 1
#define MODE_CREATE_AP 2
#define MODE_CONNECT_TO_WIFI 3

#define MODE MODE_CONNECT_TO_WIFI

#define WIFI_CHANNEL 8

const char* routerSsid = "myRouterSSID";
const char* routerPwd = "myRouterPWD";
const char* apSsid = "myAP";
const char* apPwd = "12345678";
const uint8_t peer_addr[] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}; // ESP8266的MAC地址

void onRecv(const uint8_t* mac_addr, const uint8_t* data, int len) {
    Serial.print("                                                  in ");
    Serial.println(*data);
}

void onSent(const uint8_t* mac_addr, esp_now_send_status_t status) {
    Serial.print("send callback status: ");
    Serial.println(status == ESP_NOW_SEND_SUCCESS ? "ESP_NOW_SEND_SUCCESS" : "ESP_NOW_SEND_FAIL");
}

void setup() {
    Serial.begin(115200);

    WiFi.mode(WIFI_AP_STA);

#if MODE == MODE_PASSIVE

    esp_wifi_set_promiscuous(true);
    esp_wifi_set_channel(WIFI_CHANNEL, WIFI_SECOND_CHAN_NONE);
    esp_wifi_set_promiscuous(false);

#elif MODE == MODE_CREATE_AP

    WiFi.softAP(apSsid, apPwd, WIFI_CHANNEL, false, 1);

#elif MODE == MODE_CONNECT_TO_WIFI

    WiFi.begin(routerSsid, routerPwd);
    while (WiFi.status() != WL_CONNECTED) {
        delay(1000);
        Serial.print(".");
    }

#endif

    delay(1000);

    Serial.print("Station IP Address: ");
    Serial.println(WiFi.localIP());
    Serial.printf("MAC Address: %s\n", WiFi.macAddress().c_str());
    Serial.print("Wi-Fi Channel: ");
    Serial.println(WiFi.channel());

    delay(100);

    if (esp_now_init() != ESP_OK) {
        Serial.println("Error initializing ESP-NOW");
        return;
    }

    esp_now_register_recv_cb(esp_now_recv_cb_t(onRecv));
    esp_now_register_send_cb(esp_now_send_cb_t(onSent));

    esp_now_peer_info_t peer = {};
    memcpy(peer.peer_addr, peer_addr, 6);
    peer.channel = 0;
    peer.encrypt = false;
    esp_now_add_peer(&peer);
}

void loop() {
    static uint8_t counter = 0;

    delay(700);
    Serial.print("out ");
    Serial.println(counter);
    Serial.print("esp_now_send returned ");
    switch (esp_now_send(peer_addr, (uint8_t*)&counter, sizeof(counter))) {
        case ESP_OK:
            Serial.println("ESP_OK");
            break;
        case ESP_ERR_ESPNOW_NOT_INIT:
            Serial.println("ESP_ERR_ESPNOW_NOT_INIT");
            break;
        case ESP_ERR_ESPNOW_ARG:
            Serial.println("ESP_ERR_ESPNOW_ARG");
            break;
        case ESP_ERR_ESPNOW_INTERNAL:
            Serial.println("ESP_ERR_ESPNOW_INTERNAL");
            break;
        case ESP_ERR_ESPNOW_NO_MEM:
            Serial.println("ESP_ERR_ESPNOW_NO_MEM");
            break;
        case ESP_ERR_ESPNOW_NOT_FOUND:
            Serial.println("ESP_ERR_ESPNOW_NOT_FOUND");
            break;
        case ESP_ERR_ESPNOW_IF:
            Serial.println("ESP_ERR_ESPNOW_IF");
            break;
        case ESP_ERR_ESPNOW_CHAN:
            Serial.println("ESP_ERR_ESPNOW_CHAN");
            break;
    }

    counter++;
}

测试现象

  • ESP32不连接家庭WiFi(MODE_PASSIVE或MODE_CREATE_AP模式)时,ESP-NOW通信正常;手机连接ESP32创建的AP也能正常工作。
  • ESP8266即使配置错误WiFi信道,仍能接收ESP32的数据。
  • 即使ESP32连接家庭WiFi无法接收数据,其onSent回调仍能正确识别ESP8266是否在监听;仅当ESP8266信道错误时,ESP32会返回ESP_NOW_SEND_FAIL,但ESP8266仍能接收数据。
  • ESP32连接家庭WiFi无法接收数据时,ESP8266的发送回调会正确报告发送失败。
  • 将路由器信道改为1后问题仍未解决。

补充测试

  • 调整发射功率无效果。
  • 若ESP32尝试连接不存在的WiFi,会显示处于信道14,ESP-NOW传输偶尔成功。

已测试ESP32CAM和Wemos D1 mini ESP32,结果一致。

解决方案

1. 强制ESP32连接路由器后保持指定信道

ESP32连接路由器后会自动切换到路由器的信道,需确保该信道与ESP-NOW发送端一致。在MODE_CONNECT_TO_WIFI代码块中添加信道设置:

#elif MODE == MODE_CONNECT_TO_WIFI
    WiFi.begin(routerSsid, routerPwd);
    while (WiFi.status() != WL_CONNECTED) {
        delay(1000);
        Serial.print(".");
    }
    // 连接后强制设置WiFi信道为指定值
    esp_wifi_set_channel(WIFI_CHANNEL, WIFI_SECOND_CHAN_NONE);

2. 修正ESP-NOW Peer的信道配置

添加Peer时,明确指定信道为WIFI_CHANNEL,而非默认的0:

esp_now_peer_info_t peer = {};
memcpy(peer.peer_addr, peer_addr, 6);
peer.channel = WIFI_CHANNEL; // 替换原有的0
peer.encrypt = false;
esp_now_add_peer(&peer);

3. 关闭ESP32 WiFi休眠模式

WiFi休眠可能导致ESP-NOW接收中断,在设置WiFi模式后添加休眠关闭代码:

WiFi.mode(WIFI_AP_STA);
WiFi.setSleep(false); // 关闭WiFi休眠

4. 验证路由器实际信道与配置一致

通过路由器管理页面确认当前使用的信道,确保两端代码中WIFI_CHANNEL宏的值与路由器信道完全匹配,避免信道配置不一致导致通信失败。

内容的提问来源于stack exchange,提问作者mqnc

火山引擎 最新活动