一、
无线通信模块nrf24l01采用2.4G技术,同样,蓝牙和wifi模块也是采用的2.4G技术,只是后者在技术的基础之上做了扩展,封装更高,那么我们在做通信的时候,如果只是单纯想完成两个设备之间的通信,我的建议是使用nrf24l01模块*2。之前做过蓝牙模块之间的通信,其优点在于有指定的指令集,集成度高,操作起来十分方便,但是传输速度不快,质量不可靠,实时性不高,所以需要nrf24l01。
二、
在openmv上编写nrf24l01的发送代码,Python。
openmv是用于做图像处理的一个开源项目,将摄像头和一块stm32芯片集成在一起,通过python语言来完成对单片机的控制,以及调用内部的库函数来完成图像处理的部分内容。
首先得知道nrf24l01是如何完成通信的。
1、nrf24l01需要与单片机正常通信,这是通过spi总线来完成的,四根信号线,mosi、miso、sck、cs,注意,并不是nrf24l01上的mosi与单片机的miso连接,这里我在连线的时候是有过犹豫的,之后通过实践证明以及百度,证实了mosi与mosi相连,miso与miso相连。
nrf24l01与单片机是通过spi串行通信,但具体如何完成通信,这涉及到spi协议,网上资料还是很多的,在此是调用了openmv的库内的spi相关函数。调用方法点击跳转:
在此我想说的是,即使调用了spi的库,仍然被一个地方卡住了,正确的使用是这样的:
CS.value(0)
NRF_SPI.send_recv(buff, buff, timeout=500)
CS.value(1)
可以看到,需要经过一次片选的完成才能正确的完成数据的通信,而不是一直片选中该模块就可以完成通信的。
2、nrf24l01的通信,上面说到,四根信号线用在了spi上,还有两个CE、IRQ来完成模块的自身需求,通过配置模块内部的寄存器来完成数据的发送,此处应有代码。
(如需详细了解模块内部的寄存器可以仔细阅读数据手册,那上面说的很清楚,另外,此处只将nrf24l01作为发送端,接收端同理)
def nrf_writereg(reg, dat): # NRF24L01+写寄存器
…
def nrf_readreg(reg):
…
def nrf_writebuf(reg, pBuf, datalen): #pBuf为TX的地址
…
上面这三个函数是对nrf24l01的寄存器进行的基本操作,下面上全部的代码,表示在我的设备上已正常测试通过
import sensor, image, time
import pyb
from pyb import Pin, SPI, ExtInt
# 用户配置 发送和 接收地址,频道
TX_ADDRESS = (0x34, 0x43, 0x10, 0x10, 0x01) # 定义一个静态发送地址
RX_ADDRESS = (0x34, 0x43, 0x10, 0x10, 0x01)
CHANAL = 40 #频道选择
buff = bytearray(2)
def callback(line): #中断服务函数
state = nrf_readreg(FIFO_STATUS) #读取FIFO_STATUS寄存器的值,正常为17
#print("FIFO_STATUS = ", state)
state = nrf_readreg(STATUS) #读取status寄存器的值,state为发送状态,数值46: 正常发送完成, 30:重发超过次数
#print("state = ", state)
nrf_writereg(NRF_WRITE_REG + STATUS, state) #清除中断标志
global nrf_irq_tx_flag
#if(state & RX_DR) #接收到数据
#不会接受到数据的,忽略该种情况
if(state & TX_DS): #发送完数据
nrf_irq_tx_flag = 0
nrf_writereg(FLUSH_TX, NOP) #清除TX FIFO寄存器
print("nTX_DS")
if(state & MAX_RT): #发送超时,达到最多重发次数标志位
nrf_irq_tx_flag = 0 #标记发送失败
nrf_writereg(FLUSH_TX, NOP) #清除TX FIFO寄存器
#有可能是 对方也处于 发送状态
#放弃本次发送
print("nMAX_RT")
if(state & TX_FULL): #TX FIFO 满
print("nTX_FULL")
# 配置spi协议端口,波特率12500*1000
nrf_tx_buff = 'H+!0'
NRF_SPI = SPI(2)
# 配置nrf的CE,io输出模式,初始电平为0
CE = pyb.Pin(pyb.Pin.board.P4, pyb.Pin.OUT)
# 配置IRQ为下降沿触发中断,handler为回调函数(中断服务函数)
NRF_IRQ = pyb.ExtInt(pyb.Pin.board.P5, pyb.ExtInt.IRQ_FALLING, pyb.Pin.PULL_UP, callback)
NRF_IRQ.enable()
# CS
CS = pyb.Pin(pyb.Pin.board.P3, pyb.Pin.OUT)
DATA_PACKET = 32 #一次传输最大可支持的字节数(1~32)
RX_FIFO_PACKET_NUM = 80 #接收 FIFO 的 包 数目 ( 总空间 必须要大于 一副图像的大小,否则 没法接收完 )
ADR_WIDTH = 5 #定义地址长度(3~5)
IS_CRC16 = 1 #1表示使用 CRC16,0表示 使用CRC8 (0~1)
nrf_irq_tx_flag = 0
# 内部配置参量
TX_ADR_WIDTH = ADR_WIDTH #发射地址宽度
TX_PLOAD_WIDTH = DATA_PACKET #发射数据通道有效数据宽度0~32Byte
RX_ADR_WIDTH = ADR_WIDTH #接收地址宽度
RX_PLOAD_WIDTH= DATA_PACKET #接收数据通道有效数据宽度0~32Byte
# /******************************** NRF24L01+ 寄存器命令 宏定义***************************************/
# SPI(nRF24L01) commands , NRF的SPI命令宏定义,详见NRF功能使用文档
NRF_READ_REG = 0x00 # Define read command to register
NRF_WRITE_REG = 0x20 # Define write command to register
RD_RX_PLOAD = 0x61 # Define RX payload register address
WR_TX_PLOAD = 0xA0 # Define TX payload register address
FLUSH_TX = 0xE1 # Define flush TX register command
FLUSH_RX = 0xE2 # Define flush RX register command
REUSE_TX_PL = 0xE3 # Define reuse TX payload register command
NOP = 0xFF # Define No Operation, might be used to read status register
# SPI(nRF24L01) registers(addresses) ,NRF24L01 相关寄存器地址的宏定义
CONFIG = 0x00 # 'Config' register address
EN_AA = 0x01 # 'Enable Auto Acknowledgment' register address
EN_RXADDR = 0x02 # 'Enabled RX addresses' register address
SETUP_AW = 0x03 # 'Setup address width' register address
SETUP_RETR= 0x04 # 'Setup Auto. Retrans' register address
RF_CH = 0x05 # 'RF channel' register address
RF_SETUP = 0x06 # 'RF setup' register address
STATUS = 0x07 # 'Status' register address
OBSERVE_TX= 0x08 # 'Observe TX' register address
CD = 0x09 # 'Carrier Detect' register address
RX_ADDR_P0= 0x0A # 'RX address pipe0' register address
RX_ADDR_P1= 0x0B # 'RX address pipe1' register address
RX_ADDR_P2= 0x0C # 'RX address pipe2' register address
RX_ADDR_P3= 0x0D # 'RX address pipe3' register address
RX_ADDR_P4= 0x0E # 'RX address pipe4' register address
RX_ADDR_P5= 0x0F # 'RX address pipe5' register address
TX_ADDR = 0x10 # 'TX address' register address
RX_PW_P0 = 0x11 # 'RX payload width, pipe0' register address
RX_PW_P1 = 0x12 # 'RX payload width, pipe1' register address
RX_PW_P2 = 0x13 # 'RX payload width, pipe2' register address
RX_PW_P3 = 0x14 # 'RX payload width, pipe3' register address
RX_PW_P4 = 0x15 # 'RX payload width, pipe4' register address
RX_PW_P5 = 0x16 # 'RX payload width, pipe5' register address
FIFO_STATUS= 0x17 # 'FIFO Status Register' register address
#几个重要的状态标记
TX_FULL = 0x01 #TX FIFO 寄存器满标志。 1 为 满,0为 不满
MAX_RT = 0x10 #达到最大重发次数中断标志位
TX_DS = 0x20 #发送完成中断标志位
RX_DR = 0x40 #接收到数据中断标志位
def nrf_writereg(reg, dat): # NRF24L01+写寄存器
buff[0] = reg #先发送寄存器
buff[1] = dat #再发送数据
CS.value(0)
NRF_SPI.send_recv(buff, buff, timeout=500)
CS.value(1)
return buff[0]
def nrf_readreg(reg):
buff[0] = reg #先发送寄存器
buff[1] = 0
CS.value(0)
NRF_SPI.send_recv(buff, buff, timeout=500)
CS.value(1)
return buff[1] #返回读取的值
def nrf_writebuf(reg, pBuf, datalen): #pBuf为TX的地址
buff = bytearray(datalen+1)
buff[0] = reg
ctr = 1
for i in pBuf:
buff[ctr] = i
ctr += 1
CS.value(0)
NRF_SPI.send_recv(buff, buff, timeout=500)
CS.value(1)
return reg #返回NRF24L01的状态
def nrf_link_check(): #检测NRF24L01+与MCU是否正常连接
NRF_CHECH_DATA = 0xd2 #此值为校验数据时使用,可修改为其他值
buff = bytearray(6)
buff[0] = NRF_WRITE_REG + TX_ADDR
buff[1] = NRF_CHECH_DATA
buff[2] = NRF_CHECH_DATA
buff[3] = NRF_CHECH_DATA
buff[4] = NRF_CHECH_DATA
buff[5] = NRF_CHECH_DATA
CS.value(0)
NRF_SPI.send_recv(buff, buff)
CS.value(1)
buff[0] = TX_ADDR
CS.value(0)
NRF_SPI.send_recv(buff, buff)
CS.value(1)
#比较
for i in (buff[1], buff[2], buff[3], buff[4], buff[5]):
if i != NRF_CHECH_DATA:
return 0 #MCU与NRF不正常连接
return 1 #MCU与NRF成功连接
def nrf_init():
## 配置nrf的寄存器
# CE置低,即将开始配置
NRF_SPI.init(SPI.MASTER, baudrate=12500000,polarity=0, phase=0, bits=8, firstbit=SPI.MSB, ti=False, crc=None)
CE.value(0)
nrf_writereg(NRF_WRITE_REG + SETUP_AW, ADR_WIDTH - 2) #设置地址长度为 TX_ADR_WIDTH
nrf_writereg(NRF_WRITE_REG + RF_CH, CHANAL) #设置RF通道为CHANAL
nrf_writereg(NRF_WRITE_REG + RF_SETUP, 0x0f) #设置TX发射参数,0db增益,2Mbps,低噪声增益开启
nrf_writereg(NRF_WRITE_REG + EN_AA, 0x01) #使能通道0的自动应答
nrf_writereg(NRF_WRITE_REG + EN_RXADDR, 0x01) #使能通道0的接收地址
#RX模式配置
#nrf_writebuf(NRF_WRITE_REG + RX_ADDR_P0, RX_ADDRESS, RX_ADR_WIDTH) #写RX节点地址
nrf_writereg(NRF_WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH) #选择通道0的有效数据宽度
#nrf_writereg(NRF_WRITE_REG + CONFIG, 0x0B | (IS_CRC16 << 2)); #配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式
#TX模式配置
nrf_writebuf(NRF_WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH) #写TX节点地址
nrf_writereg(NRF_WRITE_REG + SETUP_RETR, 0x00) #设置自动重发间隔时间:250us + 86us;最大自动重发次数:15次
nrf_writereg(FLUSH_TX, NOP) #清除TX FIFO寄存器
# CE置高,配置完成
CE.value(1)
time.sleep(1)
return nrf_link_check()
def nrf_tx(txbuf, datalen): #NRF24L01+数据发送
if(txbuf == None or datalen == 0):
return 0
global nrf_irq_tx_flag
if(nrf_irq_tx_flag == 0): #上一包发送完之后才能发送下一个包
#默认每次发送一个32byte的包
nrf_irq_tx_flag = 1
#需要 先发送一次数据包后才能 中断发送
CE.value(0) #ce为低,进入待机模式1
nrf_writebuf(NRF_WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH) #写TX节点地址
nrf_writebuf(NRF_WRITE_REG + RX_ADDR_P0, RX_ADDRESS, RX_ADR_WIDTH) #设置RX节点地址 ,主要为了使能ACK!!!
nrf_writereg(NRF_WRITE_REG + CONFIG, 0x0A | (IS_CRC16 << 2)) #配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,发射模式,开启所有中断
nrf_writebuf(WR_TX_PLOAD, txbuf, datalen) #写数据到TX BUF 最大 32个字节
CE.value(1) #CE为高,txbuf非空,发送数据包
i = 0x0fff
while(i != 0):
i -= 1
#print(nrf_readreg(STATUS))
return 1
else:
return 0
while(nrf_init() == 0):
print('nrf not link openmv')
print('nrf link openmv')
print(NRF_SPI)
while(True):
time.sleep(1000)
nrf_tx(nrf_tx_buff.encode('utf-8'), DATA_PACKET)
三、头疼的坑,勿入
1、需要先测试nrf24l01与单片机是否通过spi正常通信(串行),这里有个坑1之前提到过就是片选CS的问题
2、坑2:引脚irq触发中断,其中中断服务函数必须带一个参数line,即使函数里并没用到这个参数,也不用传入参数,但必须这么申明,即def callback(line):
3、坑3:中断服务函数里面需要清除nrf的状态标志寄存器state,清除的方法:从state读到什么状态就往寄存器写什么状态即完成清除。
nrf_writereg(NRF_WRITE_REG + STATUS, state) #清除中断标志
4、坑4:在写入需要发送的数据之前,之前,之前,必须再次写TX、RX节点地址,虽然在初始化里面已经做过这项工作了,目的是:主要为了使能ACK!!!
四、
调试告一段落,过程中,虽多次心态崩了,但还是有收获的。
上面的代码是最大众化的,有了上面的基础,到后来的发送模式,多通道通信也就不在话下了,已测试通过,在此就不在赘述了。
–end
一、
无线通信模块nrf24l01采用2.4G技术,同样,蓝牙和wifi模块也是采用的2.4G技术,只是后者在技术的基础之上做了扩展,封装更高,那么我们在做通信的时候,如果只是单纯想完成两个设备之间的通信,我的建议是使用nrf24l01模块*2。之前做过蓝牙模块之间的通信,其优点在于有指定的指令集,集成度高,操作起来十分方便,但是传输速度不快,质量不可靠,实时性不高,所以需要nrf24l01。
二、
在openmv上编写nrf24l01的发送代码,Python。
openmv是用于做图像处理的一个开源项目,将摄像头和一块stm32芯片集成在一起,通过python语言来完成对单片机的控制,以及调用内部的库函数来完成图像处理的部分内容。
首先得知道nrf24l01是如何完成通信的。
1、nrf24l01需要与单片机正常通信,这是通过spi总线来完成的,四根信号线,mosi、miso、sck、cs,注意,并不是nrf24l01上的mosi与单片机的miso连接,这里我在连线的时候是有过犹豫的,之后通过实践证明以及百度,证实了mosi与mosi相连,miso与miso相连。
nrf24l01与单片机是通过spi串行通信,但具体如何完成通信,这涉及到spi协议,网上资料还是很多的,在此是调用了openmv的库内的spi相关函数。调用方法点击跳转:
在此我想说的是,即使调用了spi的库,仍然被一个地方卡住了,正确的使用是这样的:
CS.value(0)
NRF_SPI.send_recv(buff, buff, timeout=500)
CS.value(1)
可以看到,需要经过一次片选的完成才能正确的完成数据的通信,而不是一直片选中该模块就可以完成通信的。
2、nrf24l01的通信,上面说到,四根信号线用在了spi上,还有两个CE、IRQ来完成模块的自身需求,通过配置模块内部的寄存器来完成数据的发送,此处应有代码。
(如需详细了解模块内部的寄存器可以仔细阅读数据手册,那上面说的很清楚,另外,此处只将nrf24l01作为发送端,接收端同理)
def nrf_writereg(reg, dat): # NRF24L01+写寄存器
…
def nrf_readreg(reg):
…
def nrf_writebuf(reg, pBuf, datalen): #pBuf为TX的地址
…
上面这三个函数是对nrf24l01的寄存器进行的基本操作,下面上全部的代码,表示在我的设备上已正常测试通过
import sensor, image, time
import pyb
from pyb import Pin, SPI, ExtInt
# 用户配置 发送和 接收地址,频道
TX_ADDRESS = (0x34, 0x43, 0x10, 0x10, 0x01) # 定义一个静态发送地址
RX_ADDRESS = (0x34, 0x43, 0x10, 0x10, 0x01)
CHANAL = 40 #频道选择
buff = bytearray(2)
def callback(line): #中断服务函数
state = nrf_readreg(FIFO_STATUS) #读取FIFO_STATUS寄存器的值,正常为17
#print("FIFO_STATUS = ", state)
state = nrf_readreg(STATUS) #读取status寄存器的值,state为发送状态,数值46: 正常发送完成, 30:重发超过次数
#print("state = ", state)
nrf_writereg(NRF_WRITE_REG + STATUS, state) #清除中断标志
global nrf_irq_tx_flag
#if(state & RX_DR) #接收到数据
#不会接受到数据的,忽略该种情况
if(state & TX_DS): #发送完数据
nrf_irq_tx_flag = 0
nrf_writereg(FLUSH_TX, NOP) #清除TX FIFO寄存器
print("nTX_DS")
if(state & MAX_RT): #发送超时,达到最多重发次数标志位
nrf_irq_tx_flag = 0 #标记发送失败
nrf_writereg(FLUSH_TX, NOP) #清除TX FIFO寄存器
#有可能是 对方也处于 发送状态
#放弃本次发送
print("nMAX_RT")
if(state & TX_FULL): #TX FIFO 满
print("nTX_FULL")
# 配置spi协议端口,波特率12500*1000
nrf_tx_buff = 'H+!0'
NRF_SPI = SPI(2)
# 配置nrf的CE,io输出模式,初始电平为0
CE = pyb.Pin(pyb.Pin.board.P4, pyb.Pin.OUT)
# 配置IRQ为下降沿触发中断,handler为回调函数(中断服务函数)
NRF_IRQ = pyb.ExtInt(pyb.Pin.board.P5, pyb.ExtInt.IRQ_FALLING, pyb.Pin.PULL_UP, callback)
NRF_IRQ.enable()
# CS
CS = pyb.Pin(pyb.Pin.board.P3, pyb.Pin.OUT)
DATA_PACKET = 32 #一次传输最大可支持的字节数(1~32)
RX_FIFO_PACKET_NUM = 80 #接收 FIFO 的 包 数目 ( 总空间 必须要大于 一副图像的大小,否则 没法接收完 )
ADR_WIDTH = 5 #定义地址长度(3~5)
IS_CRC16 = 1 #1表示使用 CRC16,0表示 使用CRC8 (0~1)
nrf_irq_tx_flag = 0
# 内部配置参量
TX_ADR_WIDTH = ADR_WIDTH #发射地址宽度
TX_PLOAD_WIDTH = DATA_PACKET #发射数据通道有效数据宽度0~32Byte
RX_ADR_WIDTH = ADR_WIDTH #接收地址宽度
RX_PLOAD_WIDTH= DATA_PACKET #接收数据通道有效数据宽度0~32Byte
# /******************************** NRF24L01+ 寄存器命令 宏定义***************************************/
# SPI(nRF24L01) commands , NRF的SPI命令宏定义,详见NRF功能使用文档
NRF_READ_REG = 0x00 # Define read command to register
NRF_WRITE_REG = 0x20 # Define write command to register
RD_RX_PLOAD = 0x61 # Define RX payload register address
WR_TX_PLOAD = 0xA0 # Define TX payload register address
FLUSH_TX = 0xE1 # Define flush TX register command
FLUSH_RX = 0xE2 # Define flush RX register command
REUSE_TX_PL = 0xE3 # Define reuse TX payload register command
NOP = 0xFF # Define No Operation, might be used to read status register
# SPI(nRF24L01) registers(addresses) ,NRF24L01 相关寄存器地址的宏定义
CONFIG = 0x00 # 'Config' register address
EN_AA = 0x01 # 'Enable Auto Acknowledgment' register address
EN_RXADDR = 0x02 # 'Enabled RX addresses' register address
SETUP_AW = 0x03 # 'Setup address width' register address
SETUP_RETR= 0x04 # 'Setup Auto. Retrans' register address
RF_CH = 0x05 # 'RF channel' register address
RF_SETUP = 0x06 # 'RF setup' register address
STATUS = 0x07 # 'Status' register address
OBSERVE_TX= 0x08 # 'Observe TX' register address
CD = 0x09 # 'Carrier Detect' register address
RX_ADDR_P0= 0x0A # 'RX address pipe0' register address
RX_ADDR_P1= 0x0B # 'RX address pipe1' register address
RX_ADDR_P2= 0x0C # 'RX address pipe2' register address
RX_ADDR_P3= 0x0D # 'RX address pipe3' register address
RX_ADDR_P4= 0x0E # 'RX address pipe4' register address
RX_ADDR_P5= 0x0F # 'RX address pipe5' register address
TX_ADDR = 0x10 # 'TX address' register address
RX_PW_P0 = 0x11 # 'RX payload width, pipe0' register address
RX_PW_P1 = 0x12 # 'RX payload width, pipe1' register address
RX_PW_P2 = 0x13 # 'RX payload width, pipe2' register address
RX_PW_P3 = 0x14 # 'RX payload width, pipe3' register address
RX_PW_P4 = 0x15 # 'RX payload width, pipe4' register address
RX_PW_P5 = 0x16 # 'RX payload width, pipe5' register address
FIFO_STATUS= 0x17 # 'FIFO Status Register' register address
#几个重要的状态标记
TX_FULL = 0x01 #TX FIFO 寄存器满标志。 1 为 满,0为 不满
MAX_RT = 0x10 #达到最大重发次数中断标志位
TX_DS = 0x20 #发送完成中断标志位
RX_DR = 0x40 #接收到数据中断标志位
def nrf_writereg(reg, dat): # NRF24L01+写寄存器
buff[0] = reg #先发送寄存器
buff[1] = dat #再发送数据
CS.value(0)
NRF_SPI.send_recv(buff, buff, timeout=500)
CS.value(1)
return buff[0]
def nrf_readreg(reg):
buff[0] = reg #先发送寄存器
buff[1] = 0
CS.value(0)
NRF_SPI.send_recv(buff, buff, timeout=500)
CS.value(1)
return buff[1] #返回读取的值
def nrf_writebuf(reg, pBuf, datalen): #pBuf为TX的地址
buff = bytearray(datalen+1)
buff[0] = reg
ctr = 1
for i in pBuf:
buff[ctr] = i
ctr += 1
CS.value(0)
NRF_SPI.send_recv(buff, buff, timeout=500)
CS.value(1)
return reg #返回NRF24L01的状态
def nrf_link_check(): #检测NRF24L01+与MCU是否正常连接
NRF_CHECH_DATA = 0xd2 #此值为校验数据时使用,可修改为其他值
buff = bytearray(6)
buff[0] = NRF_WRITE_REG + TX_ADDR
buff[1] = NRF_CHECH_DATA
buff[2] = NRF_CHECH_DATA
buff[3] = NRF_CHECH_DATA
buff[4] = NRF_CHECH_DATA
buff[5] = NRF_CHECH_DATA
CS.value(0)
NRF_SPI.send_recv(buff, buff)
CS.value(1)
buff[0] = TX_ADDR
CS.value(0)
NRF_SPI.send_recv(buff, buff)
CS.value(1)
#比较
for i in (buff[1], buff[2], buff[3], buff[4], buff[5]):
if i != NRF_CHECH_DATA:
return 0 #MCU与NRF不正常连接
return 1 #MCU与NRF成功连接
def nrf_init():
## 配置nrf的寄存器
# CE置低,即将开始配置
NRF_SPI.init(SPI.MASTER, baudrate=12500000,polarity=0, phase=0, bits=8, firstbit=SPI.MSB, ti=False, crc=None)
CE.value(0)
nrf_writereg(NRF_WRITE_REG + SETUP_AW, ADR_WIDTH - 2) #设置地址长度为 TX_ADR_WIDTH
nrf_writereg(NRF_WRITE_REG + RF_CH, CHANAL) #设置RF通道为CHANAL
nrf_writereg(NRF_WRITE_REG + RF_SETUP, 0x0f) #设置TX发射参数,0db增益,2Mbps,低噪声增益开启
nrf_writereg(NRF_WRITE_REG + EN_AA, 0x01) #使能通道0的自动应答
nrf_writereg(NRF_WRITE_REG + EN_RXADDR, 0x01) #使能通道0的接收地址
#RX模式配置
#nrf_writebuf(NRF_WRITE_REG + RX_ADDR_P0, RX_ADDRESS, RX_ADR_WIDTH) #写RX节点地址
nrf_writereg(NRF_WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH) #选择通道0的有效数据宽度
#nrf_writereg(NRF_WRITE_REG + CONFIG, 0x0B | (IS_CRC16 << 2)); #配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式
#TX模式配置
nrf_writebuf(NRF_WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH) #写TX节点地址
nrf_writereg(NRF_WRITE_REG + SETUP_RETR, 0x00) #设置自动重发间隔时间:250us + 86us;最大自动重发次数:15次
nrf_writereg(FLUSH_TX, NOP) #清除TX FIFO寄存器
# CE置高,配置完成
CE.value(1)
time.sleep(1)
return nrf_link_check()
def nrf_tx(txbuf, datalen): #NRF24L01+数据发送
if(txbuf == None or datalen == 0):
return 0
global nrf_irq_tx_flag
if(nrf_irq_tx_flag == 0): #上一包发送完之后才能发送下一个包
#默认每次发送一个32byte的包
nrf_irq_tx_flag = 1
#需要 先发送一次数据包后才能 中断发送
CE.value(0) #ce为低,进入待机模式1
nrf_writebuf(NRF_WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH) #写TX节点地址
nrf_writebuf(NRF_WRITE_REG + RX_ADDR_P0, RX_ADDRESS, RX_ADR_WIDTH) #设置RX节点地址 ,主要为了使能ACK!!!
nrf_writereg(NRF_WRITE_REG + CONFIG, 0x0A | (IS_CRC16 << 2)) #配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,发射模式,开启所有中断
nrf_writebuf(WR_TX_PLOAD, txbuf, datalen) #写数据到TX BUF 最大 32个字节
CE.value(1) #CE为高,txbuf非空,发送数据包
i = 0x0fff
while(i != 0):
i -= 1
#print(nrf_readreg(STATUS))
return 1
else:
return 0
while(nrf_init() == 0):
print('nrf not link openmv')
print('nrf link openmv')
print(NRF_SPI)
while(True):
time.sleep(1000)
nrf_tx(nrf_tx_buff.encode('utf-8'), DATA_PACKET)
三、头疼的坑,勿入
1、需要先测试nrf24l01与单片机是否通过spi正常通信(串行),这里有个坑1之前提到过就是片选CS的问题
2、坑2:引脚irq触发中断,其中中断服务函数必须带一个参数line,即使函数里并没用到这个参数,也不用传入参数,但必须这么申明,即def callback(line):
3、坑3:中断服务函数里面需要清除nrf的状态标志寄存器state,清除的方法:从state读到什么状态就往寄存器写什么状态即完成清除。
nrf_writereg(NRF_WRITE_REG + STATUS, state) #清除中断标志
4、坑4:在写入需要发送的数据之前,之前,之前,必须再次写TX、RX节点地址,虽然在初始化里面已经做过这项工作了,目的是:主要为了使能ACK!!!
四、
调试告一段落,过程中,虽多次心态崩了,但还是有收获的。
上面的代码是最大众化的,有了上面的基础,到后来的发送模式,多通道通信也就不在话下了,已测试通过,在此就不在赘述了。
–end
举报