datasheet

STM32驱动NRF24L01

2019-01-09来源: eefocus关键字:STM32  驱动NRF24L01

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数据手册下载

关键字:STM32  驱动NRF24L01

编辑:什么鱼 引用地址:http://www.eeworld.com.cn/mcu/2019/ic-news010942847.html
本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:STM32学习笔记——PWM基础知识与720电机驱动
下一篇:STM32驱动MPU6050(二)——软件实现

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

STM32堆栈设置

1.堆和栈大小 定义大小在startup_stm32f2xx.sStack_Size      EQU     0x00000400                AREA    STACK, NOINIT, READWRITE, ALIGN=3Stack_Mem      
发表于 2019-04-16
STM32堆栈设置

STM32堆和栈(Heap & Stack)的资料理解

源起:在移植cjson的过程中,解析json包的时候发现动态内存分配不足而导致解析失败,为解决这一问题,而深入了解stm32的堆和栈。stm32的存储器结构。Flash,SRAM寄存器和输入输出端口被组织在同一个4GB的线性地址空间内。可访问的存储器空间被分成8个主要块,每个块为512MB。FLASH存储下载的程序。SRAM是存储运行程序中的数据。而SRAM一般分这几个部分:静态存储区:内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。它主要存放静态数据、全局数据和常量。栈区:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率
发表于 2019-04-16
STM32堆和栈(Heap & Stack)的资料理解

STM32定义堆栈地址到ram区顶部

本设置针对stm32f103rbt6的设置,该芯片RAM大小为20kB,故RAM区地址范围为0x20000000—0x20005000,芯片信息如下图所示;第一步:设置.sct文件;;*************************************************************; *** Scatter-Loading Description Filegenerated by uVision ***; *************************************************************LR_IROM1 0x08000000 0x00020000  
发表于 2019-04-16
STM32定义堆栈地址到ram区顶部

STM32之程序如何防止堆栈溢出

近日为某个项目写了个草稿程序,即非正式程序,后来发现老是进入hardfaulthandler,原来是堆栈溢出,后仔细查看发现函数调用纵深太深,最多的时候可保持7个函数在堆栈中调用。因此有心得如下:一、函数调用不要纵深太深,即以下模式:main(){   fun1();}fun1(){  fun2();}fun2(){   fun3();}fun3(){  fun4();}fun4(){  fun5();}fun5(){  fun6();}fun6(){   fun7();}这样子main函数要调用fun1函数完成某个功能,则要一直调到
发表于 2019-04-16

stm32之堆栈

stm32中的堆栈设置keil编译完成时存储情况当编译成功时,会出现: BUILD://Program Size: Code=340 RO-data=252 RW-data=0 ZI-data=1632Code:程序代码部分RO-data: 程序定义的常量const tempRW-data:已初始化的全局变量ZI-data:未初始化的全局变量片中的:flash=Code+RO-data+RW-dataRAM=RW-data+ZI-data通过上面的BUILD可以看出,这个程序已经用了1600多的RAM,为什么会出用到这么多的RAM呢?在startup_stm32f10x_md.s文件中存在:St
发表于 2019-04-16

说说STM32的堆栈与内存

1.概念这里所说的堆栈,是针对单片机所说的“堆”与“栈”,指的是内存中一片特殊用途的区域。而不是数据结构中的堆栈(虽然其实规则一样)。这里所说的内存,是指RAM,RAM包括SRAM,DRAM等。而不是什么手机内存卡之类。这里所说的flash,指的是用作为ROM的存储器,保存代码与常量数据。而不是动画制作。。。栈的生长方向:指的是入栈方向,从高地址向低地址生长叫做向下生长,或逆向生长;反过来就叫向上生长,或正向生长。STM32的栈是向下生长。2.内存中的堆栈安排确切地说,是keil mdk根据STM32的特性,对stm32的RAM甚至flash进行部署。编译工程后,在生成的.map文件里可以看到具体的安排。双击工程界面的工程根目录
发表于 2019-04-16
说说STM32的堆栈与内存

小广播

何立民专栏

单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2019 EEWORLD.com.cn, Inc. All rights reserved