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);//初始化指定IO
    
    GPIO_InitStructure.GPIO_Pin  = NRF_IRQ_PIN;//配置IRQ
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //PB15 上拉输入  
    GPIO_Init(GPIOA,&GPIO_InitStructure);

    my_spi_init();
    NRF_CE(0); 			//使能24L01
	SPI_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节点地址,主要为了使能ACK
    
    MySPI_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通道为40
    MySPI_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通道为40
    MySPI_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);//初始化指定IO
    
    GPIO_InitStructure.GPIO_Pin  = NRF_IRQ_PIN;//配置IRQ
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //PB15 上拉输入  
    GPIO_Init(GPIOA,&GPIO_InitStructure);

    my_spi_init();
    NRF_CE(0); 			//使能24L01
	SPI_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节点地址,主要为了使能ACK
    
    MySPI_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通道为40
    MySPI_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通道为40
    MySPI_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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OneOS操作系统入门-驱动-03:I2C总线及驱动

一、I2C总线 1.1、I2C总线简介 IIC(Inter-Integrated Circuit) 总线是一种由 PHILIPS 公司开发的两线式串行总线&#xff0c;用于连接微控制器以及其外围设备。它是由数据线 SDA 和时钟线 SCL 构成的串行总线&#xff0c;可发送和接收数据&#xff0c;在 CPU 与被控 IC…

【可实战】Bug的判定标准、分类、优先级、定位方法、提交Bug(包含常见面试题)

一、Bug相关概念 &#xff08;一&#xff09;bug判定标准 &#xff08;二&#xff09;常见 Bug 分类 &#xff08;三&#xff09;bug优先级 1.bug严重程度与优先级的关系 有些很严重的Bug&#xff0c;只在极端的条件下才出现&#xff0c;用户碰到的概率很低&#xff0c;这种情…

nginx学习之路-nginx配置https服务器

文章目录 1. 生成证书2. 配置证书1. 拷贝证书文件2. 修改conf/nginx.conf文件内容 3. 查看效果1. 重载配置2. 访问 1. 生成证书 在linux系统下执行&#xff0c;使用openssl命令。&#xff08;windows环境也可以使用cmder&#xff09; # 1. 生成私钥 server2025.key(无密码保护…

【mybatis】Mybatis整体架构解析

从本篇开始我们开始学习mybatis的系列源码&#xff0c;主要的主题可能就是四个方面 从整体把握mybatis系统架构通过一个查询SQL 源码解析核心流程mybatis的缓存机制-源码级别mybatis的插件机制-源码级别spring是如何整合的mybatis框架的 1.整体架构 上述是mybatis的源码&…

DDcGAN_多分辨率图像融合的双鉴别条件生成对抗网络_y译文马佳义

摘要&#xff1a; 在本文中&#xff0c;我们提出了一种新的端到端模型&#xff0c;称为双鉴别条件生成对抗网络&#xff08;DDcGAN&#xff09;&#xff0c;用于融合不同分辨率的红外和可见光图像。我们的方法建立了一个生成器和两个鉴别器之间的对抗博弈。生成器的目的是基于特…

K8s高可用集群之Kubernetes集群管理平台、命令补全工具、资源监控工具部署及常用命令

K8s高可用集群之Kubernetes管理平台、补全命令工具、资源监控工具部署及常用命令 1.Kuboard可视化管理平台2.kubectl命令tab补全工具3.MetricsServer资源监控工具4.Kubernetes常用命令 1.Kuboard可视化管理平台 可以选择安装k8s官网的管理平台&#xff1b;我这里是安装的其他开…

计算机网络-数据链路层(CSMA/CD协议,CSMA/CA协议)

2.2 ppp协议 点对点协议ppp是目前使用最广泛的点对点数据链路层协议。 2.3 媒体接入控制基本概念 共享信道要着重考虑的一个问题就是如何协调多个发送和接收站点对一个共享传输媒体的占用&#xff0c;即媒体接入控制MAC。 2.3.1 静态划分信道 频分复用 时分复用 波分复用 码分复…

富芮坤FR800X系列之软件开发工具链(如IDE、编译器、调试器等)

文章目录 一、IDE&#xff08;集成开发环境&#xff09;二、编译器三、调试器四、其他辅助工具五、小结 FR800x系列作为一款低功耗蓝牙芯片&#xff0c;其软件开发工具链对于开发者来说至关重要。以下是对FR800x软件开发工具链的详细介绍&#xff0c;包括IDE&#xff08;集成开…

Oracle数据库如何找到 Top Hard Parsing SQL 语句?

有一个数据库应用程序存在过多的解析问题&#xff0c;因此需要找到产生大量硬解析的主要语句。 什么是硬解析 Oracle数据库中的硬解析&#xff08;Hard Parse&#xff09;是指在执行SQL语句时&#xff0c;数据库需要重新解析该SQL语句&#xff0c;并创建新的执行计划的过程。这…

从零开始开发纯血鸿蒙应用之实现起始页

从零开始开发纯血鸿蒙应用 一、前言二、主要页面三、应用起始页四、MainPageContent 实现1、一级结构2、二级结构2.1、EmptyContent2.2、FileListContent2.2.1、ViewAction&#xff1a;2.2.2、EditAction2.2.3、DeleteAction2.2.4、ShareAction 五、载入起始页的时机五、总结 一…

5G NTN(七) 高层(1)

说明&#xff1a;本专题主要基于3GPP协议38.821 目录 1. Idle态移动性增强 1.1 TA问题 1.1.1 TA的大小 1.1.2 针对NTN LEO的移动TA&#xff0c;场景C2和D2 1.1.3 针对NTN LEO的固定TA&#xff0c;场景C2和D2 1.1.3.1 方法1&#xff1a;当UE位置信息无法获取的时候 1.1.…

Spring Cloud微服务多模块架构:父子工程搭建实践

一、前言 在现代微服务架构中&#xff0c;Spring Cloud 提供了一整套工具和技术栈来简化分布式系统的开发。为了更好地组织和管理复杂的微服务项目&#xff0c;使用 Maven 多模块&#xff08;父子工程&#xff09; 是一种高效的方法。 ‍ 父子工程 是 Maven 中的一种项目结构…

PDF2Audio - 阅读 PDF 的新方式

1000 Stars 127 Forks 10 Issues 0 贡献者 Apache-2.0 License Python 语言 代码: GitHub - lamm-mit/PDF2Audio 更多AI开源软件&#xff1a;AI开源 - 小众AI PDF2Audio&#xff0c;它将彻底改变我们阅读和理解 PDF 文件的方式。我们不再需要盯着屏幕&#xff0c;而是让信息以声…

pdf预览 报:Failed to load module script

pdf 预览报&#xff1a; Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of “application/octet-stream”. Strict MIME type checking is enforced for module scripts per HTML spec. 报错原因&#xff1a…

游戏引擎学习第74天

仓库: https://gitee.com/mrxiao_com/2d_game (仓库满了) gitee 好像一个仓库最多1G https://gitee.com/mrxiao_com/2d_game_2 后面改到https://gitee.com/mrxiao_com/2d_game_2 仓库 代码占的内存不大主要是markdown截图700多兆比较占内存 Blackboard: 以对处理实体对的方式进…

基于等保的安全审计运维系统

摘要 本文研究与设计一种基于等级保护&#xff08;等保&#xff09;要求的安全审计运维系统&#xff0c;以适应日益严峻的网络安全形势和不断提高的安全审计需求。随着信息技术的快速发展和应用广泛&#xff0c;信息系统安全面临的威胁也在不断增加&#xff0c;特别是在关键信…

基于单片机中药存放环境监测系统的实现

基于单片机中药存放环境监测系统的实现 项目开发背景 随着现代中药的广泛应用&#xff0c;中药材的存储环境对其质量有着至关重要的影响。温湿度、烟雾、火灾等环境因素&#xff0c;若不加以控制&#xff0c;将会导致中药材失效或变质。因此&#xff0c;设计一个基于单片机的…

「Java 数据结构全面解读」:从基础到进阶的实战指南

「Java 数据结构全面解读」&#xff1a;从基础到进阶的实战指南 数据结构是程序设计中的核心部分&#xff0c;用于组织和管理数据。Java 提供了丰富的集合框架和工具类&#xff0c;涵盖了常见的数据结构如数组、链表、栈、队列和树等。本文将系统性地介绍这些数据结构的概念、…

webserver的http实现

1、用了状态机&#xff0c;为什么要用状态机&#xff1f; 在逻辑处理模块中&#xff0c;响应的http请求采用主从状态机完成&#xff0c; 传统的控制流程都是按照顺序执行的&#xff0c;状态机能够处理任意顺序的事件&#xff0c;并能提供有意义的响应--即使这些事件发生的顺序和…

Uniapp Android 本地离线打包(详细流程)

一、简介 App 离线 SDK 暂时不支持 Kotlin&#xff0c;未来不清楚。 uniapp 提供了 云打包 与 本地打包 两种方案&#xff0c;云打包 需要排队且还有次数限制&#xff0c;本地打包 则就没有这些限制&#xff0c;而且会 本地打包 对开发 原生插件 有很大的帮助。 细节&#x…