본문 바로가기

ESP32

ESP32 ESP-NOW 양방향 커뮤니케이션

반응형

ESP32 ESP-NOW 프로토콜 양방향 커뮤니케이션

 

ESP-NOW 통신은 Espressif 시스템즈에서 개발한 IP 연결이 필요 없는(connectionless) 무선 통신 프로토콜입니다. ESP32, ESP8266 등 ESP 칩셋 기반 보드 간의 근거리 통신을 위해 설계되었으며, Wi-Fi 공유기나 인터넷 연결 없이 장치 간 직접 통신을 가능하게 합니다.

 

주요 특징

  • 연결 불필요: Wi-Fi 네트워크에 연결할 필요 없이 장치 간 직접 통신합니다.
  • 저전력 및 고속: 짧은 패킷 전송을 특징으로 하며, 저전력으로 빠르게 데이터를 주고받을 수 있습니다.
  • 다중 장치 통신: 일대일(단방향, 양방향), 일대다, 다대다 통신 등 다양한 구성이 가능하며 메시 네트워크로도 활용될 수 있습니다.
  • MAC 주소 기반: 데이터 송수신을 위해 상대방 장치의 MAC 주소를 알아야 합니다.
  • 짧은 메시지 전송: 최대 250바이트 크기의 작은 메시지 전송에 유용합니다.
  • 통신 거리: 환경에 따라 달라지지만, 최대 약 450미터까지 통신 범위가 확장될 수 있습니다.

 

활용 분야

 

스마트 홈 자동화, 센서 네트워크, 원격 제어 시스템 등 인터넷 연결 없이 기기 간 빠르고 안정적인 통신이 필요한 IoT 프로젝트에 매우 적합합니다.  

 

 

 

  • 우리가 아는 대로 ESP-NOW는 Espressif Systems가 자사의 Wi-Fi 칩을 위해 개발한 무선 통신 프로토콜입니다.
  • 이를 통해 Wi-Fi 액세스 포인트가 필요 없이 기기가 서로 직접 통신할 수 있습니다.
  • ESP-NOW를 사용하면 각 보드가 동시에 데이터를 송수신할 수 있습니다. 따라서 두 보드 간에 양방향 통신을 구축할 수 있습니다.
  • 양방향 통신을 위해 첫 번째 ESP32 에는 DHT11 센서를 사용하고 두 번째 ESP32 에는 BMP180을 사용합니다.
  • BMP180에서 압력과 고도를 동시에 읽고 , DHT11 센서에서 온도와 습도를 동시에 읽어서 데이터를 교환합니다 .

 

 

계속 진행하기 전에 ESP32 보드 두 개가 필요하고 슬레이브 ESP32의 MAC 주소를 알아야 합니다.

먼저 아래 코드에서 MAC 주소를 얻어 기록해 두세요.

 

보드 MAC 주소 가져오기

 

#include "WiFi.h"

void setup(){
 Serial.begin(115200);
 WiFi.mode(WIFI_MODE_STA);
 Serial.println(WiFi.macAddress());
}

void loop(){}

 

결과

 

 

DHT11과 ESP32의 연결 다이어그램

 

 

 

ESP32와 BMP180 하드웨어 연결

 

 

 

이제 아래 코드를 복사하여 첫 번째 ESP32 장치에 업로드하세요. 업로드하기 전에 슬레이브 장치의 MAC 주소를 입력해야 합니다.

 

uint8_t broadcastAddress[] = {0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX };

 

ESP Now: DHT11 센서 코드가 있는 ESP32

 

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

DHT dht;
float BMP180_Pres;
float BMP180_Alt;

uint8_t broadcastAddress[] = {0x30, 0xC6, 0xF7, 0x23, 0x34, 0x44};
String success;

typedef struct struct_message {
    float temp;
    float hum;
    float pres;
    float alt;
} struct_message;

struct_message DHT11_data;
struct_message BMP180_data;
esp_now_peer_info_t peerInfo;

void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.print("\r\nDelivery Status: ");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Deliverd Successfully" : "Delivery Fail");
  if (status ==0){
    success = "Delivery Success :)";
  }
  else{
    success = "Delivery Fail :(";
  }
}

void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
  memcpy(&BMP180_data, incomingData, sizeof(BMP180_data));
  BMP180_Pres = BMP180_data.pres;
  BMP180_Alt = BMP180_data.alt;
}
 
void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  dht.setup(0);                 /*Connect the DHT11's data pin to GPIO0*/
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  esp_now_register_send_cb(OnDataSent);
 
  memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  peerInfo.channel = 0; 
  peerInfo.encrypt = false;
       
  if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
  }
  esp_now_register_recv_cb(OnDataRecv);
}
 
void loop() {
  DHT11_data.temp = dht.getTemperature(); /*Get the Temperature value*/
  DHT11_data.hum = dht.getHumidity();       /*Get the Humidity value*/

  esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &DHT11_data, sizeof(DHT11_data));
   
  if (result == ESP_OK) {
    Serial.println("Sent Successfullt");
  }
  else {
    Serial.println("Getiing Error while sending the data");
  }

  Serial.print("Pressure: ");
  Serial.print(BMP180_data.pres);
  Serial.println(" Pa");
  Serial.print("Altitude: ");
  Serial.print(BMP180_data.alt);
  Serial.println(" Meters");
  Serial.println();

  delay(3000);
}

 

이제 코드를 업로드하세요. (코드를 업로드하는 동안 ESP32 보드가 부팅 모드인지 확인하세요.)

코드를 업로드한 후 직렬 모니터를 열고 통신 속도를 115200 으로 설정한 다음 ESP32 보드를 재설정하고 아래 이미지에 표시된 대로 IP 주소를 확인합니다.

 

결과

 

 

코드를 이해하세요

 

esp_now.h, DHT.h, 및 WiFi.h 라이브러리를 추가합니다. 

 

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

 

아래와 같이 객체를 생성합니다.

 

DHT dht;

 

이제 ESP32 수신기의 MAC 주소를 추가하세요.

우리의 MAC 주소는 30:C6:F7:23:34:44입니다.

 

uint8_t broadcastAddress[] = {0x30, 0xC6, 0xF7, 0x23, 0x34, 0x44};

 

여기서는 데이터를 보내고 받는 구조를 만들었습니다.

 

typedef struct struct_message {
    float temp;
    float hum;
    float pres;
    float alt;
} struct_message;

 

DHT11_data 및 BMP180_data라는 struct_message 변수를 생성하십시오.

 

 

struct_message DHT11_data;

struct_message BMP180_data;

 

esp_now_peer_info_t는 피어의 정보를 저장하는 변수입니다.

 

esp_now_peer_info_t peerInfo;

 

중요 기능: ESP32가 데이터를 보낼 때의 콜백 함수

 

OnDataSent() 메시지가 전송될 때 실행되는 콜백 함수입니다.

 

void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.print("\r\nDelivery Status: ");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Deliverd Successfully" : "Delivery Fail");
  if (status ==0){
    success = "Delivery Success :)";
  }
  else{
   success = "Delivery Fail :(";
  }
}

 

중요 기능: ESP32가 데이터를 수신할 때의 콜백 함수

 

ESP32가 ESP-NOW를 통해 데이터를 수신하면 호출되는 콜백 함수를 만듭니다.

 

void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
  memcpy(&BMP180_data, incomingData, sizeof(BMP180_data));
  BMP180_Pres = BMP180_data.pres;
  BMP180_Alt = BMP180_data.alt;
}

 

setup 함수에서

 

직렬 모니터 초기화

Serial.begin(115200);

 

GPIO 0 핀을 데이터 통신 핀으로 설정합니다.

dht.setup(0);

 

ESP32를 Wi-Fi 스테이션 모드로 설정:

 

WiFi.mode(WIFI_STA);

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

 

이제 메시지가 전송될 때 호출될 콜백 함수를 등록합니다.

 

esp_now_register_send_cb(OnDataSent);

 

그 다음에는 데이터를 전송하기 위해 다른 ESP-NOW 장치와 페어링해야 합니다. 다음 줄에서 수행하는 작업이 바로 그것입니다:

 

memcpy(peerInfo.peer_addr, broadcastAddress, 6);
peerInfo.channel = 0;
peerInfo.encrypt = false;
if (esp_now_add_peer(&peerInfo) != ESP_OK){
  Serial.println("Failed to add peer");
  return;
}

 

 

loop 함수에서

 

DHT11에서 온도 와 습도 값 을 읽어 저장합니다.

 

DHT11_data.temp = dht.getTemperature(); /*Get the Temperature value*/
DHT11_data.hum = dht.getHumidity();       /*Get the Humidity value*/

 

여기서는 3초마다 온도와 습도를 전송합니다.

 

esp_err_t result = esp_now_send(broadcastAddress,(uint8_t *) &msg, sizeof(msg));

 

메시지 상태가 성공적으로 전송되었는지 확인하세요.

 

if (result == ESP_OK) {
  Serial.println("Sent with success");
}
else {
  Serial.println("Error sending the data");
}

 

여기서 수신된 압력과 고도를 직렬 모니터에 인쇄합니다.

 

Serial.print("Pressure: ");
 Serial.print(BMP180_data.pres);
 Serial.println(" Pa");
 Serial.print("Altitude: ");
 Serial.print(BMP180_data.alt);
 Serial.println(" Meters");
  Serial.println();

 

3초간 기다리세요

delay(3000);

 

이제 아래 코드를 복사하여 두 번째 장치에 업로드하고 직렬 모니터에서 결과를 확인하세요.

 

Before uploading make sure you have updated your MAC address

uint8_t broadcastAddress[] = {0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX };

 

ESP Now: BMP180 센서 코드가 포함된 ESP32

 

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

Adafruit_BMP085 bmp;
float DHT11_Temp;
float DHT11_Hum;

uint8_t broadcastAddress[] = {0x24, 0x0A, 0xC4, 0x59, 0xBB, 0x50};
String success;

typedef struct struct_message {
    float temp;
    float hum;
    float pres;
    float alt;
} struct_message;

struct_message DHT11_data;
struct_message BMP180_data;
esp_now_peer_info_t peerInfo;

void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.print("\r\nDelivery Status:\t");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Successfully" : "Delivery Fail");
  if (status ==0){
    success = "Delivery Success :)";
  }
  else{
    success = "Delivery Fail :(";
  }
}

void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
  memcpy(&DHT11_data, incomingData, sizeof(DHT11_data));
  DHT11_Temp = DHT11_data.temp;
  DHT11_Hum = DHT11_data.temp;
}
 
void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);

  if (!bmp.begin()) {
      Serial.println("Could not find a valid BMP085 sensor, check wiring!");
      while (1) {}
  }
 
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  esp_now_register_send_cb(OnDataSent);
 
  memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  peerInfo.channel = 0; 
  peerInfo.encrypt = false;
       
  if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
  }
  esp_now_register_recv_cb(OnDataRecv);
}
 
void loop() {
  BMP180_data.pres = bmp.readPressure();
  BMP180_data.alt = bmp.readAltitude();

  esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &BMP180_data, sizeof(BMP180_data));
   
  if (result == ESP_OK) {
    Serial.println("Sent Successfully");
  }
  else {
    Serial.println("Error sending the data");
  }

  Serial.print("Temperature: ");
  Serial.print(DHT11_data.temp);
  Serial.println(" ºC");
  Serial.print("Humidity: ");
  Serial.print(DHT11_data.hum);
  Serial.println(" %");
  Serial.println();

  delay(3000);
}

 

  • 이제 코드를 업로드하세요. (코드를 업로드하는 동안 ESP32 보드가 부팅 모드인지 확인하세요.)
  • 코드를 업로드한 후 직렬 모니터를 열고 통신 속도를 115200 으로 설정한 다음 ESP32 보드를 재설정하고 아래 이미지에 표시된 대로 IP 주소를 확인합니다.

 

결과

 

 

코드를 이해하세요

 

e sp_now.h, DHT.h, 및 WiFi.h 라이브러리를 추가합니다.

 

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

 

이제 ESP32 수신기의 MAC 주소를 추가하세요.

우리의 MAC 주소는 30:C6:F7:23:34:44입니다.

 

uint8_t broadcastAddress[] = {0x30, 0xC6, 0xF7, 0x23, 0x34, 0x44};

 

여기서는 데이터를 보내고 받는 구조를 만들었습니다.

 

typedef struct struct_message {
    float temp;
    float hum;
    float pres;
    float alt;
} struct_message;

 

DHT11_data 및 BMP180_data라는 struct_message 변수를 생성하십시오.

 

struct_message DHT11_data;
struct_message BMP180_data;

 

OnDataSent()는 메시지가 전송될 때 실행되는 콜백 함수입니다. 

 

void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.print("\r\nDelivery Status:\t");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Successfully" : "Delivery Fail");
  if (status ==0){
    success = "Delivery Success :)";
  }
  else{
    success = "Delivery Fail :(";
  }
}

 

ESP32가 ESP-NOW를 통해 데이터를 수신하면 호출되는 콜백 함수를 만듭니다.

 

void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
  memcpy(&DHT11_data, incomingData, sizeof(DHT11_data));
  DHT11_Temp = DHT11_data.temp;
  DHT11_Hum = DHT11_data.temp;
}

 

setup 함수에서

 

직렬 모니터 초기화

Serial.begin(115200);

 

이제 begin() 함수를 사용하여 모듈이 연결되었는지 여부를 확인하기 위해 if 조건문을 사용했습니다.

 

if (!bmp.begin()) {
      Serial.println("Could not find a valid BMP085 sensor, check wiring!");
      while (1) {}
  }

 

ESP32를 Wi-Fi 스테이션 모드 로 설정합니다 .

WiFi.mode(WIFI_STA);

 

ESP-NOW 초기화 :

 

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

 

이제 메시지가 전송될 때 호출될 콜백 함수를 등록합니다.

esp_now_register_send_cb(OnDataSent);

 

그 후에는 다른 ESP-NOW 기기 와 페어링하여 데이터를 전송해야 합니다. 다음 줄에서 이 작업을 수행합니다.

 

memcpy(peerInfo.peer_addr, broadcastAddress, 6);
peerInfo.channel = 0;
peerInfo.encrypt = false;
if (esp_now_add_peer(&peerInfo) != ESP_OK){
  Serial.println("Failed to add peer");
  return;
}

 

loop 함수에서

 

BMP 센서 에서 압력과 고도를 측정 하여 저장합니다.

 

BMP180_data.pres = bmp.readPressure();
BMP180_data.alt = bmp.readAltitude();

 

판독값이 성공적으로 전송되면 인쇄 Sent with success하거나 Error sending the data.

 

if (result == ESP_OK) {
  Serial.println("Sent with success");
}
else {
  Serial.println("Error sending the data");
}

 

수신된 온도 및 습도를 직렬 모니터에 인쇄합니다.

 

Serial.print("Temperature: ");
Serial.print(DHT11_data.temp);
Serial.println(" ºC");
Serial.print("Humidity: ");
Serial.print(DHT11_data.hum);
Serial.println(" %");
Serial.println();

 

3초간 기다리세요

delay(3000);

 

튜토리얼 내용은 다음 링크를 참고했습니다. 

 

 

반응형

캐어랩 고객 지원

취업, 창업의 막막함, 외주 관리, 제품 부재!

당신의 고민은 무엇입니까? 현실과 동떨어진 교육, 실패만 반복하는 외주 계약, 아이디어는 있지만 구현할 기술이 없는 막막함.

우리는 알고 있습니다. 문제의 원인은 '명확한 학습, 실전 경험과 신뢰할 수 있는 기술력의 부재'에서 시작됩니다.

이제 고민을 멈추고, 캐어랩을 만나세요!

코딩(펌웨어), 전자부품과 디지털 회로설계, PCB 설계 제작, 고객(시장/수출) 발굴과 마케팅 전략으로 당신을 지원합니다.

제품 설계의 고수는 성공이 만든 게 아니라 실패가 만듭니다. 아이디어를 양산 가능한 제품으로!

귀사의 제품을 만드세요. 교육과 개발 실적으로 신뢰할 수 있는 파트너를 확보하세요.

지난 30년 여정, 캐어랩이 얻은 모든 것을 함께 나누고 싶습니다.

카카오 채널 추가하기

카톡 채팅방에서 무엇이든 물어보세요

당신의 성공을 위해 캐어랩과 함께 하세요.

캐어랩 온라인 채널 바로가기

캐어랩