
这次我们来看一个基于 NRF24L01 无线模块和 ESP32 的环境检测传输系统设计。这个项目的核心目标是让你能够用一套成本低廉、开发便捷的硬件方案实现环境数据比如温湿度的无线采集与传输。它结合了 ESP32 强大的 Wi-Fi/蓝牙能力和 NRF24L01 的低功耗、远距离 2.4GHz 无线通信特性非常适合作为物联网、智能家居或远程监控的入门级实践项目。这个设计最值得关注的点在于其“混搭”架构使用 ESP32 作为主控和数据汇聚/转发节点而 NRF24L01 则负责与分布式的传感器节点进行通信。这意味着你可以将多个搭载了 NRF24L01 和传感器的 STM32 或 Arduino 设备部署在不同位置它们将采集的数据通过 NRF24L01 发送给中央的 ESP32再由 ESP32 通过 Wi-Fi 上传到服务器或本地显示。整个方案硬件门槛低代码基于 Arduino 框架对新手友好。本文将带你从零开始一步步完成这个系统的搭建。我们会先梳理整个系统的核心能力与硬件选型然后分别讲解发送端STM32/Arduino 传感器 NRF24L01和接收端ESP32 NRF24L01的硬件连接、库安装、代码编写与烧录。最后我们会测试无线通信的稳定性并探讨如何将 ESP32 接收到的数据通过串口打印或 Wi-Fi 发送出去。无论你是想学习无线通信还是为毕业设计、科创比赛寻找一个可靠的物联网原型这篇文章都能提供一条清晰的实现路径。1. 核心能力速览在深入细节之前我们先通过一个表格快速了解这个项目的关键信息帮助你判断是否适合你的需求。能力项说明项目类型物联网无线传感网络原型系统核心功能通过 NRF24L01 模块无线传输环境传感器数据如温湿度由 ESP32 接收并处理/转发。发送端主控STM32 系列如 STM32F103C8T6或 Arduino如 Arduino Uno/Nano接收端主控ESP32 开发板如 ESP32-WROOM-32无线模块NRF24L01增强版建议使用带 PALNA 的版本以增加距离通信协议2.4GHz ISM 频段 SPI 接口通信开发环境Arduino IDE推荐或 PlatformIO关键库RF24库用于 NRF24L01 驱动、传感器对应库如DHT通信距离理论视距可达数十米至百米受模块版本、天线、环境干扰影响数据接口接收端 ESP32 可提供串口输出并可扩展 Wi-Fi 上传MQTT/HTTP适合场景物联网教学实验、分布式环境监测原型、智能家居传感器节点、低功耗无线数据采集2. 适用场景与使用边界这个设计方案并非一个商业级的产品而是一个极具学习价值和原型验证能力的工程实践。理解它的适用边界能帮助你更好地利用它并避免走入误区。它非常适合以下场景嵌入式与物联网入门学习如果你想一次性接触 STM32/Arduino、ESP32、SPI 通信、无线模块和传感器这个项目几乎涵盖了所有基础知识点。毕业设计或课程设计提供一个完整的“数据采集-无线传输-数据汇聚”框架你可以更换不同的传感器如光照、气体、土壤湿度来适配不同的题目。智能家居原型验证在决定使用 Zigbee、蓝牙 Mesh 或 Wi-Fi 直连之前可以用此方案快速验证多个房间温湿度监测的可行性。小型分布式监测系统例如在温室、仓库或实验室内部署多个检测点将数据汇总到一个中心节点。需要注意的使用边界非高可靠性通信NRF24L01 工作在拥挤的 2.4GHz 频段易受 Wi-Fi、蓝牙等干扰。在复杂电磁环境中通信稳定性会下降不适合对数据丢包率要求极高的控制场景。传输速率有限其数据吞吐量远低于 Wi-Fi适合传输传感器产生的低频、小数据包如几秒一次的温度值。功耗考量虽然 NRF24L01 本身有低功耗模式但本项目示例代码通常为简化起见未做深度优化。若需要电池长期供电需自行优化发送端的睡眠与唤醒策略。网络拓扑简单本项目演示的是最简单的点对点或一对多一个接收端多个发送端星型网络。要实现复杂的多跳自组织网络需要更复杂的协议栈这超出了本基础项目的范围。安全与隐私NRF24L01 的通信默认是明文的。如果传输的数据涉及隐私需要在应用层自行添加加密。同时部署时应注意不要监测他人隐私空间。3. 环境准备与前置条件动手之前请确保你已准备好以下软硬件环境。这是项目成功的基础。硬件清单发送端1套或以上主控芯片STM32F103C8T6蓝色 pill 板或 Arduino Uno/Nano。无线模块NRF24L01 模块 *1强烈建议使用带外部天线和 PALNA 的版本如 NRF24L01PALNA。传感器DHT11 或 DHT22 温湿度传感器 *1或其他你感兴趣的传感器如 BMP280。杜邦线若干公对公、母对母、公对母。电源USB 数据线或 3.7V 锂电池为发送端供电。接收端1套主控芯片ESP32 开发板如 ESP32-WROOM-32*1。无线模块NRF24L01 模块 *1版本最好与发送端一致。杜邦线若干。电源USB 数据线为 ESP32 供电。公共部分电脑用于编程和串口监控。USB 转串口工具如果你的 STM32 板没有内置 USB 转串口芯片如 CH340则需要一个。软件环境准备Arduino IDE从官网下载并安装最新版。开发板支持包ESP32在 Arduino IDE 的“文件”-“首选项”-“附加开发板管理器网址”中添加https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json。然后在“工具”-“开发板”-“开发板管理器”中搜索并安装esp32。STM32需要安装 STM32 的 Arduino 核心。可以通过“开发板管理器”安装STM32 Cores或者使用Roger Clark的 STM32 核心。安装后在开发板中选择对应的型号如Generic STM32F1 series-BluePill F103C8。Arduino如果是 Arduino Uno/Nano则已内置支持。必要的库RF24库用于驱动 NRF24L01。在 Arduino IDE 的“项目”-“加载库”-“管理库”中搜索RF24并安装作者为TMRh20。DHT sensor library用于读取 DHT11/DHT22 数据。同样在库管理中搜索安装。Adafruit Unified SensorDHT 库的依赖库通常安装 DHT 库时会提示安装请一并安装。4. 硬件连接详解NRF24L01 模块与不同主控的连接是项目的关键。模块引脚定义通常为GND,VCC,CE,CSN,SCK,MOSI,MISO,IRQ。其中IRQ在本基础项目中可悬空。4.1 发送端以 STM32F103C8T6 为例连接将 NRF24L01 模块连接到 STM32 的 SPI1 接口是常见做法。以下是连接对照表NRF24L01 引脚STM32F103C8T6 引脚功能说明VCC3.3V务必接 3.3V接 5V 会烧毁模块。GNDGND共地。CEPA1(或其他任意 GPIO)芯片使能用于控制工作模式。CSNPA4(或其他任意 GPIO)SPI 片选低电平有效。SCKPA5SPI 时钟线。MOSIPA7主设备输出从设备输入。MISOPA6主设备输入从设备输出。DHT11 传感器连接VCC-3.3V或5V(DHT11 兼容 3.3V-5.5V)GND-GNDDATA-PA0(或其他任意 GPIO)4.2 接收端ESP32连接ESP32 有多个 SPI 接口这里使用默认的 VSPI (SPI3)。连接如下NRF24L01 引脚ESP32 引脚功能说明VCC3.3V接 3.3V 电源引脚。GNDGND共地。CEGPIO5(或其他任意 GPIO)芯片使能。CSNGPIO15(或其他任意 GPIO)SPI 片选。SCKGPIO18(VSPI SCK)SPI 时钟线。MOSIGPIO23(VSPI MOSI)主设备输出。MISOGPIO19(VSPI MISO)主设备输入。注意引脚定义在代码中需要严格对应。CE和CSN可以更换为其他你喜欢的 GPIO但代码中必须同步修改。5. 发送端代码编写与烧录发送端STM32/Arduino的任务是初始化传感器和 NRF24L01循环读取传感器数据并通过无线模块发送出去。5.1 STM32 发送端代码示例以下是一个基于RF24库和DHT库的示例代码框架。请根据你的实际连接修改引脚定义。/** * NRF24L01 发送端代码 (STM32F103C8T6) * 功能读取 DHT11 温湿度通过 NRF24L01 发送 */ #include SPI.h #include nRF24L01.h #include RF24.h #include DHT.h // 定义 NRF24L01 引脚 #define CE_PIN PA1 #define CSN_PIN PA4 // 定义 DHT11 引脚和类型 #define DHTPIN PA0 #define DHTTYPE DHT11 // 创建 NRF24 和 DHT 对象 RF24 radio(CE_PIN, CSN_PIN); DHT dht(DHTPIN, DHTTYPE); // 设置通信管道地址收发双方必须一致 const byte address[6] 00001; // 5字节地址 // 定义要发送的数据结构 struct SensorData { float temperature; float humidity; uint32_t nodeID; // 发送节点ID用于区分多个发送端 }; SensorData dataToSend; uint32_t myNodeID 1; // 假设此发送端ID为1 void setup() { Serial.begin(115200); // 用于调试输出 while (!Serial); // 等待串口连接仅用于调试实际应用可去掉 // 初始化 DHT 传感器 dht.begin(); delay(2000); // 给传感器稳定时间 // 初始化 NRF24L01 if (!radio.begin()) { Serial.println(NRF24L01 初始化失败检查硬件连接。); while (1); // 停止执行 } radio.openWritingPipe(address); // 设置发送管道地址 radio.setPALevel(RF24_PA_MAX); // 设置功率级别MAX, HIGH, LOW, MIN radio.setDataRate(RF24_250KBPS); // 设置数据速率250KBPS, 1MBPS, 2MBPS radio.setChannel(76); // 设置通信频道0-125避免常用WiFi频道 radio.stopListening(); // 设置为发送模式 Serial.println(发送端初始化完成准备发送数据...); dataToSend.nodeID myNodeID; } void loop() { // 读取温湿度 float h dht.readHumidity(); float t dht.readTemperature(); // 检查读取是否成功 if (isnan(h) || isnan(t)) { Serial.println(读取 DHT 传感器失败); delay(2000); return; } // 填充数据 dataToSend.temperature t; dataToSend.humidity h; // 通过 NRF24L01 发送数据 bool report radio.write(dataToSend, sizeof(dataToSend)); // 调试信息输出到串口 Serial.print(节点 ); Serial.print(dataToSend.nodeID); Serial.print(: 温度); Serial.print(t); Serial.print(°C, 湿度); Serial.print(h); Serial.print(% - 发送); Serial.println(report ? 成功 : 失败); // 每 5 秒发送一次 delay(5000); }5.2 代码烧录到 STM32在 Arduino IDE 中选择正确的开发板工具-开发板-Generic STM32F1 series-BluePill F103C8。选择正确的烧录方式工具-Upload method-STM32CubeProgrammer (DFU)或Serial取决于你的烧录器。连接好 USB 转串口工具选择对应的端口。点击上传按钮将代码编译并烧录到 STM32。对于 Arduino Uno/Nano 发送端代码逻辑完全相同只需修改CE_PIN、CSN_PIN、DHTPIN为你实际连接的 Arduino 引脚如9,10,2并选择对应的 Arduino 开发板即可。6. 接收端代码编写与烧录接收端ESP32的任务是初始化 NRF24L01持续监听无线数据接收到数据后通过串口打印出来为后续通过 Wi-Fi 上传做好准备。6.1 ESP32 接收端代码示例/** * NRF24L01 接收端代码 (ESP32) * 功能接收无线数据并通过串口打印 */ #include SPI.h #include nRF24L01.h #include RF24.h // 定义 NRF24L01 引脚 (与硬件连接一致) #define CE_PIN 5 #define CSN_PIN 15 // 创建 NRF24 对象 RF24 radio(CE_PIN, CSN_PIN); // 设置通信管道地址必须与发送端一致 const byte address[6] 00001; // 定义接收数据结构必须与发送端严格一致 struct SensorData { float temperature; float humidity; uint32_t nodeID; }; SensorData dataReceived; void setup() { Serial.begin(115200); while (!Serial); // 等待串口连接便于调试 Serial.println(ESP32 NRF24L01 接收端启动...); // 初始化 NRF24L01 if (!radio.begin()) { Serial.println(NRF24L01 初始化失败); while (1); } radio.openReadingPipe(0, address); // 打开接收管道0并设置地址 radio.setPALevel(RF24_PA_MAX); // 功率级别与发送端匹配 radio.setDataRate(RF24_250KBPS); // 数据速率与发送端匹配 radio.setChannel(76); // 频道与发送端匹配 radio.startListening(); // 设置为接收模式 Serial.println(开始监听无线数据...); } void loop() { if (radio.available()) { // 检查是否有数据到来 radio.read(dataReceived, sizeof(dataReceived)); // 读取数据 // 打印接收到的数据 Serial.print(收到数据 [节点:); Serial.print(dataReceived.nodeID); Serial.print(] - 温度: ); Serial.print(dataReceived.temperature); Serial.print( °C, 湿度: ); Serial.print(dataReceived.humidity); Serial.println( %); // 此处可以添加代码将 dataReceived 通过 Wi-Fi 发送到服务器 // 例如使用 HTTP Client 或 MQTT Client } // 短暂延迟避免 loop 空转消耗 CPU delay(10); }6.2 代码烧录到 ESP32 并测试在 Arduino IDE 中选择开发板工具-开发板-ESP32 Arduino- 选择你的具体型号如ESP32 Dev Module。选择正确的端口。点击上传按钮。烧录完成后打开 Arduino IDE 的串口监视器将波特率设置为115200。确保发送端已上电并运行。观察串口监视器你应该能看到类似以下的输出ESP32 NRF24L01 接收端启动... 开始监听无线数据... 收到数据 [节点:1] - 温度: 25.30 °C, 湿度: 56.00 % 收到数据 [节点:1] - 温度: 25.32 °C, 湿度: 55.80 %如果能看到规律性的数据恭喜你无线通信链路已经打通7. 功能扩展ESP32 数据上传至网络仅仅在串口显示数据还不够ESP32 的核心优势是 Wi-Fi。我们可以轻松地将接收到的数据上传到物联网平台如阿里云、腾讯云或自己搭建的服务器。7.1 通过 HTTP POST 上传数据以下示例展示如何将数据以 JSON 格式 POST 到一个假设的服务器接口。你需要修改ssid、password和serverUrl。// 在 setup() 函数中初始化 Wi-Fi #include WiFi.h #include HTTPClient.h const char* ssid 你的Wi-Fi名称; const char* password 你的Wi-Fi密码; const char* serverUrl http://your-server.com/api/sensor-data; // 替换为你的服务器地址 void setup() { // ... 之前的 NRF24 初始化代码 ... // 连接 Wi-Fi WiFi.begin(ssid, password); Serial.print(正在连接Wi-Fi); while (WiFi.status() ! WL_CONNECTED) { delay(500); Serial.print(.); } Serial.println(\nWi-Fi连接成功!); Serial.print(IP地址: ); Serial.println(WiFi.localIP()); } // 在 loop() 函数中接收到数据后调用上传函数 void uploadDataToServer(SensorData data) { if (WiFi.status() WL_CONNECTED) { HTTPClient http; http.begin(serverUrl); http.addHeader(Content-Type, application/json); // 构建 JSON 数据 String jsonPayload {; jsonPayload \node_id\: String(data.nodeID) ,; jsonPayload \temperature\: String(data.temperature) ,; jsonPayload \humidity\: String(data.humidity); jsonPayload }; int httpResponseCode http.POST(jsonPayload); if (httpResponseCode 0) { String response http.getString(); Serial.print(HTTP 响应代码: ); Serial.println(httpResponseCode); Serial.print(服务器响应: ); Serial.println(response); } else { Serial.print(HTTP POST 失败错误代码: ); Serial.println(httpResponseCode); } http.end(); } else { Serial.println(Wi-Fi 断开连接无法上传数据); } } void loop() { if (radio.available()) { radio.read(dataReceived, sizeof(dataReceived)); // ... 打印数据的代码 ... // 调用上传函数 uploadDataToServer(dataReceived); } delay(10); }7.2 通过 MQTT 发布数据对于物联网应用MQTT 是更轻量、高效的选择。你需要一个 MQTT 代理Broker如公共的test.mosquitto.org或自建的 EMQX。#include WiFi.h #include PubSubClient.h // 需要安装 PubSubClient 库 // Wi-Fi 配置同上 const char* mqtt_server broker.hivemq.com; // 示例公共 broker const int mqtt_port 1883; const char* mqtt_topic your_project/sensor/data; WiFiClient espClient; PubSubClient client(espClient); void reconnectMQTT() { while (!client.connected()) { Serial.print(尝试连接 MQTT...); String clientId ESP32Client- String(random(0xffff), HEX); if (client.connect(clientId.c_str())) { Serial.println(MQTT 连接成功); } else { Serial.print(失败状态码); Serial.print(client.state()); Serial.println( 5秒后重试...); delay(5000); } } } void setup() { // ... 初始化 NRF24 和 Wi-Fi ... client.setServer(mqtt_server, mqtt_port); } void loop() { if (!client.connected()) { reconnectMQTT(); } client.loop(); if (radio.available()) { radio.read(dataReceived, sizeof(dataReceived)); // ... 打印数据的代码 ... // 发布 MQTT 消息 String payload {\node\: String(dataReceived.nodeID) ,\temp\: String(dataReceived.temperature) ,\humi\: String(dataReceived.humidity) }; if (client.publish(mqtt_topic, payload.c_str())) { Serial.println(MQTT 发布成功); } else { Serial.println(MQTT 发布失败); } } delay(10); }8. 系统调试与性能优化项目搭建完成后稳定性和性能是关键。以下是几个关键的调试和优化方向。8.1 通信稳定性测试与优化增加重发机制在发送端代码中radio.write函数本身有自动应答和重传机制需启用radio.setAutoAck(true)。你可以通过其返回值判断单次发送是否成功并在失败时进行有限次重试。bool sendSuccess false; for (int i 0; i 3; i) { // 最多重试3次 if (radio.write(dataToSend, sizeof(dataToSend))) { sendSuccess true; break; } delay(50); } Serial.println(sendSuccess ? 发送成功 : 发送失败);调整发射功率与数据速率setPALevel和setDataRate需要权衡。RF24_PA_MAX功率最大距离最远但耗电也高RF24_250KBPS速率低抗干扰能力更强但吞吐量小。在复杂环境中降低速率 (RF24_250KBPS) 可能比提高功率更有效。避开 Wi-Fi 信道使用setChannel()将通信频道设置在 Wi-Fi 不常用的区域如 76, 100 等可以减少干扰。电源滤波NRF24L01 对电源噪声敏感。务必确保电源稳定最好在模块的VCC和GND之间并联一个 10uF 的电解电容和一个 0.1uF 的陶瓷电容并尽量靠近模块引脚。8.2 增加多个发送节点系统设计为星型网络一个 ESP32 可以接收多个发送端的数据。只需为每个发送端设置不同的nodeID并在接收端代码中识别即可。发送端的管道地址 (address) 可以相同一对多广播也可以不同一对一。一对多更简单接收端只需打开一个读取管道。8.3 降低发送端功耗如果发送端由电池供电需要优化功耗深度睡眠在两次发送间隔让 STM32/Arduino 和 NRF24L01 进入深度睡眠模式。对于 STM32可以使用Stop或Standby模式对于 Arduino可以使用LowPower库。缩短射频开启时间发送数据后立即调用radio.powerDown()关闭射频部分。降低发送频率根据应用需求尽可能延长数据发送间隔如从 5 秒改为 60 秒。9. 常见问题与排查方法在实践过程中你可能会遇到以下问题。这里提供一份排查清单。问题现象可能原因排查方式解决方案发送端/接收端初始化失败1. 电源问题电压不足或接错2. SPI 引脚连接错误3. 模块损坏1. 用万用表测量模块 VCC-GND 电压是否为稳定的 3.3V。2. 逐一检查 CE, CSN, SCK, MOSI, MISO 连线是否松动、接错。3. 更换模块测试。1. 确保使用 3.3V 供电并增加滤波电容。2. 对照引脚定义表重新连接。3. 更换模块。能初始化但收不到数据1. 收发双方地址不一致2. 收发双方功率、速率、频道设置不一致3. 距离过远或有严重遮挡/干扰4. 发送端未成功进入发送模式 (stopListening)1. 检查代码中address数组是否完全相同。2. 检查setPALevel,setDataRate,setChannel参数。3. 将设备靠近排除环境因素。4. 在发送端代码中加入Serial.println打印发送状态。1. 统一地址。2. 统一通信参数。3. 缩短距离或使用带天线的 PALNA 模块。4. 确保发送端调用了radio.stopListening()。数据接收乱码或错误1. 收发双方数据结构struct定义不一致2. SPI 时钟速度过快某些 STM32 板需调整3. 电源噪声导致数据传输错误1. 对比发送和接收端的SensorData结构体确保成员变量类型和顺序完全一致。2. 在radio.begin()后尝试降低 SPI 速度非标准 API需查阅库的高级用法。3. 加强电源滤波。1. 使用完全相同的数据结构定义。2. 确保使用稳定的 3.3V 电源并添加电容。通信距离非常近1. 使用的基础版 NRF24L01无放大2. 天线放置不当或损坏3. 环境干扰严重如 2.4G Wi-Fi 路由器旁4. 发射功率设置过低1. 确认模块型号。2. 检查天线是否焊接牢固PCB 天线或连接好外置天线。3. 更换测试地点或频道。1. 更换为NRF24L01PALNA版本。2. 确保天线竖直向上远离金属。3. 将setPALevel设为RF24_PA_MAX。ESP32 Wi-Fi 与 NRF24L01 同时工作不稳定1. 两者共用 SPI 总线冲突如果接错2. Wi-Fi 和 NRF24L01 同频段干扰3. ESP32 电源带载能力不足1. 确保 NRF24L01 接在正确的 VSPI 引脚上。2. 观察关闭 Wi-Fi 后 NRF24 通信是否变稳定。3. 使用外部电源为 ESP32 供电或检查 USB 线质量。1. 核对引脚连接。2. 将 NRF24L01 频道 (setChannel) 调整到远离 Wi-Fi 信道的区域。3. 使用质量好的 USB 线或外部 5V 电源。10. 项目总结与进阶方向通过这个项目我们完成了一个从传感器数据采集、无线传输到数据汇聚显示的完整链路。它验证了 NRF24L01 与 ESP32、STM32/Arduino 协同工作的可行性为你构建更复杂的物联网系统打下了坚实基础。这个方案最值得尝试的点在于其高度的灵活性和可扩展性。你可以轻易地将 DHT11 替换为任何其他数字或模拟传感器如光照、火焰、气体传感器只需修改发送端的传感器读取代码。接收端 ESP32 作为网关其强大的网络功能让你可以轻松地将数据流向云端、手机 App 或本地数据库。对于初次尝试者建议先确保点对点通信稳定再考虑增加节点或网络功能。最容易踩的坑通常是电源和引脚连接务必仔细检查。如果你想进一步探索可以考虑以下方向双向通信让 ESP32 不仅可以接收数据还能向特定节点发送控制指令如打开继电器。低功耗网络优化发送端的睡眠策略使用纽扣电池让节点工作数月。网状网络 (Mesh)研究更高级的 RF24Network 库实现节点间中继扩大网络覆盖范围。数据可视化将 ESP32 接收的数据通过 Wi-Fi 发送到 Node-RED、Home Assistant 或自建的 Web 服务器实现图形化仪表盘。外壳与部署为你的发送端和接收端设计 3D 打印外壳并将其部署到实际环境中进行长期稳定性测试。这个项目的所有代码和思路都已为你铺好剩下的就是动手实践和不断调试。建议收藏本文在搭建过程中遇到问题时随时回来查阅排查清单。