STM32驱动NRF24L01

前言:

为了方便查看博客,特意申请了一个公众号,附上二维码,有兴趣的朋友可以关注,和我一起讨论学习,一起享受技术,一起成长。

STM32驱动NRF24L01_第1张图片


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 结构框图

STM32驱动NRF24L01_第2张图片

如图右侧为六个控制和数据信号,分别为 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 状态机

STM32驱动NRF24L01_第3张图片

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

模式 PWR_UP register PRIM_RX register CE FIFO state
RX Mode 1 1 1 -
TX Mode 1 0 1 数据存在TX FIFO寄存器中
TX Mode 1 0 最小 10us高电平 停留在发送模式,直到数据发送完
待机模式2 1 0 1 TX FIFO为空
待机模式1 1 - 0 无数据传输
掉电模式 0 - - -

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

1.3 硬件设计

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

STM32驱动NRF24L01_第4张图片

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

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;

  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 ACK EN_AA
4)使能 PIPE 0 EN_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 ACK EN_AA
3)使能 PIPE 0 EN_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 个发射端进行识别。

STM32驱动NRF24L01_第5张图片

数据通道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位共用地址+各自的地址(最低字节)。如下图所示:

STM32驱动NRF24L01_第6张图片

1.6 NRF24L01的SPI通信模式

STM32驱动NRF24L01_第7张图片

从图中可以看出, 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<len;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测试程序 进行下载验证。测试比较简单,就是一收一发,往复循环。

现象:

STM32驱动NRF24L01_第8张图片

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

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


参考:

1.STM32控制NRF24L01无线模块进行通信
2.nRF24L01–中文资料

3.NRF24L01+的5个通道调试经验

你可能感兴趣的:(stm32开发,spi驱动,STM32学习笔记)