既然是一对多可变payload宽度的通信,肯定是包含两个方面:
(1)能进行一对多通信(同个频道下一般最多是一对六)
(2)发送的数据包宽度是可变的
配置NRF24L01进行一对多通信,前提是一对一通信机制必须要清楚。
我个人的理解是这样的
PTX端需要配置的地址TX_ADDR和RX_ADDR
PRX端需要配置的地址RX_ADDR
至于以上地址在这个机制中是怎么用的,为什么会相同,下面会解释。
进入正题
ShockBurst™下数据包格式:
PTX端发送数据前,会先对数据进行打包。在这个数据包红色框中的就是PTX发射端的地址TX ADDR。当PRX接收到一包有效的数据时,它会解析这个数据包中的Address地址是否跟它自身RX_ADDR相同,如果是相同的,那它就认为这是个发给我的包,如果不相同呢,那肯定是发给别人的包,就会被丢弃。好的,发送和接收都搞明白了,还有应答信号(前提是使能了自动应答)。前面说了PRX会对比Address地址是否跟自身RX_ADDR相同,一旦对比成功,PRX会自动转换到发送模式并以这个地址作为发送地址发送应答信号。那么PTX是怎么接收这个应答信号的呢(前提是使能了自动应答),PTX在发送了一包数据后会自动转换为接收模式,等待接收PRX发过来的应答信号。那PTX是怎么知道需要接收哪个从机发送过来的应答信号呢,PTX端的RX_ADDR就起作用了,PTX也会检测应答包中的地址是不是跟自身的RX_ADDR地址相同,相同就表示这是个正确的应答包,TX_DS中断被触发,MCU通过识别中断号就能知道发送成功。
明白了一对一通信的机制,也就明白了为什么PTX端的TX_ADDR,RX_ADDR,和PRX端的RX_ADDR是相同的。其实这三个地址说白了就是一个地址,就是PRX某个PIPEx的地址,这就是一对多通信的基础
一般来说一对多说的是,一个接收N个发送
MultiCeiver(多方通信):
MultiCeiver 是接收模式下的一个功能,包含了一组共六个并行的数据通道,每个通道都拥有独一无二的地址。一个RF通道对应一个逻辑数据通道。在NRF24L01+中,每个数据通道都有其自身的物理地址。
NRF24L01+配置成PRX(接收者)后,在同一通信频道中,可以接收6个不同数据通道的数据。6个NRF24L01+被配置为PTX(发送者),他们能与同一个PRX通信。PRX能同时搜寻所有的数据通道。但是同一时刻只有一个数据通道能接收数据包。所有的数据通道都能工作在Enhanced ShockBurst™下。
以下配置所有的数据通道都一样:
CRC使能/失能(CRC在Enhanced ShockBurst™下一般都是被使能的)
CRC编码
RX地址宽度
通信频道
传输速率
LNA增益
数据通道的使能在EN_RXADDR寄存器。默认情况下只有数据通道0和1被使能。每个数据通道的地址在RX_ADDR_Px寄存器中设置。
NOTE:确保每个数据通道的地址都是不同的。否则GG
每个通道有5个字节的可配置地址。数据通道0有独一无二的5个字节的地址。数据管道1~5共享4地址字节。但是6个通道的最低字节必须是不同的。如图13的例子所示:
PRX使用MultiCeiver™ 和 Enhanced ShockBurst™与多个PTX通信。为了确保从PRX发送的应答包能被正确的PTX接收,PRX会获取当前接收到的数据包中的通道地址,然后以这个地址作为发送地址发送应答数据包。图14中的例子解释了PRX和PTX的地址配置详情。在PRX中RX_ADDR_Pn是管道地址,必须是独一无二的。在PTX中TX_ADDR是指定通道的通道地址,必须跟RX_ADDR_P0(没错就是RX_ADDR_P0不是RX_ADDR_Pn)中设置的地址相同。也就是说假如有6个PTX跟1个PRX建立通信,这6个PTX的TX ADDR1~TX ADDR6就必须要一一对应PRX端通道0~通道5的地址,而每个PTX端的接收通道0(RX_ADDR_P0)必须跟其对应的TX ADDR相同。
只有当一个数据通道接收一个正确的数据包时,其他的通道才能开始接收数据。
二 配置可变宽度的数据包
Enhanced ShockBurst™有两种可供选择的payload长度:
(1)static length,通过设置接收端的RX_PW_Px寄存实现,接收端TX FIFO中的数据长度必须跟接收端设置的想等。
(2)Dynamic payload length(DPL):DPL允许PTX端发送可变长度payload给接收端,而接收端不需要使用RX_PW_Px寄存器,MCU使用R_RX_PL_WID命令能读出payload的长度。
使用DPL模式,必须使能FREATURE寄存器的EN_DPL位,在接收模式下,DYNPD寄存器的DPL_Px必须要设置。
NOTE:MCU最好能每次都检查一下接收到的payload的长度是不否大于32字节,如果大于32字节可能是接收到看错误的信息,需要丢弃。丢弃一帧数据包使用Flush_RX命令。
注意:PTX和PRX同时需要设置FREATURE寄存器的EN_DPL位和DYNPD寄存器的DPL_Px位。
举个一对六的配置
接收节点
const u8 PIPE0_RX_ADDRESS[RX_ADR_WIDTH]={0x78,0x78,0x78,0x78,0x78};//接收通道0地址
const u8 PIPE1_RX_ADDRESS[RX_ADR_WIDTH]={0xF1,0xB3,0xB4,0xB5,0xB6};//接收通道0地址
const u8 PIPE2_RX_ADDRESS[1]={0xCD};//接收通道0地址,PIPE2~5共用PIPE1的4字节地址,低字节地址在前,下同
const u8 PIPE3_RX_ADDRESS[1]={0xA3};//接收通道0地址
const u8 PIPE4_RX_ADDRESS[1]={0x0F};//接收通道0地址
const u8 PIPE5_RX_ADDRESS[1]={0x05};//接收通道0地址
void NRF24L01_RX_Mode(void)
{
NRF24L01_CE_L();
NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)PIPE0_RX_ADDRESS,RX_ADR_WIDTH);//写通道0地址
NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P1,(u8*)PIPE1_RX_ADDRESS,RX_ADR_WIDTH);//写通道1地址
NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P2,(u8*)PIPE2_RX_ADDRESS,1);//写通道2地址
NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P3,(u8*)PIPE3_RX_ADDRESS,1);//写通道3地址
NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P4,(u8*)PIPE4_RX_ADDRESS,1);//写通道4地址
NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P5,(u8*)PIPE5_RX_ADDRESS,1);//写通道5地址
NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x3F); //使能所有通道自动应答
NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x3F);//使能所有接收地址
NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,0x40); //设置发送频道24.064Ghz
// NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);//通道0数据宽度,DPL不需要设置接收数据宽度所以注释掉,下同
// NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P1,RX_PLOAD_WIDTH);//通道1数据宽度
NRF24L01_Write_Reg(NRF_WRITE_REG+FEATURE,0x04|0x02); //配合DPL功能使用
NRF24L01_Write_Reg(NRF_WRITE_REG+DYNPD,0x3f); //使能所有通道DPL功能
NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x07);
NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);//主接收
NRF24L01_CE_H(); //启动接收
}
发送节点0的代码,1~5只要更换本地地址和接收地址就行啦,6个不同的地址下面都列出来了
u8 const PIPE0_TX_ADDRESS[TX_ADR_WIDTH]= {0x78,0x78,0x78,0x78,0x78}; //PTX0本地地址
u8 const PIPE0_RX_ADDRESS[RX_ADR_WIDTH]= {0x78,0x78,0x78,0x78,0x78}; //PIPE0接收地址
u8 const PIPE1_TX_ADDRESS[TX_ADR_WIDTH]= {0xF1,0xB3,0xB4,0xB5,0xB6,}; //PTX1本地地址
u8 const PIPE1_RX_ADDRESS[RX_ADR_WIDTH]= {0xF1,0xB3,0xB4,0xB5,0xB6,}; //PIPE1接收地址
u8 const PIPE2_TX_ADDRESS[TX_ADR_WIDTH]= {0xCD,0xB3,0xB4,0xB5,0xB6}; //PTX2本地地址
u8 const PIPE2_RX_ADDRESS[RX_ADR_WIDTH]= {0xCD,0xB3,0xB4,0xB5,0xB6}; //PIPE2接收地址
u8 const PIPE3_TX_ADDRESS[TX_ADR_WIDTH]= {0xA3,0xB3,0xB4,0xB5,0xB6}; //PTX3本地地址
u8 const PIPE3_RX_ADDRESS[RX_ADR_WIDTH]= {0xA3,0xB3,0xB4,0xB5,0xB6}; //PIPE3接收地址
u8 const PIPE4_TX_ADDRESS[TX_ADR_WIDTH]= {0x0F,0xB3,0xB4,0xB5,0xB6}; //PTX4本地地址
u8 const PIPE4_RX_ADDRESS[RX_ADR_WIDTH]= {0x0F,0xB3,0xB4,0xB5,0xB6}; //PIPE4接收地址
u8 const PIPE5_TX_ADDRESS[TX_ADR_WIDTH]= {0x05,0xB3,0xB4,0xB5,0xB6}; //PTX5本地地址
u8 const PIPE5_RX_ADDRESS[RX_ADR_WIDTH]= {0x05,0xB3,0xB4,0xB5,0xB6}; //PIPE5接收地址
void NRF24L01_TX_Mode(void)
{
NRF24L01_CE_L();
NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(u8*)PIPE0_TX_ADDRESS,TX_ADR_WIDTH);//写发送端的地址
NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)PIPE0_RX_ADDRESS,RX_ADR_WIDTH);//写接收端PIPE0的地址
NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01); //使能PIPE0自动应答
NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01); //使能PIPE0接收地址
NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);
NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,0x40);
NRF24L01_Write_Reg(NRF_WRITE_REG+FEATURE,0x04|0x02); //配合DPL功能使用
NRF24L01_Write_Reg(NRF_WRITE_REG+DYNPD,0x3f); //使能所有通道DPL功能
NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x07);
NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);
NRF24L01_CE_H();
}
制作信标灯
2017/3/18
来源:CSDN
作者:TTea
链接:https://blog.csdn.net/wg1194024093/article/details/62416536