NRF24模块仅接收首个负载:原因排查与修复咨询
问题描述
使用pyNRF库为NRF24无线模块编写脚本,接线方式与官方示例一致,运行官方simple_receiver和simple_sender脚本时通信正常,但自定义脚本仅能接收首个消息,之后接收器陷入停滞:nrf.data_ready()始终返回True,接收的负载不再更新,且首字节数据错误。
发送端核心代码:
while True: if not self.sending_data.empty(): for _ in range(self.sending_data.qsize()-1): send=self.sending_data.get_nowait() if not send: continue if send[0][9] and send[0][10]: pass else: payload = struct.pack("<B"+"?"*13+"f"*6+"h"*2, 0x01, *send[0].values(), *send[1].values(), send[2][0][0], send[2][0][1]) nrf.reset_packages_lost() nrf.send(payload) print("<B"+"?"*13+"f"*6+"h"*2) print(not send) print(len(send[0].values())) print(len(send[1].values())) print(payload) # Send the payload to the address specified above. try: if payload: nrf.wait_until_sent() print("sented") except TimeoutError: print("Timed out") time.sleep(0.2) continue if nrf.get_packages_lost() == 0: print(f"Success: lost={nrf.get_packages_lost()}, retries={nrf.get_retries()}") else: print(f"Error: lost={nrf.get_packages_lost()}, retries={nrf.get_retries()}") time.sleep(1)
接收端核心代码:
while True: while nrf.data_ready(): # Count message and record time of reception. count += 1 now = datetime.now() # Read pipe and payload for message. pipe = nrf.data_pipe() payload = nrf.get_payload() print(payload) # If the length of the message is 9 bytes and the first byte is 0x01, then we try to interpret the bytes # sent as an example message holding a temperature and humidity sent from the "simple-sender.py" program. protocol = payload[0] if len(payload) > 0 else -1 hex = ':'.join(f'{i:02x}' for i in payload) # Show message received as hex. print(f"{now:%Y-%m-%d %H:%M:%S.%f}: pipe: {pipe}, len: {len(payload)}, bytes: {hex}, count: {count}, protocol: {protocol}") nrf.show_registers() if payload[0] == 0x01: for i in payload: print(i) print("Payload rx: " + str(struct.unpack("<B"+"?"*13+"f"*6+"h"*2, payload))) values = struct.unpack("<B"+"?"*13+"f"*6+"h"*2, payload) self.queue.put_nowait(values) time.sleep(0.1)
配置修改说明:仅将数据速率设为2MBps,负载结构从示例的
payload = struct.pack("<Bff", 0x01, temperature, humidity)
修改为自定义结构:
payload = struct.pack("<B"+"?"*13+"f"*6+"h"*2, 0x01, *send[0].values(), *send[1].values(), send[2][0][0], send[2][0][1])
核心原因
- 负载长度不匹配:NRF24模块默认要求固定长度的负载,自定义负载长度(计算得42字节)远大于示例的9字节,但收发两端未配置对应的数据宽度,导致模块无法正确解析后续数据包,陷入错误状态。
- 接收状态未重置:首次接收后,模块的接收中断标志或缓冲区未被正确清空,导致
nrf.data_ready()始终返回True,但实际无新数据。 - 发送端逻辑漏洞:队列处理逻辑可能丢弃数据不彻底,或导致
payload变量未初始化(队列为空时),引发异常或重复发送旧数据。
修复步骤
1. 统一收发两端的负载宽度配置
先计算自定义负载的实际长度:
import struct print(struct.calcsize("<B"+"?"*13+"f"*6+"h"*2)) # 输出应为42
在收发两端的初始化代码中添加:
nrf.set_payload_size(42) # 设置为自定义负载的实际长度
2. 修复接收端状态重置逻辑
在接收端的while nrf.data_ready()循环末尾,添加缓冲区清空或状态标志清除代码:
nrf.flush_rx() # 清空接收缓冲区,重置模块接收状态 # 或使用 nrf.clear_status_flags() 清除中断标志
3. 修复发送端队列处理逻辑
修正队列数据获取逻辑,避免未初始化变量和数据丢弃不彻底:
if not self.sending_data.empty(): # 只保留队列最新的一条数据,丢弃旧数据(需保留所有数据则删除此循环) while self.sending_data.qsize() > 1: self.sending_data.get_nowait() send = self.sending_data.get_nowait() if not send: continue # 后续payload打包逻辑... else: payload = None # 避免队列为空时引用未定义的payload变量
4. 验证负载长度一致性
每次打包后打印负载长度,确保发送的负载长度固定为42字节:
payload = struct.pack(...) print(f"Payload length: {len(payload)}") # 需稳定输出42
若长度不一致,检查send[0].values()、send[1].values()的元素数量是否符合13个布尔值+6个浮点数的要求,以及send[2]的两个短整数是否正确。
5. 调整数据速率(可选)
2MBps速率对信号质量要求较高,若环境存在干扰,可尝试降为1MBps测试:
nrf.set_data_rate(nrf.DATA_RATE_1MBPS)
内容的提问来源于stack exchange,提问作者minestone
相关产品推荐
相关产品推荐

