NRF24L01学习操作教程(一)——NRF基础知识与相关寄存器介绍_nrf24l01模块使用教程(1)

​ 可以设置接收发送模式下地址的宽度,默认使用5字节的宽度。

2.2.5自动重发寄存器(地址:04)

image-20230510203431603

​ nRF24L01配置为Enhanced ShockBurst 发送模式下时,自动重发功能是针对自动应答系统的发送方。在每次发送结束后系统都会进入接收模式并在设定的时间范围内等待应答信号,如果没有收到应答信号,则系统返回到发送模式并重发数据直到收到确认信号或重发次数超过设定值(达到最大的重发次数。

2.2.6射频频率设置寄存器(地址:05)

image-20230510204613860

频率计算公式:2400+RF_CH(MHz),即NRF可设置的频率为2400~2525(MHZ)之间

2.2.7射频配置寄存器(地址:06)

image-20230510205234408

2.2.8状态寄存器(地址:07)

image-20230510210320065

image-20230510210334095

​ nRF24L01的中断引脚(IRQ)为低电平触发,当状态寄存器中TX_DS、RX_DR、MAX_RT 为高时触发中断。当MCU给中断源写‘1’时,中断引脚被禁止。可屏蔽中断可以被IRQ中断屏蔽。通过设置可屏蔽中断位为高,则中断响应被禁止。默认状态下所有的中断源是被禁止的。

2.2.9数据通道接收地址配置寄存器(地址0A-0F)

image-20230510211123985

​ 注意,数据通道2~数据通道5的地址高四字节,与数据通道1地址的高四字节相同。

2.2.10发送地址配置寄存器(地址10)

image-20230510211627786

2.2.11接收通道0有效数据宽度配置寄存器(地址11)

image-20230510212316936

2.2.12FIFO状态寄存器(地址17)

image-20230510212523998

image-20230510212537576

三、NRF24L01驱动程序

​ 根据NRF官方手册的寄存器操作,这里编写了基于STM32 HAL库的驱动程序,.c文件和.h文件如下。代码里有详细的函数注释

//NRF24L01 驱动函数
#include "NRF24L01.h"
#include "main.h"
#include "spi.h"
#include "stdio.h"
#include "string.h"

unsigned char INIT_ADDR[5]= {0x00,0x1A,0xB1,0xB1,0x01}; //节点地址

void delay\_us(uint32\_t n)
{
	unsigned char i;
	while(n--)
	{
		i = 8;
		while(i--);
	}
}

//初始化24L01的IO口
void NRF24L01\_Init(void)
{
	Clr_NRF24L01_CE;    // chip enable
	Set_NRF24L01_CSN;   // Spi disable
	delay\_us(100);
}

//上电检测NRF24L01是否在位
//写5个数据然后再读回来进行比较,
//相同时返回值:0,表示在位;否则返回1,表示不在位
unsigned char NRF24L01\_Check(void)
{
	unsigned char buf[5]= {0XA5,0XA5,0XA5,0XA5,0XA5};
	unsigned char buf1[5];
	unsigned char i;    	 
	NRF24L01\_Write\_Buf(SPI_WRITE_REG+TX_ADDR,buf,5);//写入5个字节的地址. 
	NRF24L01\_Read\_Buf(TX_ADDR,buf1,5); //读出写入的地址 
	for(i=0;i<5;i++)if(buf1[i]!=0XA5)break;	 							   
	if(i!=5)return 1;//检测24L01错误 
	return 0;		 //检测到24L01
}

//封装spi读写函数
unsigned char nRF24\_SPI\_Send\_Byte(unsigned char txdata)
{
	unsigned char rxdata;
	HAL\_SPI\_TransmitReceive(&hspi1, &txdata, &rxdata, 1, 0x10);
	return(rxdata);							// return read unsigned char
}


//封装SPI写寄存器,regaddr:要写的寄存器,data:写入寄存器的值
unsigned char NRF24L01\_Write\_Reg(unsigned char regaddr,unsigned char data)
{
	unsigned char status;
	Clr_NRF24L01_CSN;                    //使能SPI传输
	status =nRF24\_SPI\_Send\_Byte(regaddr); //发送寄存器号
	nRF24\_SPI\_Send\_Byte(data);            //写入寄存器的值
	Set_NRF24L01_CSN;                    //禁止SPI传输
	return(status);       		         //返回状态值
}

//封装SPI读寄存器值 ,regaddr:要读的寄存器
unsigned char NRF24L01\_Read\_Reg(unsigned char regaddr)
{
	unsigned char reg_val;
	Clr_NRF24L01_CSN;                //使能SPI传输
	nRF24\_SPI\_Send\_Byte(regaddr);     //发送寄存器号
	reg_val=nRF24\_SPI\_Send\_Byte(0XFF);//读取寄存器内容
	Set_NRF24L01_CSN;                //禁止SPI传输
	return(reg_val);                 //返回状态值
}

//在指定位置读出指定长度的数据
//\*pBuf:数据指针
//返回值,此次读到的状态寄存器值
unsigned char NRF24L01\_Read\_Buf(unsigned char regaddr,unsigned char \*pBuf,unsigned char datalen)
{
	unsigned char status;
	Clr_NRF24L01_CSN;                     //使能SPI传输
	status=nRF24\_SPI\_Send\_Byte(regaddr);   //发送寄存器值(位置),并读取状态值
	HAL\_SPI\_Receive(&hspi1, pBuf, datalen, 0x10);
	Set_NRF24L01_CSN;                     //关闭SPI传输
	return status;                        //返回读到的状态值
}

//在指定位置写指定长度的数据
//\*pBuf:数据指针
//返回值,此次读到的状态寄存器值
unsigned char NRF24L01\_Write\_Buf(unsigned char regaddr, unsigned char \*pBuf, unsigned char datalen)
{
	unsigned char status;
	Clr_NRF24L01_CSN;                                    //使能SPI传输
	status = nRF24\_SPI\_Send\_Byte(regaddr);                //发送寄存器值(位置),并读取状态值
	HAL\_SPI\_Transmit(&hspi1, pBuf, datalen, 0x10);
	Set_NRF24L01_CSN;                                    //关闭SPI传输
	return status;                                       //返回读到的状态值
}

//启动NRF24L01发送一次数据
//txbuf:待发送数据首地址
//返回值:发送完成状况
unsigned char NRF24L01\_TxPacket(unsigned char \*txbuf)
{
	unsigned char state;
	Clr_NRF24L01_CE;
	NRF24L01\_Write\_Buf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);//写数据到TX BUF 32个字节
	Set_NRF24L01_CE;                                     //启动发送
	while(READ_NRF24L01_IRQ!=0);                         //等待发送完成
	state=NRF24L01\_Read\_Reg(STATUS);                     //读取状态寄存器的值
	NRF24L01\_Write\_Reg(SPI_WRITE_REG+STATUS,state);      //清除TX\_DS或MAX\_RT中断标志
	if(state&MAX_TX)                                     //达到最大重发次数
	{
		NRF24L01\_Write\_Reg(FLUSH_TX,0xff);               //清除TX FIFO寄存器
		return MAX_TX;
	}
	if(state&TX_OK)                                      //发送完成
	{
		return TX_OK;
	}
	return 0xff;                                         //其他原因发送失败
}

//启动NRF24L01发送一次数据
//rxbuf:待发送数据首地址
//返回值:0,接收完成;其他,错误代码
unsigned char NRF24L01\_RxPacket(unsigned char \*rxbuf)
{
	unsigned char state;
	state=NRF24L01\_Read\_Reg(STATUS);                //读取状态寄存器的值
	NRF24L01\_Write\_Reg(SPI_WRITE_REG+STATUS,state); //清除TX\_DS或MAX\_RT中断标志
	if(state&RX_OK)                                 //接收到数据
	{
		NRF24L01\_Read\_Buf(RD_RX_PLOAD,rxbuf,RX_PLOAD_WIDTH);//读取数据
		NRF24L01\_Write\_Reg(FLUSH_RX,0xff);          //清除RX FIFO寄存器
		return 0;
	}
	return 1;                                      //没收到任何数据
}

//该函数初始化NRF24L01到RX模式
//numofslave:接收地址的低字节
//设置RX地址,写RX数据宽度,选择RF频道,波特率和LNA HCURR
//当CE变高后,即进入RX模式,并可以接收数据了
void RX\_Mode(unsigned char numofslave)
{
	INIT_ADDR[0]=numofslave;
	Clr_NRF24L01_CE;
	//写RX节点地址
	NRF24L01\_Write\_Buf(SPI_WRITE_REG+RX_ADDR_P0,(unsigned char\*)INIT_ADDR,RX_ADR_WIDTH);
	//使能通道0的自动应答
	NRF24L01\_Write\_Reg(SPI_WRITE_REG+EN_AA,0x01);
	//使能通道0的接收地址
	NRF24L01\_Write\_Reg(SPI_WRITE_REG+EN_RXADDR,0x01);
	//设置RF通信频率(频率计算公式:2400+RF\_CH(MHZ))
	NRF24L01\_Write\_Reg(SPI_WRITE_REG+RF_CH,40);
	//选择通道0的有效数据宽度
	NRF24L01\_Write\_Reg(SPI_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);
	//设置TX发射参数,0db增益,2Mbps,低噪声增益开启
	NRF24L01\_Write\_Reg(SPI_WRITE_REG+RF_SETUP,0x0f);
	//配置基本工作模式的参数;PWR\_UP,EN\_CRC,16BIT\_CRC,PRIM\_RX接收模式
	NRF24L01\_Write\_Reg(SPI_WRITE_REG+CONFIG, 0x0f);
	//CE为高,进入接收模式
	Set_NRF24L01_CE;
	
}

//该函数初始化NRF24L01到TX模式
//numofslave:发送地址的低字节
//设置TX地址,写TX数据宽度,设置RX自动应答的地址,填充TX发送数据,
//选择RF频道,波特率和LNA HCURR PWR\_UP,CRC使能
//当CE变高后,即进入RX模式,并可以接收数据了
//CE为高大于10us,则启动发送.
void TX\_Mode(unsigned char numofslave)
{
	INIT_ADDR[0]=numofslave;
	Clr_NRF24L01_CE;
	//写TX节点地址
	NRF24L01\_Write\_Buf(SPI_WRITE_REG+TX_ADDR,(unsigned char\*)INIT_ADDR,TX_ADR_WIDTH);
	//设置TX节点地址,主要为了使能ACK
	NRF24L01\_Write\_Buf(SPI_WRITE_REG+RX_ADDR_P0,(unsigned char\*)INIT_ADDR,RX_ADR_WIDTH);
	//使能通道0的自动应答
	NRF24L01\_Write\_Reg(SPI_WRITE_REG+EN_AA,0x01);
	//使能通道0的接收地址
	NRF24L01\_Write\_Reg(SPI_WRITE_REG+EN_RXADDR,0x01);
	//设置自动重发间隔时间:500us + 86us;最大自动重发次数:10次
	NRF24L01\_Write\_Reg(SPI_WRITE_REG+SETUP_RETR,0x1a);
	//设置RF通道为40
	NRF24L01\_Write\_Reg(SPI_WRITE_REG+RF_CH,40);
	//设置TX发射参数,0db增益,2Mbps,低噪声增益开启
	NRF24L01\_Write\_Reg(SPI_WRITE_REG+RF_SETUP,0x0f);
	//配置基本工作模式的参数;PWR\_UP,EN\_CRC,16BIT\_CRC,PRIM\_RX发送模式,开启所有中断
	NRF24L01\_Write\_Reg(SPI_WRITE_REG+CONFIG,0x0e);
	// CE为高,10us后启动发送
	Set_NRF24L01_CE;
}

以下是.h文件

#ifndef \_\_NRF24L01\_H
#define \_\_NRF24L01\_H

/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
//NRF24L01寄存器操作命令
#define SPI\_READ\_REG 0x00 //读配置寄存器,低5位为寄存器地址
#define SPI\_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 FIFO\_STATUS 0x17 //FIFO状态寄存器;bit0,RX FIFO寄存器空标志;bit1,RX FIFO满标志;bit2,3,保留
                              //bit4,TX FIFO空标志;bit5,TX FIFO满标志;bit6,1,循环发送上一数据包.0,不循环;
/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
//NRF24L01控制操作

//NRF2401片选信号
#define Clr\_NRF24L01\_CE HAL\_GPIO\_WritePin(CE\_24L01\_GPIO\_Port, CE\_24L01\_Pin, GPIO\_PIN\_RESET)
#define Set\_NRF24L01\_CE HAL\_GPIO\_WritePin(CE\_24L01\_GPIO\_Port, CE\_24L01\_Pin, GPIO\_PIN\_SET)

//SPI片选信号
#define Clr\_NRF24L01\_CSN HAL\_GPIO\_WritePin(CSN\_24L01\_GPIO\_Port, CSN\_24L01\_Pin, GPIO\_PIN\_RESET)
#define Set\_NRF24L01\_CSN HAL\_GPIO\_WritePin(CSN\_24L01\_GPIO\_Port, CSN\_24L01\_Pin, GPIO\_PIN\_SET)

//NRF2401\_IRQ数据输入
#define READ\_NRF24L01\_IRQ HAL\_GPIO\_ReadPin(IRQ\_24L01\_GPIO\_Port, IRQ\_24L01\_Pin)

//NRF24L01发送接收地址、发送接收数据宽度定义
#define TX\_ADR\_WIDTH 5 //5字节的地址宽度
#define RX\_ADR\_WIDTH 5 //5字节的地址宽度
#define TX\_PLOAD\_WIDTH 8 //8节的用户数据宽度
#define RX\_PLOAD\_WIDTH 8 //8字节的用户数据宽度

/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
//函数声明
void NRF24L01\_Init(void);                                //NRF24l01初始化
void RX\_Mode(unsigned char numofslave);   //配置为接收模式
void TX\_Mode(unsigned char numofslave);  //配置为发送模式
unsigned char NRF24L01\_Write\_Buf(unsigned char regaddr, unsigned char \*pBuf, unsigned char datalen); //写数据区
unsigned char NRF24L01\_Read\_Buf(unsigned char regaddr, unsigned char \*pBuf, unsigned char datalen);  //读数据区
unsigned char NRF24L01\_Read\_Reg(unsigned char regaddr);		                 //读寄存器
unsigned char NRF24L01\_Write\_Reg(unsigned char regaddr, unsigned char data);              //写寄存器
unsigned char NRF24L01\_Check(void);                                 //检查NRF24L01是否在位
unsigned char NRF24L01\_TxPacket(unsigned char \*txbuf);                         //发送一个包的数据
unsigned char NRF24L01\_RxPacket(unsigned char \*rxbuf);                         //接收一个包的数据
/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
#endif

总结

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!

mAtn-1715592081756)]

[外链图片转存中…(img-LmUIxtQf-1715592081757)]

[外链图片转存中…(img-kI6kxxGh-1715592081757)]

[外链图片转存中…(img-aSkYHuQ1-1715592081758)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!

  • 25
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值