历史上的今天
返回首页

历史上的今天

今天是:2025年01月09日(星期四)

正在发生

2019年01月09日 | STM32驱动NRF24L01

2019-01-09 来源:eefocus

1. 简介


NRF24L01是 nordic 的无线通信芯片,它具有以下特点:

1) 2.4G 全球开放的 ISM 频段(2.400 - 2.4835GHz),免许可证使用;

2)最高工作速率 2Mbps,高校的 GFSK 调制,抗干扰能力强;

3) 125 个可选的频道,满足多点通信和调频通信的需要;

4)内置 CRC 检错和点对多点的通信地址控制;

5)低工作电压(1.9~3.6V),待机模式下状态为 26uA;掉电模式下为 900nA;

6)可设置自动应答,确保数据可靠传输;

7)工作于EnhancedShockBurst 具有Automatic packet handling,Auto packet transaction handling ,可以实现点对点或是 1 对 6 的无线通信,速度可以达到 2M(bps),具有可选的内置包应答机制,极大的降低丢包率。

8)通过 SPI 总线与单片机进行交互,最大通信速率为10Mbps;


1.1 结构框图


在这里插入图片描述

如图右侧为六个控制和数据信号,分别为 CSN、 SCK、 MISO、 MOSI、 IRQ、 CE。


信号线功能

CSN芯片的片选线, CSN 为低电平芯片工作

SCK芯片控制的时钟线(SPI 时钟)

MISO芯片控制数据线(Master input slave output)

MOSI芯片控制数据线(Master output slave input)

IRQ中断信号。无线通信过程中 MCU 主要是通过 IRQ 与 NRF24L01 进行通信

CE芯片的模式控制线。 在 CSN 为低的情况下, CE 协同 NRF24L01 的 CONFIG 寄存器共同决定 NRF24L01 的状态


1.2 NRF24L01 状态机


在这里插入图片描述


NRF24L01 的状态机如上图 所示,对于 NRF24L01 的固件编程工作主要是参照 NRF24L01 的状态机。主要有以下几个状态:

模式PWR_UP registerPRIM_RX registerCEFIFO state

RX Mode111-

TX Mode101数据存在TX FIFO寄存器中

TX Mode10最小 10us高电平停留在发送模式,直到数据发送完

待机模式2101TX FIFO为空

待机模式11-0无数据传输

掉电模式0---

注:PWR_UP: 上电;PRIM_RX: 掉电;CE: 芯片使能 (PWR_UP和PRIM_RX 在配置寄存器(CONFIG)中设置位0和位1:)


1.3 硬件设计

原理图已经在数据手册给出,我们只需参照其设计即可,主要是在 PCB 上,注意天线部分器件的摆放和天线的净空处理,使天线能够达到最佳效果(这个可以参照数据手册的建议,当然也可以根据需求做更改)。


在这里插入图片描述


此处验证采用的是现成的模块。


1.4 固件编程

1) 置 CSN 为低,使能芯片,配置芯片各个参数。配置参数在 Power Down 状态中完成。

2) 如果是 Tx 模式,填充 Tx FIFO。

3) 配置完成以后,通过 CE 与 CONFIG 中的 PWR_UP 与 PRIM_RX 参数确定 24L01要切换到的状态。


Tx Mode: PWR_UP=1; PRIM_RX=0; CE=1 (保持超过 10us 就可以);

Rx Mode: PWR_UP=1; PRIM_RX=1; CE=1;


IRQ 引脚会在以下三种情况变低:中断时变为低电平

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

Rx FIFO 收到数据;

达到最大重发次数;


将 IRQ 接到外部中断输入引脚,通过中断程序进行处理。nRF24L01 的中断引脚(IRQ)为低电平触发,当状态寄存器中TX_DS(数据发送完成中断位)、RX_DR(接收数据中断位) 或MAX_RT(达到最多次重发中断位)为高时触发中断。当MCU 给中断源写‘1’时,中断引脚被禁止。可屏蔽中断可以被IRQ 中断屏蔽。通过设置可屏蔽中断位为高,则中断响应被禁止。默认状态下所有的中断源是被禁止的。


1.4.1 Tx 模式初始化

初始化步骤配置NRF24L01寄存器

1)写 Tx 节点的地址TX_ADDR

2)写 Rx 节点的地址(使能 Auto Ack)RX_ADDR_P0

3)使能 AUTO ACKEN_AA

4)使能 PIPE 0EN_RXADDR

5)配置自动重发次数SETUP_RETR

6)选择通信频率RF_CH

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

8 ) 选择通道 0 有效数据宽度Rx_Pw_P0

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

按照如上思路即可配置 TX 模式:


/*****************************************************************************

* 函  数:void NRF24L01_TX_Mode(void)

* 功  能:NRF24L01发送模式配置

* 参  数:无

* 返回值:无

* 备  注:无

*****************************************************************************/

void NRF24L01_TX_Mode(void)

{

NRF_CE2_LOW;

NRF24L01_Write_Buf2(W_REGISTER+TX_ADDR,TX_ADR_WIDTH,(uint8_t *)TX_ADDRESS_X);//写TX节点地址

NRF24L01_Write_Buf2(W_REGISTER+RX_ADDR_P0,RX_ADR_WIDTH, (uint8_t *) RX_ADDRESS_X);//写RX节点地址,为了自动使能ACK

NRF24L01_Write_Reg2(W_REGISTER+EN_AA, 0x01);//使能通道0自动应答

NRF24L01_Write_Reg2(W_REGISTER+EN_RXADDR, 0x01);//使能通道0接收地址

NRF24L01_Write_Reg2(W_REGISTER+SETUP_PETR, 0x1a);//设置自动重发间隔时间:500us+86us,最大重大次数:10次

NRF24L01_Write_Reg2(W_REGISTER+RF_CH, 40);//设置通道为40

NRF24L01_Write_Reg2(W_REGISTER+RF_SETUP, 0x0f);//设置发射参数:0dB增益;2Mnps;低噪声增益开启

NRF24L01_Write_Reg2(W_REGISTER+NRF24L01_CONFIG,0x0e);//基本参数:PWR_UP;EN_CRC;16BIT_CRC;发送模式;开启所有中断

NRF_CE2_HIGH;//NRF_CE为高,10us后启动发送数据

}


1.4.2 Rx 模式初始化

初始化步骤配置NRF24L01寄存器

1)写 Rx 节点的地址RX_ADDR_P0

2)使能 AUTO ACKEN_AA

3)使能 PIPE 0EN_RXADDR

4)选择通信频率RF_CH

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

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

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

/*****************************************************************************

* 函  数:void NRF24L01_TX_Mode(void)

* 功  能:NRF24L01发送模式配置

* 参  数:无

* 返回值:无

* 备  注:无

*****************************************************************************/

void NRF24L01_RX_Mode(void)

{

NRF_CE2_LOW;

NRF24L01_Write_Buf2(W_REGISTER+RX_ADDR_P0, RX_ADR_WIDTH, (uint8_t *) RX_ADDRESS_X);//写RX地址节点

NRF24L01_Write_Reg2(W_REGISTER+EN_AA,0x01);//使能通道0自动应答

NRF24L01_Write_Reg2(W_REGISTER+EN_RXADDR,0x01);//使能通道0接收地址

NRF24L01_Write_Reg2(W_REGISTER+RF_CH, 40);//设置RF通信频率

NRF24L01_Write_Reg2(W_REGISTER+RX_PW_P0,RX_PLOAD_WIDTH);//选择通道0有效数据宽度

NRF24L01_Write_Reg2(W_REGISTER+RF_SETUP, 0x0f);//设置TX发射参数:0db增益,2Mbps,低噪声增益开启

NRF24L01_Write_Reg2(W_REGISTER+NRF24L01_CONFIG, 0x0f);//基本参数:PWR_UP;EN_CRC;16BIT_CRC;接收模式;开启所有中断

NRF_CE2_HIGH;//CE为高,进入接收模式

}


1.5 NRF24L01的收发模式

收发模式有Enhanced ShockBurstTM收发模式、ShockBurstTM 收发模式和直接收发模式三种。


ShockBurstTM模式:


ShockBurst模式下,nRF24L01 可以与成本较低的低速 MCU 相连,高速信号处理是由芯片内部的射频协议处理的。nRF24L01 提供 SPI 接口数据率取决于单片机本身接口速度。ShockBurst 模式通过允许与单片机低速通信而无线部分高速通信减小了通信的平均消耗电流。


在 ShockBurstTM 接收模式下,当接收到有效的地址和数据时 IRQ 通知 MCU ,随后MCU可将接收到的数据从RX FIFO寄存器中读出。


在 ShockBurstTM 发送模式下,nRF24L01 自动生成前导码及 CRC 校验,数据发送完毕后 IRQ 通知 MCU ,减少了 MCU 的查询时间,也就意味着减少了MCU 的工作量同时减少了软件的开发时间。nRF24L01 内部有三个不同的RX FIFO寄存器 6 个通道共享此寄存器和三个不同的TX FIFO寄存器在掉电模式下待机模式下和数据传输的过程中 MCU 可以随时访问FIFO寄存器。这就允许 SPI 接口可以以低速进行数据传送并且可以应用于MCU硬件上没有SPI接口的情况下。


增强型的ShockBurstTM模式:


增强型ShockBurstTM模式可以使得双向链接协议执行起来更为容易有效,典型的双向链接为发送方要求终端设备在接收到数据后有应答信号以便于发送方检测有无数据丢失失。一旦数据丢失,则通过重新发送功能将丢失的数据恢复。增强型的ShockBurstTM模式可以同时控制应答及重发功能(数据重发设置寄存器(SETUP_RETR))而无需增加MCU工作量。


nRF24L01 在接收模式下可以接收6 路不同通道的数据,每一个数据通道使用不同的地址,但是共用相同的频道。也就是说6 个不同的 nRF24L01 设置为发送模式后可以与同一个设置为接收模式的 nRF24L01 进行通讯,而设置为接收模式的nRF24L01 可以对这6 个发射端进行识别。


在这里插入图片描述


数据通道0 是唯一 的一个可以配置为40 位自身地址的数据通道。1~5 数据通道都为8 位自身地址和32 位公用地址。所有的 数据通道都可以设置为增强型ShockBurst 模式。NRF24L01 在确认收到数据后记录地址,并以此地址为目标地址发送应答信号,在发送端,数据通道0被用作接收应答信号,因此属通道0 的接收地址要与发送地址端地址相等,以确保接收到正确的应答信号。


nRF24l01 配置为增强型的ShockBurstTM模式下,只要 MCU 有数据发送,就会启动增强型的ShockBurstTM模式来发送数据。发送结束后NRF24L01 转到接收模式且等待终端应答信号,若为收到应答,NRF24L01 将启动重发数据,直至收到 ACK 信号或者超出最大重发次数为止,超过重发次数,将产生 MAX_RT 中断。收到确认信号,NRF24L01 就认为最后一包数据已经发送成功,将把 TX_FIFO 中的数据清除且产生 TX_DS 中断(IRQ信号置高)。


Enhanced ShockBurstTM发射流程:


A. 把接收机的地址和要发送的数据按时序送入NRF24L01;

B. 配置CONFIG寄存器,使之进入发送模式。

C. 微控制器把CE置高(至少10us),激发NRF24L01进行Enhanced ShockBurstTM发射;

D.N24L01的Enhanced ShockBurstTM发射:(1) 给射频前端供电; (2)射频数据打包(加字头、CRC校验码); (3) 高速发射数据包; (4)发射完成,NRF24L01进入空闲状态。


Enhanced ShockBurstTM接收流程:

A. 配置本机地址和要接收的数据包大小;

B. 配置CONFIG寄存器,使之进入接收模式,把CE置高。

C. 130us后,NRF24L01进入监视状态,等待数据包的到来;

D.当接收到正确的数据包(正确的地址和CRC校验码),NRF2401自动把字头、地址和CRC校验位移去;

E. NRF24L01 通过把 STATUS 寄存器的 RX_DR 置位(STATUS一般引起微控制器中断)通知微控制器;

F. 微控制器把数据从 NewMsg_RF2401 读出;

G. 所有数据读取完毕后,可以清除 STATUS 寄存器。NRF2401可以进入四种主要的模式之一。


1.5 NRF24L01的数据通道

nRF24L01 配置为接收模式时可以接收 6 路不同地址相同频率的数据。每个数据通道拥有自己的地址并且可以通过寄存器来进行分别配置。数据通道是通过寄存器EN_RXADDR来设置的,默认状态下只有数据通道0和数据通道1是开启状态的。每一个数据通道的地址是通过寄存器RX_ADDR_Px来配置的。通常情况下不允许不同的数据通道设 置完全相同的地址。 数据通道0有40 位可配置地址。数据通道1~5的地址为:32位共用地址+各自的地址(最低字节)。如下图所示:


在这里插入图片描述


1.6 NRF24L01的SPI通信模式


在这里插入图片描述


从图中可以看出, SCK 空闲的时候是低电平的,而数据在 SCK 的上升沿被读写。所以,我们需要设置 SPI 的 CPOL 和 CPHA均为 0(SPI模式0),来满足 NRF24L01 对 SPI 操作的要求。


/*****************************************************************************

* 函  数:void SPI_GPIO_Init(void)

* 功  能:SPI1相关GPIO初始化配置

* 参  数:无

* 返回值:无

* 备  注:无

*****************************************************************************/

void SPI_GPIO_Init(void)

{

   GPIO_InitTypeDef GPIO_InitStructure;

   

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

   

   GPIO_InitStructure.GPIO_Pin = SPI1_CLK|SPI1_MISO|SPI1_MOSI;

   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

   

   GPIO_Init(GPIOA,&GPIO_InitStructure);

   GPIO_SetBits(GPIOA,SPI1_CLK|SPI1_MISO|SPI1_MOSI);

}


/*****************************************************************************

* 函  数:void SPI1_Init(void)

* 功  能:SPI1初始化配置

* 参  数:无

* 返回值:无

* 备  注:无

*****************************************************************************/

void SPI1_Init(void)

{

   SPI_InitTypeDef SPI1_InitStructure;

   

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);//spi1在APB2总线上

   

   SPI1_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工

   SPI1_InitStructure.SPI_Mode = SPI_Mode_Master;//设置SPI工作模式:设置为主SPI

   SPI1_InitStructure.SPI_DataSize = SPI_DataSize_8b;//设置SPI的数据大小:SPI发送接收8位帧结构

   SPI1_InitStructure.SPI_CPOL = SPI_CPOL_Low;//选择了串行时钟的稳态:时钟悬空低电平

   SPI1_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;//数据捕获于第一个时钟沿

   SPI1_InitStructure.SPI_NSS = SPI_NSS_Soft;//NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制

   SPI1_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;//定义波特率预分频的值:波特率预分频值为16:72/16=4.5MHz

   SPI1_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始

   SPI1_InitStructure.SPI_CRCPolynomial = 7;//CRC值计算的多项式

   SPI_Init(SPI1,&SPI1_InitStructure);

   SPI_Cmd(SPI1,ENABLE);


   SPI1_ReadWrite_Byte(0xFF);//启动传输

}


/*****************************************************************************

* 函  数:uint8_t SPI1_ReadWrite_Byte(uint8_t tx_dat)

* 功  能:SPI1收发数据

* 参  数:tx_dat:发送的数据

* 返回值:接收的数据

* 备  注:无

*****************************************************************************/


uint8_t SPI1_ReadWrite_Byte(uint8_t tx_dat)

{

   while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)==RESET);

   SPI_I2S_SendData(SPI1,tx_dat);

   

   while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)==RESET);

   return SPI_I2S_ReceiveData(SPI1);

}


相关 SPI 的介绍,请移步 SPI专题(一)——基础知识 查看。


2. 软件实现

这里就贴一下 NRF24L01 涉及的程序:


/*****************************************************************************

* 函  数:void NRF24L01_GPIO_Init(void)

* 功  能:NRF24L01相关GPIO初始化

* 参  数:void

* 返回值:无

* 备  注:无

*****************************************************************************/

void NRF24L01_GPIO_Init(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC,ENABLE);


//SPI1上还挂了flash和sd卡,一直片选置高,排除干扰

GPIO_InitStructure.GPIO_Pin = FLASH_CS|SD_CARD_CS;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA,&GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = NRF_CE;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA,&GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = NRF_IRQ;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//中断上拉输入

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA,&GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = NRF_CS;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOC,&GPIO_InitStructure);

GPIO_SetBits(GPIOA,NRF_IRQ|NRF_CE);

GPIO_SetBits(GPIOC,NRF_CS);


//第二模块相关的GPIO

GPIO_InitStructure.GPIO_Pin = NRF_CE2;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOC,&GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = NRF_IRQ2;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOC,&GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = NRF_CS2;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOC,&GPIO_InitStructure);

GPIO_SetBits(GPIOC,NRF_IRQ2|NRF_CE2);

GPIO_SetBits(GPIOC,NRF_CS2);

}


/*****************************************************************************

* 函  数:uint8_t NRF24L01_Write_Reg(uint8_t res,uint8_t value)

* 功  能:从寄存器写入一字节数据

* 参  数:res:寄存器地址;value:写入的值

* 返回值:status:读取的寄存器状态值

* 备  注:无

*****************************************************************************/

uint8_t NRF24L01_Write_Reg(uint8_t res,uint8_t value)

{

uint8_t status;

NRF_CS_LOW;

status = SPI1_ReadWrite_Byte(res);

SPI1_ReadWrite_Byte(value);

NRF_CS_HIGH;


return status;//返回寄存器状态值

}


/*****************************************************************************

* 函  数:uint8_t NRF24L01_Read_Reg(uint8_t res)

* 功  能:从寄存器读取一字节数据

* 参  数:res:寄存器地址

* 返回值:ret:读取的值

* 备  注:无

*****************************************************************************/

uint8_t NRF24L01_Read_Reg(uint8_t res)

{

uint8_t ret;

NRF_CS_LOW;

SPI1_ReadWrite_Byte(res);

ret = SPI1_ReadWrite_Byte(0xFF);//在读取数据前稳定MISO的电平,防止触发slave设备

NRF_CS_HIGH;


return ret;

}


/*****************************************************************************

* 函  数:uint8_t NRF24L01_Read_Buf(uint8_t res,uint8_t len,uint8_t *pBuf)

* 功  能:在指定位置读取一定长度的数据

* 参  数:res:指定位置;len:数据长度;*pBuf:指定数据的首地址

* 返回值:status:寄存器的状态

* 备  注:无

*****************************************************************************/

uint8_t NRF24L01_Read_Buf(uint8_t res,uint8_t len,uint8_t *pBuf)

{

uint8_t status,i;


NRF_CS_LOW;

status = SPI1_ReadWrite_Byte(res);

for(i=0;i

{

pBuf[i] = SPI1_ReadWrite_Byte(0xFF);

}

NRF_CS_HIGH;


return status;

}


/*****************************************************************************

* 函  数:uint8_t NRF24L01_Write_Buf(uint8_t res,uint8_t len,uint8_t *pBuf)

* 功  能:在指定位置写入一定长度的数据

* 参  数:res:指定位置;len:数据长度;*pBuf:指定数据的首地址

* 返回值:status:寄存器的状态

* 备  注:无

*****************************************************************************/

uint8_t NRF24L01_Write_Buf(uint8_t res,uint8_t len,uint8_t *pBuf)

{

uint8_t status,i;


NRF_CS_LOW;

status = SPI1_ReadWrite_Byte(res);

for (i = 0; i < len; i++)

{

SPI1_ReadWrite_Byte(*pBuf++);

//SPI1_ReadWrite_Byte(pBuf[i]);

}

NRF_CS_HIGH;

return status;

}


/*****************************************************************************

* 函  数:uint8_t NRF24L01_Check(void)

* 功  能:检测NRF24L01是否存在

* 参  数:无

* 返回值:0:成功;1:失败

* 备  注:往NRF24L01的发送地址寄存器写入5字节数据再读出来,判断24L01是否已正常工作

*****************************************************************************/

uint8_t NRF24L01_Check(void)

{

uint8_t buf[5]={0xa5,0xa5,0xa5,0xa5,0xa5};

uint8_t i;


NRF24L01_Write_Buf(W_REGISTER+TX_ADDR,5,buf);//写入5字节的地址

NRF24L01_Read_Buf(TX_ADDR,5,buf);

for(i=0;i<5;i++)

{

if(buf[i]!=0xa5)

break;

}

if(i!=5)

return 1;

return 0;

}


/*****************************************************************************

* 函  数:void NRF24L01_TX_Mode(void)

* 功  能:NRF24L01发送模式配置

* 参  数:无

* 返回值:无

* 备  注:无

*****************************************************************************/

void NRF24L01_TX_Mode(void)

{

NRF_CE_LOW;

NRF24L01_Write_Buf(W_REGISTER+TX_ADDR,TX_ADR_WIDTH,(uint8_t *)TX_ADDRESS_X);//写TX节点地址

NRF24L01_Write_Buf(W_REGISTER+RX_ADDR_P0,RX_ADR_WIDTH, (uint8_t *) RX_ADDRESS_X);//写RX节点地址,为了自动使能ACK

NRF24L01_Write_Reg(W_REGISTER+EN_AA, 0x01);//使能通道0自动应答

NRF24L01_Write_Reg(W_REGISTER+EN_RXADDR, 0x01);//使能通道0接收地址

NRF24L01_Write_Reg(W_REGISTER+SETUP_PETR, 0x1a);//设置自动重发间隔时间:500us+86us,最大重大次数:10次

NRF24L01_Write_Reg(W_REGISTER+RF_CH, 40);//设置通道为40

NRF24L01_Write_Reg(W_REGISTER+RF_SETUP, 0x0f);//设置发射参数:0dB增益;2Mnps;低噪声增益开启

NRF24L01_Write_Reg(W_REGISTER+NRF24L01_CONFIG,0x0e);//基本参数:PWR_UP;EN_CRC;16BIT_CRC;发送模式;开启所有中断

NRF_CE_HIGH;//NRF_CE为高,10us后启动发送数据

delay_us(12);

}


/*****************************************************************************

* 函  数:void NRF24L01_TX_Mode(void)

* 功  能:NRF24L01发送模式配置

* 参  数:无

* 返回值:无

* 备  注:无

*****************************************************************************/

void NRF24L01_RX_Mode(void)

{

NRF_CE_LOW;

NRF24L01_Write_Buf(W_REGISTER+RX_ADDR_P0, RX_ADR_WIDTH, (uint8_t *) RX_ADDRESS_X);//写RX地址节点

NRF24L01_Write_Reg(W_REGISTER+EN_AA,0x01);//使能通道0自动应答

NRF24L01_Write_Reg(W_REGISTER+EN_RXADDR,0x01);//使能通道0接收地址

NRF24L01_Write_Reg(W_REGISTER+RF_CH, 40);//设置RF通信频率

NRF24L01_Write_Reg(W_REGISTER+RX_PW_P0,RX_PLOAD_WIDTH);//选择通道0有效数据宽度

NRF24L01_Write_Reg(W_REGISTER+RF_SETUP, 0x0f);//设置TX发射参数:0db增益,2Mbps,低噪声增益开启

NRF24L01_Write_Reg(W_REGISTER+NRF24L01_CONFIG, 0x0f);//基本参数:PWR_UP;EN_CRC;16BIT_CRC;接收模式;开启所有中断

NRF_CE_HIGH;//CE为高,进入接收模式

}


/*****************************************************************************

* 函  数:uint8_t NRF24L01_TX_Packet(uint8_t *txbuf)

* 功  能:NRF24L01发送一次数据

* 参  数:*txbuf:等待发送数据的首地址

* 返回值:MAX_TX:最大重发次数;TX_OK:发送完成;0xFF:发送失败

* 备  注:无

*****************************************************************************/

uint8_t NRF24L01_TX_Packet(uint8_t *txbuf)

{

uint8_t ret;


NRF_CE_LOW;

NRF24L01_Write_Buf(W_TX_PAYLOAD, TX_PLOAD_WIDTH, txbuf);//写数据到txbuf,32字节

NRF_CE_HIGH;//启动发送

while (NRF_IRQ_STATUS);//等待发送完成

ret = NRF24L01_Read_Reg(NRF24L01_STATUS);//读取状态寄存器的值

NRF24L01_Write_Reg(W_REGISTER+NRF24L01_STATUS, ret);//清除TX_DS or MAX_RT的中断标志

if(ret&MAX_TX)//达到最大重发次数

{

NRF24L01_Write_Reg(FLUSH_TX, 0XFF);//清除TX FIFO寄存器

return MAX_TX;

}

if(ret&TX_OK)//发送完成

{

return TX_OK;

}

return 0xFF;//发送失败

}


/*****************************************************************************

* 函  数:uint8_t NRF24L01_RX_Packet(uint8_t *rxbuf)

* 功  能:NRF24L01接收一次数据

* 参  数:*rxbuf:等待接收数据的首地址

* 返回值:0:接收成功;1:接收数据失败

* 备  注:无

*****************************************************************************/

uint8_t NRF24L01_RX_Packet(uint8_t *rxbuf)

{

uint8_t ret;



NRF_CE_HIGH;

while(NRF_IRQ_STATUS);

NRF_CE_LOW;


ret = NRF24L01_Read_Reg(NRF24L01_STATUS);//读取状态寄存器的值

NRF24L01_Write_Reg(W_REGISTER+NRF24L01_STATUS, ret);//清除TX_DS or MAX_RT的中断标志

if(ret&RX_OK)//接收到数据

{

NRF24L01_Read_Buf(R_RX_PAYLOAD,RX_PLOAD_WIDTH,rxbuf);//读取数据

NRF24L01_Write_Reg(FLUSH_RX,0xFF);//清除RX FIFO寄存器

return 0;

}

return 1;//没有接收到数据

}


/*****************************************************************************

* 函  数:void NRF24L01_Init(void)

* 功  能:NRF24L01初始化

* 参  数:无

* 返回值:无

* 备  注:对应GPIO设置

*****************************************************************************/

void NRF24L01_Init(void)

{

NRF24L01_GPIO_Init();

FLASH_CS_HIGH;

SD_CARD_CS_HIGH;

NRF_CS_HIGH;

NRF_CE_LOW;

}


如有兴趣,可在此处:NRF24L01的STM32测试程序 进行下载验证。测试比较简单,就是一收一发,往复循环。


现象:

在这里插入图片描述


当然也可以都挂载在一个 SPI 上,只要 CS 信号不冲突,也可以正常实现。


文中的寄存器等介绍,可在NORDIC官网进行下载:nRF24L01数据手册下载

推荐阅读

史海拾趣

Atmel (Microchip)公司的发展小趣事

2016年,Atmel被美国芯片制造商Microchip以35.6亿美元收购。这一收购事件标志着Atmel发展史上的一个重要转折点。在被收购后,Atmel成为了Microchip的一部分,继续发挥其在微控制器领域的优势,同时也获得了Microchip在技术支持、市场渠道等方面的强大支持。这使得Atmel能够更快地推出新产品、拓展新市场,进一步巩固其市场地位。

依必安派特(ebmpapst)公司的发展小趣事

在快速发展的过程中,依必安派特也面临着一些挑战。其中之一就是仿冒产品的泛滥。为了维护品牌形象和客户利益,依必安派特积极打击仿冒产品。例如,在2023年,依必安派特和地方政府联手突击了一家位于广东的仿冒产品工厂,揭示了其造假行为。这一行动不仅保护了依必安派特的品牌声誉和客户信任,也为中国市场的公平竞争环境做出了贡献。

Hendon Semiconductors公司的发展小趣事

随着电子产品的不断小型化和集成化,表面贴装技术(SMT)成为了电子制造行业的重要趋势。Hendon Semiconductors紧跟这一趋势,不断提升其表面贴装和精密制造能力。公司引进了先进的生产设备和测试仪器,确保产品的质量和可靠性。同时,Hendon Semiconductors还加强了对生产过程的监控和管理,通过严格的质量控制体系确保每一片电路板都符合客户的要求。

Electromagnetic Industries Llp公司的发展小趣事

在技术创新的同时,EMI公司也注重市场拓展。公司根据市场需求和产品特点,制定了有针对性的营销策略。一方面,公司积极参加国内外各种电子展会和论坛,展示产品和技术实力;另一方面,公司加强与客户的沟通和合作,深入了解客户需求,提供个性化的解决方案。通过这些努力,EMI公司的市场份额不断扩大,品牌影响力也逐渐提升。

Advanced Microelectronic Products Inc公司的发展小趣事

AMP公司深知人才是企业发展的核心动力。因此,公司高度重视人才培养和团队建设。公司建立了一套完善的人才培养机制,通过内部培训、外部引进等方式,不断提升员工的专业技能和综合素质。同时,公司还注重团队建设,鼓励员工之间的合作与交流,营造积极向上的工作氛围。这些举措为AMP公司的持续发展提供了有力的人才保障。

广东奥科公司的发展小趣事

广东奥科公司在创立之初,面临着资金短缺、技术瓶颈以及市场竞争激烈的困境。然而,公司的创始人凭借对电子行业的深厚理解和对市场需求的敏锐洞察,坚信公司能够在这个领域取得成功。他们带领团队夜以继日地研发新产品,不断优化生产工艺,逐步在市场上打开局面。这段时期,广东奥科公司凭借坚韧不拔的精神和持续的努力,为公司的未来发展奠定了坚实的基础。

问答坊 | AI 解惑

单身男女找缘份

看看你的缘份是谁,预定你后面的楼位,不要定从复了啊。 我先来定108号了。 不过要定位子先要发点东西 来啊。 …

查看全部问答>

单片机解密,芯片解密PCB抄板,烧录IC

深圳市南源电子科技有限公司 芯片解密/单片机解密/IC解密/PLD解密/CPLD解密: (慎重声明:仅限合法研究用途) 单片机(MCU)解密、IC解密 、PLD解密、CPLD解密、鉴定芯片型号;成功率高,周期短,费用合理. 大量供应PIC/EMC兼容IC,性能稳定, ...…

查看全部问答>

红外发光二极管的接收头主要用什么?

红外发光二极管的接收头主要用什么?外发光二极管又是用什么样的二极管? [ 本帖最后由 冷枫yj 于 2009-5-15 10:37 编辑 ]…

查看全部问答>

wince 5.0 如何加载touch驱动

各位大侠,我在wince5.0的PB中搞了好久加载touch驱动就是没有搞出来,各位帮帮忙了,告诉小女子怎么加载?…

查看全部问答>

想买一块嵌入式开发板,大家有什么好的建议?

请推荐一款嵌入式开发板子,可以移植uclinux,wince,arm 平台的,其他平台也ok了.基本的 usb device .LCD 触摸屏的最好 了,LAN interface.....大家有什么好介绍..…

查看全部问答>

请问QV2 D极为何会发黑,而且QV2零件还是好的

请教各位大侠以下问题:  以下图中QV2 N-MOS的D极在线路板上为何会有烧黑的痕迹,而且该MOS管用万用表量测还是好的, 这应该是个利用电感 升压的电路,输入是+12v ,输出为-52v左右,是共Voip电压使用的, 电感LV4=6.8uH +/-20% -4.5A ...…

查看全部问答>

发现SM32的STOP休眠模式很难适用实时低功耗应用!

STM32有三种休眠模式:SLEEP、STOP、STANDBY;休眠层次依次加深,功耗越来越低。SLEEP 模式最容易使用,任何中断或事件都可以唤醒CPU。但低功耗的表现不尽如意。STANDBY 模式下对于实时采集系统来说,几乎没法用。STOP 模式怎么 ...…

查看全部问答>

请教,怎样对STM32FARM中Flash的某一位擦除?

    想把数据分块存储在Flash中,想单独对Flsh中某一部分进行擦除和写入,而不是对整个业擦除。     看了Flash.c文件中的选择擦除函数,没看懂什么意思,这个函数没有指定擦除地址竟然能实现擦 ...…

查看全部问答>