谷动谷力

 找回密码
 立即注册
查看: 2898|回复: 0
打印 上一主题 下一主题
收起左侧

玩转 ESP32:动手做一个双向通讯的无线遥控器

[复制链接]
跳转到指定楼层
楼主
发表于 2022-4-27 12:45:37 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
玩转 ESP32:动手做一个双向通讯的无线遥控器

今天我们来玩儿ESP-NOW。

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

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


气象站项目预览


空旷距离能通信200米,同时连接WiFi的无线遥控系统 #esp32 #arduino #无线通讯 #遥控器 #电子技术

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地址。


  1. #include "WiFi.h"

  2. void setup(){
  3.   Serial.begin(115200);
  4.   WiFi.mode(WIFI_MODE_STA);
  5.   Serial.println(WiFi.macAddress());
  6. }

  7. void loop(){

  8. }
复制代码


获取到主机的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返回是否发送出去,回调函数中展示是否成功发送给接收方。


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

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

  5. // Structure example to send data
  6. // Must match the receiver structure
  7. typedef struct struct_message {
  8.   char a[32];
  9.   int b;
  10.   float c;
  11.   bool d;
  12. } struct_message;

  13. // Create a struct_message called myData
  14. struct_message myData;

  15. esp_now_peer_info_t peerInfo;

  16. // callback when data is sent
  17. void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  18.   Serial.print("\r\nLast Packet Send Status:\t");
  19.   Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
  20. }

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

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

  26.   // Init ESP-NOW
  27.   if (esp_now_init() != ESP_OK) {
  28.     Serial.println("Error initializing ESP-NOW");
  29.     return;
  30.   }

  31.   // Once ESPNow is successfully Init, we will register for Send CB to
  32.   // get the status of Trasnmitted packet
  33.   esp_now_register_send_cb(OnDataSent);
  34.   
  35.   // Register peer
  36.   memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  37.   peerInfo.channel = 0;  
  38.   peerInfo.encrypt = false;
  39.   
  40.   // Add peer        
  41.   if (esp_now_add_peer(&peerInfo) != ESP_OK){
  42.     Serial.println("Failed to add peer");
  43.     return;
  44.   }
  45. }

  46. void loop() {
  47.   // Set values to send
  48.   strcpy(myData.a, "THIS IS A CHAR");
  49.   myData.b = random(1,20);
  50.   myData.c = 1.2;
  51.   myData.d = false;
  52.   
  53.   // Send message via ESP-NOW
  54.   esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
  55.    
  56.   if (result == ESP_OK) {
  57.     Serial.println("Sent with success");
  58.   }
  59.   else {
  60.     Serial.println("Error sending the data");
  61.   }
  62.   delay(2000);
  63. }
复制代码


完整接收程序

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


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

  3. // Structure example to receive data
  4. // Must match the sender structure
  5. typedef struct struct_message {
  6.     char a[32];
  7.     int b;
  8.     float c;
  9.     bool d;
  10. } struct_message;

  11. // Create a struct_message called myData
  12. struct_message myData;

  13. // callback function that will be executed when data is received
  14. void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
  15.   memcpy(&myData, incomingData, sizeof(myData));
  16.   Serial.print("Bytes received: ");
  17.   Serial.println(len);
  18.   Serial.print("Char: ");
  19.   Serial.println(myData.a);
  20.   Serial.print("Int: ");
  21.   Serial.println(myData.b);
  22.   Serial.print("Float: ");
  23.   Serial.println(myData.c);
  24.   Serial.print("Bool: ");
  25.   Serial.println(myData.d);
  26.   Serial.println();
  27. }

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

  34.   // Init ESP-NOW
  35.   if (esp_now_init() != ESP_OK) {
  36.     Serial.println("Error initializing ESP-NOW");
  37.     return;
  38.   }
  39.   
  40.   // Once ESPNow is successfully Init, we will register for recv CB to
  41.   // get recv packer info
  42.   esp_now_register_recv_cb(OnDataRecv);
  43. }

  44. void loop() {

  45. }
复制代码

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

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

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

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

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


参考资料:



0.jpg (7.07 KB, 下载次数: 153)

0.jpg
+10
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|深圳市光明谷科技有限公司|光明谷商城|Sunshine Silicon Corpporation ( 粤ICP备14060730号|Sitemap

GMT+8, 2024-12-29 02:03 , Processed in 0.102059 second(s), 42 queries .

Powered by Discuz! X3.2 Licensed

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表