STM32驱动NRF24L01

一、NRF24L01的相关介绍

1.2 引脚的介绍

关于SPI的引脚就不再说了,这里介绍其余的两个引脚:

        CE 模块控制引脚:芯片开启信号,激活RX或TX模式

        IRQ 模块中断信号输出引脚:其低电平有效,也就是中断时变为低电平,要使用中断时就设置为上拉输入。。我们也可以屏蔽中断信号,直接将这个引脚设置为下拉输入。在以下三种情况变低:

                        Tx FIFO 发完并且收到ACK(使能ACK情况下)

                        Rx FIFO 收到数据

                        达到最大重发次数

1.3 NRF工作模式的介绍

        NRF24L01的工作模式,由CECONFIG寄存器(0X00)PWR_UP(第1位)和PRIM_RX(第0位)位共同控制。

NRF24L01所处模式

PWR_UP位状态

PRIM_RX 位状态

CEFIFO 寄存器状态
关断模式 Shutdown0---
待机模式  Standby1-0无数据传输
发射空闲模式 Idle-TX101TX FIFO为空
发射模式  TX101

                  数据在TX FIFO寄存器中

                停留在发送模式,直至发送完成

接收模式  RX111-

1.3.1 Shutdown 关断工作模式

        在Shutdown 工作模式下,Si24R1所有收发功能模块关闭,芯片停止工作,消耗电流最小,但所有内部寄存器值和FIFO值保持不变,仍可通过SPI实现对寄存器的读写。 设置CONFIG寄存器的PWR_UP位的值为0,芯片立即返回到Shutdown工作模式。

1.3.2 Standby 待机工作模式

         在Standby 工作模式,只有晶体振荡器电路工作,保证了芯片在消耗较少电流的同 时能够快速启动。设置CONFIG寄存器下的PWR_UP位的值为1,芯片待时钟稳定后 进入Standby 模式。芯片的时钟稳定时间一般为1.5~2ms,与晶振的性能有关。当引脚 CE=1 时,芯片将由Standby 模式进入到 Idle-TX 或 RX 模式,当 CE=0 时,芯片将由 Idle-TX、TX 或 RX模式返回到Standby模式。

1.3.3 Idle-TX 发射空闲工作模式

        在Idle-TX 工作模式下,晶体振荡器电路及时钟电路工作。相比于Standby模式, 芯片消耗更多的电流。当发送端TX FIFO寄存器为空,并且引脚CE=1时,芯片进入到 Idle-TX 模式。在该模式下,如果有新的数据包被送到TX FIFO中,芯片内部的电路将 立即启动,切换到TX模式将数据包发送。

         在Standby 和 Idle-TX 工作模式下,所有内部寄存器值和 FIFO 值保持不变,仍可 通过SPI实现对寄存器的读写。

1.3.4 TX 发射工作模式

        当需要发送数据时,需要切换到TX工作模式。芯片进入到TX工作模式的条件为: TX FIFO 中有数据, CONFIG寄存器的PWR_UP位的值为1,PRIM_RX位的值为0, 同时要求引脚CE上有一个至少持续10us的高脉冲。Idle-TX模式切换到TX模式的时 间为 120us~130us 之间,但不会超过 130us。单包数据发送完成后,如果 CE=1, 则由 TX FIFO的状态来决定芯片所处的工作模式,当TX FIFO还有数据,芯片继续保持在 TX工作模式,并发送下一包数据;当TX FIFO没有数据,芯片返回Idle-TX模式;如 果CE=0,立即返回Standby模式。数据发射完成后,芯片产生数据发射完成中断。

1.3.5 RX接收工作模式

        当需要接收数据时,需要切换到RX工作模式。芯片进入到RX工作模式的条件为: 设置寄存器CONFIG的PWR_UP位的值为1,PRIM_RX位的值为1,并且引脚CE=1。 芯片由Standby 模式切换到RX模式的时间为120~130us。当接收到数据包的地址与芯片的地址相同,并且CRC检查正确时,数据会自动存入RX FIFO,并产生数据接收中 断。芯片最多可以同时存三个有效数据包,当FIFO已满,接收到的数据包被自动丢掉。

二、NRF24L01的初始化

首先是关于引脚的初始化,至于SPI时序这里就不多介绍了,可以看这篇文章协议篇之SPI通信(软件篇),而本篇文章就是基于这篇文章写的。至于是使用SPI的哪个模式可以看手册,这里我截取出来了:其中空闲时SCK为低电平,第一个边沿采样,所以使用模式0。

void NRF24L01_Init(void)
{/***** NRF的GPIO初始化 *****/GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	 //使能PB端口时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	 //使能PA端口时钟GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin = NRF_CE_PIN;	//推挽 (配置CE)	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化指定IOGPIO_InitStructure.GPIO_Pin  = NRF_IRQ_PIN;//配置IRQGPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //PB15 上拉输入  GPIO_Init(GPIOA,&GPIO_InitStructure);my_spi_init();NRF_CE(0); 			//使能24L01SPI_NSS(1);			//SPI片选取消
}

NRF24L01的通信条件:

1.   发射接收频道相同(设置频道寄存器RF_CH  0-125);

2.   发射接收地址相同(设置TX_ADDR和RX_ADDR_P0相同  5个8位地址);

3.   发射接收数据宽度相等( n<=32);

4.   发射接收速率相同(250k 1M 2M);

三、NRF的命令以及寄存器

3.1  NRF的命令

        要实现对NRF的读写操作,就需要将命令以及寄存器地址结合起来使用,来实现对寄存器的操作,命令如下:

/*************************  NRF24L01寄存器操作命令  *************************/
#define NRF_READ_REG    0x00  //读配置寄存器,低5位为寄存器地址
#define NRF_WRITE_REG   0x20  //写配置寄存器,低5位为寄存器地址
#define RD_RX_PLOAD     0x61  //读RX有效数据,1~32字节
#define WR_TX_PLOAD     0xA0  //写TX有效数据,1~32字节
#define FLUSH_TX        0xE1  //清除TX FIFO寄存器.发射模式下用
#define FLUSH_RX        0xE2  //清除RX FIFO寄存器.接收模式下用
#define REUSE_TX_PL     0xE3  //重新使用上一包数据,CE为高,数据包被不断发送.
#define NOP             0xFF  //空操作,可以用来读状态寄存器	 

3.2  NRF的寄存器

3.2.1 配置寄存器CONFIG0X00

3.2.2 自动应答使能寄存器EN_AA,0X01)

3.2.3 RX地址使能寄存器EN_RXADDR,0X02)

3.2.4 自动重发设置寄存器SETUP_RETR0X04

3.2.5 射频频率设置寄存器RF_CH,0X05)

频率计算公式:2400+RF_CH  (Mhz)

3.2.6 射频配置寄存器RF_SETUP,0X06)

3.2.7 状态寄存器STATUS0X07

3.2.8 数据通道接收地址寄存器(RX_ADDR_P0~P5,0X0A~0X0F)

3.2.9 发送地址设置寄存器TX_ADDR,0X10)

3.2.10 接收通道有效数据宽度设置寄存器(RX_PW_P0~P5,0X11~0X16)

类似的,其他通道方法同RX_PW_P0。

四、NRF的检查

        时序以及初始化搞好了,那么如何检测时序以及NRF是否正确呢?别的芯片一般可以通过读ID来判断,那么这个芯片的方法是往可读可写寄存器写数据然后读里面的数据是否正确。我们往发送通道写5个字节的数据,然后挨个读取内容,内容一致就说明检测正确,否则失败。

uint8_t NRF24L01_Check(void)
{u8 buf[5] = { 0x01,0x01,0x01,0x01,0x01 };u8 i; MySPI_WriteLen(NRF_WRITE_REG+TX_ADDR,buf,5);//写入5个字节的地址MySPI_ReadLen(TX_ADDR,buf,5); //读出写入的地址for(i=0;i<5;i++)if(buf[i]!=0x01)break;if(i!=5)return 1;//检测24L01错误return 0;         //检测到24L01
}

五、设置NRF为发送模式发送数据

        在对NRF寄存器进行读写操作时,我们需要更改其工作模式,手册里面有提到这句话:

注:只能在Shutdown、Standby和Idle-TX模式下才能对寄存器进行配置。

5.1 设置NRF为发射模式

        由于对寄存器配置时不能为发射或者接收模式,所以我们先将CE置低位使其工作模式更改为待机模式,然后按照下列流程来配置NRF:        

设置为发送模式的流程:

        1)写Tx 节点的地址 TX_ADDR

        2)写Rx 节点的地址(主要是为了使能Auto AckRX_ADDR_P0

        3)使能AUTO ACK EN_AA

        4)使能PIPE 0 EN_RXADDR

        5)配置自动重发次数 SETUP_RETR

        6)选择通信频率 RF_CH

        7)配置发射参数(低噪放大器增益、发射功率、无线速率) RF_SETUP

        8)配置24L01 的基本参数以及切换工作模式 CONFIG

        首先是写Tx节点地址,我们定义有关数组,存放五个字节的数据(TX_ADDR长度有40位,看上面关于他的介绍)利用写寄存器命令和TX_ADDR寄存器地址将这五个字节的地址写入。

        第二步是写Rx节点地址,主要是为了使能自动应答,其地址和Tx节点地址相同,可以看关于Ack模式的介绍有这么一段话“接收端在发送ACK信号时,取接收管道地址作为目标地址来发送ACK信号,所 以发送端需要设置接收管道0地址与自身发送地址相同,以便接收ACK信号

        第三步是配置使能自动应答寄存器,我们使能数据管道0自动确认,所以写入0x01;具体为什么这么配置可以看上文3.2.2关于这个寄存器的介绍。

        第四步是配置使能接收数据管道地址,由于我们发射端需要接收Ack信号,所以我们要使能数据管道0,写入0x01。

        第五步是设置自动重发间隔时间以及最大自动重发次数,低四位由于配置自动重发计数,高四位用于配置自动重发延时,可以看3.2.4关于这个寄存器的介绍。我这里配置为0x1a,设置自动重发间隔时间:500us + 86us;最大自动重发次数:10次。

        第六步是设置通信频率,其值可以为0-125,见3.2.5;我这里写入40,也就是2440MHz。

        第七步是配置发射参数,可以根据寄存器的介绍自己去配置。

        第八步是配置基本参数以及切换工作模式,见寄存器的描述,这里代码如下:

/***** 将NRF设置位发送模式 *****/
void NRF24L01_TX_Mode(void)
{NRF_CE(0);//将CE置低配置为待机模式才能对寄存器进行配置MySPI_WriteLen(NRF_WRITE_REG+TX_ADDR,(u8*)TX_ADDRESS,TX_ADR_WIDTH);//写TX节点地址MySPI_WriteLen(NRF_WRITE_REG+RX_ADDR_P0,(u8*)TX_ADDRESS,RX_ADR_WIDTH);//设置RX节点地址,主要为了使能ACKMySPI_WriteByte(NRF_WRITE_REG+EN_AA,0x01);//使能通道0的自动应答MySPI_WriteByte(NRF_WRITE_REG+EN_RXADDR,0x01);//使能通道0的自动应答MySPI_WriteByte(NRF_WRITE_REG+SETUP_RETR,0x1a);//设置自动重发间隔时间:500us + 86us;最大自动重发次数:10次MySPI_WriteByte(NRF_WRITE_REG+RF_CH,40);       //设置RF通道为40MySPI_WriteByte(NRF_WRITE_REG+RF_SETUP,0x0f);  //设置TX发射参数,0db增益,2Mbps,低噪声增益开启MySPI_WriteByte(NRF_WRITE_REG+CONFIG,0x0e);    //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式,开启所有中断NRF_CE(1);//CE为高,10us后启动发送
}

5.2  NRF发送数据

        要想启动NRF发送数据,我们先将CE拉低进入待机模式才能配置寄存器,利用写函数加写发射负载数据命令写入要发送的数据,注意这个数据大小为1-32字节。然后我们启动发送,将NRF的CE脚拉高进入发射模式,然后读IQR引脚判断是否发送完成(Tx FIFO发完并收到Ack变为低电平)。然后我们读取状态寄存器,其值代表的状态可以看寄存器介绍的3.2.7,首先判断是否到达最大重发次数,其中MAX_TX为0x10,而状态寄存器第四位就是达到最大重发次数中断位,其判断发送完成原理也是如此。

/***********************************************************
函数名称:NRF24L01_TxPacket(u8 *txbuf)
函数功能:启动NRF24L01发送一次数据
入口参数:txbuf  待发送的数据首地址
返回参数:返回值:TX_OK,接收完成,0xff,错误代码
************************************************************/
u8 NRF24L01_TxPacket(u8 *txbuf)
{u8 sta;NRF_CE(0);MySPI_WriteLen(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);//写数据到TX BUF  32个字节NRF_CE(1);//启动发送while(READ_IRQ!=0);//等待发送完成sta=MySPI_ReadByte(STATUS);  //读取状态寄存器的值	   MySPI_WriteByte(NRF_WRITE_REG+STATUS,sta); //清除TX_DS或MAX_RT中断标志if(sta&MAX_TX)//达到最大重发次数{MySPI_WriteByte(FLUSH_TX,0xff);//清除TX FIFO寄存器 return MAX_TX; }if(sta&TX_OK)//发送完成{return TX_OK;}return 0xff;//其他原因发送失败    
}

六、设置NRF为接收模式并接收数据

6.1 设置NRF为接收模式

        其流程如下,和发送模式配置原理类似,可以参考发送模式,这里不再介绍。但是需要注意的就是配置要和发送模式相同,否则会导致通信不上。

设置为发送模式的流程:

        1)写Rx 节点的地址 RX_ADDR_P0

        2)使能AUTO ACK EN_AA

        3)使能PIPE 0 EN_RXADDR

        4)选择通信频率 RF_CH

        5)选择通道0 有效数据宽度 RX_PW_P0

        6)配置发射参数(低噪放大器增益、发射功率、无线速率) RF_SETUP

        7)配置24L01 的基本参数以及切换工作模式 CONFIG。

/***** 将NRF设置为接收模式 *****/
void NRF24L01_RX_Mode(void)
{NRF_CE(0);	 MySPI_WriteLen(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RX_ADDRESS,RX_ADR_WIDTH);//设置RX节点地址MySPI_WriteByte(NRF_WRITE_REG+EN_AA,0x01);//使能通道0的自动应答MySPI_WriteByte(NRF_WRITE_REG+EN_RXADDR,0x01);//使能通道0的自动应答MySPI_WriteByte(NRF_WRITE_REG+RF_CH,40);       //设置RF通道为40MySPI_WriteByte(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);//选择通道0的有效数据宽度 MySPI_WriteByte(NRF_WRITE_REG+RF_SETUP,0x0f);  //设置TX发射参数,0db增益,2Mbps,低噪声增益开启MySPI_WriteByte(NRF_WRITE_REG+CONFIG,0x0f);    //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式,开启所有中断NRF_CE(1);//CE为高,10us后启动发送
}

6.2 接收数据

        通过读取状态寄存器的值判断是否接收到了数据,如果接收到了数据就将数据读取到数组并清除Rx FIFO寄存器方便下次的接收。

/***********************************************************
函数名称:NRF24L01_RxPacket(u8 *rxbuf)
函数功能:启动NRF24L01接收一次数据
入口参数:rxbuf:待接收数据首地址
返回参数:返回值:0,接收完成;其他,错误代码
************************************************************/
u8 NRF24L01_RxPacket(u8 *rxbuf)
{u8 sta;		    							      sta=MySPI_ReadByte(STATUS);  //读取状态寄存器的值    	 MySPI_WriteByte(NRF_WRITE_REG+STATUS,sta); //清除TX_DS或MAX_RT中断标志if(sta&RX_OK)//接收到数据{MySPI_ReadLen(RD_RX_PLOAD,rxbuf,RX_PLOAD_WIDTH);//读取数据MySPI_WriteByte(FLUSH_RX,0xff);//清除RX FIFO寄存器 return 0; }	   return 1;//没收到任何数据
}

nrf24l01.c

#include "stm32f10x.h"                  // Device header
#include "nrf24l01.h"
#include "spi.h"const u8 TX_ADDRESS[TX_ADR_WIDTH]={0x34,0x43,0x10,0x10,0x01}; //发送地址
const u8 RX_ADDRESS[RX_ADR_WIDTH]={0x34,0x43,0x10,0x10,0x01};void NRF24L01_Init(void)
{/***** NRF的GPIO初始化 *****/GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	 //使能PB端口时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	 //使能PA端口时钟GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin = NRF_CE_PIN;	//推挽 (配置CE)	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化指定IOGPIO_InitStructure.GPIO_Pin  = NRF_IRQ_PIN;//配置IRQGPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //PB15 上拉输入  GPIO_Init(GPIOA,&GPIO_InitStructure);my_spi_init();NRF_CE(0); 			//使能24L01SPI_NSS(1);			//SPI片选取消
}
/***** 检测NRF  成功为0 *****/
uint8_t NRF24L01_Check(void)
{u8 buf[5] = { 0x01,0x01,0x01,0x01,0x01 };u8 i; MySPI_WriteLen(NRF_WRITE_REG+TX_ADDR,buf,5);//写入5个字节的地址MySPI_ReadLen(TX_ADDR,buf,5); //读出写入的地址for(i=0;i<5;i++)if(buf[i]!=0x01)break;if(i!=5)return 1;//检测24L01错误return 0;		 //检测到24L01
}
/***** 将NRF设置位发送模式 *****/
void NRF24L01_TX_Mode(void)
{NRF_CE(0);//将CE置低配置为待机模式才能对寄存器进行配置MySPI_WriteLen(NRF_WRITE_REG+TX_ADDR,(u8*)TX_ADDRESS,TX_ADR_WIDTH);//写TX节点地址MySPI_WriteLen(NRF_WRITE_REG+RX_ADDR_P0,(u8*)TX_ADDRESS,RX_ADR_WIDTH);//设置RX节点地址,主要为了使能ACKMySPI_WriteByte(NRF_WRITE_REG+EN_AA,0x01);//使能通道0的自动应答MySPI_WriteByte(NRF_WRITE_REG+EN_RXADDR,0x01);//使能通道0的自动应答MySPI_WriteByte(NRF_WRITE_REG+SETUP_RETR,0x1a);//设置自动重发间隔时间:500us + 86us;最大自动重发次数:10次MySPI_WriteByte(NRF_WRITE_REG+RF_CH,40);       //设置RF通道为40MySPI_WriteByte(NRF_WRITE_REG+RF_SETUP,0x0f);  //设置TX发射参数,0db增益,2Mbps,低噪声增益开启MySPI_WriteByte(NRF_WRITE_REG+CONFIG,0x0e);    //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式,开启所有中断NRF_CE(1);//CE为高,10us后启动发送
}
/***** 将NRF设置为接收模式 *****/
void NRF24L01_RX_Mode(void)
{NRF_CE(0);	 MySPI_WriteLen(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RX_ADDRESS,RX_ADR_WIDTH);//设置RX节点地址MySPI_WriteByte(NRF_WRITE_REG+EN_AA,0x01);//使能通道0的自动应答MySPI_WriteByte(NRF_WRITE_REG+EN_RXADDR,0x01);//使能通道0的自动应答MySPI_WriteByte(NRF_WRITE_REG+RF_CH,40);       //设置RF通道为40MySPI_WriteByte(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);//选择通道0的有效数据宽度 MySPI_WriteByte(NRF_WRITE_REG+RF_SETUP,0x0f);  //设置TX发射参数,0db增益,2Mbps,低噪声增益开启MySPI_WriteByte(NRF_WRITE_REG+CONFIG,0x0f);    //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式,开启所有中断NRF_CE(1);//CE为高,10us后启动发送
}/***********************************************************
函数名称:NRF24L01_TxPacket(u8 *txbuf)
函数功能:启动NRF24L01发送一次数据
入口参数:txbuf  待发送的数据首地址
返回参数:返回值:TX_OK,接收完成,0xff,错误代码
************************************************************/
u8 NRF24L01_TxPacket(u8 *txbuf)
{u8 sta;NRF_CE(0);MySPI_WriteLen(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);//写数据到TX BUF  32个字节NRF_CE(1);//启动发送while(READ_IRQ!=0);//等待发送完成sta=MySPI_ReadByte(STATUS);  //读取状态寄存器的值	   MySPI_WriteByte(NRF_WRITE_REG+STATUS,sta); //清除TX_DS或MAX_RT中断标志if(sta&MAX_TX)//达到最大重发次数{MySPI_WriteByte(FLUSH_TX,0xff);//清除TX FIFO寄存器 return MAX_TX; }if(sta&TX_OK)//发送完成{return TX_OK;}return 0xff;//其他原因发送失败    
}/***********************************************************
函数名称:NRF24L01_RxPacket(u8 *rxbuf)
函数功能:启动NRF24L01接收一次数据
入口参数:rxbuf:待接收数据首地址
返回参数:返回值:0,接收完成;其他,错误代码
************************************************************/
u8 NRF24L01_RxPacket(u8 *rxbuf)
{u8 sta;		    							      sta=MySPI_ReadByte(STATUS);  //读取状态寄存器的值    	 MySPI_WriteByte(NRF_WRITE_REG+STATUS,sta); //清除TX_DS或MAX_RT中断标志if(sta&RX_OK)//接收到数据{MySPI_ReadLen(RD_RX_PLOAD,rxbuf,RX_PLOAD_WIDTH);//读取数据MySPI_WriteByte(FLUSH_RX,0xff);//清除RX FIFO寄存器 return 0; }	   return 1;//没收到任何数据
}

nrf24l01.h

#ifndef __NRF24L010_H
#define __NRF24L010_H#include "stm32f10x.h"                  // Device header#define NRF_IRQ_PORT        GPIOA
#define NRF_IRQ_PIN         GPIO_Pin_8
#define NRF_CE_PORT         GPIOB
#define NRF_CE_PIN          GPIO_Pin_11#define NRF_CE(x)    NRF_CE_PORT->BSRR = NRF_CE_PIN<<(16*(!x))
#define READ_IRQ    (BitAction)(NRF_IRQ_PORT->IDR & NRF_IRQ_PIN)/*************************  NRF24L01寄存器操作命令  *************************/
#define NRF_READ_REG    0x00  //读配置寄存器,低5位为寄存器地址
#define NRF_WRITE_REG   0x20  //写配置寄存器,低5位为寄存器地址
#define RD_RX_PLOAD     0x61  //读RX有效数据,1~32字节
#define WR_TX_PLOAD     0xA0  //写TX有效数据,1~32字节
#define FLUSH_TX        0xE1  //清除TX FIFO寄存器.发射模式下用
#define FLUSH_RX        0xE2  //清除RX FIFO寄存器.接收模式下用
#define REUSE_TX_PL     0xE3  //重新使用上一包数据,CE为高,数据包被不断发送.
#define NOP             0xFF  //空操作,可以用来读状态寄存器	 
//SPI(NRF24L01)寄存器地址
#define CONFIG          0x00  //配置寄存器地址;bit0:1接收模式,0发射模式;bit1:电选择;bit2:CRC模式;bit3:CRC使能;//bit4:中断MAX_RT(达到最大重发次数中断)使能;bit5:中断TX_DS使能;bit6:中断RX_DR使能
#define EN_AA           0x01  //使能自动应答功能  bit0~5,对应通道0~5
#define EN_RXADDR       0x02  //接收地址允许,bit0~5,对应通道0~5
#define SETUP_AW        0x03  //设置地址宽度(所有数据通道):bit1,0:00,3字节;01,4字节;02,5字节;
#define SETUP_RETR      0x04  //建立自动重发;bit3:0,自动重发计数器;bit7:4,自动重发延时 250*x+86us
#define RF_CH           0x05  //RF通道,bit6:0,工作通道频率;
#define RF_SETUP        0x06  //RF寄存器;bit3:传输速率(0:1Mbps,1:2Mbps);bit2:1,发射功率;bit0:低噪声放大器增益
#define STATUS          0x07  //状态寄存器;bit0:TX FIFO满标志;bit3:1,接收数据通道号(最大:6);bit4,达到最多次重发//bit5:数据发送完成中断;bit6:接收数据中断;
#define MAX_TX  		0x10  //达到最大发送次数中断
#define TX_OK   		0x20  //TX发送完成中断
#define RX_OK   		0x40  //接收到数据中断#define OBSERVE_TX      0x08  //发送检测寄存器,bit7:4,数据包丢失计数器;bit3:0,重发计数器
#define CD              0x09  //载波检测寄存器,bit0,载波检测;
#define RX_ADDR_P0      0x0A  //数据通道0接收地址,最大长度5个字节,低字节在前
#define RX_ADDR_P1      0x0B  //数据通道1接收地址,最大长度5个字节,低字节在前
#define RX_ADDR_P2      0x0C  //数据通道2接收地址,最低字节可设置,高字节,必须同RX_ADDR_P1[39:8]相等;
#define RX_ADDR_P3      0x0D  //数据通道3接收地址,最低字节可设置,高字节,必须同RX_ADDR_P1[39:8]相等;
#define RX_ADDR_P4      0x0E  //数据通道4接收地址,最低字节可设置,高字节,必须同RX_ADDR_P1[39:8]相等;
#define RX_ADDR_P5      0x0F  //数据通道5接收地址,最低字节可设置,高字节,必须同RX_ADDR_P1[39:8]相等;
#define TX_ADDR         0x10  //发送地址(低字节在前),ShockBurstTM模式下,RX_ADDR_P0与此地址相等
#define RX_PW_P0        0x11  //接收数据通道0有效数据宽度(1~32字节),设置为0则非法
#define RX_PW_P1        0x12  //接收数据通道1有效数据宽度(1~32字节),设置为0则非法
#define RX_PW_P2        0x13  //接收数据通道2有效数据宽度(1~32字节),设置为0则非法
#define RX_PW_P3        0x14  //接收数据通道3有效数据宽度(1~32字节),设置为0则非法
#define RX_PW_P4        0x15  //接收数据通道4有效数据宽度(1~32字节),设置为0则非法
#define RX_PW_P5        0x16  //接收数据通道5有效数据宽度(1~32字节),设置为0则非法
#define NRF_FIFO_STATUS 0x17  //FIFO状态寄存器;bit0,RX FIFO寄存器空标志;bit1,RX FIFO满标志;bit2,3,保留//bit4,TX FIFO空标志;bit5,TX FIFO满标志;bit6,1,循环发送上一数据包.0,不循环;
//
//24L01发送接收数据宽度定义
#define TX_ADR_WIDTH    5   	//5字节的地址宽度
#define RX_ADR_WIDTH    5   	//5字节的地址宽度
#define TX_PLOAD_WIDTH  32  	//32字节的用户数据宽度
#define RX_PLOAD_WIDTH  32  	//32字节的用户数据宽度void NRF24L01_Init(void);						//初始化
void NRF24L01_RX_Mode(void);					//配置为接收模式
void NRF24L01_TX_Mode(void);					//配置为发送模式
u8 NRF24L01_Write_Reg(u8 reg, u8 value);		//写寄存器
u8 NRF24L01_Check(void);						//检查24L01是否存在
u8 NRF24L01_TxPacket(u8 *txbuf);				//发送一个包的数据
u8 NRF24L01_RxPacket(u8 *rxbuf);				//接收一个包的数据
void NRF24L01_Check_detection(void);
void NRF24L01_Text(u8 mode);#endif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/64670.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

线性代数期末复习 [基础篇]

关于第六点: AXB 在期末考试中一般A都是可逆的 我们可以先把A的逆求出来,X A − 1 B A^-1B A−1B,或者 (A,B) -> r (E, A − 1 B A^-1B A−1B) 如果A矩阵不可逆,转变为方程组求解问题,假设都是二维矩阵 A(x1,x2) (b1,b2) Ax1 b1,Ax2 b2 XAB 如果A可逆,直接XB A − 1 A^-…

Kali 自动化换源脚本编写与使用

1. 背景与需求 在使用 Kali Linux 的过程中&#xff0c;软件源的配置对系统的更新与软件安装速度至关重要。 Kali 的默认官方源提供了安全且最新的软件包&#xff0c;但有时由于网络条件或地理位置的限制&#xff0c;使用官方源可能会出现速度较慢的问题。 为了解决这一问题&a…

【Unity3D】ECS入门学习(十二)IJob、IJobFor、IJobParallelFor

IJob&#xff1a;开启单个线程进行计算&#xff0c;线程内不允许对同一个数据进行操作&#xff0c;也就是如果你想用多个IJob分别计算&#xff0c;将其结果存储到同一个NativeArray<int>数组是不允许的&#xff0c;所以不要这样做&#xff0c;如下例子就是反面教材&#…

InfoNCE Loss详解(上)

引言 InfoNCE对比学习损失是学习句嵌入绕不开的知识点&#xff0c;本文就从头开始来探讨一下它是怎么来的。 先验知识 数学期望与大数定律 期望(expectation&#xff0c;expected value&#xff0c;数学期望&#xff0c;mathematical expectation)是随机变量的平均值&#…

.Net加密与Java互通

.Net加密与Java互通 文章目录 .Net加密与Java互通前言RSA生成私钥和公钥.net加密出数据传给Java端采用java方给出的公钥进行加密采用java方给出的私钥进行解密 .net 解密来自Java端的数据 AES带有向量的AES加密带有向量的AES解密无向量AES加密无向量AES解密 SM2(国密)SM2加密Sm…

工作中常用Vim的命令

Hi, 我是你们的老朋友&#xff0c;主要专注于嵌入式软件开发&#xff0c;有兴趣不要忘记点击关注【码思途远】 目录 0. ctags -R 1.认识 Vim的几种工作模式 2.高频使用命令 2.1 修改文件 2.2 关于行号 2.3 删除多行&#xff0c;删除部分 2.4 复制粘贴 2.5 光标移动 2.…

什么是 Azure OpenAI ?了解微软 Azure OpenAI 和 OpenAI 的关系

一、什么是Azure OpenAI &#xff1f; 微软已与 OpenAI 合作以实现三个主要目标&#xff1a; ⦿利用 Azure 的基础结构&#xff08;包括安全性、合规性和区域可用性&#xff09;&#xff0c;帮助用户构建企业级应用程序。 ⦿在微软产品&#xff08;包括 Azure AI 产品以及以外…

Linux day 1129

家人们今天继续学习Linux&#xff0c;ok话不多说一起去看看吧 三.Linux常用命令 3.1 Linux命令体验 3.1.1 常用命令演示 在这一部分中&#xff0c;我们主要介绍几个常用的命令&#xff0c;让大家快速感 受以下 Linux 指令的操作方式。主要包含以下几个指令&#xff1a; ls命…

SAP HCM 标准报表与前台操作的增强差异逻辑分析(rhgrenz4)

导读 增强差异:SAP的HCM模块组织和人事增强都有标准的增强点&#xff0c;不管你调用标准的函数还是前台操作都会触发对应的增强。所以很多业务不需要考虑那么多分散点&#xff0c;只要找到一个合适的增强点&#xff0c;就能解决很多和外围系统集成的业务逻辑&#xff0c;今天遇…

EZ-USB™ FX3 USB 5 Gbps 外设控制器

EZ-USB™ FX3 USB 5 Gbps 外设控制器 EZ-USB™ FX3 提供 USB 5Gbps 至 32 位数据总线&#xff0c;并配备 ARM9&#xff0c;可为任何系统添加 USB 3.0 连接 英飞凌的 EZ-USB™ FX3 是业界用途最广泛的 USB 外围设备控制器&#xff0c;可以为几乎任何系统添加 USB 5Gbps 连接。 …

【数据仓库】spark大数据处理框架

文章目录 概述架构spark 架构角色下载安装启动pyspark启动spark-sehll启动spark-sqlspark-submit经验 概述 Spark是一个性能优异的集群计算框架&#xff0c;广泛应用于大数据领域。类似Hadoop&#xff0c;但对Hadoop做了优化&#xff0c;计算任务的中间结果可以存储在内存中&a…

数据库容灾备份的意义+分类+执行工具!

数据库容灾解决方案的背景 数据库容灾&#xff08;Disaster Recovery&#xff0c;DR&#xff09;解决方案的背景主要源于企业对数据安全性、业务连续性和系统高可用性的需求。随着数字化转型的加速&#xff0c;企业的数据量迅猛增长&#xff0c;数据库已成为支撑核心业务的关键…

PDF怎么压缩得又小又清晰?5种PDF压缩方法

PDF 文件在日常办公与学习中使用极为频繁&#xff0c;可想要把它压缩得又小又清晰却困难重重。一方面&#xff0c;PDF 格式本身具有高度兼容性&#xff0c;集成了文字、图像、矢量图等多样元素&#xff0c;压缩时难以兼顾不同元素特性&#xff0c;稍不注意&#xff0c;文字就会…

GoldenDB组件及对应的用户和进程

1. GoldenDB组件及对应的用户和进程 GoldenDB数据库由管理节点、全局事务节点GTM、计算节点CN、数据节点DN等组成。 1.1. 管理节点 管理节点分为集群管理、Insight运维管理平台&#xff08;InsightServer、RDB、ZK&#xff09;。 1.1.1. 集群管理 1. 集群管理包括Metadatas…

OpenStack系列第四篇:云平台基础功能与操作(Dashboard)

文章目录 1. 镜像&#xff08;Image&#xff09;添加镜像查看镜像删除镜像 2. 卷&#xff08;Volume&#xff09;创建卷查看卷删除卷 3. 网络&#xff08;虚拟网络&#xff09;创建网络查看网络删除网络 4. 实例类型创建实例类型查看实例类型删除实例类型 4. 密钥对&#xff08…

CSDN编辑器

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

四大自平衡树对比:AVL树、红黑树、B树与B+树

AVL树、红黑树、B树和B树的对比与应用场景 树系列相关文章&#xff08;置顶&#xff09; 1、从链表到平衡树&#xff1a;二叉查找树的退化与优化 2、自平衡二叉查找树&#xff1a;如何让二叉查找树始终保持高效 3、AVL树入门&#xff1a;理解自平衡二叉查找树的基础 4、红黑树全…

Linux下读取Windows下保存的文件,报错信息中出现“^M“时如何解决?【由于Windows和Linux的换行方式不同造成的-提供两种转换方式】

Windows 和 Linux 的文本文件使用的换行符不同&#xff1a; Windows 使用 \r\n &#xff08;回车 换行&#xff09;。Linux 使用 \n &#xff08;换行&#xff09;。 因此&#xff0c;当在 Linux 系统上运行带有 Windows 换行符的脚本或读取相关文件时&#xff0c;可能会出现…

npm ERR! ECONNRESET 解决方法

问题&#xff1a;npm 命令遇到的错误是 ECONNRESET&#xff0c;这通常与网络连接问题相关。设置代理解决问题。 一、查看当前代理设置 npm config get proxy npm config get https-proxy二、设置代理 npm config set proxy http://your-proxy-address:port npm config set h…

【UE5】UnrealEngine源码构建2:windows构建unreal engine 5.3.2

参考大神知乎的文章:UE5 小白也能看懂的源码编译指南 据说会耗费400G的空间。 代码本身并不大,可能是依赖特别多,毕竟看起来UE啥都能干,核心还是c++的, 【UE5】UnrealEngine源码构建1:tag为5.3.2源码clone 本着好奇+ 学习的态度,想着也许有机会能更为深入的熟悉UE的机制…