查看: 610|回复: 8

多个ESP8266相互通讯

[复制链接]
  • TA的每日心情
    奋斗
    2020-5-26 15:06
  • 签到天数: 3 天

    [LV.2]偶尔看看I

    发表于 2020-5-17 11:06 | 显示全部楼层 |阅读模式
    本帖最后由 chuanping87 于 2020-5-17 11:31 编辑

    前几天有朋友问有没有2个ESP8266相互通讯的 ,无意间我发现了这篇文章,现在分享给大家。
    文章源地址:https://randomnerdtutorials.com/esp-now-esp8266-nodemcu-arduino-ide/


    ESP-NOW是
    Espressif开发的一种协议,在Espressif网站上表示,它使多个设备无需使用Wi-Fi即可相互通信。该协议类似于低功率的2.4GHz无线连接(…)。设备之间需要进行配对,然后才能进行通信。配对完成后,连接安全且点对点,无需握手。”这意味着在将设备彼此配对后,连接将保持不变。换句话说,如果您的一块板突然断电或重置,则在重新启动时,它将自动连接到其对等端以继续通信。
    ESP-NOW支持以下功能:
    • 加密和未加密的单播通信;
    • 混合加密和未加密对等设备;
    • 最多可以承载250字节有效负载;
    • 发送回调函数,可以设置为通知应用层
      传输成功或失败。
    ESP-NOW技术还具有以下限制:
    • 有限的加密对等体。工作站模式下最多支持10个加密对等体;在SoftAP或SoftAP + Station模式下最多6个;
    • 支持多个未加密的对等方,但是它们的总数应少于20,其中包括已加密的对等方。
    • 有效负载限制为250个字节。
    简而言之,ESP-NOW是一种快速通信协议,可用于在ESP8266板之间交换小消息(最大250字节)。
    ESP-NOW具有多种用途,您可以在不同的设置中进行单向或双向通信。
    这种配置非常容易实现,并且很容易将数据从一块板发送到另一块板,例如传感器读数或控制GPIO的ON和OFF命令。
    • 一个“主” ESP8266向多个ESP8266“从”发送数据
    一块ESP8266板向不同的ESP8266板发送相同或不同的命令。此配置是构建遥控器之类的理想选择。整个房屋中可以有几块ESP8266板,这些板由一个主ESP8266板控制。

    • 一个ESP8266“从站”从多个“主站”接收数据
    如果要将多个传感器节点的数据收集到一个ESP8266板中,则此配置非常理想。例如,可以将其配置为Web服务器以显示来自所有其他板的数据。


    注意:在ESP-NOW文档中,没有“发送方/主方”和“接收方/从方”之类的东西。每个板都可以是发送者或接收者。但是,为了使事情更清楚,我们将使用术语“发送者”和“接收者”或“主”和“从”。
    ESP-NOW双向通讯
    使用ESP-NOW,每个板可以同时是发送者和接收者。因此,您可以在板之间建立双向通信。
    例如,您可以使两个板彼此通信。

    您可以在此配置中添加更多的开发板,并使它们看起来像一个网络(所有ESP8266开发板都相互通信)。
    总而言之,ESP-NOW是构建网络的理想选择,在该网络中,您可以有多个ESP8266板相互交换数据
    ESP8266:取得板子MAC地址
    要通过ESP-NOW进行通信,您需要知道ESP8266接收器的MAC地址。这样您便知道将信息发送到哪个设备。
    每个ESP8266都有一个[这就是我们识别每块板以使用ESP-NOW向其发送数据的方式(了解如何获取和更改ESP8266 MAC地址)。

    取得板子MAC地址

    #include <ESP8266WiFi.h>

    void setup(){
    Serial.begin(115200);
    Serial.println();
    Serial.print("ESP8266 Board MAC Address: ");
    Serial.println(WiFi.macAddress());
    }

    void loop()
    {

    }

    上载代码后,以115200的波特率打开Serial Monitor,然后按ESP8266 RESET按钮。MAC地址应如下打印:

    保存您的板卡MAC地址,因为您需要它通过ESP-NOW将数据发送到正确的板卡。
    ESP8266 NodeMCU发送方
    #include <ESP8266WiFi.h>
    #include <espnow.h>

    // REPLACE WITH RECEIVER MAC Address
    uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};//接收方MAC地址

    // Structure example to send data
    // Must match the receiver structure
    typedef struct struct_message {
      char a[32];
      int b;
      float c;
      String d;
      bool e;
    } struct_message;

    // Create a struct_message called myData
    struct_message myData;

    // Callback when data is sent
    void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) {
      Serial.print("Last Packet Send Status: ");
      if (sendStatus == 0){
        Serial.println("Delivery success");
      }
      else{
        Serial.println("Delivery fail");
      }
    }

    void setup() {
      // Init Serial Monitor
      Serial.begin(115200);

      // Set device as a Wi-Fi Station
      WiFi.mode(WIFI_STA);

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

      // Once ESPNow is successfully Init, we will register for Send CB to
      // get the status of Trasnmitted packet
      esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
      esp_now_register_send_cb(OnDataSent);
      
      // Register peer
      esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0);
    }

    void loop() {
      // Set values to send
      strcpy(myData.a, "THIS IS A CHAR");
      myData.b = random(1,20);
      myData.c = 1.2;
      myData.d = "Hello";
      myData.e = false;

      // Send message via ESP-NOW
      esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));

      delay(2000);
    }

    代码如何工作
    首先,包括 ESP8266WiFi.h 和 espnow.h 库。
    #include <ESP8266WiFi.h>#include <espnow.h>
    在下一行中,应插入ESP8266接收器MAC地址。
    uint8_t broadcastAddress[ = {0x5C, 0xCF, 0x7F, 0x99, 0x9A, 0xEA};
    在我们的例子中,接收者的MAC地址是: 5C:CF:7F:99:9A:EA,但您需要用自己的MAC地址替换该变量。
    然后,创建一个包含我们要发送的数据类型的结构。我们称这种结构struct_message它包含5种不同的变量类型。您可以更改此设置以发送所需的任何变量类型。
    typedef struct struct_message {  char a[32;  int b;  float c;  String d;  bool e;} struct_message;
    创建一个新的类型变量 struct_message 它被称作 myData 将存储变量值。
    struct_message myData;
    接下来,定义 OnDataSent()功能。这是一个回调函数,将在发送消息时执行。在这种情况下,无论是否成功发送该消息,都会简单地打印出来。
    void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) {  Serial.print("Last Packet Send Status: ");  if (sendStatus == 0){    Serial.println("Delivery success");  }  else{    Serial.println("Delivery fail");  }}
    在里面 设定(),初始化串行监视器以进行调试:
    Serial.begin(115200);
    将设备设置为Wi-Fi站点:
    WiFi.mode(WIFI_STA);
    立即初始化ESP:
    if (esp_now_init() != 0) {  Serial.println("Error initializing ESP-NOW");  return;}
    设置ESP8266角色:
    esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
    它接受以下角色: ESP_NOW_ROLE_CONTROLLER, ESP_NOW_ROLE_SLAVE, ESP_NOW_ROLE_COMBO, ESP_NOW_ROLE_MAX。
    成功初始化ESP-NOW之后,注册将在发送消息时调用的回调函数。在这种情况下,我们注册OnDataSent() 先前创建的功能。
    esp_now_register_send_cb(OnDataSent);
    然后,与另一个ESP-NOW设备配对以发送数据:
    esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0);
    的 esp_now_add_peer 按此顺序接受以下参数:mac地址,角色,Wi-Fi通道,密钥和密钥长度。
    在里面 环(),我们将每2秒通过ESP-NOW发送一条消息(您可以更改此延迟时间)。
    首先,我们将变量值设置如下:
    strcpy(myData.a, "THIS IS A CHAR");myData.b = random(1,20);myData.c = 1.2;myData.d = "Hello";myData.e = false;
    请记住 myData是一个结构。在这里,我们分配要在结构内部发送的值。例如,第一行分配一个字符,第二行分配一个随机的Int数,一个Float,一个String和一个Boolean变量。
    我们创建这种结构来向您展示如何发送最常见的变量类型。您可以更改结构以发送任何其他类型的数据。
    最后,发送消息如下:
    esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
    的 环() 每2000毫秒(2秒)执行一次。
    delay(2000);


    ESP8266 NodeMCU接收
    #include <ESP8266WiFi.h>
    #include <espnow.h>

    // Structure example to receive data
    // Must match the sender structure
    typedef struct struct_message {
        char a[32];
        int b;
        float c;
        String d;
        bool e;
    } struct_message;

    // Create a struct_message called myData
    struct_message myData;

    // Callback function that will be executed when data is received
    void OnDataRecv(uint8_t * mac, uint8_t *incomingData, uint8_t len) {
      memcpy(&myData, incomingData, sizeof(myData));
      Serial.print("Bytes received: ");
      Serial.println(len);
      Serial.print("Char: ");
      Serial.println(myData.a);
      Serial.print("Int: ");
      Serial.println(myData.b);
      Serial.print("Float: ");
      Serial.println(myData.c);
      Serial.print("String: ");
      Serial.println(myData.d);
      Serial.print("Bool: ");
      Serial.println(myData.e);
      Serial.println();
    }

    void setup() {
      // Initialize Serial Monitor
      Serial.begin(115200);
      
      // Set device as a Wi-Fi Station
      WiFi.mode(WIFI_STA);

      // Init ESP-NOW
      if (esp_now_init() != 0) {
        Serial.println("Error initializing ESP-NOW");
        return;
      }
      
      // Once ESPNow is successfully Init, we will register for recv CB to
      // get recv packer info
      esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
      esp_now_register_recv_cb(OnDataRecv);
    }

    代码如何工作
    与发送者类似,首先包括以下库:
    #include <esp_now.h>#include <WiFi.h>
    创建一个结构以接收数据。此结构应与发件人草图中定义的结构相同。
    typedef struct struct_message {  char a[32;  int b;  float c;  String d;  bool e;} struct_message;
    创建一个 struct_message 变量称为 myData。
    struct_message myData;
    创建一个回调函数,当ESP8266通过ESP-NOW接收数据时将调用该函数。该函数称为onDataRecv() 并应接受以下几个参数:
    void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
    我们复制内容 入库数据 数据变量放入 myData 变量。
    memcpy(&myData, incomingData, sizeof(myData));
    现在 myData结构内部包含多个变量,以及发送方ESP8266发送的值。访问变量一个,例如,我们只需要致电 myData.a。
    在此示例中,我们仅打印接收到的数据,但是在实际应用中,例如,您可以在显示器上打印数据。
      Serial.print("Bytes received: ");  Serial.println(len);  Serial.print("Char: ");  Serial.println(myData.a);  Serial.print("Int: ");  Serial.println(myData.b);  Serial.print("Float: ");  Serial.println(myData.c);  Serial.print("String: ");  Serial.println(myData.d);  Serial.print("Bool: ");  Serial.println(myData.e);  Serial.println();}
    在里面 设定(),初始化串行通信以进行调试。
    Serial.begin(115200);
    将设备设置为Wi-Fi站。
    WiFi.mode(WIFI_STA);
    立即初始化ESP:
    if (esp_now_init() != ESP_OK) {  Serial.println("Error initializing ESP-NOW");  return;}
    设置ESP8266角色:
    esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
    注册接收数据时将调用的回调函数。在这种情况下,我们注册OnDataRecv() 先前创建的功能。
    esp_now_register_recv_cb(OnDataRecv);测试ESP-NOW通信
    将发送者草图上载到一个板,将接收者草图上载到另一板。不要忘记在发送者草图上插入接收者MAC地址。
    现在,打开两个Arduino IDE窗口。一个给接收者,另一个给发送者。打开每个板卡的串行监视器。每个板应该是不同的COM端口。
    这就是您在发送方获得的东西。

    这就是您应该在接收器端得到的。请注意,Int变量会在每次接收到的读数之间变化(因为我们在发送方将其设置为随机数)。

    测试了两块板之间的通信范围,并且能够在旷野中获得长达140米(约459英尺)的稳定通信。在本实验中,两个ESP8266车载天线都指向彼此。


    该用户从未签到

    发表于 2020-5-17 20:22 | 显示全部楼层
    非常感谢楼主分享,这对我非常有用。太感谢了。

    该用户从未签到

    发表于 2020-5-18 16:44 | 显示全部楼层
    这个支持广播吗?
  • TA的每日心情
    奋斗
    2020-5-26 15:06
  • 签到天数: 3 天

    [LV.2]偶尔看看I

     楼主| 发表于 2020-5-19 23:41 | 显示全部楼层
    arduino-lhs 发表于 2020-5-17 20:22
    非常感谢楼主分享,这对我非常有用。太感谢了。

    不用客气,互相学习
  • TA的每日心情
    奋斗
    2020-5-26 15:06
  • 签到天数: 3 天

    [LV.2]偶尔看看I

     楼主| 发表于 2020-5-19 23:42 | 显示全部楼层
    qllaoda1 发表于 2020-5-18 16:44
    这个支持广播吗?

    没有试过,你可以尝试一下
  • TA的每日心情
    郁闷
    2020-5-9 23:03
  • 签到天数: 201 天

    [LV.7]常住居民III

    发表于 2020-6-26 22:36 | 显示全部楼层
    好东西,进我的收藏夹吃灰吧
  • TA的每日心情
    郁闷
    2019-11-8 09:38
  • 签到天数: 28 天

    [LV.4]偶尔看看III

    发表于 2020-6-27 13:07 | 显示全部楼层
    感觉好复杂,这个简单的,不限局域网 https://www.arduino.cn/thread-91649-1-1.html
  • TA的每日心情
    奋斗
    2020-7-4 09:19
  • 签到天数: 1819 天

    [LV.Master]伴坛终老

    发表于 2020-6-28 06:47 来自手机 | 显示全部楼层
    1.图片缺失 2.机器翻译有误 3.隐藏了最重要的链路层和网络层内容
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    热门推荐

    5分钟带你快速了解新一代开发板:M5STACK
    5分钟带你快速了解新一代
    一、什么是M5Stack M5Stack是一种模块化、可堆叠扩展的开发板,每个模块
    创客火首发无人机编队套装,开启不一样的人工智能教育
    创客火首发无人机编队套装
    2017年国务院发布《新一代人工智能发展规划》,提出要广泛开展人工智能科普活动,在中
    求助,用l298n模块控制电机转速,老是无缘无故的转动怎么...
    求助,用l298n模块控制电
    代码如下:int state1=0; int state2=0; void setup() { pinMode(9,OUTPUT); pinMode(
    【干货分享】mega2560原理图PCB图纸altium designer18
    【干货分享】mega2560原理
    分享一下mega2560的板子 AD版本 **** 本内容被作者隐藏 **** ergo
    绑定github账号,免费增加设备额度
    绑定github账号,免费增加
    免费增加blinker设备额度的方法: 1.登录点灯管理台( https://admin.diandeng.tech/
    Copyright   ©2015-2016  Arduino中文社区  Powered by©Discuz!   
    快速回复 返回顶部 返回列表