第七一〇步 「 不就是調個2.4Ghz無線通信么,誒,怎麼不通" 解決之道

第七一〇步 「 不就是調個2.4Ghz無線通信么,誒,怎麼不通" 解決之道

來自專欄格無物致知4 人贊了文章

本文主要內容

本文專註於解決2.4G無線通信模塊 nRF24L01P 調試中遇到的兩個問題:

1.發送節點發送失敗,狀態寄存器(status)返回0x1E

2.僅能完成第一次發送接收,後續的發送接收操作失敗

通過分享自己的問題和解決方案,希望能幫助到,在調試過程中遇到此類問題,此時很頭疼的朋友。

後續會帶來整個2.4G調試過程中的心得體會。


問題1 發送節點發送失敗,狀態寄存器(status)返回0x1E

首先 specification 中狀態寄存器的定義如下:

正常發送的情況下,在完成發送後,狀態寄存器中的值應該為 0x20 。TX_DS 位置起。而後通過直接寫入當前寄存器中的值(成功發送的情況下即為 0x20),清除該位,準備下一次發送。

那麼問題來了,如果發送之後寄存器的值為 0x1E 。首先代表什麼?從上圖中可以看出,MAX_RT 以及 RX_P_NO 均被置起,分別表示重發次數到達上限以及接收緩衝區空。

我猜你可能現在跟我當時一樣一頭霧水,我不是在發送么,和接收緩衝區有什麼關係?重發到達上限,在什麼情況下會重發?

這一切都和 L01 的 ACK確認機制以及相應的重發機制有關。 L01 在默認情況下實現了數據鏈路層功能,通過 CRC校驗, ACK 以及重發機制確保數據幀能夠完整準確地到達接收端。在成功接收後,接收端會向發送端發送 ACK 消息,發送端以接收到 ACK 作為一幀消息的完成標誌,如果一段時間後仍未接收到確認消息,發送端會重發此幀。另外這些數據鏈路層功能均可關閉。

簡單說,說人話,0x1E代表著壓根沒完成發送。問題1可以泛化為發送失敗。

發送端或者接收端均可能導致這個問題。

問題定位

當然首先你得有個接收端。

想當年,我調試完發送端後太激動了,就想著直接發送看看能不能發送成功,能不能讀取到 0x20。結果可想而知....

排除SPI匯流排上可能存在的問題

在調試模塊之前,可以通過寄存器存儲讀取測試,檢查 SPI 通信是否正常。可以參照下面的教程

新手如何快速搞通NRF24L01通信_單片機學習網?

www.rationmcu.com圖標

注意 我在使用 STM32 HAL 庫的SPI函數時發現上電後的第一次 SPI 讀寫操作一定會失敗,目前還不清楚原因。同樣使用 STM32 HAL 庫,如果遇到相同的問題,可以暫時通過上電後進行一次空讀寫操作避免這個問題

確保發送接收端處於相應工作模式

在發送模式和接收模式的轉換過程中,需要將模塊用於控制發送接收的引腳 CE(與 SPI 匯流排中的片選信號 CS 區分)拉低,完成修改寄存器中工作模式的操作後,再拉高 CE 引腳完成轉換。

示常式序中的默認寄存器操作一般沒有什麼問題,包括設置速度,頻率,接收通道等。在一對一通信中一般不需要修改。

關於地址的問題會在後文中展開,在調試一對一通信中,三個地址只要保持一致即可。(發送端發送地址,發送端 ACK 接收地址,接收端接收地址)

*設置正確的接收與發送長度

在設置發送接收數據長度時需要注意,要將發送接收數據長度設為一致。我在調試中犯下的錯誤就是將接收長度設為32,但發送長度被設為1,在這種發送接收長度懸殊的情況下。永遠無法完成接收。(小几率可能會接收到一次)發送端一直不能接收到 ACK 消息,狀態寄存器中的值一直為 0x1E.

其他一些問題

如果你使用的是帶有功率放大器的模塊,需要大得多的能量,那麼使用電源適配器從牆上電源取電要比從電腦 USB 取電要穩定。

核對模塊的引腳與單片機的連接是否正確,主要是CE、CS、IRQ三個非 SPI 引腳的連接。

問題2 僅能完成第一次發送接收,後續的發送接收操作失敗

一般來說問題2出現於解決了問題1後,如果你使用常式中 while 循環檢測 IRQ 引腳電平,等待低電平,阻塞方式接收的話,一般不會出現問題2的困擾。

問題2一般出現在使用中斷方式接收時,沒有複位狀態寄存器,即通過上圖中 write 1 to clear it 的方式,複位本次發送接收中產生的寄存器位,導致下一次發送接收無法開始。產生了「僅能完成第一次發送接收,後續的發送接收操作失敗」的現象。

我們直接來看我當時有問題以及之後修正的代碼,其中我標記的清除寄存器的語句,在一開始沒有被添加,導致了問題2的出現。

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){ if(GPIO_Pin == GPIO_PIN_2) { LED1_TOGGLE(); uint8_t status; status = NRF24_Read_Reg(STATUS); NRF24_Write_Reg(NRF_WRITE_REG + STATUS,status);//就是這句,這樣做就可以 //清除本次發送接收中的寄存器 if(status & 0x40) { printf("2.4g:rec
"
); NRF24_Read_Packet(nrf_Rec_Mess.message_Buffer); flag_nrf_Rec_mess = TRUE; } else if(status & TX_OK) { //send printf("2.4g:send_ok
"
); } else if(status & MAX_TX) { //wrong printf("2.4g:max_rt
"
); } else { printf("2.4g:None
"
); } }}

我解釋下這段程序,首先這是 STM32 HAL 庫中的外部中斷服務程序,當外部引腳出現電平變化後,進入這段程序,如果發生事件的是 GPIO2,我的 IRQ 引腳連接在 PD2,則視為有2.4Ghz 通信的事件發生。

總共有三種中斷:TX_DS 發送成功,RX_DR 接收消息,以及 MAX_RT 一般來說表示發送失敗。後續程序判斷當前的中斷類型,並執行相應操作。

我們如果只需要某種中斷類型,比如接收中斷,實際上還有另外一種方法,即在寄存器組中屏蔽不需要的中斷,見下圖 Config 寄存器的 6-4 位。

以上的問題解決了,2.4Ghz 通信中最簡單的一關,一對一通信,我們應該就沒有問題了,後續我自己也會做一下一對多,多對多的通信實驗,再把經歷和大家分享。

可是一對一真的就沒有問題了么??

問題x 正常通信,但一旦下載過新的程序就無法通信,重新上電,恢復正常通信。

我實在搞不懂這是怎麼回事,我使用的是 STM32F407VE ,STM32 HAL庫,Keil 5 以及Jlink,遇到類似問題的同學請務必聯繫我,我們一起琢磨下。

推薦閱讀:

關於免費SSL證書的那些事兒
Airbnb今日宣布重大轉型,要和攜程、窮游競爭了
移動時代的搜索新商業
【科技】中國現階段的科技實力達到什麼水平了?
科技圈的壟斷優勢從來都只是童話,圖解摩爾定律的過去與未來

TAG:科技 | 無線通信 | 單片機 |