You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派4与MicroPython环境下Raspberry Pi Pico间NRF24L01通信故障求助

Raspberry Pi 4与Raspberry Pi Pico的NRF24L01无线通信故障排查

我正尝试使用两块NRF24L01模块搭建无线通信系统,采用Raspberry Pi 4 Model B作为一端(使用pyRF24库),Raspberry Pi Pico运行MicroPython作为另一端。此前用RPi4搭配RPi Zero(均用pyRF24库)通信完全正常,但替换为Pico后,无论哪端作为发送/接收,均无法传输数据,且无错误提示。已多次检查引脚连接:

MISO: GP4
MOSI: GP7
SCK: GP6
CSN: GP15
CE: GP14

测试代码

Raspberry Pi 4 Model B代码(基于pyRF24库)

"""
Simple example of using the RF24 class.

See documentation at https://nRF24.github.io/pyRF24
"""

import time
import struct
from pyrf24 import RF24, RF24_PA_MAX, RF24_DRIVER

print(__file__)  # print example name

########### USER CONFIGURATION ###########
# CE Pin uses GPIO number with RPi and SPIDEV drivers, other drivers use
# their own pin numbering
# CS Pin corresponds the SPI bus number at /dev/spidev<a>.<b>
# ie: radio = RF24(<ce_pin>, <a>*10+<b>)
# where CS pin for /dev/spidev1.0 is 10, /dev/spidev1.1 is 11 etc...
CSN_PIN = 0  # aka CE0 on SPI bus 0: /dev/spidev0.0
if RF24_DRIVER == "MRAA":
    CE_PIN = 15  # for GPIO22
elif RF24_DRIVER == "wiringPi":
    CE_PIN = 3  # for GPIO22
else:
    CE_PIN = 22
radio = RF24(CE_PIN, CSN_PIN)

# using the python keyword global is bad practice. Instead we'll use a 1 item
# list to store our float number for the payloads sent
payload = [0.0]

# For this example, we will use different addresses
# An address need to be a buffer protocol object (bytearray)
address = [b"1Node", b"2Node"]
# It is very helpful to think of an address as a path instead of as
# an identifying device destination

# to use different addresses on a pair of radios, we need a variable to
# uniquely identify which address this radio will use to transmit
# 0 uses address[0] to transmit, 1 uses address[1] to transmit
radio_number = bool(
    int(input("Which radio is this? Enter '0' or '1'. Defaults to '0' ") or 0)
)

# initialize the nRF24L01 on the spi bus
if not radio.begin():
    raise OSError("nRF24L01 hardware isn't responding")

# set the Power Amplifier level to -12 dBm since this test example is
# usually run with nRF24L01 transceivers in close proximity of each other
radio.set_pa_level(RF24_PA_MAX)  # RF24_PA_MAX is default

# set TX address of RX node (uses pipe 0)
radio.stop_listening(address[radio_number])  # enter inactive TX mode

# set RX address of TX node into an RX pipe
radio.open_rx_pipe(1, address[not radio_number])  # using pipe 1

# To save time during transmission, we'll set the payload size to be only what
# we need. A float value occupies 4 bytes in memory using struct.calcsize()
# "<f" means a little endian unsigned float
radio.payload_size = struct.calcsize("<f")

# for debugging
# radio.print_details()
# or for human readable data
# radio.print_pretty_details()


def master(count: int = 5):  # count = 5 will only transmit 5 packets
    """Transmits an incrementing float every second"""
    radio.listen = False  # ensures the nRF24L01 is in TX mode

    while count:
        # use struct.pack() to pack your data into a usable payload
        # into a usable payload
        buffer = struct.pack("<f", payload[0])
        # "<f" means a single little endian (4 byte) float value.
        start_timer = time.monotonic_ns()  # start timer
        result = radio.write(buffer)
        end_timer = time.monotonic_ns()  # end timer
        if not result:
            print("Transmission failed or timed out")
        else:
            print(
                "Transmission successful! Time to Transmit:",
                f"{(end_timer - start_timer) / 1000} us. Sent: {payload[0]}",
            )
            payload[0] += 0.01
        time.sleep(1)
        count -= 1

    # recommended behavior is to keep radio in TX mode while idle
    radio.listen = False  # enter inactive TX mode


def slave(timeout: int = 6):
    """Polls the radio and prints the received value. This method expires
    after 6 seconds of no received transmission."""
    radio.listen = True  # put radio into RX mode

    start = time.monotonic()
    while (time.monotonic() - start) < timeout:
        has_payload, pipe_number = radio.available_pipe()
        if has_payload:
            length = radio.payload_size  # grab the payload length
            # fetch 1 payload from RX FIFO
            received = radio.read(length)
            # expecting a little endian float, thus the format string "<f"
            # received[:4] truncates padded 0s in case dynamic payloads are disabled
            payload[0] = struct.unpack("<f", received[:4])[0]
            # print details about the received packet
            print(f"Received {length} bytes on pipe {pipe_number}: {payload[0]}")
            start = time.monotonic()  # reset the timeout timer

    # recommended behavior is to keep radio in TX mode while idle
    radio.listen = False  # enter inactive TX mode

if radio_number == 1:
    slave()
else:
    master()

Raspberry Pi Pico代码(使用MicroPython的nrf24l01库)

from machine import Pin, SPI
import time, struct
from nrf24l01 import NRF24L01

# SPI & Pins
spi = SPI(0, baudrate=4000000, polarity=0, phase=0, sck=Pin(6), mosi=Pin(7), miso=Pin(4))
csn = Pin(15, mode=Pin.OUT)
ce = Pin(14, mode=Pin.OUT)

nrf = NRF24L01(spi, csn, ce, payload_size=4)
pipes = (b"1Node", b"2Node")

# Select role: 0 = sender, 1 = reciever
ROLE = 0

if ROLE == 0:  # Master / Sender
    print("Pipe to send: ", pipes[0])
    print("Pipe to recieve: ", pipes[1])
    nrf.open_tx_pipe(pipes[0])
    nrf.open_rx_pipe(1, pipes[1])
    nrf.stop_listening()
    value = 0.0
    while True:
        buf = struct.pack("<f", value)
        nrf.send(buf)
        print("Sent:", value)
        value += 0.01
        time.sleep(1)

else:  # Slave / Reciever
    print("Pipe to send: ", pipes[1])
    print("Pipe to recieve: ", pipes[0])
    nrf.open_tx_pipe(pipes[1])
    nrf.open_rx_pipe(1, pipes[0])
    nrf.start_listening()
    while True:
        if nrf.any():
            buf = nrf.recv()
            value = struct.unpack("<f", buf)[0]
            print("Received:", value)

可能的故障原因

  • 射频参数不匹配:RPi4端设置了RF24_PA_MAX,但Pico端MicroPython库默认PA级别可能不同;两端未明确设置同一频道,pyRF24默认频道为76,部分MicroPython库默认频道可能不一致。
  • SPI配置或库实现差异:Pico端stop_listening无参数,需确认库是否正确设置了TX地址;虽然SPI模式设置为0(匹配RPi4),但需检查硬件电平兼容性。
  • 电源供应不足:NRF24L01发射时峰值电流较高,Pico的3.3V引脚可能无法提供足够电流,导致模块无法正常工作。
  • 地址/管道配置隐性问题:虽然表面地址匹配,但需确认库对地址的处理是否一致(比如是否自动截断或补全地址长度)。

Pico上使用MicroPython驱动NRF24L01的注意细节

  • 电源稳定性优先:给NRF24L01单独接3.3V电源,并添加100uF滤波电容,避免使用Pico的3.3V引脚直接供电。
  • 强制统一射频参数:手动设置两端的频道、PA级别、数据速率,确保完全一致(比如频道设为40,PA级别设为MAX,数据速率设为1Mbps)。
  • 选择可靠的库:使用维护活跃的MicroPython NRF24L01库,避免过时库的功能缺失或bug。
  • 确认SPI引脚无冲突:Pico的SPI引脚可能被其他功能占用,需确保使用的引脚未被复用为其他外设。

进一步调试建议

  • 打印寄存器配置:RPi4端启用radio.print_pretty_details(),Pico端添加代码读取并打印模块寄存器值,对比两端配置是否一致。
  • 测试单向通信并检查返回值:固定一端发送固定字节(如b"test"),另一端监听,同时检查Pico端send()方法的返回值,确认是否发送成功。
  • 更换频道测试:手动设置两端为同一非WiFi干扰频道(如40),排除频道冲突问题。
  • 硬件连接排查:用万用表检查SPI引脚连接是否牢固,CE/CSN引脚电平是否在对应模式下正常变化。

内容的提问来源于stack exchange,提问作者Nicolas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 12:44:53