掌握nRF24L01:无线通信、Arduino集成、电路与代码全攻略
本教程将学习如何使用nRF24L01收发模块实现两块Arduino开发板间的无线通信。nRF24L01模块是Arduino无线通信的热门选择。 我已在多个Arduino项目中使用此模块,可在此查看部分项目: 可观看以下视频或阅读下方图文教程。内容涵盖nRF24L01收发模块所有必知要点:模块引脚图、工作原理、接线及多个代码示例。 为讲解无线通信,我们将做两个例子:第一个从一块Arduino向另一块发送简单的“Hello World”消息;第二个实现双向通信,第一块Arduino的摇杆控制第二块的舵机,反之第二块的按钮控制第一块的LED。 近观NRF24L01收发模块。它使用2.4 GHz频段,波特率250 kbps至2 Mbps可选。开阔地低波特率下通信距离可达100米。 完整规格参数: 模块可用125个不同信道,意味着可在一地组建125个独立工作的调制解调器网络。每个信道最多6个地址,或每个单元可同时与最多6个其他单元通信。 模块发射时功耗约12mA,甚至低于单个LED。工作电压1.9-3.6V,好消息是其他引脚耐5V逻辑,可直接接Arduino无需电平转换。 三个引脚用于SPI通信,需接Arduino的SPI引脚,注意不同Arduino板SPI引脚不同。CSN和CE引脚可接任意数字引脚,用于设置模块待机/激活模式、切换发射/命令模式。最后一个是中断引脚,非必用。 NRF24L01有多种变体。最流行的是板载天线版。体积更紧凑,但传输距离降至约100米。 第二种变体无板载天线,改为SMA接口,可接吸盘天线以获得更好传输距离。 第三种变体除吸盘天线外,还集成RFX2401C芯片,含PA(功率放大器)和LNA(低噪声放大器)。这放大NRF24L01信号,开阔地通信距离可达1000米。 详细看NRF24L01引脚图,以及NRF24L01+ PA/LNA模块。 两款模块引脚图相同,接线方式一致。 NRF24L01模块连接Arduino开发板的方式如下: 如前所述,不同Arduino板SPI引脚不同,接线时请注意。 本教程所需组件获取链接: 连接好NRF24L01模块到Arduino板后,准备编写发射端和接收端代码。 首先需下载安装RF24库简化编程。也可从Arduino IDE库管理器直接安装。搜索“rf24”,找到并安装TMRh20, Avamander维护的版本。 以下是无线通信的两个代码及其说明。 需包含基础SPI库和新安装的RF24库,创建RF24对象。两个参数为CSN和CE引脚。 接着创建字节数组作为地址(即两模块通信的管道)。 可将此地址改为任意5字母字符串,以选择与哪个接收端通信。本例中发射端和接收端使用相同地址。 setup中初始化radio对象,用radio.openWritingPipe()设置接收端地址(即之前设定的5字母字符串)。 接收端用radio.openReadingPipe()设置相同地址,建立双向通信。 用radio.setPALevel()设置功率放大器级别,本例设为最低(模块距离很近)。 注意:用高功率级别时,建议在模块GND和3.3V间并联旁路电容,以获得更稳定电压。 radio.stopListening()设置模块为发射模式,radio.startListening()设置为接收模式。 loop中,发射端创建字符数组赋值“Hello World”,用radio.write()发送。第一参数为待发送变量。 变量名前的“&”表示取变量地址(存储待发数据的指针),第二参数设置取多少字节。此处sizeof()取字符串“text”全部字节。末尾加1秒延时。 radio.write()单次最多发送32字节。 接收端loop中,用radio.available()检查是否有数据可收。若真,先创建32元素数组“text”存储入站数据。 用radio.read()读取数据存入“text”变量。最后串口打印文本。上传两程序后,打开接收端串口监视器,每秒打印一次“Hello World”。 值得注意的是,电源噪声是用NRF24L01通信时最常见问题。通常RF电路或射频信号对电源噪声敏感。因此,在电源线并联去耦电容总是好主意。电容可为10uF至100uF任意值。 另一常见问题:Arduino 3.3V引脚不总能给NRF24L01供足电。用外部电源供电也是好主意。 看第二个例子,两块Arduino双向无线通信。电路原理图: 所需组件获取链接: 以下是两个代码及说明。 发射端代码 接收端代码 与前例不同之处:双向通信需创建两个管道/地址。 setup中需定义两个管道,注意:第一块Arduino的写地址必须是第二块的读地址,反之亦然——第一块的读地址是第二块的写地址。 loop中用radio.stopListening()设第一块Arduino为发射端,读取摇杆模拟值映射0-180,用radio.write()发送给接收端。 另一端用radio.startListening()设第二块Arduino为接收端,检查是否有可用数据。有数据时循环读取,存入“angleV”变量并用该值旋转舵机。 接着发射端设为接收模式,用空“while”循环等待第二块Arduino发回数据——即按钮按下状态。按钮按下则LED点亮。此过程持续循环,两块Arduino持续收发数据。 再看一个用NRF24L01模块的代码示例。除数据结构与发送方式外,其余不变。 发射端代码 可创建struct(结构体),实际是多类型变量的集合。 注意结构体数据最大32字节。此处含三个byte变量、一个int(4字节)、一个float(4字节)、一个4字符String(4字节),共15字节。 接收端代码 接收端必须定义相同结构体才能接收数据。为测试无线通信是否正常,我在串口监视器打印每个变量。 NRF24L01模块是Arduino项目需要无线通信时的绝佳选择。我已在许多Arduino项目中使用它。 列出所有用到该模块的项目/教程: 每个项目/教程都详细讲解如何使用NRF24L01模块,含电路图、改进代码实现等。 我最爱的项目是这个定制设计的Arduino遥控发射器。实际是14通道遥控器,可控制几乎任何Arduino项目。 本教程到此结束,希望你喜欢并学到新知识. 评论区欢迎提问。
概览

nRF24L01收发模块

频率范围 2.4 – 2.5GHz ISM频段 数据速率 250Kbps / 1Mbps / 2Mbps 最大输出功率 0dBm 工作电压 1.9 – 3.6V 最大工作电流 12.3mA 待机电流 22µA 逻辑输入 5V兼容 通信距离 100米(开阔地) 工作原理


模块变体

nRF24L01模块引脚图

如何将nRF24L01连接到Arduino

Arduino SCK MISO MOSI SS Uno 13 12 11 10 Nano 13 12 11 10 Mega 52 50 51 53
Arduino与nRF24L01代码
发射端代码
/* * Arduino无线通信教程 * 示例1 - 发射端代码 * * by Dejan Nedelkovski, www.HowToMechatronics.com * * Library: TMRh20/RF24, https://github.com/tmrh20/RF24/ */ #include <SPI.h> #include <nRF24L01.h> #include <RF24.h> RF24 radio(7, 8); // CE, CSN const byte address[6] = "00001"; void setup() { radio.begin(); radio.openWritingPipe(address); radio.setPALevel(RF24_PA_MIN); radio.stopListening(); } void loop() { const char text[] = "Hello World"; radio.write(&text, sizeof(text)); delay(1000); }接收端代码
/* * Arduino无线通信教程 * 示例1 - 接收端代码 * * by Dejan Nedelkovski, www.HowToMechatronics.com * * Library: TMRh20/RF24, https://github.com/tmrh20/RF24/ */ #include <SPI.h> #include <nRF24L01.h> #include <RF24.h> RF24 radio(7, 8); // CE, CSN const byte address[6] = "00001"; void setup() { Serial.begin(9600); radio.begin(); radio.openReadingPipe(0, address); radio.setPALevel(RF24_PA_MIN); radio.startListening(); } void loop() { if (radio.available()) { char text[32] = ""; radio.read(&text, sizeof(text)); Serial.println(text); } }代码解析
RF24 radio(7, 8); // CE, CSNconst byte address[6] = "00001";radio.openWritingPipe(address);radio.openReadingPipe(0, address);radio.setPALevel(RF24_PA_MIN);// 发射端 radio.stopListening();// 接收端 radio.startListening();void loop() { const char text[] = "Hello World"; radio.write(&text, sizeof(text)); delay(1000); }void loop() { if (radio.available()) { char text[32] = ""; radio.read(&text, sizeof(text)); Serial.println(text); } }故障排查

双向无线通信:双NRF24L01与Arduino

nRF24L01源代码
/* * Arduino无线通信教程 * 示例2 - 发射端代码 * * by Dejan Nedelkovski, www.HowToMechatronics.com * * Library: TMRh20/RF24, https://github.com/tmrh20/RF24/ */ #include <SPI.h> #include <nRF24L01.h> #include <RF24.h> #define led 12 RF24 radio(7, 8); // CE, CSN const byte addresses[][6] = {"00001", "00002"}; boolean buttonState = 0; void setup() { pinMode(12, OUTPUT); radio.begin(); radio.openWritingPipe(addresses[1]); // 00002 radio.openReadingPipe(1, addresses[0]); // 00001 radio.setPALevel(RF24_PA_MIN); } void loop() { delay(5); radio.stopListening(); int potValue = analogRead(A0); int angleValue = map(potValue, 0, 1023, 0, 180); radio.write(&angleValue, sizeof(angleValue)); delay(5); radio.startListening(); while (!radio.available()); radio.read(&buttonState, sizeof(buttonState)); if (buttonState == HIGH) { digitalWrite(led, HIGH); } else { digitalWrite(led, LOW); } }/* * Arduino无线通信教程 * 示例2 - 接收端代码 * * by Dejan Nedelkovski, www.HowToMechatronics.com * * Library: TMRh20/RF24, https://github.com/tmrh20/RF24/ */ #include <SPI.h> #include <nRF24L01.h> #include <RF24.h> #include <Servo.h> #define button 4 RF24 radio(7, 8); // CE, CSN const byte addresses[][6] = {"00001", "00002"}; Servo myServo; boolean buttonState = 0; void setup() { pinMode(button, INPUT); myServo.attach(5); radio.begin(); radio.openWritingPipe(addresses[0]); // 00001 radio.openReadingPipe(1, addresses[1]); // 00002 radio.setPALevel(RF24_PA_MIN); } void loop() { delay(5); radio.startListening(); if ( radio.available()) { while (radio.available()) { int angleV = 0; radio.read(&angleV, sizeof(angleV)); myServo.write(angleV); } delay(5); radio.stopListening(); buttonState = digitalRead(button); radio.write(&buttonState, sizeof(buttonState)); } }const byte addresses[][6] = {"00001", "00002"};// 发射端 radio.openWritingPipe(addresses[1]); // 00001 radio.openReadingPipe(1, addresses[0]); // 00002// 接收端 radio.openWritingPipe(addresses[0]); // 00002 radio.openReadingPipe(1, addresses[1]); // 00001radio.stopListening(); int potValue = analogRead(A0); int angleValue = map(potValue, 0, 1023, 0, 180); radio.write(&angleValue, sizeof(angleValue));radio.startListening(); if ( radio.available()) { while (radio.available()) { int angleV = 0; radio.read(&angleV, sizeof(angleV)); myServo.write(angleV); }示例3——单包发送多变量
/* Arduino无线通信教程 示例1 - 发射端代码 by Dejan Nedelkovski, www.HowToMechatronics.com Library: TMRh20/RF24, https://github.com/tmrh20/RF24/ */ #include <SPI.h> #include <nRF24L01.h> #include <RF24.h> RF24 radio(7, 8); // CE, CSN const byte address[6] = "00001"; // 结构体最大32字节 - NRF24L01缓冲区限制 struct Data_Package { byte a = 0; byte b = 125; byte c = 255; int d = 1024; float e = 3.141592; String f = "Test"; }; Data_Package data; // 创建上述结构的变量 void setup() { radio.begin(); radio.openWritingPipe(address); radio.setPALevel(RF24_PA_MIN); radio.stopListening(); } void loop() { // 将结构体整个数据发送给接收端 radio.write(&data, sizeof(Data_Package)); delay(500); }// 结构体最大32字节 - NRF24L01缓冲区限制 struct Data_Package { byte a = 0; byte b = 125; byte c = 255; int d = 1024; float e = 3.141592; String f = "Test"; }; Data_Package data; // 创建上述结构的变量/* Arduino无线通信教程 示例1 - 接收端代码 by Dejan Nedelkovski, www.HowToMechatronics.com Library: TMRh20/RF24, https://github.com/tmrh20/RF24/ */ #include <SPI.h> #include <nRF24L01.h> #include <RF24.h> RF24 radio(7, 8); // CE, CSN const byte address[6] = "00001"; // 结构体最大32字节 - NRF24L01缓冲区限制 struct Data_Package { byte a = 0; byte b = 125; byte c = 255; int d = 1024; float e = 3.141592; String f = "Test"; }; Data_Package data; // 创建上述结构的变量 void setup() { Serial.begin(9600); radio.begin(); radio.openReadingPipe(0, address); radio.setPALevel(RF24_PA_MIN); radio.startListening(); } void loop() { // 检查是否有数据可接收 if (radio.available()) { radio.read(&data, sizeof(Data_Package)); // 读取整个数据并存入'data'结构体 } Serial.print("a: "); Serial.print(data.a); Serial.print(" b: "); Serial.print(data.b); Serial.print(" c: "); Serial.print(data.c); Serial.print(" d: "); Serial.print(data.d); Serial.print(" e: "); Serial.print(data.e); Serial.print(" f: "); Serial.println(data.f); }
结语

制造工艺
- 使用 OpenSensors 监测空气质量:Arduino 与 Python 实战指南
- 用 Arduino 制作万能红外遥控器:分步指南
- DIY 数字身高仪:Arduino Nano + VL53L0X 激光测距 + OLED 显示
- JX 波形发生器 – 基于 Arduino 的 DDS 振荡器,带 OLED 显示屏
- DIY VR 滑板:用 Arduino、Google Cardboard 与蓝牙打造虚拟滑雪体验
- Arduino Mega 2560 接 NEO-6M GPS 模块完整教程
- 热敏电阻测温轻松上手:Arduino 分步实战教程
- Arduino 合成乐音:从零实现 88 键钢琴全音域
- Arduino Modbus 从机开发全攻略:基于 RS485 扩展板的分步实现指南
- ArduRadio 闹钟收音机:DIY Arduino FM 收音机与闹钟系统
- Arduino Due 望远镜自动导星系统 rDUINOScope:GPS、RTC、蓝牙、触控屏全集成
- 脑机接口:重连思维与行动