NRF24L01使用

NRF24L01

NRF24L01是工作在2.4~2.5GHz世界通用ISM频段的单片机无线收发芯片。

  1. NRF24L01的无线速率可设置1或2Mbps
  2. 使用SPI接口,接口速率支持0~8Mbps
  3. 同一频道下可接收6个通道数据,共有128个频道可以切换
  4. 芯片工作电压1.9~3.6V

image-20201207193321574

image-20210223100414921

管脚功能
CSN芯片片选线,CSN为低电平芯片工作
SCK芯片控制的时钟线
MISO芯片控制数据线
MOSI芯片控制数据线
IRQ中断信号,通讯中MCU主要通过IRQ与24L01通信
CE芯片的模式控制线

增强型的ShockBurstTM模式

NRF24L01集成了所有高速链路层的自动应答、自动重发、数据包识别等操作,无需MCU介入。

接收模式下,NRF24L01可同时接收6个不同通道的数据,每个通道使用不同的地址。芯片可通过STATUS寄存器的RX_P_NO来获取接收数据的通道号。接收时芯片还会通过PID(数据包识别)来判断是否与上一个数据相同,CRC检测数据的完整性,并进行自动应答。接收完毕芯片触发中断RX_DR,数据存储在RX_FIFO中。

发送模式下,在将打包完的数据发送后,芯片将等待接收端的应答信号,若有则触发中断TX_DS并清除TX_FIFO;若无则自动重发,重发次数大于重发计数器ARC_CNT是,STATUS状态寄存器的MAX_RT置“1”,不清除TX_FIFO的数据。

数据长度,NRF24L01的发送数据长度最长32字节,其支持静态和动态1两种模式。在静态模式中,我们通过RX_PW_Px寄存器来接收数据长度,该模式下发送数据长度必须于设定值相同,若要更改数据长度需要操作相关寄存器。在动态模式中,我们需要先设置FEATUREDYNPD寄存器来开启,在接收端可使用命令R_RX_PL_WID来获取数据长度。

NRF24L01的6个通道地址有一定的规则,其中只有数据通道0可配置40位地址。而数据通道1~5则是32位共用地址+各自地址。

地址设置

需要注意:由于芯片要求,在向寄存器写入地址信息时是低字节先写;在配置数据通道2~5,由于仅最后一位可配置,因此定义仅需与设置最后一位即可。

const u8 TX_ADDRESS[TX_ADR_WIDTH]={0x77,0x35,0xF9,0xD3,0xE7}; //发送地址(本机)
const u8 RX0_ADDRESS[RX_ADR_WIDTH]={0x77,0x35,0xF9,0xD3,0xE7}; //接收地址0
const u8 RX1_ADDRESS[RX_ADR_WIDTH]={0xC2,0xC2,0xC2,0xC2,0xC2}; //接收地址1
const u8 RX2_ADDRESS[RX_ADR_WIDTH]={0xC3}; //接收地址2
const u8 RX3_ADDRESS[RX_ADR_WIDTH]={0xC4}; //接收地址3
const u8 RX4_ADDRESS[RX_ADR_WIDTH]={0xC5}; //接收地址4
const u8 RX5_ADDRESS[RX_ADR_WIDTH]={0xC6}; //接收地址5

调试思路

SPI通信

NRF24L01使用SPI通信,驱动它的第一步就是通信部分的,将底层通讯部分的程序封装后,后续的寄存器操作等都是可以跨平台移植的。而SPI的通讯又可以分为模拟和硬件两种实现方式,模拟即通过软件操作GPIO来实现SPI通讯协议,这个方法由于时序是软件操作,对单片机工作频率有限定,更改工作频率可能回导致不可用。硬件即使用单片机内部的片上外设,这个相对更加稳定,但其管脚固定,且有些单片机并没有硬件的SPI外设。两种方法需要根据实际情况选择,这里展示STC15和STM32的硬件SPI下的使用方法

STC15

u8 SPIx_ReadWriteByte(u8 byte)
{
  u8 d_read,d_send=byte;
	
	SPDAT = d_send;//发送数据
	while(!(SPSTAT&SPIF)) //等待数据发送完毕
		;
	SPSTAT = SPIF|WCOL; //清除状态位
	d_read = SPDAT;
  return d_read; 
}

STM32

uint8_t SPIx_ReadWriteByte(SPI_HandleTypeDef* hspi,uint8_t byte)
{
  uint8_t d_read,d_send=byte;
  if(HAL_SPI_TransmitReceive(hspi,&d_send,&d_read,1,0xFF)!=HAL_OK)
  {
    d_read=0xFF;
  }
  return d_read; 
}
动态长度

数据的动态长度必须对下图两个寄存器进行操作

image-20210223132727702image-20210223132745730

	NRF24L01_Write_Reg(NRF_WRITE_REG+DYNPD,0x3F);		//开启6通道DPL
	NRF24L01_Write_Reg(NRF_WRITE_REG+FEATURE,0x04|0x02);//开启DPL和ACK	

在接受端想要获取数据长度便需要发送相关命令,而不是读取RX_PL_Px寄存器中的值

image-20210223132706619

NRF24L01_Read_Buf(R_RX_PL_WID,&length,1);		//读取数据长度

如果在开启32位固定数据长度的情况下,想要实现动态长度一般的效果,便可使用如下代码,核心是对数据进行打包,将长度自动防入发送数据的第一位。

uint8_t NRF24L01_SendSring(uint8_t *txbuf,uint8_t length)
{
	uint8_t sta,i;
	uint8_t tx_buffer[32];//发送数据缓存
	tx_buffer[0]=length-1;//发送数据的首位为数据长度,sizeof求得长度包括了‘\0’
	for(i=0;i<length;i++)
	{
		tx_buffer[i+1] = txbuf[i];//将待发送数据放到数据长度后,组成一个完整需要发送的数据
	}
	
	SPI1_SetSpeed(SPI_BAUDRATEPRESCALER_16); //spi速度为6.75Mhz(24L01的最大SPI时钟为10Mhz) 
	NRF24L01_CE_LOW();
	NRF24L01_Write_Reg(FLUSH_TX,0xff);
  	NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,length);//写数据到TX BUF  32个字节
 	NRF24L01_CE_HIGH();//启动发送	 
  
	while(NRF24L01_IRQ_PIN_READ()!=0);//等待发送完成
  
	sta=NRF24L01_Read_Reg(STATUS);  //读取状态寄存器的值	   
	NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta); //清除TX_DS或MAX_RT中断标志
	if(sta&MAX_TX)//达到最大重发次数
	{
		NRF24L01_Write_Reg(FLUSH_TX,0xff);//清除TX FIFO寄存器 
		return MAX_TX; 
	}
	if(sta&TX_OK)//发送完成
	{
		return TX_OK;
	}
	return 0xff;//其他原因发送失败
}

文中若有错误,欢迎各位在评论区指正,共同学习!


  1. 在许多的中文手册中并未对动态长度部分进行翻译,建议看英文手册 ↩︎

  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
nrf24l01是一款2.4GHz无线收发模块,主要用于短距离通信。下面简要介绍一下它的使用方法。 硬件连接: nrf24l01模块的引脚包括VCC、GND、CE、CSN、SCK、MOSI和MISO,需要连接到单片机上。其中VCC和GND连接电源,CE、CSN、SCK、MOSI和MISO连接SPI接口。 软件编程: 使用nrf24l01需要编写一些驱动程序。驱动程序的主要功能包括初始化nrf24l01、设置工作模式、发送数据和接收数据等。下面是一个简单的示例代码: ```c #include <SPI.h> #include <nRF24L01.h> #include <RF24.h> // 初始化nrf24l01 RF24 radio(9, 10); // CE和CSN引脚连接到9和10号引脚 void setup() { radio.begin(); radio.setChannel(1); // 设置通信频道,范围是0-125 radio.setDataRate(RF24_1MBPS); // 设置数据传输速率,范围是RF24_250KBPS、RF24_1MBPS和RF24_2MBPS radio.setPALevel(RF24_PA_MIN); // 设置发射功率,范围是RF24_PA_MIN、RF24_PA_LOW、RF24_PA_HIGH和RF24_PA_MAX radio.openWritingPipe(0x1234567890LL); // 设置发送管道地址 radio.openReadingPipe(1, 0x1234567891LL); // 设置接收管道地址 radio.startListening(); // 开始监听接收数据 } void loop() { // 发送数据 char data[] = "hello world"; radio.write(&data, sizeof(data)); // 接收数据 if (radio.available()) { char buffer[32]; radio.read(&buffer, sizeof(buffer)); Serial.println(buffer); } } ``` 在这个示例代码中,首先初始化nrf24l01,然后设置通信频道、数据传输速率、发射功率、发送管道地址和接收管道地址等参数。在主循环中,先发送一段数据,然后监听接收数据。如果有数据接收到,就将其打印出来。 需要注意的是,nrf24l01的驱动程序可能因不同的硬件平台和应用场景而有所不同,上述示例代码仅供参考。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值