STM32 + 无线通信模块 NRF24L01 数据收发
NRF24L01的模塊資料,網(wǎng)上已很詳盡了,在這不再重復(fù)描述知識點(diǎn)了。
這篇文章的目的,旨在把主要知識點(diǎn)膠接起來,梳理成一套完整的步驟,使器件快速上手匯入工作使用。
將按操作順序,拆分成7個(gè)步驟,注解重點(diǎn)、暗坑。以方便自己進(jìn)行知識管理,亦方便同行兄弟查閱。
代碼方面,盡量做到一行代碼一行解釋。(如有訂正和疑問,可留言交流,將迅速回復(fù)。)
目錄
一、思維導(dǎo)圖
二、 引腳連接,解釋
三、SPI初始化、函數(shù)封裝
四、NRF24L01參數(shù)寫入
五、中斷處理函數(shù)
六、發(fā)送數(shù)據(jù)
七、接收數(shù)據(jù)
八、代碼下載
一、思維導(dǎo)圖
3種主要工作模式、8個(gè)命令字、每包32字節(jié)有效數(shù)據(jù),等等這些,直接思維導(dǎo)圖更有效,不用文字啰嗦。
對主要點(diǎn)進(jìn)行了組織,包括了工作模式、命令字等圖例,認(rèn)真過一遍,心里馬上就能有個(gè)框框。
點(diǎn)擊一下圖片能變成清晰的大圖。當(dāng)然,右擊保存就更方便查看了。
二、 引腳連接,解釋
明確一個(gè),NRF24L01和SI24R1的引腳、程序是通用的,無需任何修改,市面上大部份的NRF24L01模塊,用的是SI24R1的芯片。兩者間通信也互通,已測試確認(rèn)!
下面是一個(gè)通用模塊的引腳,以安信可的SI24R1模塊為例:
共8個(gè)引腳:
三、SPI初始化、函數(shù)封裝
NRF的配置,就是把各種參數(shù)(數(shù)值),如頻道,速率,目標(biāo)地址等,用SPI方式寫到指定地址(芯片的寄存器).
?這個(gè)寫入配置的動(dòng)作,拆分開來看,理解為兩部分,是在操作兩種通信,別混亂。
首先主機(jī)按NRF datasheet的要求,設(shè)置和通過SPI通信,向NRF芯片特定地址(寄存器)寫入?yún)?shù)值;
而這些寫入的數(shù)值,就是用于控制NRF與別一個(gè)NRF的通信參數(shù)。
這兩個(gè)通信,理解一下~
1:主機(jī)和NRF間的通信:? ? ? ?
- 使用SPI,主機(jī)完成對NRF操控,所有操控其實(shí)就是4個(gè)操作:寫參數(shù)、讀參數(shù)、寫要發(fā)送的數(shù)據(jù),讀出收到的數(shù)據(jù);?
- 上面的操控,分拆到SPI的操作上,就是常用的6個(gè)函數(shù):SPI初始化、字節(jié)收發(fā)、寫1字節(jié),讀1字節(jié),寫N字節(jié),讀N字節(jié);
- 寫入?yún)?shù):是NRF與NRF間通信的參數(shù)值, 如頻道 ,速率,CRC校檢,自動(dòng)回答,自動(dòng)重發(fā),目標(biāo)地址....
- 讀取參數(shù),主要是STATUS狀態(tài)寄存器的值,用于判斷中斷源;
- 寫入發(fā)送數(shù)據(jù),把待發(fā)送的數(shù)據(jù)寫到TX_FIFO. NRF按包發(fā)送數(shù)據(jù),包中有效數(shù)據(jù)最大32字節(jié);要手動(dòng)做分包處理;
- 讀出收到數(shù)據(jù),檢測到RX_DR中斷發(fā)生后(IRQ引腳被拉低),用SPI把RX_FIFO緩沖區(qū)的值,讀取存放到指自已的緩沖區(qū);
- NRF的SPI通信速度可達(dá)10MHz,但為保證數(shù)據(jù)傳輸?shù)耐暾坏舭?#xff0c;盡量不要超過8MHz;
- NRF要求SPI通信時(shí),在上升沿采樣數(shù)據(jù),要注意時(shí)序。
2:NRF和NRF間的收發(fā)通信:
- NRF按主機(jī)剛才寫到芯片的參數(shù)值開始工作(手動(dòng)),通過電波傳輸?shù)搅硪粋€(gè)芯片中或接收別一芯片的數(shù)據(jù)(自動(dòng))。
- 這部份通信我們要做的,僅是控制CE引腳的高低電平,配合CONFIG寄存器,使NRF在接收、發(fā)送、待機(jī)三種狀態(tài)切換。
- NRF間的無線通信,基本沒我們什么事。
編程順序:? GPIO配置? >? SPI配置? >? SPI(5個(gè)小函數(shù))? >? 寫NRF配置? >? NRF中斷處理(3種情況)? >? NRF收、發(fā)(2個(gè)主函數(shù))
GPIO初始化代碼:
/*** SPI通信引腳, CS, SCK, MOSI, MISO ***/ GPIOSet (NRF24L01_SPI_CSN_GPIO, NRF24L01_SPI_CSN_PIN, G_MODE_OUT , G_OTYPE_PP, G_OSPEED_25M, G_PUPD_UP , 0); // cs GPIOSet (NRF24L01_SPI_CLK_GPIO , NRF24L01_SPI_CLK_PIN , G_MODE_AF , G_OTYPE_PP , G_OSPEED_25M , G_PUPD_DOWN , G_AF_SPI2 ); // sck GPIOSet (NRF24L01_SPI_MOSI_GPIO ,NRF24L01_SPI_MOSI_PIN , G_MODE_AF , G_OTYPE_PP , G_OSPEED_25M , G_PUPD_DOWN , G_AF_SPI2 ); // mosi GPIOSet (NRF24L01_SPI_MISO_GPIO ,NRF24L01_SPI_MISO_PIN , G_MODE_AF , G_OTYPE_PP , G_OSPEED_25M , G_PUPD_DOWN , G_AF_SPI2 ); // miso /*** NRF控制引腳, CE, IRQ ***/ GPIOSet (NRF24L01_CE_GPIO , NRF24L01_CE_PIN , G_MODE_OUT , G_OTYPE_PP , G_OSPEED_25M , G_PUPD_DOWN , 0); // CE GPIOSet (NRF24L01_IRQ_GPIO , NRF24L01_IRQ_PIN , G_MODE_IN , G_OTYPE_PP , G_OSPEED_25M , G_PUPD_UP , 0); // IRQ NRF24L01芯片的IRQ引腳下拉能力很弱,注意外部上拉電阻大小,及MCU的上下拉GPIOSet是個(gè)自己封裝的初始化函數(shù),不用管,重點(diǎn)看其中的參數(shù)就好,注意各上下拉。
SPI 初始化代碼:
/*** SPI通信部分 ***/ CSN_HIGH; //失能NRF NRF24L01_SPI_EN_CLOCK ; // 時(shí)鐘 NRF24L01_SPIX->CR1 = 0; // 清0 NRF24L01_SPIX->CR1 |= 0<<0; // 采樣沿?cái)?shù), NRF要求上升沿采樣 CPHA:時(shí)鐘相位,0x1=在第2個(gè)時(shí)鐘邊沿進(jìn)行數(shù)據(jù)采樣, NRF24L01_SPIX->CR1 |= 0<<1; // 時(shí)鐘線閑時(shí)極性, CPOL:時(shí)鐘極性,0x1=空閑狀態(tài)時(shí),SCK保持高電平 NRF24L01_SPIX->CR1 |= 1<<2; // 主從模式, 0=從,1=主 NRF24L01_SPIX->CR1 |= 2<<3; // 波特率控制[5:3], 0=fPCLK/2, 1=/4倍 2=/8 3/16 NRF24L01_SPIX->CR1 |= 0<<7; // LSB先行, 0=MSB, 1=LSB NRF24L01_SPIX->CR1 |= 1<<8; // 內(nèi)部從器件選擇,根據(jù)9位設(shè)置(失能內(nèi)部NSS) NRF24L01_SPIX->CR1 |= 1<<9; // 軟件從器件管理 : 0=禁止軟件管理從設(shè)備, 1=使能軟件從器件管理(軟件NSS) NRF24L01_SPIX->CR1 |= 0<<11; // 數(shù)據(jù)幀格式, 0=8位, 1=16位 NRF24L01_SPIX->CR1 |= 1<<6; // 使能SPI 初始化重點(diǎn):
- NRF要求在上升沿時(shí)采集數(shù)值。這就要閑時(shí)電平和采樣沿要配合好。
- NRF的SPI可達(dá)10MHz, 但實(shí)際使用時(shí),不要超過8MHz。這個(gè)在SPI的波特率中可控制,因?yàn)镾PI通信速率受限低速一方。
- 重要:如果多個(gè)設(shè)備共用同一SPI,把各自的SPI配置封裝成函數(shù),每次使用SPI通信前各自調(diào)用一次,以使用自己的配置。
插個(gè)話題,為什么使用寄存器操作編程?因?yàn)?#xff1a;使用寄存器=簡單+清晰,你看,不是嗎?
SPI收發(fā)函數(shù)
/***************************************************************************** *函 數(shù): u8 SPI_RW(u8 Data) *功 能: SPI寫入一個(gè)字節(jié),并返回一個(gè)字節(jié) *參 數(shù): 要寫入的一字節(jié) *返回值: 返回一字節(jié)數(shù)據(jù) *****************************************************************************/ u8 SPI_SendByte(u8 Data) {u8 retry =0;while((NRF24L01_SPIX ->SR & 2) == 0){ // 理解方式,應(yīng)該把前式的結(jié)果理解為一個(gè)寄存器位值,如果這個(gè)位值是等號后面的值,就等待retry++;if(retry>200) return 0;}NRF24L01_SPIX ->DR = Data;retry=0;while((NRF24L01_SPIX->SR & 1) == 0 ){retry++;if(retry>200) return 0;}return NRF24L01_SPIX->DR ; }/***************************************************************************** *函 數(shù):u8 Nrf24l01_WriteReg(u8 reg,u8 value) *功 能:向指定寄存器地址,寫一個(gè)字節(jié)數(shù)據(jù) *參 數(shù):reg: 寄存器地址 * val: 要寫入的值 *返回值:status *****************************************************************************/ u8 Nrf24l01_WriteReg(u8 reg,u8 value) {u8 status; CSN_LOW;status = SPI_SendByte(reg) ;SPI_SendByte(value);CSN_HIGH; return status; }/***************************************************************************** *函 數(shù):u8 NRF24l01_read_reg(u8 reg) *功 能:向指定寄存器地址,讀出一字節(jié)數(shù)據(jù) *參 數(shù):reg: 寄存器地址 *返回值:reg_val(第二個(gè)讀取到的字節(jié)) *****************************************************************************/ u8 Nrf24l01_ReadReg(u8 reg) {u8 reg_val; CSN_LOW;SPI_SendByte(reg);reg_val = SPI_SendByte(0xFF);CSN_HIGH; return reg_val; }/***************************************************************************** *函 數(shù):u8 Nrf24l01_WriteBuf(u8 reg, u8 *pBuf, u8 len) *功 能:寫一組數(shù)據(jù)到寄存器 *參 數(shù):reg: 寄存器地址 * pBuf: 要寫入數(shù)據(jù)的地址 * len: 要寫入的數(shù)據(jù)長度 *返回值:status *備 注:NRF2401代碼移植只需把SPI驅(qū)動(dòng)修改成自己的即可 *****************************************************************************/ u8 Nrf24l01_WriteBuf(u8 reg, u8 *pBuf, u8 len) {u8 status; CSN_LOW;status = SPI_SendByte(reg);for(u8 i=0; i<len; i++) {SPI_SendByte(pBuf[i]); }CSN_HIGH; return status; }/***************************************************************************** *函 數(shù): u8 vNrf24l01_ReadBuf(u8 reg, u8 *pBuf, u8 len) *功 能: 向指定寄存器地址,讀出指定長度的數(shù)據(jù) *參 數(shù): reg : 寄存器地址 * pBuf : 數(shù)據(jù)存放緩沖區(qū) * len : 讀取的字節(jié)數(shù)量 *返回值: status : 設(shè)備狀態(tài)字 *****************************************************************************/ u8 Nrf24l01_ReadBuf(u8 reg, u8 *pBuf, u8 len) {u8 status; CSN_LOW;status = SPI_SendByte(reg);for(u8 i = 0; i<len ;i++){pBuf[i] = SPI_SendByte(0xFF); }CSN_HIGH; return status; }注意:在進(jìn)入下一步配置NRF24L01前,必須先測試一下SPI通信是否成功 。一般是往NRF的發(fā)送地址寄存器寫入五個(gè)字節(jié),再讀出來,把讀出的數(shù)據(jù)和原數(shù)據(jù)對比,?就能知道SPI是否配置正確、 NRF24L01是否連接成功。
代碼程序中,有個(gè)連接測試函數(shù),可以作模塊的連接,沒有貼上來,留郵箱吧。
四、NRF24L01參數(shù)寫入
使用上面初始化的SPI,和剛封裝好的幾個(gè)函數(shù),就可以把需要的參數(shù),寫到NRF特定的地址(寄存器), 完成對其配置。
NRF24L01 參數(shù)配置代碼:
/*** NRF24L01通信配置 30,2M,***/ CE_LOW; // 熱待機(jī)模式, 只有在ce置低時(shí),才能配置寄存器 //delayUs(2000); // PowerDown 切換為 PowerUp需要1.5ms Nrf24l01_WriteReg(W_REGISTER + RF_CH, 30); // 射頻通道,即頻率(0-125) Nrf24l01_WriteReg(W_REGISTER + RF_SETUP, 0x0F); // 設(shè)置TX發(fā)射參數(shù),0db增益,2Mbps,低噪聲增益關(guān)閉 (注意:低噪聲增益關(guān)閉/開啟直接影響通信,要開啟都開啟,要關(guān)閉都關(guān)閉0x0f)0x07 Nrf24l01_WriteReg(W_REGISTER + SETUP_AW, 0x03); // 地址長度,默認(rèn)值時(shí)0x03,即5字節(jié) Nrf24l01_WriteBuf(W_REGISTER + TX_ADDR, (u8*)TX_ADDRESS, 5); // 寫TX節(jié)點(diǎn)地址, 地址寬度:5字節(jié),40位 Nrf24l01_WriteBuf(W_REGISTER + RX_ADDR_P0, (u8*)TX_ADDRESS, 5); // 設(shè)置TX節(jié)點(diǎn)地址,主要為了使能ACK,, 地址寬度:5字節(jié),40位 Nrf24l01_WriteReg(W_REGISTER + SETUP_RETR, 0x0A); // 設(shè)置自動(dòng)重發(fā)間隔時(shí)間:500us + 86us;最大自動(dòng)重發(fā)次數(shù):10次 0x1A Nrf24l01_WriteReg(W_REGISTER + EN_RXADDR, 0x01); // 使能通道0的接收地址 Nrf24l01_WriteReg(W_REGISTER + EN_AA, 0x01); // 使能通道0自動(dòng)應(yīng)答 Nrf24l01_WriteReg(W_REGISTER + RX_PW_P0, 32); // 選擇通道0的有效數(shù)據(jù)寬度 Nrf24l01_WriteReg(FLUSH_TX, 0xff); // 清除TX_FIFO Nrf24l01_WriteReg(W_REGISTER+STATUS, 0X7E); // 清除所有中斷,防止一進(jìn)去接收模式就觸發(fā)中斷 Nrf24l01_WriteReg(W_REGISTER+CONFIG, 0x0F); // 配置為接收模式 CE_HIGH; // CE置高,進(jìn)入狀態(tài)重點(diǎn):
- CE引腳置低,方可配置NRF寄存器!? 各教程都這教的,但測試過不置低也可正常配置。
- RF_CH,:頻道,2.4G為基址,1M為間隔值,如上面的30,代表使用2.430G的頻率進(jìn)行芯片間通信??稍O(shè)值0~125。
- RF_SETUP: 發(fā)射功率可配置,說白了就是的耗電程度。接收狀態(tài)的功率是不能設(shè)置的,所以接收才是耗電的大頭。數(shù)據(jù)傳輸率,常說的空中速率,一般設(shè)置2M
- 地址長度,5字節(jié),這個(gè)很獨(dú)特
- TX_ADDR:數(shù)據(jù)要發(fā)送到的目標(biāo)地址
- RX_ADDR_P0: 接收通道0的接收地址,接收這個(gè)地址設(shè)備發(fā)來的數(shù)據(jù),這里設(shè)為和TX_ADDR一致,是為了自動(dòng)應(yīng)答。
- NRF共有6個(gè)接收通道,p0~p5, 可同時(shí)監(jiān)聽6個(gè)不同地址的信號,p0通道也用于作自動(dòng)應(yīng)答作用。
- TX_FIFO, 發(fā)送數(shù)據(jù)緩沖區(qū),96字節(jié),32字節(jié)為一組,共3組,可理解為緩沖區(qū)可存放3組發(fā)送數(shù)據(jù)。
- RX_FIFO, 同上,兩個(gè)FIFO相互獨(dú)立。 雖然是FIFO,雖然有3組,但最好還是一包一包收發(fā),狀態(tài)切換時(shí)間難把握。
- 倒數(shù)第二行,配置為接收模式,注意,這個(gè)時(shí)候還沒開始工作的,還處于PownDown狀態(tài),狀態(tài)和模式是兩回事。
- 最后一行,CE置高10us后,才進(jìn)入工作狀態(tài),因之前配置的是接收模式,所以將進(jìn)入接收狀態(tài)
五、中斷處理函數(shù)
為什么要先說中斷?感覺先了解了中斷,那么發(fā)送、接收就更好理解。
其實(shí)不應(yīng)該叫中斷的,但這樣好理解,還是遵從約定俗成吧。
中斷時(shí), IRQ電平被拉低,是由NRF控制產(chǎn)生的,三種情況可觸發(fā):發(fā)送成功、達(dá)到重發(fā)最大次數(shù)、接收到數(shù)據(jù)。
發(fā)送成功:
- 1:PTX發(fā)送數(shù)據(jù)后,馬上開始計(jì)時(shí),130us后切換到接收模式,此時(shí)計(jì)時(shí)還在繼續(xù)
- 2:PRX在收到數(shù)據(jù)后,經(jīng)CRC校檢,數(shù)據(jù)完整后發(fā)回ACK信號
- 3:PTX在規(guī)定時(shí)間內(nèi)收到ACK信號,則置位TX_DS標(biāo)志,IRQ引腳被拉低
達(dá)到重發(fā)最大次數(shù):
- 1:PTX發(fā)送數(shù)據(jù)后,馬上開始計(jì)時(shí),130us后切換到接收模式,此時(shí)計(jì)時(shí)還在繼續(xù)
- 2:PTX在規(guī)定時(shí)間內(nèi),沒收到ACK信號,原因很多:如PRX沒收到數(shù)據(jù),CRC校驗(yàn)錯(cuò)誤....
- 3:PTX再次發(fā)送一次數(shù)據(jù),重復(fù)步驟1
- 4:SETUP_RETR寄存器可設(shè)置重發(fā)的次數(shù),達(dá)到最大次數(shù)后,MAX_RT位被置位,IRQ引腳被拉低。
接收到數(shù)據(jù):
- PRX收到數(shù)據(jù),經(jīng)CRC校檢,數(shù)據(jù)完整,有效數(shù)據(jù)存放到RX_FIFO,RX_DR位置高,IRQ引腳被拉低。
說說清理中斷,要清理的中斷有兩處:
- NRF的中斷位,上面的三種標(biāo)志中斷位,都在寄存器STATUS中,各位置1可清0,IRQ引腳即回到高電平。
- 單片機(jī)mcu的中斷位,清理外部中斷線標(biāo)志位,否則會(huì)在中斷函數(shù)里死循環(huán)。
中斷處理函數(shù)代碼:
void NRF24L01_IRQ_IRQHANDLER(void) { u8 status=0 ;CE_LOW; // 拉低CE,以便讀取NRF中STATUS中的數(shù)據(jù) status = Nrf24l01_ReadReg(R_REGISTER + STATUS); // 讀取STATUS中的數(shù)據(jù),以便判斷是由什么中斷源觸發(fā)的IRQ中斷/*** 發(fā)送完成中斷 ***/if(status & STATUS_TX){ Nrf24l01_WriteReg(W_REGISTER+STATUS, STATUS_TX); // 清NRF中斷:發(fā)送完成Nrf24l01_WriteReg(FLUSH_TX, 0xff); // 清發(fā)送緩沖區(qū):TX_FIFOprintf("\r\n發(fā)送成功!!!!\r\n");vNrf24l01_RxMode (); // 切換為接收狀態(tài)}/*** 接收完成中斷 ***/if(status & STATUS_RX){ memset (NRF_RX_DATA , 0, 32); Nrf24l01_ReadBuf(R_RX_PAYLOAD, NRF_RX_DATA , RX_PAYLO_WIDTH); // 讀數(shù)據(jù)Nrf24l01_WriteReg(W_REGISTER+STATUS, STATUS_RX); // 清NRF中斷:收到數(shù)據(jù)Nrf24l01_WriteReg(FLUSH_RX,0xff); // 清除RX FIFO(注意:這句話很必要) printf("\r\n接收到數(shù)據(jù): %s\r\n", NRF_RX_DATA); vNrf24l01_RxMode (); // 切換為接收狀態(tài)}/*** 最大重發(fā)次數(shù)中斷 ***/if(status & STATUS_MAX){ Nrf24l01_WriteReg(W_REGISTER+STATUS, 0x70); // 清NRF中斷:三個(gè)Nrf24l01_WriteReg(FLUSH_TX, 0xff); // 清除TX_FIFO printf("\r\n發(fā)送失敗,達(dá)到最大重發(fā)次數(shù)!!!\r\n"); vNrf24l01_RxMode(); // 切換為接收狀態(tài)}EXTI->PR |= NRF24L01_IRQ_PIN ; // 清理外部中斷線標(biāo)志位 }六、發(fā)送數(shù)據(jù)
NRF的數(shù)據(jù)收發(fā),是一包一包進(jìn)行的,一包(幀)數(shù)據(jù):包括了前導(dǎo)碼、目標(biāo)地址、包控制域、有效數(shù)據(jù)、CRC, 但我們只管有效數(shù)據(jù),其它的不用我們負(fù)責(zé),NRF發(fā)送時(shí)自動(dòng)打包,接收到數(shù)據(jù)時(shí)自動(dòng)拆包。
每一包的有效數(shù)據(jù)最大為32個(gè)字節(jié)。當(dāng)然,也可以只發(fā)一個(gè)字節(jié)的數(shù)據(jù)。
要發(fā)送的數(shù)據(jù)大于32字節(jié),就要分包進(jìn)行,自行手動(dòng)分包處理。
因?yàn)樵谂渲貌糠謺r(shí),已配置好了頻道,速率,重發(fā)次數(shù)等各種參數(shù),在需要發(fā)送數(shù)據(jù)時(shí),只要往芯片寫入要發(fā)送的數(shù)據(jù)和地址,然后切換為發(fā)送狀態(tài),芯片就會(huì)自動(dòng)發(fā)送。
發(fā)送成功(收到ack),會(huì)產(chǎn)生TX_DS中斷。
發(fā)送失敗了(達(dá)到最大重發(fā)次數(shù)), 也會(huì)產(chǎn)生MAR_RT中斷。
在中斷函數(shù)里,根據(jù)情況作處理就好。
發(fā)送數(shù)據(jù)代碼:
void vNrf24l01_TxPacket(u8 *txbuf) {CE_LOW; Nrf24l01_WriteBuf(W_TX_PAYLOAD, txbuf, 32); // 寫數(shù)據(jù)到TX_BUFF Nrf24l01_WriteBuf(W_REGISTER+TX_ADDR, (u8*)TX_ADDRESS, 5); // 寫入要發(fā)送的目標(biāo)地址 Nrf24l01_WriteBuf(W_REGISTER+RX_ADDR_P0, (u8*)TX_ADDRESS, 5); // 通道0的地址設(shè)為和目標(biāo)地址一致,以接收自動(dòng)回復(fù)auto_ack信號 Nrf24l01_WriteReg(W_REGISTER+CONFIG, 0x0E); // 設(shè)置為發(fā)送模式,開啟所有中斷 CE_HIGH; }發(fā)送就這幾句!
重點(diǎn):RX_ADDR_P0的地址和TX_ARRD一樣,目的是自動(dòng)應(yīng)答。有個(gè)前提,在配置中已使能自動(dòng)應(yīng)答。
把操作封裝成一個(gè)函數(shù),要發(fā)什么,就往函數(shù)里掉數(shù)據(jù)就好,每次不要大于32字節(jié)。
七、接收數(shù)據(jù)
當(dāng)系統(tǒng)或程序運(yùn)行時(shí),大部分時(shí)間是運(yùn)行在接收狀態(tài)下的。如:
- 第四個(gè)部分配置步驟完成后,程序已處在接收狀態(tài)。
- 第五個(gè)部分,在中斷處理函數(shù)中,三種中斷處理后,也切換為接收狀態(tài),當(dāng)然,也可以切換為更省電的待機(jī)狀態(tài)。
NRF有6個(gè)接收通道,指在可同時(shí)監(jiān)聽接收同一個(gè)頻道,同一速率的6個(gè)不同設(shè)備的數(shù)據(jù)。
常用的只是通道P0, 如果只使能了通道P0,那就只能接收到P0中地址設(shè)備發(fā)來的數(shù)據(jù)。
可以使能全部6個(gè)通道,設(shè)置6個(gè)不同設(shè)備地址,就可以監(jiān)聽接收6個(gè)設(shè)備發(fā)來的數(shù)據(jù)(同一時(shí)間,只能接收其中1個(gè)設(shè)備的數(shù)據(jù));
注意,接收數(shù)據(jù),指在接收中斷發(fā)生后,我們從RX_FIFO中把數(shù)據(jù)讀存到主機(jī)。而中斷發(fā)生前的監(jiān)聽接收,NRF自動(dòng)完成。
接收數(shù)據(jù)的代碼:
接收本來就是最簡單的,沒啥特別代碼,下面的代碼,只是在中斷處理函數(shù)里,再貼出來而已。
Nrf24l01_ReadBuf(R_RX_PAYLOAD, NRF_RX_DATA , RX_PAYLO_WIDTH); // 讀數(shù)據(jù)到數(shù)組 Nrf24l01_WriteReg(W_REGISTER+STATUS, STATUS_RX); // 清NRF中斷:收到數(shù)據(jù) Nrf24l01_WriteReg(FLUSH_RX,0xff); // 清除RX FIFO(注意:這句話很必要)把接收到的數(shù)據(jù),先存放NRF_RX_DATA數(shù)組,再進(jìn)行處理,不要在中斷函數(shù)中處理。
讀完后,記得要清理RX_FIFO,不然它一直占用NRF的緩沖區(qū)。RX_FIFO共96字節(jié),分成32字節(jié)3組,NRF每次接收到數(shù)據(jù)就存放到最后面的一組中,當(dāng)存滿了3組,后面再接收到的數(shù)據(jù),就會(huì)被NRF掉棄。
八、代碼下載
兩種方式,
1:代碼已打包并上傳成CSDN下載資源:
無線通信_NRF24L01.zip_nrf24l01發(fā)送前導(dǎo)碼-嵌入式文檔類資源-CSDN下載
2:由于咨詢代碼的人多,已把代碼打包上傳到Q群,群文件夾里找吧:262901124.
最后,如果你有更完善的代碼,或修改后的代碼,請回贈(zèng)我一份,謝謝~~~
寫了三四個(gè)小時(shí),累~~~
總結(jié)
以上是生活随笔為你收集整理的STM32 + 无线通信模块 NRF24L01 数据收发的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 橡皮擦是黑色的
- 下一篇: 无线通信模块定点传输-点对多点的具体传输