본문으로 이동

아두이노:RF통신 nRF24L01+

학교의 모든 지식. SMwiki
Sam (토론 | 기여)님의 2026년 7월 23일 (목) 15:14 판 (새 문서: {{아두이노}} == 개요 == nRF24L01+ 모듈을 이용한 통신을 다루는 문서. 2.4GHz의 이론에 대하여선 아두이노:2.4GHz 송수신 문서를 참고하자. === nRF24L01+ 모듈 규격 === nRF24L01+ 모듈은 이 대역에서 동작하는 GFSK 방식의 반이중(half-duplex) 트랜시버로, 한 순간에는 송신 또는 수신 중 하나만 수행하지만 소프트웨어적으로 역할을 빠르게 전환해 양방향 통신을 구현할 수 있다.<...)
(차이) ← 이전 판 | 최신판 (차이) | 다음 판 → (차이)

아두이노 관련 정보를 모으기 위한 틀. 틀:아두이노

  1. 아두이노:개요
  2. 아두이노:하드웨어
    1. 아두이노:우노보드
    2. 아두이노:ESP32
  3. 아두이노:코드
    1. 아두이노:컴퓨터에서 보드로
    2. 아두이노:안드로이드에서 보드로
    3. 아두이노:기초 문법
    4. 아두이노:라이브러리
  4. 아두이노:핀 사용
    1. 아두이노:전원공급
  5. 아두이노:시리얼 통신
    1. 아두이노:엑셀기록
    2. 아두이노:파이썬과 통신
  6. 아두이노:편의함수
  7. 센서 사용
    1. 아두이노:모션센서(미완)
    2. 아두이노:온습도센서
    3. 아두이노:조도센서(미완)
    4. 아두이노:인체감지센서(미완)
    5. 아두이노:pH미터 만들기(Gravity 아날로그 pH센서)
    6. 가스센서
      1. 아두이노:MOS 센서
  8. 아두이노:LCD 사용
  9. 아두이노:스위치 사용
  10. 아두이노:릴레이
  11. 통신 관련, 정보 교환
    1. 아두이노:2.4GHz 송수신
      1. 아두이노:WIFI
      2. 아두이노:블루투스(외장모듈)
      3. 아두이노:RF통신 nRF24L01+
    2. 아두이노:IR 송수신
    3. 아두이노:RFID
  12. 아두이노:해결되지 않은 다양한 의문들
  13. 수업용 간단 실습
    1. 아두이노:LED
    2. 아두이노:초음파센서
    3. 아두이노:전압계 만들기
    4. 아두이노:저항계 만들기
  14. 아두이노 모터 출력
    1. 아두이노:서보 모터
    2. 아두이노:DC 모터
    3. 아두이노:BLDC 모터
  15. 미완문서
    1. 아두이노:스테핑 모터(미완)
  16. 분류:아두이노 프로젝트

nRF24L01+ 모듈을 이용한 통신을 다루는 문서. 2.4GHz의 이론에 대하여선 아두이노:2.4GHz 송수신 문서를 참고하자.

nRF24L01+ 모듈 규격

[편집 | 원본 편집]

nRF24L01+ 모듈은 이 대역에서 동작하는 GFSK 방식의 반이중(half-duplex) 트랜시버로, 한 순간에는 송신 또는 수신 중 하나만 수행하지만 소프트웨어적으로 역할을 빠르게 전환해 양방향 통신을 구현할 수 있다.[1] 주요 특징:

  • 초저전력: 송신 시 약 12 mA(0 dBm 기준)로 LED 한 개보다 적게 소비하며, 대기 22 µA, 파워다운 900 nA 수준이다.
  • 저가: 모듈당 미화 2달러 내외로 매우 저렴하다.
  • 다중 노드: 최대 125개 채널, 채널당 6개 주소(파이프)를 지원해 하나의 수신 허브가 최대 6개 송신 노드와 통신할 수 있다.
  • 하드웨어 프로토콜: Enhanced ShockBurst 엔진이 패킷 조립, 자동 응답(ACK), 재전송, CRC를 하드웨어에서 처리한다.
주요 사양
항목 표준 모듈 PA/LNA 모듈
동작 주파수 2.400 – 2.525 GHz 2.400 – 2.525 GHz
공급 전압 1.9 – 3.6 V 1.9 – 3.6 V
로직 입력 5 V 허용(tolerant) 5 V 허용
출력 전력 −18 dBm ~ 0 dBm −18 dBm ~ +20 dBm
송신 전류(최대) 약 11.3 mA @ 0 dBm 약 115 mA @ +20 dBm
대기 전류 22 µA 22 µA
파워다운 전류 900 nA 900 nA
데이터 속도 250 kbps / 1 Mbps / 2 Mbps 250 kbps / 1 Mbps / 2 Mbps
페이로드 크기 1 – 32 바이트 1 – 32 바이트
채널 수 126 (1 MHz 간격) 126 (1 MHz 간격)
통신 거리 최대 약 100 m(개활지) 최대 약 1,000 m(외장 안테나)

모듈 종류

[편집 | 원본 편집]
  • 기판 안테나형(PCB 안테나): 소형·컴팩트, 개활지 기준 약 100 m. 실내·벽 통과 시 거리 감소.
  • PA/LNA + 외장 안테나형: 전력 증폭기(PA)와 저잡음 증폭기(LNA)를 내장해 최대 약 1 km까지 도달. 전류 소모가 크므로 별도 3.3 V 전원 권장.

배선 (Arduino Uno / Nano 기준)

[편집 | 원본 편집]
nRF24L01+ ↔ 아두이노 연결
nRF24L01+ 핀 아두이노 Uno/Nano 핀 비고
VCC 3.3 V 절대 5 V 연결 금지
GND GND
CE D9 (변경 가능) 코드와 일치시킬 것
CSN D10 (변경 가능) 코드와 일치시킬 것
SCK D13(칩마다 다름) 하드웨어 SPI 고정
MOSI D11(칩마다 다름) 하드웨어 SPI 고정
MISO D12(칩마다 다름) 하드웨어 SPI 고정
IRQ (미사용) 인터럽트용, 선택 사항

전원 안정화 (매우 중요)

[편집 | 원본 편집]

아두이노 내장 3.3 V 레귤레이터는 전류 공급 능력이 부족해 통신 불안정의 가장 흔한 원인이다.

  • VCC–GND 사이에 10 µF ~ 100 µF 전해 커패시터를 최대한 모듈 가까이 병렬 연결한다.
  • PA/LNA 모듈이나 다수 노드 사용 시 별도 외장 3.3 V 레귤레이터를 권장한다.
  • 어댑터 보드(소켓형)를 쓰면 레귤레이터와 디커플링이 내장되어 편리하다.

동작 원리

[편집 | 원본 편집]

SPI 인터페이스

[편집 | 원본 편집]

모듈은 SPI 슬레이브로 동작하며, 아두이노(마스터)의 하드웨어 SPI 핀(MOSI, MISO, SCK)에 반드시 연결해야 한다. 여기에 더해 두 개의 제어 핀을 사용한다.

  • CE (Chip Enable): 송신/수신 모드를 활성화하는 핀. 임의의 디지털 핀 사용 가능.
  • CSN (Chip Select Not): SPI 슬레이브 선택 핀. 임의의 디지털 핀 사용 가능.

Enhanced ShockBurst

[편집 | 원본 편집]

Enhanced ShockBurst는 하드웨어 기반 프로토콜 엔진으로 다음을 자동 처리한다.

  1. 자동 패킷 조립: 프리앰블, 주소, CRC 필드를 페이로드에 자동 추가.
  2. 자동 응답 및 재전송: 수신 측이 ACK를 자동 전송하며, 송신 측은 ACK를 못 받으면 최대 15회까지 자동 재전송.
  3. 동적 페이로드 길이: 1~32바이트 가변 길이 지원.
  4. 멀티 파이프: 서로 다른 주소를 가진 6개 데이터 파이프를 동시에 수신 대기.

라이브러리 설치

[편집 | 원본 편집]

가장 널리 쓰이는 라이브러리는 TMRh20이 유지보수하는 RF24 라이브러리다.

  1. 아두이노 IDE를 연다.
  2. 메뉴에서 스케치 → 라이브러리 포함하기 → 라이브러리 관리를 선택한다.
  3. 검색창에 RF24를 입력하고 TMRh20의 RF24 by TMRh20을 설치한다.

필요한 헤더는 다음과 같다.

#include <SPI.h>       // SPI 통신
#include <nRF24L01.h>  // 레지스터 정의
#include <RF24.h>      // RF24 드라이버 클래스

예제들

[편집 | 원본 편집]

예제 1: 단방향 통신 ("Hello World")

[편집 | 원본 편집]

가장 기본적인 예제로, 송신기가 문자열을 1초마다 보내고 수신기가 시리얼 모니터에 출력한다. 최신 RF24 라이브러리는 주소를 uint64_t 대신 바이트 배열로 지정하는 방식을 권장한다.

송신기 (Transmitter)

[편집 | 원본 편집]
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

RF24 radio(9, 10);  // CE, CSN 핀

const byte address[6] = "00001";  // 5바이트 주소(파이프)

void setup() {
  Serial.begin(9600);
  if (!radio.begin()) {
    Serial.println(F("무선 모듈이 응답하지 않습니다!"));
    while (1) {}  // 무한 루프로 정지
  }
  radio.openWritingPipe(address);   // 송신 파이프 열기
  radio.setPALevel(RF24_PA_LOW);    // 출력 레벨(테스트 시 LOW 권장)
  radio.setDataRate(RF24_250KBPS);  // 데이터 속도(거리↑, 안정성↑)
  radio.stopListening();            // 송신 모드로 전환
}

void loop() {
  const char text[] = "Hello World";
  bool ok = radio.write(&text, sizeof(text));
  Serial.println(ok ? F("전송 성공") : F("전송 실패"));
  delay(1000);
}

수신기 (Receiver)

[편집 | 원본 편집]
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

RF24 radio(9, 10);  // CE, CSN 핀

const byte address[6] = "00001";  // 송신기와 동일해야 함

void setup() {
  Serial.begin(9600);
  if (!radio.begin()) {
    Serial.println(F("무선 모듈이 응답하지 않습니다!"));
    while (1) {}
  }
  radio.openReadingPipe(0, address);  // 수신 파이프 0번 열기
  radio.setPALevel(RF24_PA_LOW);
  radio.setDataRate(RF24_250KBPS);
  radio.startListening();             // 수신 모드로 전환
}

void loop() {
  if (radio.available()) {
    char text[32] = "";
    radio.read(&text, sizeof(text));
    Serial.print(F("수신: "));
    Serial.println(text);
  }
}

예제 2: 구조체로 여러 값 한 번에 전송

[편집 | 원본 편집]

온도·습도·기압처럼 여러 값을 한 패킷(≤ 32바이트)에 담아 보낼 때 struct를 사용한다.

공통 구조체 정의

[편집 | 원본 편집]
struct SensorData {
  byte  id;           // 1바이트
  float temperature;  // 4바이트
  float humidity;     // 4바이트
  int   pressure;     // 2바이트
};  // 총 11바이트 (32바이트 이하)

송신기

[편집 | 원본 편집]
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

RF24 radio(9, 10);
const byte address[6] = "00001";

struct SensorData {
  byte  id;
  float temperature;
  float humidity;
  int   pressure;
};

SensorData data;

void setup() {
  radio.begin();
  radio.openWritingPipe(address);
  radio.setPALevel(RF24_PA_LOW);
  radio.stopListening();
}

void loop() {
  data.id = 1;
  data.temperature = 24.5;
  data.humidity    = 55.2;
  data.pressure    = 1013;
  radio.write(&data, sizeof(data));
  delay(1000);
}

수신기

[편집 | 원본 편집]
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

RF24 radio(9, 10);
const byte address[6] = "00001";

struct SensorData {
  byte  id;
  float temperature;
  float humidity;
  int   pressure;
};

SensorData data;

void setup() {
  Serial.begin(9600);
  radio.begin();
  radio.openReadingPipe(0, address);
  radio.setPALevel(RF24_PA_LOW);
  radio.startListening();
}

void loop() {
  if (radio.available()) {
    radio.read(&data, sizeof(data));
    Serial.print(F("ID: "));    Serial.print(data.id);
    Serial.print(F("  온도: ")); Serial.print(data.temperature);
    Serial.print(F("  습도: ")); Serial.print(data.humidity);
    Serial.print(F("  기압: ")); Serial.println(data.pressure);
  }
}

예제 3: 양방향 통신 (송수신 전환)

[편집 | 원본 편집]

한 노드가 송신과 수신을 번갈아 수행한다. 두 노드는 서로 다른 주소를 쓴다.

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

RF24 radio(9, 10);

// 두 개의 주소: 송신자와 수신자는 아래 노드 순서를 반대로 하면 된다.
const byte addresses[][6] = {"NODE1", "NODE2"};  // 문자열이 아니라 바이트 배열로 채널을 잡는다. 5개 문자열만 가능.
// 배열 크기는 6개로 하고, 마지막에는 \0을 넣어 종료를 알린다.

bool isNode1 = true;  // 상대 노드에서는 false로 설정

void setup() {
  Serial.begin(9600);
  radio.begin();
  if (isNode1) {
    radio.openWritingPipe(addresses[1]);     // NODE2로 송신
    radio.openReadingPipe(1, addresses[0]);  // NODE1로 수신
  } else {
    radio.openWritingPipe(addresses[0]);
    radio.openReadingPipe(1, addresses[1]);
  }
  radio.setPALevel(RF24_PA_LOW);
}

void loop() {
  // --- 송신 단계 ---
  radio.stopListening();
  const char msg[] = "PING";
  radio.write(&msg, sizeof(msg));

  // --- 수신 단계 ---
  radio.startListening();
  unsigned long started = millis();
  while (!radio.available()) {
    if (millis() - started > 200) return;  // 200ms 타임아웃
  }
  char reply[32] = "";
  radio.read(&reply, sizeof(reply));
  Serial.print(F("응답 수신: "));
  Serial.println(reply);

  delay(500);
}

주요 함수 정리

[편집 | 원본 편집]
RF24 라이브러리 핵심 메서드
함수 설명
radio.begin() 모듈 초기화. 성공 시 true 반환
radio.openWritingPipe(addr) 송신 파이프 주소 설정
radio.openReadingPipe(n, addr) n번(0~5) 수신 파이프 주소 설정
radio.startListening() 수신 모드 진입
radio.stopListening() 송신 모드 진입
radio.write(&buf, len) 데이터 송신(ACK 수신 시 true)
radio.available() 수신 데이터 존재 여부
radio.read(&buf, len) 수신 데이터 읽기
radio.setPALevel(level) 출력 레벨: RF24_PA_MIN / LOW / HIGH / MAX
radio.setDataRate(rate) 속도: RF24_250KBPS / RF24_1MBPS / RF24_2MBPS
radio.setChannel(ch) 채널(0~125) 설정
radio.setRetries(delay, count) 재전송 간격·횟수 설정
radio.printDetails() 디버깅 정보 시리얼 출력

문제 해결 (Troubleshooting)

[편집 | 원본 편집]
  • 전송이 계속 실패하거나 데이터가 안 옴 → 전원 문제일 가능성이 가장 큼. VCC–GND에 10~100 µF 커패시터 추가, 외장 3.3 V 전원 사용.
  • 송·수신이 안 됨 → 양쪽의 주소·데이터 속도·채널이 일치하는지 확인.
  • radio.begin()이 false → SPI 배선(MOSI/MISO/SCK) 및 CE/CSN 핀 번호 확인. printDetails()로 레지스터 값이 0x00/0xFF만 나오면 배선 불량.
  • 거리가 짧음 → 데이터 속도를 250 kbps로 낮추고, PA 레벨을 높이거나 PA/LNA 외장 안테나 모듈 사용.
  • 간헐적 끊김 → Wi-Fi(1~11 채널) 간섭 회피를 위해 상위 채널(예: 100번 이상) 사용.

안전 및 규제

[편집 | 원본 편집]
  • 2.4GHz ISM 대역은 비면허 대역이나, 출력 및 사용 규정은 국가별로 다를 수 있으므로 고출력 PA/LNA 모듈 사용 시 국내 전파 규정을 확인한다.
  • 다수 모듈을 밀집 배치할 경우 상호 간섭을 줄이기 위해 채널을 분리한다.
  1. How To Mechatronics, "nRF24L01 – How It Works".

외부 링크

[편집 | 원본 편집]