nRF24L01学习(1)

nRF24L01学习(1)

时间: 2020年9月14日~9月18日
设备: 树莓派4B、nRF24L01无线模块
语言: Python

前言

第一次使用python写东西(Hello World除外),第一次使用树莓派完成某个功能,第一次接触SPI接口的工作原理,所以过程坎坷,简单的驱动程序花了一周时间,而且只是完成了发送端的驱动程序,但是这算是我朝某个目标行进的第一步,码住留以后查阅。

遇到的问题

1、SPI接口的理解

这个问题是我遇到的最大的问题,也是花费时间最多的。

学习的开始就是查阅资料看看前人经验,但是我查阅了两天时间网上关于nRF24L01的经验全部是关于寄存器的,这段时间学到了寄存器的值对nRF状态的影响和反映,但是对于如何用八个管脚去处理那么多寄存器毫无头绪。把电源、时钟、片选、中断管脚排除后,确定树莓派和nRF交流仅靠MOSI和MISO两个管脚后,一点一点分析别人的代码,最后到了第三天才慢慢知道nRF怎么区分树莓派送过来的信号是指令还是数据。

大多数情况下,树莓派和nRF的交流每次以八位二进制为一个单位进行,而主机对nRF的指令是固定不变的信号类似关键字。

例如nRF从MOSI管脚收到树莓派的一个信号为00000000,这是读取地址为00000寄存器的指令,即树莓派让nRF在下一次交流的时候把地址为00000的寄存器里的数据从MISO发过来,所以树莓派在发送读取指令后一般会从MOSI再发送11111111(空操作指令)当作下一次的交流让nRF把东西从MISO发过来。所以树莓派要读地址为AAAAA寄存器的内容,就从MOSI管脚发送000AAAAA,再发送11111111同时读取MISO返回来的数据。

又如nRF从MOSI管脚收到00110000,这是改写地址为10000寄存器的指令,即树莓派告诉nRF“我会在下一次交流把要填入10000寄存器的数据发过来”,之后就通过MOSI进行下一次交流把要填入的八位二进制输进去,而不是像读寄存器指令一样发送11111111总的来说,树莓派要改写地址为AAAAA寄存器的内容,就从MOSI进行两次交流,即发送两次信号,001AAAAA(指令)和BBBBBBBB(要填入的八位二进制)

而其它指令不需要知道寄存器地址,就是完全固定死的信号:
RD_RX_PLOAD 0x61(01100001) 读取接收数据寄存器指令
WR_TX_PLOAD 0xA0(10100000) 写入发送数据寄存器指令
FLUSH_TX 0xE1(11100001) 清除发送数据寄存器指令
FLUSH_RX 0xE2(11100010) 清除接收数据寄存器指令
REUSE_TX_PL 0xE3(11100011) 数据重发指令
NOP 0xFF(11111111) 空操作用于读寄存器

nRF和主机交流一次,MOSI和MISO怎么传输信号?

srdata = '01010101'
ssrdata = list(srdata)
def SPI_RW_reg(sdata):
    i = 0
    GPIO.output(send_CLK,0)			#时钟控制
    for ii in sdata:							#八位二进制逐个交替交换
        time.sleep(0.0001)						#
        GPIO.output(send_mosi, int(ii))		   #第i位二进制输出
        GPIO.output(send_CLK,1)		#时钟控制	#ii为1就输出高电平
        time.sleep(0.0001)						#ii为0就输出低电平
        ssrdata[i] = str(GPIO.input(send_miso))#第i位二进制输入
        GPIO.output(send_CLK,0)		#时钟控制	#同理
        i = i + 1
    srdata = ''.join(ssrdata)
    return srdata					#返回收到的八位二进制
2、Python处理二进制数

因为nRF和主机交流一次是八位二进制交替进行,所以二进制的处理就显得比较重要了,但是Python用其它进制表示数据必须是str类型,然后前面带着进制标志(0b,0o,0x)。
所以我干脆使用str类型处理二进制数,然后单个二进制数处理过程就是利用list()函数把字符串变成列表,把各位分隔后再利用int和str的转换进行赋值和输出等操作,完成处理后再用’’.join()整合回字符串;而对于非单个二进制数的处理,就直接照着str类型处理就好了。

srdata = '01010101'
ssrdata = list(srdata)					#中间列表
def SPI_RW_reg(sdata):
    i = 0
    GPIO.output(send_CLK,0)
    for ii in sdata:
        time.sleep(0.0001)
      	GPIO.output(send_mosi, int(ii))			#str型转换为int型输出
        GPIO.output(send_CLK,1)
        time.sleep(0.0001)
        ssrdata[i] = str(GPIO.input(send_miso))	#输入的int型转换为str型赋值
        GPIO.output(send_CLK,0)
        i = i + 1
    srdata = ''.join(ssrdata)
    return srdata
3、分段检查

代码写完后运行,不报错但是查看nRF的FIFO_STATUS和STATUS寄存器发现两个nRF没有完成无线通信,我怎么知道是发送端的问题还是接收端的问题?
网上检查发送端问题基本是通过发送端是否接收到接收端应答信号判断是否发送成功,但是接收不到应答信号也不能判断是发送端还是接收端的问题,这就比较鸡肋了。最后在一个论坛找到了解决办法。
基本思想就是关闭两端的自动应答,之后才能通过状态寄存器的值判断是没发送成功还是没接收成功。其实认真阅读nRF的手册,就可以知道这个办法。orangesssss
这也暴露了我的一个大问题,对资料的细节关注不够才导致了我的摸索坎坷。

4、接收不到数据

检查状态寄存器无变化,载波检测也无变化,发送端和接收端地址一致、频率一致、数据宽度一致。我猜测是时序问题,或者是我没注意到的设置细节问题。但时间问题,确认发送端发送没问题后,接收端问题留下次学习的时候寻找。

完整代码

import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)
#管脚设置
send_IRQ = 24       # interrupt
send_CLK  = 25      # clock
send_CSN = 8        # select
send_mosi = 10
send_miso  = 9
rec_IRQ = 5      
rec_CLK  = 16      
rec_CSN = 7       
rec_mosi = 20 
rec_miso = 19
send_CE = 6
rec_CE = 26
GPIO.setup(send_CLK,GPIO.OUT)
GPIO.setup(rec_CLK,GPIO.OUT)
GPIO.setup(send_mosi,GPIO.OUT)
GPIO.setup(send_miso,GPIO.IN)
GPIO.setup(rec_mosi,GPIO.OUT)
GPIO.setup(rec_miso,GPIO.IN)
GPIO.setup(send_CSN,GPIO.OUT)
GPIO.setup(rec_CSN,GPIO.OUT)
GPIO.setup(send_CE,GPIO.OUT)
GPIO.setup(rec_CE,GPIO.OUT)
GPIO.setup(send_IRQ,GPIO.IN)
GPIO.setup(rec_IRQ,GPIO.IN)

GPIO.output(send_CSN,1)		#片选信号拉高初始化
GPIO.output(rec_CSN,1)


srdata = '01010101'
print(GPIO.input(send_IRQ))	#中断检查
ssrdata = list(srdata)
def SPI_RW_reg(sdata):      #发送端树莓派与nRF交流的函数
    i = 0
    GPIO.output(send_CLK,0)
    for ii in sdata:
        time.sleep(0.0001)
        GPIO.output(send_mosi, int(ii))
        GPIO.output(send_CLK,1)
        time.sleep(0.0001)
        ssrdata[i] = str(GPIO.input(send_miso))
        GPIO.output(send_CLK,0)
        i = i + 1
    srdata = ''.join(ssrdata)
    return srdata

rdata = '00000000'
rrsdata = list(rdata)
def SPI_rec_RW_reg(rsdata):       #接收端树莓派与nRF交流的函数
    GPIO.output(rec_CLK,0)
    jj = 0
    for j in rsdata:
        time.sleep(0.0001)
        GPIO.output(rec_mosi,int(j))
        GPIO.output(rec_CLK,1)
        time.sleep(0.0001)
        rrsdata[jj] = str(GPIO.input(rec_miso))
        GPIO.output(rec_CLK,0)
        jj = jj + 1
    rdata = ''.join(rrsdata)
    return rdata

def s_write_reg(ADDR,data):       #发送端改写nRF寄存器的值
    command = ['0','0','1','0','0','0','0','0']
    addr = list(ADDR)
    command[3] = addr[3]
    command[4] = addr[4]
    command[5] = addr[5]
    command[6] = addr[6]
    command[7] = addr[7]
    GPIO.output(send_CSN,0)
    addr0 = ''.join(command)
    SPI_RW_reg(addr0)
    SPI_RW_reg(data)
    GPIO.output(send_CSN,1)

def r_write_reg(ADDR,data):      #接收端改写nRF寄存器的值
    command = ['0','0','1','0','0','0','0','0']
    addr = list(ADDR)
    command[3] = addr[3]
    command[4] = addr[4]
    command[5] = addr[5]
    command[6] = addr[6]
    command[7] = addr[7]
    GPIO.output(rec_CSN,0)
    addr0 = ''.join(command)
    SPI_rec_RW_reg(addr0)
    SPI_rec_RW_reg(data)
    GPIO.output(rec_CSN,1)

def s_read_reg(ADDR):       #发送端读取寄存器的值
    command = ['0','0','0','0','0','0','0','0']
    addr = list(ADDR)
    command[3] = addr[3]
    command[4] = addr[4]
    command[5] = addr[5]
    command[6] = addr[6]
    command[7] = addr[7]
    addr0 = ''.join(command)
    GPIO.output(send_CSN,0)
    SPI_RW_reg(addr0)
    data = SPI_RW_reg('11111111')
    GPIO.output(send_CSN,1)
    return data

def r_read_reg(ADDR):       #接收端读取寄存器的值
    command = ['0','0','0','0','0','0','0','0']
    addr = list(ADDR)
    command[3] = addr[3]
    command[4] = addr[4]
    command[5] = addr[5]
    command[6] = addr[6]
    command[7] = addr[7]
    addr0 = ''.join(command)
    GPIO.output(rec_CSN,0)
    SPI_rec_RW_reg(addr0)
    data = SPI_rec_RW_reg('11111111')
    GPIO.output(rec_CSN,1)
    return data

recdata = ['00000000','00000000','00000000','00000000','00000000']
def r_read_RXFIFO():      #接收端读取接受数据寄存器
    GPIO.output(rec_CSN,0)
    SPI_rec_RW_reg('01100001')
    for num in range(0,5):
        recdata[num] = SPI_RW_reg('11111111')
        print('receive data' + recdata[num])
    GPIO.output(rec_CSN,1)
    return recdata

def s_read_RXFIFO():         	 #发送端读取接受数据寄存器
    GPIO.output(send_CSN,0)
    SPI_RW_reg('01100001')
    for num in range(0,5):
        recdata[num] = SPI_RW_reg('11111111')
        print('receive data' + recdata[num])
    GPIO.output(send_CSN,1)
    return recdata

def r_write_TXFIFO(data):        #接收端写入发送数据寄存器
    GPIO.output(rec_CSN,0)
    SPI_rec_RW_reg('10100000')
    SPI_rec_RW_reg(data)
    GPIO.output(rec_CSN,1)

def s_write_TXFIFO(data):        #发送端写入发送数据寄存器
    GPIO.output(send_CSN,0)
    SPI_RW_reg('10100000')
    SPI_RW_reg(data)
    GPIO.output(send_CSN,1)

#清除数据寄存器
def s_FLUSHTX():
    GPIO.output(send_CSN,0)
    SPI_RW_reg('11100001')
    GPIO.output(send_CSN,1)

def r_FLUSHTX():
    GPIO.output(rec_CSN,0)
    SPI_rec_RW_reg('11100001')
    GPIO.output(rec_CSN,1)

def s_FLUSHRX():
    GPIO.output(send_CSN,0)
    SPI_RW_reg('11100010')
    GPIO.output(send_CSN,1)

def r_FLUSHRX():
    GPIO.output(rec_CSN,0)
    SPI_rec_RW_reg('11100010')
    GPIO.output(rec_CSN,1)

checkdata = ['00000000','00000000','00000000','00000000','00000000']

#检查和设置发送端和接收端地址的函数
def rcheck_RXADDR_P0():
    GPIO.output(rec_CSN,0)
    SPI_rec_RW_reg('00001010')
    for num in range(0,5):
        checkdata[num] = SPI_rec_RW_reg('11111111')
    GPIO.output(rec_CSN,1)
    return checkdata

def scheck_TXADDR():
    GPIO.output(send_CSN,0)
    SPI_RW_reg('00010000')
    for num in range(0,5):
        checkdata[num] = SPI_RW_reg('11111111')
    GPIO.output(send_CSN,1)
    return checkdata

def swrite_TXADDR(addrdata):
    GPIO.output(send_CSN,0)
    SPI_RW_reg('00110000')
    for num in range(0,5):
        SPI_RW_reg(addrdata[num])
    GPIO.output(send_CSN,1)

def rwrite_RXADDR_P0(addrdata):
    GPIO.output(rec_CSN,0)
    SPI_rec_RW_reg('00101010')
    for num in range(0,5):
        SPI_rec_RW_reg(addrdata[num])
    GPIO.output(rec_CSN,1)

#set mode配置状态寄存器config第二位PWR_UP置1后经过1.5ms才进入状态-I
s_write_reg('00000000','00001110')
r_write_reg('00000000','00001111')
time.sleep(0.0015)

#set ADDR设置发送端和接受端地址,二者一样才能通信
swrite_TXADDR(['11100111','11100111','11100111','11100111','11100111'])
rwrite_RXADDR_P0(['11100111','11100111','11100111','11100111','11100111'])

#set EN_AA关闭自动应答,方便分开检查发送和接收的完成情况
s_write_reg('00000001','00000000')
r_write_reg('00000001','00000000')

#set EN_RXADDR接收数据通道使能
s_write_reg('00000010','00000000')
r_write_reg('00000010','00000001')

#set SETUP_RETR关闭自动应答,方便分开检查发送和接收完成情况
s_write_reg('00000100','00000000')
r_write_reg('00000100','00000000')

#set RF_CH设置发送频率
s_write_reg('00000101','01111111')
r_write_reg('00000101','01111111')

#set RF_SETUP设置数据传输率和发射功率
s_write_reg('00000110','00001111')
r_write_reg('00000110','00001111')

#设置接收有效数据宽度
r_write_reg('000010001','00000001')

#清除发送数据寄存器,并输入待发送的信号
s_FLUSHTX()
data_tosend = input('input the data tosend:')
for num in range(0,5):
    s_write_TXFIFO(data_tosend)
print('s_FIFO_STATUS' + s_read_reg('00010111'))


GPIO.output(rec_CE,1)   	#使接收端进入接收模式,置1后需等待130us
time.sleep(0.0002)     		#等待200us

#开始发送
for num in range(0,5):
    GPIO.output(send_CE,1)
    time.sleep(0.00002)     #等待20us,因为CE需要保持高电平10us以上
    GPIO.output(send_CE,0)
    time.sleep(0.0002)      #等待200us,条件满足后需要130us才完成发送

print('CD' + r_read_reg('00001001')) #查看接收端是否检测到载波信号
GPIO.output(rec_CE,0)

#检查发送端和接收端的状态
print('s_STATUSreg' + s_read_reg('00000111'))
print('s_FIFO_STATUS' + s_read_reg('00010111'))
print('r_STATUSreg' + r_read_reg('00000111'))
print('r_FIFO_STATUS' + r_read_reg('00010111'))
#查看接收端接收数据寄存器的值
print('received data' + str(r_read_RXFIFO()))

GPIO.cleanup()               #清除管脚设置

学习资料

nRF24L01中文手册
nRF24L01寄存器中文手册
nRF24L01工作原理解析
代码借鉴

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值