前面已經總結過STM32Fxx的特點和傳輸過程,下面以nRF24L01+ 2.4GHz無線收發器為例,來說明如何使用SPI。
一、nRF24L01+ 2.4GHz無線收發器的介紹
1. 主要特性
- 全球2.4GHz ISM頻段操作
- 250Kbps, 1Mbps, 2Mbps三種空中傳輸速率
- 超低功耗
- 輸出功率為 0dBm時發射功耗為11.3mA
- 空中傳輸速率為2Mbps時接收功耗為13.5mA
- Power down模式功耗低至900nA, Standby-I模式功耗低至26uA
- 1.9~3.6V的電壓工作范圍
- 支持6個接收通道(地址)
- IO口能承受5V電壓
- ±60ppm 16MHz晶體振盪器
- 4×4mm QFN封裝
2. SPI操作時序
2.1 讀操作時序圖
圖1. nRF24L01+ 讀操作時序
①:發送指令+寄存器地址,都是從CSN(片選線,下同)的下降沿開始
②:主機(即STM32F4xx,下同)發送8位指令代碼(C7~C0,下同)
③:不管主機發送何指令,從機(即nRF24L01+,下同)第一字節都會返回狀態寄存器的值(寄存器0x07)
④:從機數據在每一個SCK的上升沿輸出,首先輸出的是第一字節(最低字節)的最高位,...,最后輸出的是最高字節的最低位
⑤:讀取操作都是以CSN的上升沿結束
2.2 寫操作時序
圖2. nRF24L01+ 寫操作時序
①:同讀操作
②:同讀操作
③:同讀操作
④:主機數據在每一個SCK的上升沿寫入從機,首先寫入的是第1個字節的最高位,...,最后寫入的是最后一個字節的最低位
⑤:同讀操作
2.3 狀態機
圖3. nRF24L01+ 狀態圖
- Power Down 模式
在該模式下,nRF24L01+的功耗最小,不能進行發送或者接收。但是所有寄存器的值保持不變,SPI處於有效狀態,允許對寄存器,TX/RX FIFO進行操作,PWR_UP(此位在CONFIG寄存器中)清0即進入該狀態。
- Standby-I 模式
將PWR_UP置1,即進入Standby-I模式,該模式既降低了nRF24L01+的平均功耗,同時又保持盡可能短的啟動時間,將CE置1然后后清0,就可以進入TX/RX模式,然后又返回到Standby-I模式。
- Standby-II 模式
當nRF24L01+設置為接收機(PTX),並且CE=1,TX FIFO為空時即進入該模式。相比Standby-I模式,這種模式相對耗電,一旦發送FIFO有新數據,就會立即將數據打包發送出去。
- TX 模式
進入該模式需要滿足以下條件:
- PWR_UP=1
- PRIM_RX=0
- TX FIFO不為空
- CE=1脈沖寬度超過10us
- RX 模式
進入該模式需要滿足以下條件
- PWR_UP=1
- PRIM_RX=1
- CE=1
二、程序實現
根據上面nRF24L01+的時序,結合前面介紹的STM32F4xx SPI的操作小結,SPI設置成全雙工收發模式,NSS(片選引腳)單獨用一個IO口來控制,對nRF24L01+讀寫操作程序如下:
1. SPI發送/接收子函數
1 /* SPI 發送*/ 2 void _SPIDataSet(SPI_TypeDef * SPIx, unsigned char *Buf, unsigned char Cnt) 3 { 4 for(; Cnt; Cnt--) 5 { 6 while((SPIx -> SR & SPI_SR_TXE) != SPI_SR_TXE); 7 SPIx -> DR = *Buf++; 8 } 9 while(SPIx -> SR & SPI_SR_BSY); 10 Cnt = SPIx -> DR; 11 } 12 13 /* SPI 接收*/ 14 void _SPIDataGet(SPI_TypeDef * SPIx, unsigned char *Buf, unsigned char Cnt) 15 { 16 for(; Cnt; Cnt--) 17 { 18 while((SPIx -> SR & SPI_SR_TXE) != SPI_SR_TXE); 19 SPIx -> DR = 0xFF; 20 while((SPIx -> SR & SPI_SR_RXNE) != SPI_SR_RXNE); 21 *Buf++ = SPIx -> DR; 22 } 23 24 }
L6:寫入數據前必須保證TX緩存器為空
L9:確保最后一位數據發送完畢
L10:使RXNE位清0(對DR進行讀操作,將使RXNE清0),若RXNE若置1,SPI不會接受新數據。
L19:由於SPI工作與全雙工模式,即發送1位數據才會接收1位數據,此語句本質是讓SPI輸出SCK,使nRF24L01+輸出數據
L20: 確保接收到完整的數據
2. 對nRF24L01+寄存器的讀/寫操作
1 /* 寫nRF24L01+ 寄存器 */ 2 void DataSet(unsigned char CMD, /* 寄存器地址 */ 3 unsigned char *Val, /* 發送數據指針 */ 4 unsigned char Cnt /* 數據數量 */) 5 { 6 nRF24L01_CSN = 0; 7 _SPIDataSet(SPI1, &CMD, 1); 8 _SPIDataSet(SPI1, Val, Cnt); 9 nRF24L01_CSN = 1; 10 } 11 12 13 /* 讀nRF24L01+ 寄存器 */ 14 void DataGet(unsigned char CMD, /* 寄存器地址 */ 15 unsigned char *Buf, /* 接收數據指針 */ 16 unsigned char Cnt /* 數據大小 */) 17 { 18 nRF24L01_CSN = 0; 19 _SPIDataSet(SPI1, &CMD, 1); 20 _SPIDataGet(SPI1, Buf, Cnt); 21 nRF24L01_CSN = 1; 22 }
L6, L18: CSN的下降沿開始讀/寫操作
L9, L21: CSN的上升沿結束讀/寫操作
下圖所示為通過邏輯分析儀抓取的設置nRF24L01+ pipe0接收地址(寄存器0xA)的波形:
圖4. 設置Pipe0(寄存器0xA)接收地址波形
下圖所示為通過邏輯分析儀抓取的讀取nRF24L01+ pipe0接收地址(寄存器0xA)的波形:
圖5. 讀取Pipe0(寄存器0xA)接收地址波形
More~
1. 假如使用 Auto Acknowledgment 功能,發送端(PTX)Pipe0接收地址必須和發送地址 相同,這是用於接收接收端(PRX)的相應
2. 接收數據數量(最大32字節)必須寫入RX_PW_Px寄存器(x為通道編號)
3. 調試失敗,排查以下幾點:
- 硬件連接是否正確
- 寄存器讀寫操作是否正確
- 確保Standby-I/II 模式變換到TX 模式時,CE高電平時間足夠(大於130us)
- 發送端(PTX)和接收端(PRX)數據的大小要一致,比如接收端(PRX)接收數據大小設置為8字節,那么主機就要給發送端(PTX)的TX FIFO傳輸8個字節
/×××××××××××××××××××××××××××××××××××××××× THE END××××××××××××××××××××××××××××××××××××××××××××/