深度解析NRF24L01

本文將深度解析一款爛大街的無線芯片,NRF24L01(及國產完全兼容的SI24R1)。實在是現在網上很多寫NRF24L01的文章抓不到重點,一些冷門用法沒人寫,就寫了這個文章。推薦選用SI24R1,原因是功能完全相同,但SI24R1內置PA,最大輸出是7dbm,而挪威原版的NRF24L01+最大輸出只有0dbm。因爲2.4G是ISM頻段,功率即正義!

以下以SI24R1爲例進行說明

讀寫控制

spi配置

遵循以下配置即可:

  1. CPOL 1 & CPHA 1或者CPOL 0 & CPHA 0,手冊推薦使用後者,但是前者也是能用的
  2. SPI CLK 配置10MHZ以下即可
  3. SPI位寬配置爲8bit
  4. MSB在前

讀寄存器

  1. 手冊明確說明,CS拉低後的第一個字節被認爲是命令字,這樣也就沒辦法做常CS了,也就是必須把CS接到MCU,並保證在傳輸命令字之前CS有一個下降沿,這樣才能讀寫有效!
  2. 所有的命令字如下
    按照說明進行配置就可以了

基本傳輸

不使用其ARQ機制(在NRF24L01+被稱爲Enhanced ShockBurst™)的話,一次最基礎的傳輸需要配置的寄存器數量是非常少的。

RX配置:

EN_AA(0x01) → 0x00 配置不使用自動ACK

EN_RXADDR(0x02) → 0x01 配置使能接收地址0

SETUP_SW(0x03) → 0x03 配置使用5字節地址,這個地址最好長一點,雖然短了會省一些空中帶寬,但是也會增加碰撞的概率,爲了穩定性,最好還是用最長的

RF_SETUP(0x06) → 0x07 配置使用1MBPS的空速,最大輸出功率

RX_PW_P0(0x11) → 0x0A 配置使用固定接收長度10

CONFIG(0x00) → 0x03 配置使能,配置爲接收模式

RF_CH(0x05) → 0x0A 配置射頻信道爲10,即2410MHZ,這個地方要注意,當使用2MBPS的空速時,相鄰信道間最小要間隔2MHZ的頻率,對於1MBPS和256kbps來說,信道間隔爲1MHZ即可

RX_ADDR_P0 → 任意五字節地址,配置接收地址0

TX_ADDR → 任意五字節地址,最好和RX_ADDR_P0一樣

TX配置:

將CONFIG的最低位設置爲0,其他與RX一樣。

需要注意的地方是,在配置CONFIG的時候,CE必須爲低,因爲模塊不允許在工作模式下配置收發模式。

對於TX_ADDR和RX_ADDR的理解是這樣的,RX_ADDR爲要接收誰發送的消息,每個模塊在發送的時候把自己的TX_ADDR寫進去,這樣所有的模塊都去監測空中消息,當空中消息的ADDR與自己的某個使能的RX_ADDR匹配時就會進行接收。

參數配置

完整的配置時序如下:

發送處理

數據發送的時序,目前由於配置的是固定接收長度,因此需要寫入正好10字節才能進行正常傳輸,,又由於我們沒有屏蔽任何中斷,因此當發送成功後會觸發一次中斷,一般在發送之前先調用FLUSH_TX(0xE1)命令清除一下FIFO,避免堆積導致的阻塞。

中斷中需要讀取STATUS寄存器,並將其寫回,寫回的動作將會清除中斷

接收處理

接收端在接收到數據後會觸發一箇中斷,同樣的讀取STATUS寄存器確定是否是接收中斷,並在此之後清除STATUS。然後通過命令R_RX_PL_WID(0x60)指令讀取當前接收到的數據包的長度,當然當長度約定爲固定值時,該行爲可以忽略。

之後按照長度將數據讀取出來即可,一般在讀取結束之後使用FLUSH_RX(0XE2)清除一下FIFO,避免堆積可能導致的阻塞

添加CRC

crc是硬件行爲,當偵測到crc錯誤的時候,按照基本傳輸配置的話,接收端將不會產生數據接收中斷。配置方式就是將CONFIG寄存器當中對應的位置上就可以了,其他配置與基本傳輸相同。

RX配置:

CONFIG(0x00) → 0x0F 配置使能,配置爲接收模式,啓用CRC16

TX配置:

CONFIG(0x00) → 0x0E 配置使能,配置爲發送模式,啓用CRC16

使用動態長度

如果都是用靜態長度的話,其實傳輸不夠靈活,所以NRF24L01提供了動態負載長度的功能,使用動態負載長度之後,只管對TX FIFO寫入數據,只要別超過32字節就可以,因爲FIFO深度就是32。寫入結束後,直接拉起CE啓動傳輸,數據就會被打包傳輸。此時在接收端只需要檢查接收長度,並按照接收長度讀取出數據即可。上面做普通傳輸的地方已經寫了怎麼在中奪冠中獲取接收到的長度。使用動態負載長度後,對於RX_PW_Px寄存器就可以不去設置了。此時需要在TX和RX中多配置兩個寄存器,分別如下:

TX&RX

DYNPD(0x1C) → 0x01 使能通道1的動態負載長度

FEATURE(0x1D) → 0x04 使能動態負載長度特性

使用ARQ(Enhanced ShockBurst™)

這個特性不知道爲什麼被很多人吐槽爲影響穩定性,實際測試正確的使用ARQ還是對丟包問題有一定改善的。

這個特性原理很簡單,就是NRF24L01內置了引擎,當發送完一個數據包後自動轉入接收模式等待ACK,接收端接收到數據包之後,自動切換到發送模式發送一個ACK,之後切換回接收模式。發送端接收到ACK後切換回發送模式。一旦發送端沒有接收到ACK,在延遲設定的時間後會發起一次重發,直到成功收到ACK或者到達最大重發次數。下面這個圖就是一個傳輸過程的示意圖:

裏面關於中斷的說明,當接收機第一次接收到數據包之後會觸發一次RX中斷,由於ACK丟失,主機不會產生TX完成中斷而是會進行重發,接收機收到重發的包之後,因爲之前已經接收過該數據包,則數據包被丟棄,但是會自動ACK,主機收到正常的ACK之後纔會產生TX完成中斷。

使用ARQ比較簡單,只需要使能該特性,並配置最大重傳次數和重傳延遲時間就可以了,需要注意的是使用ARQ時必須使能CRC且需要設置RX_ADDR_P0與TX_ADDR相同,必須設置地址相同的原因是,接收機回ACK的時候會將數據包的地址寫進去,這個地址就是之前發送方發送時填進去的TX_ADDR,如果發送方想收到這個ACK就必須配置成可以接收這個地址的配置,也就是RX_ADDR_P0需要與TX_ADDR相同。相對於基本傳輸,修改EN_AA的配置並多配置一個寄存器即可

RX & TX

EN_AA(0x01) → 0x01 配置通道0使用自動ACK

SETUP_RETR(0x04) → 0x35 配置最大重傳5次,重傳延遲1ms,需要注意這個地方,手冊有說明不同空速下有一個最短的重傳時間配置

多發單收

由上面介紹地址匹配時說到,單個NRF24L01接收地址可以配置6個,也就是說一個NRF24L01可以接收來自於6個模塊的消息,只要沒有發生碰撞即可。使用多地址也很簡單,使能對應的通道,並配置接收地址即可,需要注意的是,手冊有對地址設置限制的介紹:

當接收到數據後,在中斷中對STATUS寄存器進行判斷即可獲取是哪個通道發送過來的數據。

帶載ACK

使用ARQ時會自動傳輸一個ACK,既然已經有ACK了,那沒有理由阻攔我們在ACK中帶點東西回去,NRF24L01同樣提供了帶載ACK的選項。

需要注意,使用帶載ACK的話必須使能動態負載長度,其主要需要修改的寄存器爲FEATURE

TX & RX

FEATURE(0x1D) → 0x06 使能動態負載長度特性並使能帶載ACK

使用時,接收機需要先把想要在接收到數據之後填進ACK的數據寫入FIFO,寫入地址爲W_ACK_PAYLOAD(10101ppp b)其對應二進制碼中的ppp爲接收通道,也就是可以針對接收通道進行定製返回的信息,注意這個地方寫入的地址不是W_TX_PAYLOAD。

其FIFO深度爲32,共三頁,建議一般使用其中一頁即可。

負載寫入後,當接收機接收到對應通道的數據後,就會將負載加到ACK包中返回。

對於發送放來說,ACK包返回觸發的是TX完成中斷,但是對於帶載的數據包來說,同時還會觸發RX中斷,發送方按照正常的接收操作來進行就可以,數據還是通過R_RX_PAYLOAD進行讀取。

按照手冊的說法,數據應該在發送方發送之前寫入,實際測試在數據接收中斷中寫入數據到W_ACK_PAYLOAD是可以隨當次ACK返回的,但是會存在把模塊卡死的概率,並不推薦這樣使用,最好還是按照手冊說明,儘量不要這麼做。

半雙工方式工作

通過手動切換模式可以達成半雙工傳輸的模式。即模塊上電後默認配置爲接收模式,要發送是切換到發送模式,發送完成立刻切換回接收模式。在此過程中一定要注意狀態轉移圖,在模塊的不同狀態切換之間是需要時間的,主要要符合時序要求才能穩定工作。

總結

總的來說NRF24L01還是一款相對來說比較有可玩性的無線模塊,只是功率實在小了一點,在ISM頻段,被幹擾的概率過高,可以考慮上個PA什麼的,這樣可用性會提高很多。順帶該模塊的狀態轉移速度還算比較快,可以考慮基於此模塊做一下跳頻算法,這樣可以有效的提高抗干擾的能力,等有什麼時候有興趣了可以再寫一下使用NRF24L01設計一套慢跳頻的機制來提升其抗干擾能力的文章。

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