老宇哥带你玩转 ESP32:14 亲自动手做一个双向通讯的无线遥控器(一)

  • 09/21 15:44

今天我们来玩儿ESP-NOW。

相信每个玩电子的童鞋对无线通信都非常感兴趣,从孩童时期的无线遥控赛车,到学生时期的收音机,到长大后接触的各种无线控制的家电,手机等电子产品,无线通信让我们可以像神话小说中的某些绝技,可以做到隔空控制,每个人都都希望将那个遥控器掌握在自己手中。

无线遥控的本质就是发射端发射某个频率的电磁波出去,接收端接收并解码这个信号。我们经常接触的空调,电视,风扇等遥控器很多都是红外的,频率大多是38Khz;窗帘,车库门等大多是315MHz或者433MHz;国外有868MHz、915MHz等;低于1Ghz的泛称为Sub 1Ghz,不同国家有不同的免费频率段;灯,手机等大多是用2.4Ghz的,2.4G这个频段用的比较多,这个频段在全球是免费使用的,我们熟知的WiFi、蓝牙Zigbee的都是2.4Ghz的;当然还有NBIOT,2G,4G,5G,长波,中波,短波等很多频率的设备。理论来说,在相同功率下,低频能获得更好的传送距离,高频有更好的抗干扰性能,不同领域根据自身特性选择最合适的通信频率。

气象站项目预览

ESP-NOW概述

ESP-NOW 是由 Espressif 开发的一种协议,它使多个设备能够在不使用 Wi-Fi 的情况下相互通信。该协议类似于无线鼠标中用的2.4GHz无线连接。因此,设备之间的配对需要在它们通信之前进行。配对完成后,连接是安全且点对点的,无需握手,也就是他不像TCP/IP等是长连接的,换句话说,它是无连接的,如果其中一个板子突然断电,重新启动后,会自动匹配它的连接设备继续通信。

不同于传统的OSI模型,ESP-NOW去掉了其中一些层,只保留最基本的传输层,减少了网络拥堵造成的丢包延迟,实现快速响应。简单来说,ESP-NOW 是一种快速通信协议,可用于在 ESP32 板之间交换短消息(单次最多 250 字节)。

ESP-NOW的优势

  • 快速响应:开机后,设备无需任何无线连接即可直接传输数据和控制其他配对设备,响应速度以毫秒为单位
  • 远距离通信:ESP-NOW 支持远距离通信,板载天线户外空旷距离能达到200米+
  • 多跳控制:ESP-NOW可以实现设备的多跳控制,可通过单播、广播和群控方式控制数百台设备;
  • 新配网方式:提供了除 Wi-Fi 和蓝牙之外的新方式,通过蓝牙为第一台设备配置网络,其他设备不需要配置SSID/密码等信息,第一台连接到网络的设备可以直接将这些信息发送给其他设备
  • 升级:可用于固件升级或者大量数据升级的场景;
  • 调试:在一些高温高压等不太方便的场合,可以接收多个设备的数据,快速诊断设备故障
  • 低成本:可与WiFi,蓝牙等共存
  • 安全:ESP-NOW 采用 CCMP 方法保护供应商特定动作帧的安全,具体可参考 IEEE Std. 802.11-2012。

ESP-NOW通信

单向通信

一个从机向一个主机发送数据

这种情况适用于一个设备向另一个设备单向发送数据,比如一个从机采集传感器数据或将开关量发送到主机。

一个主机向多个从机发送数据

一个从机从多个主机接收数据

双向通信

主机与从机互相通信

多个设备之间互相通信

ESP-NOW非常适合组建一个小型网络,可以让多个ESP32之间交换数据。

硬件

基本演示不需要加入其它外设,板子接上串口助手观察就好了。

软件

获取板子的MAC地址

ESP-NOW是通过MAC地址做为不同设备的唯一识别的,就像不同设备的ID码一样,当然我们可以通过扫描配对的方式去自动配对,这里为了方便展示程序原理,我们就先采用最基本的方式,先通过下面的代码获取主机设备的MAC地址。

#include "WiFi.h"
 
void setup(){
  Serial.begin(115200);
  WiFi.mode(WIFI_MODE_STA);
  Serial.println(WiFi.macAddress());
}
 
void loop(){

}

获取到主机的MAC地址后,我们记下来。

初始化ESP-NOW

初始化ESP-NOW,在这个函数调用之前必须初始化WiFi。

esp_now_init();

添加配对设备

调用此函数配对设备,将MAC地址,通道,加密信息等进行配置。

esp_now_add_peer();

发送数据

向配对设备发送数据

esp_now_send();

发送数据回调函数

注册一个发送数据时调用的函数,此函数会返回是否发送成功的消息。

esp_now_register_send_cb();

接收数据回调函数

注册一个接收到数据时调用的函数。

esp_now_register_rcv_cb();

还有其它一些函数,我们用到的时候再讲。

完整发送程序

我们将之前打印的MAC地址保存下来,替换到broadcastAddress数组中。代码中,首先定义了一个结构体,包含几种不同类型的数据变量,这个就是我们要发送的数据,在setup()中先设置WiFi工作在STA模式,然后调用esp_now_init()初始化,将配对设备的信息进行添加,简单配置一下发送回调函数,打印是否发送成功,主函数中,每2秒发送一次数据。esp_now_send返回是否发送出去,回调函数中展示是否成功发送给接收方。

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

// REPLACE WITH YOUR RECEIVER MAC Address
uint8_t broadcastAddress[] = {0x8C, 0xCE, 0x4E, 0xA6, 0x73, 0x74};

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

// Create a struct_message called myData
struct_message myData;

esp_now_peer_info_t peerInfo;

// callback when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.print("rnLast Packet Send Status:t");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "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() != ESP_OK) {
    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_register_send_cb(OnDataSent);
  
  // Register peer
  memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  peerInfo.channel = 0;  
  peerInfo.encrypt = false;
  
  // Add peer        
  if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
  }
}
 
void loop() {
  // Set values to send
  strcpy(myData.a, "THIS IS A CHAR");
  myData.b = random(1,20);
  myData.c = 1.2;
  myData.d = false;
  
  // Send message via ESP-NOW
  esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
   
  if (result == ESP_OK) {
    Serial.println("Sent with success");
  }
  else {
    Serial.println("Error sending the data");
  }
  delay(2000);
}

完整接收程序

接收跟发送差不多,也是要定义一个跟发送方一样的数据结构体,用于保存接收到的数据,创建一个接收回调函数,当接收到数据时,调用此函数,将数据保存到一个结构体变量中,然后打印出来。

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

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

// Create a struct_message called myData
struct_message myData;

// callback function that will be executed when data is received
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int 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("Bool: ");
  Serial.println(myData.d);
  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() != ESP_OK) {
    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_register_recv_cb(OnDataRecv);
}
 
void loop() {

}

将上面的发送与接收程序烧录到两块板,就实现了数据的单向传输,我们看下接收方的串口打印数据:

这是最简单的一个案例,大家对ESP-NOW先有一个简单的理解,关于ESP-NOW的管理设备,删除设备,扫描从设备,自动配对等,下一期再讲,布置个作业,大家可以在发送端添加一个按钮,接收端添加一个LED等,就可以实现一个遥控器的Demo了,快去尝试一下吧。

下一节,我们会实际做一个小项目,增加以下功能:

  • 多个主机,多个从机;从机按键长按触发下进入广播模式,释放出WIFI信号,主机在上电的时候,会扫描到WIFI信号并自动配对;配对完成之后,主机从机都会将MAC地址自动写入存储空间,下次启动就不用重新配对;两个从机可以通过按键控制主机上的两个LED灯,主机也可以同时控制两个从机上的LED灯;两个从机分别采集温度湿度气压数据,传给主机;主机将数据在本地显示屏显示出来,同时在连接WiFi之后,可以通过Web端实时查看传感器数据;指示灯显示连接状态。

感谢大家,关于ESP32的学习,希望大家Enjoy!

参考资料:

1、https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/api-reference/network/esp_now.html

2、https://randomnerdtutorials.com/esp-now-esp32-arduino-ide/

3、https://github.com/espressif/esp-now

人工客服
(售后/吐槽/合作/交友)
  • 器件型号:MAX9768BETG+
    • 数量 1
    • 建议厂商 Maxim Integrated Products
    • 器件描述 Volume Control Circuit, 1 Channel(s), BICMOS, TQFN-24
    • 参考价格 $2.77
    • 风险等级
    • ECAD模型
    • 数据手册
    • 查看更多信息
  • 器件型号:LM6172IM
    • 数量 1
    • 建议厂商 Texas Instruments
    • 器件描述 Dual High Speed, Low Power, Low Distortion Voltage Feedback Amplifiers 8-SOIC -40 to 85
    • 参考价格 $10.27
    • 风险等级
    • ECAD模型

      ECAD模型

      下载ECAD模型
    • 数据手册
    • 查看更多信息
  • 器件型号:ISD2360SYI
    • 数量 1
    • 建议厂商 Nuvoton Technology Corp
    • 器件描述 IC DIGITAL CHIPCORDER 16SOP
    • 参考价格 $2.88
    • 风险等级
    • ECAD模型

      ECAD模型

      下载ECAD模型
    • 数据手册
    • 查看更多信息

相关资讯

  1. 1.
  2. 2.
  3. 3.
  4. 4.
  5. 5.
  6. 6.
  7. 7.
  8. 8.
  9. 9.
  10. 10.
  11. 11.
  12. 12.
  13. 13.
  14. 14.
  15. 15.
  16. 16.
  17. 17.
  18. 18.
  19. 19.
  20. 20.
查看全部20条内容