stm32【 NRF24L01多通道、动态数据、主从一体(2)】

nRF24L01多通道通讯

测试平台:stm32f103c8t6
库版本:官方库3.5版本

在上一篇NRF一对一通讯里详细介绍了nRF24L01模块的一对一通讯配置,以及主从一体代码的实现,文章篇幅较长,还请耐心阅读。
多通道都是基于单通道修改而来的,如果一对一调试通过了,就可以进行接下来的多通道配置。

1、nRF多通道配置

回顾上一篇,总共编写了以下的函数

//nRF配置
void NRF_SPI_Config(void);		//nRF的SPI及CE CSN IRQ接口配置
void NRF_Config(void);			//nRF初始化
u8 NRF_Check(void); 			//检查MCU和nRF的连接

//-----------------------------------------------------------
//nRF寄存器读写 调用以下API均会刷新status的值
u8 NRF_SPI_ReadReg(u8 reg);
u8 NRF_SPI_ReadBuf(u8 reg,u8 *buf,u8 len);

u8 NRF_SPI_WriteReg(u8 reg,u8 dat);
u8 NRF_SPI_WriteBuf(u8 reg ,u8 *buf,u8 len);	
//-----------------------------------------------------------

//-----------------------------------------------------------
//先调用【NRF_CE_LOW;】拉低进入待机模式或掉电模式
//再调用以下API
void NRF_RX_Mode(void);			//配置成PRX
void NRF_TX_Mode(void);			//配置成PTX
//-----------------------------------------------------------

//nRF_API
void NRF_ReceivePacket(void);
void NRF_SendPacket(u8 *TX_BUFF);	//发送固定长度有效数据包

这其中的SPI管脚配置函数和寄存器读写函数都是涉及底层接口的,不需要修改,
这次针对nRF多通道的配置只需要修改三个函数:
void NRF_Config(void);
void NRF_RX_Mode(void);
void NRF_SendPacket(u8 *TX_BUFF);

这里的多通道,指的是6通道全开,所以会对全部通道一起配置,如果不需要这么多通道的还请自行修改
上一章NRF一对一通讯里给出的配置函数是这样的

void NRF_Config(void)
{
	NRF_SPI_Config();
	
	//拉低CE,注意:需要将CE拉低,使其进入待机或者掉电模式才能读/写nRF寄存器
	NRF_CE_LOW;
	
	//初始化NRF(看数据手册)
	NRF_SPI_WriteReg(W_REGISTER | SETUP_AW, 0x03);							//配置通信地址的长度,默认值时0x03,即地址长度为5字节
	NRF_SPI_WriteReg(W_REGISTER | SETUP_RETR, 0x15); 						//自动重发延迟为500+86us,重发次数5次
	NRF_SPI_WriteReg(W_REGISTER | RF_SETUP, 0x07);   						//设置发射速率为1MHZ,发射功率为最大值0dB
	NRF_SPI_WriteReg(W_REGISTER | RF_CH, 30);        						//设置通道通信频率,工作通道频率可由以下公式计算得出:Fo=(2400+RF_CH)MHz.并且射频收发器工作的频率范围从2.400-2.525GHz

//---------------------------PRX:单通道配置------------------------------------------------------------------------	
	NRF_SPI_WriteBuf(W_REGISTER | RX_ADDR_P0, RX_ADDRESS_0, ADDRESS_WIDTH); 	//配置本机接收通道0的接收数据的地址
	NRF_SPI_WriteReg(W_REGISTER | EN_AA, 0x01);      						//接收数据后,只允许频道0自动应答
	NRF_SPI_WriteReg(W_REGISTER | EN_RXADDR, 0x01);  						//只允许频道0接收数据
	
//---------------------------PRX:数据接收长度配置----------------------------------------------------------------------------	
		NRF_SPI_WriteReg(W_REGISTER | RX_PW_P0, STATIC_PLOAD_LENGTH);
//---------------------------PTX:单通道配置------------------------------------------------------------------------	
	//发送通道地址,由于是单通道,在这里配置一次就可以了(默认通道0)
	NRF_SPI_WriteBuf(W_REGISTER | TX_ADDR, RX_ADDRESS_0, ADDRESS_WIDTH);    	//发送的数据包中被一块打包进去的接收端NRF的接收通道的地址

	NRF_SPI_WriteReg(W_REGISTER | CONFIG, 0x0C | PWR_UP | PRIM_RX);   			//默认处于接收模式

	NRF_CE_HIGH;
	delay_ms(2);

}

现在做些修改,改成下面的函数

void NRF_Config(void)
{
	NRF_SPI_Config();
	
	//拉低CE,注意:需要将CE拉低,使其进入待机或者掉电模式才能读/写nRF寄存器
	NRF_CE_LOW;
	
	//初始化NRF(看数据手册)
	NRF_SPI_WriteReg(W_REGISTER | SETUP_AW, 0x03);							//配置通信地址的长度,默认值时0x03,即地址长度为5字节
	NRF_SPI_WriteReg(W_REGISTER | SETUP_RETR, 0x15); 						//自动重发延迟为500+86us,重发次数5次
	NRF_SPI_WriteReg(W_REGISTER | RF_SETUP, 0x07);   						//设置发射速率为1MHZ,发射功率为最大值0dB
	NRF_SPI_WriteReg(W_REGISTER | RF_CH, 30);        						//设置通道通信频率,工作通道频率可由以下公式计算得出:Fo=(2400+RF_CH)MHz.并且射频收发器工作的频率范围从2.400-2.525GHz

#if RX_MULIT_CHANNEL
//---------------------------PRX:多通道配置----------------------------------------------------------------------------	
																				//通道0和1完整赋值,通道2-5只能赋值地址的第一个(最低byte)
	NRF_SPI_WriteBuf(W_REGISTER | RX_ADDR_P0, RX_ADDRESS_0, ADDRESS_WIDTH); 	//配置PRX接收通道0的接收数据的地址
	NRF_SPI_WriteBuf(W_REGISTER | RX_ADDR_P1, RX_ADDRESS_1, ADDRESS_WIDTH); 	//配置PRX接收通道1的接收数据的地址
	NRF_SPI_WriteBuf(W_REGISTER | RX_ADDR_P2, RX_ADDRESS_2, 1); 				//配置PRX接收通道2的接收数据的地址
	NRF_SPI_WriteBuf(W_REGISTER | RX_ADDR_P3, RX_ADDRESS_3, 1); 				//配置PRX接收通道3的接收数据的地址
	NRF_SPI_WriteBuf(W_REGISTER | RX_ADDR_P4, RX_ADDRESS_4, 1); 				//配置PRX接收通道4的接收数据的地址
	NRF_SPI_WriteBuf(W_REGISTER | RX_ADDR_P5, RX_ADDRESS_5, 1); 				//配置PRX接收通道5的接收数据的地址

	NRF_SPI_WriteReg(W_REGISTER | EN_AA, 0x3F);      						//接收数据后,允许所有通道自动应答
	NRF_SPI_WriteReg(W_REGISTER | EN_RXADDR, 0x3F);  						//允许所有通道接收数据

//---------------------------PRX:接收数据长度配置----------------------------------------------------------------------------	
		NRF_SPI_WriteReg(W_REGISTER | RX_PW_P0, STATIC_PLOAD_LENGTH);
		NRF_SPI_WriteReg(W_REGISTER | RX_PW_P1, STATIC_PLOAD_LENGTH);
		NRF_SPI_WriteReg(W_REGISTER | RX_PW_P2, STATIC_PLOAD_LENGTH);
		NRF_SPI_WriteReg(W_REGISTER | RX_PW_P3, STATIC_PLOAD_LENGTH);
		NRF_SPI_WriteReg(W_REGISTER | RX_PW_P4, STATIC_PLOAD_LENGTH);
		NRF_SPI_WriteReg(W_REGISTER | RX_PW_P5, STATIC_PLOAD_LENGTH);

//---------------------------PTX:多通道配置------------------------------------------------------------------------	
	//发送通道地址,由于是多通道,在发送函数里选择配置


#else
//---------------------------PRX:单通道配置------------------------------------------------------------------------	
	NRF_SPI_WriteBuf(W_REGISTER | RX_ADDR_P0, RX_ADDRESS_0, ADDRESS_WIDTH); 	//配置本机接收通道0的接收数据的地址
	NRF_SPI_WriteReg(W_REGISTER | EN_AA, 0x01);      						//接收数据后,只允许频道0自动应答
	NRF_SPI_WriteReg(W_REGISTER | EN_RXADDR, 0x01);  						//只允许频道0接收数据
	
//---------------------------PRX:数据接收长度配置----------------------------------------------------------------------------	
//固定数据长度
		NRF_SPI_WriteReg(W_REGISTER | RX_PW_P0, STATIC_PLOAD_LENGTH);

//---------------------------PTX:单通道配置------------------------------------------------------------------------	
	//发送通道地址,由于是单通道,在这里配置一次就可以了(默认通道0)
	NRF_SPI_WriteBuf(W_REGISTER | TX_ADDR, RX_ADDRESS_0, ADDRESS_WIDTH);    	//发送的数据包中被一块打包进去的接收端NRF的接收通道的地址

#endif

	NRF_SPI_WriteReg(W_REGISTER | CONFIG, 0x0C | PWR_UP | PRIM_RX);   			//默认处于接收模式

	NRF_CE_HIGH;
	delay_ms(2);

}

在上一章第5节里给出的【NRF.h】头文件里有以下的宏定义

#define RX_MULIT_CHANNEL		1			//【0:单通道(默认通道0)】【1:多通道(6通道全开)】
#define DYNAMIC_PLOAD_LENGTH	1			//【0:固定数据长度】【1:动态数据长度】

这两个宏定义是用来【开启/关闭】多通道和动态数据长度的
本篇只用到【RX_MULIT_CHANNEL】,关于动态长度留到下一篇讲解

回到新的nRF配置函数,如果【RX_MULIT_CHANNEL = 0】,仔细对比可以发现那么剩下的配置是和上一章的单通道配置是一模一样的:
配置好通讯频道之后-----PRX:单通道配置-----PRX:数据接收长度配置-----PTX:单通道配置
对于多通道来说,也是这样的配置流程,区别点就在最后一个PTX:通道配置
当【RX_MULIT_CHANNEL = 1】时:
配置好通讯频道之后-----PRX:多通道配置-----PRX:数据接收长度配置

下面来讲讲【PRX:多通道配置】
▼在多通道配置里,多了对通道1~5的通道接收地址的配置

	NRF_SPI_WriteBuf(W_REGISTER | RX_ADDR_P0, RX_ADDRESS_0, ADDRESS_WIDTH); 	//配置PRX接收通道0的接收数据的地址
	NRF_SPI_WriteBuf(W_REGISTER | RX_ADDR_P1, RX_ADDRESS_1, ADDRESS_WIDTH); 	//配置PRX接收通道1的接收数据的地址
	NRF_SPI_WriteBuf(W_REGISTER | RX_ADDR_P2, RX_ADDRESS_2, 1); 				//配置PRX接收通道2的接收数据的地址
	NRF_SPI_WriteBuf(W_REGISTER | RX_ADDR_P3, RX_ADDRESS_3, 1); 				//配置PRX接收通道3的接收数据的地址
	NRF_SPI_WriteBuf(W_REGISTER | RX_ADDR_P4, RX_ADDRESS_4, 1); 				//配置PRX接收通道4的接收数据的地址
	NRF_SPI_WriteBuf(W_REGISTER | RX_ADDR_P5, RX_ADDRESS_5, 1); 				//配置PRX接收通道5的接收数据的地址

要注意的是这里对2 ~ 5的通道地址只赋一个值,不能把5byte数据都写进去,不然会识别不了地址,在数据手册7.6章节里有对通道地址的描述
在这里插入图片描述
通道0和通道1的地址是随意设置的,不相同就行,但是通道2~5是和通道1共用高4byte,最低byte必须不同,对于【RX_ADDR_PX寄存器】的描述如下
在这里插入图片描述
注意看【RX_ADDR_P1】最大接收5byte数据,也就是我们定义的地址数组大小,而【RX_ADDR_P2~5】只接收LSB,也就是最低byte
▼我的接收通道地址

//------------------------RX通道地址【低字节在前!!!】-------------------------------------------------
u8 RX_ADDRESS_0[ADDRESS_WIDTH] = {0x00,0x34,0x22,0x1D,0x10};	//NRF的RX0通道的地址
u8 RX_ADDRESS_1[ADDRESS_WIDTH] = {0x01,0x34,0x22,0x1D,0x10};	//NRF的RX1通道的地址
u8 RX_ADDRESS_2[ADDRESS_WIDTH] = {0x02,0x34,0x22,0x1D,0x10};	//NRF的RX2通道的地址
u8 RX_ADDRESS_3[ADDRESS_WIDTH] = {0x03,0x34,0x22,0x1D,0x10};	//NRF的RX3通道的地址
u8 RX_ADDRESS_4[ADDRESS_WIDTH] = {0x04,0x34,0x22,0x1D,0x10};	//NRF的RX4通道的地址
u8 RX_ADDRESS_5[ADDRESS_WIDTH] = {0x05,0x34,0x22,0x1D,0x10};	//NRF的RX5通道的地址

我一开始测试多通道是把所有通道的5byte数据全写入,结果PRX端通道1 ~ 5通道都不能通讯,估计是因为2~5通道只接收1byte数据,写入5byte时后写入的会覆盖之前写入的数据,最终写入的是最高byte(低byte先写入),那么最终通道1 ~ 5的地址都是相同的,导致通讯失败。

通道0~5的接收地址配置完成后,就是使能通道接收功能和自动应答功能▼

	NRF_SPI_WriteReg(W_REGISTER | EN_AA, 0x3F);      						//接收数据后,允许所有通道自动应答
	NRF_SPI_WriteReg(W_REGISTER | EN_RXADDR, 0x3F);  						//允许所有通道接收数据

和单通道不同的地方在赋值不同,0x3F(0011 1111),看数据手册对应的寄存器就知道为啥是这个值了

接收数据长度配置和单通道是一样的,这里是固定长度,给0~5通道的【RX_PW_Px寄存器】都赋值【STATIC_PLOAD_LENGTH】

到此,【PRX:多通道配置】已经完成,但是现在还不能进行不同通道的通讯,因为【PTX:多通道配置】还没做呢,这个配置是在发送函数里

2、nRF发送数据(多通道)

这里强调一下,我的目的是实现主从一体的代码,因此nRF是一直运行在PRX下的,PRX的配置在【void NRF_Config(void)】里配置一次就行了,PTX在单通道下,使用哪个通道是固定的,所以在也是只需要在【void NRF_Config(void)】配置一次就可以了
而多通道就不一样了,PTX多通道模式下,如果要发送数据,得先往【TX_ADDR寄存器】写入发送到PRX端哪一个通道的通道地址,并且把这个地址也写入到【RX_ADDR_P0寄存器】,这样做是为了用来接收PRX端的Auto-ACK,在nRF里是规定了PTX模式下只能用通道0来接收数据(规定好的,不能改)
▼因此把上一篇里的发送函数【void NRF_SendPacket(u8 *TX_BUFF)】改成下面这样

void NRF_SendPacket(u8 *RX_ADDRESS_X,u8 *TX_BUFF)
{
	NRF_CE_LOW;							//拉低CE,进入待机模式或掉电模式
	
	NRF_TX_Mode();						//配置成PTX待机模式

#if RX_MULIT_CHANNEL
//---------------------------多通道发送地址选择---------------------------------------------------------------
	//RX_ADDRESS_X:PTX选择发送到PRX的哪一个通道
	NRF_SPI_WriteBuf(W_REGISTER | TX_ADDR, RX_ADDRESS_X, ADDRESS_WIDTH);
	//PTX使用pipe0来接收PRX的Auto-ACK信号
	//所以将RX_ADDRESS_X填入pipe0,这样才能对比Auto-ACK附带的通道地址
	//在退出PTX时要将RX_ADDRESS_0赋值给RX_ADDR_P0
	NRF_SPI_WriteBuf(W_REGISTER | RX_ADDR_P0, RX_ADDRESS_X, ADDRESS_WIDTH); 
#else //---------------------------单通道发送地址------------------------------------------------------------	
		//在NRF_Config里设置一次就行
#endif
	
	NRF_SPI_WriteBuf(WR_TX_PLOAD, TX_BUFF, STATIC_PLOAD_LENGTH); 	//将数据写入TX端的FIFO中,写入的个数与TX_PLOAD_WIDTH设置值相同	

	NRF_CE_HIGH;	//拉高CE,准备发射TX端FIFO中的数据
					//CE拉高后,nRF自动延迟130us后,发送数据
}

相比单通道,除了把需要发送的数组传递进去之外,还要把通道地址传递进去

注意【NRF_SPI_WriteBuf(W_REGISTER | RX_ADDR_P0, RX_ADDRESS_X, ADDRESS_WIDTH);】如果没有这一句,那么在实际测试里会出现这样的状况:
假设:作为PTX端如果数据是从通道2发送,是可以发送出去的,PRX端也能够接收到并且正常通过串口打印出来,但是PTX端得到的消息是没有应答
这是因为在【void NRF_Config(void)】的PRX多通道配置里,【RX_ADDR_P0寄存器】写的是【RX_ADDRESS_0】地址,这是给PRX模式用的,而进入PTX模式后,【RX_ADDR_P0寄存器】是用来接收自动应答信号的,PRX端发送的Auto-ACK数据包里包含了通道2的地址信息,那么PTX端发送数据后,对接收到Auto-ACK数据包进行分析,发现里面的地址是通道2地址,跟【RX_ADDR_P0寄存器】写的【RX_ADDRESS_0】地址对不上,因此会判定数据包发出去但没有应答。

所以在使用其他通道发送时,要把地址赋值给【RX_ADDR_P0寄存器】,不然是接收不到应答信号的

这里还有一点是需要修改的,进入PTX模式发送数据后,会回到PRX模式,那么在回到PRX模式时,也要把【RX_ADDR_P0寄存器】的值还原,不然在PRX模式下是不能正常运行的,因为此时【RX_ADDR_Px寄存器】里有两个相同的地址,这个还原我选择放在【void NRF_RX_Mode(void)】函数里

/********************************************************************************
  * @brief  配置接收模式(PRX)并进入待机1模式(standby-1),先调用【NRF_CE_LOW】再调用此API
			在PRX下只有CE保存高电平的期间可以接收数据
  * @param  none
  * @retval none
  *******************************************************************************/
void NRF_RX_Mode(void)
{
	NRF_MODE = 1;														//模式转换标志位
//	NRF_CE_LOW;															//拉低CE,进入待机模式或掉电模式

	NRF_SPI_WriteReg(W_REGISTER | STATUS, IRQ_CLEAR);					//清除所有中断标志,防止一进入接收模式就触发中断
	NRF_SPI_WriteReg(W_REGISTER | CONFIG, 0x0C | PWR_UP | PRIM_RX); 	//将NRF配置为待机接收模式(PRX)
	delay_ms(2);														//nRF延时1.5ms后进入待机1模式(standby-1)
	
	//进入了PTX发送数据时,为了Auto-ACK,【RX_ADDR_P0】修改成对应的通道地址【RX_ADDRESS_X】
	//此时再进入PRX,要重新配置【RX_ADDR_P0】为【RX_ADDRESS_0】,才能在PRX下正常使用通道0接收数据
	NRF_SPI_WriteBuf(W_REGISTER | RX_ADDR_P0, RX_ADDRESS_0, ADDRESS_WIDTH);

//	NRF_CE_HIGH;											//CE拉高后,nRF自动延迟130us后,进入接收模式
//	delay_us(150);											//PRX模式下该延时也可以做其他的处理
}

到此nRF多通道配置以及全部完成,可以进行实验了

3、nRF24L01多通道通讯总结

在本篇文章里,对上一篇NRF一对一通讯的三个函数进行修改

void NRF_Config(void);			//nRF初始化
void NRF_RX_Mode(void);			//配置成PRX
void NRF_SendPacket(u8 *RX_ADDRESS_X,u8 *TX_BUFF);		//发送固定长度有效数据包

就完成了多通道的通讯配置,正常的话是能够通过串口打印出通道号和接收的数据
需要注意的是:假设要使用通道X,那么不能仅仅配置通道X,要把通道X前面的所有通道都一并配置

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值