STM32驅動NRF24L01一對多的通信---可變數據包寬度

既然是一對多可變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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章