NRF24L01的学习浅析(通过软件模拟SPI)
- **NRF24L01的學(xué)習(xí)淺析**
NRF24L01簡介:
nRF24L01 是一款工作在 2.4~2.5GHz 世界通用 ISM 頻段的單片無線收發(fā)器芯片。無線收發(fā)器包括:頻率發(fā)生器、增強(qiáng)型 SchockBurstTM 模式控制器、功率放大器、晶體振蕩器、調(diào)制器、解調(diào)器。輸出功率、
頻道選擇和協(xié)議的設(shè)置可以通過 SPI 接口進(jìn)行設(shè)置。
極低的電流消耗:當(dāng)工作在發(fā)射模式下發(fā)射功率為-6dBm 時電流消耗為 9mA,接收模式時為 12.3mA。
掉電模式和待機(jī)模式下電流消耗更低。
引腳圖如下
因?yàn)樵撃K沒有對應(yīng)的電源指示燈,所以在這里提醒下大家一定注意接線,引腳1對應(yīng)的GND有方框框起來。
功能描述
工作模式:
nRF24L01 可以設(shè)置為以下幾種主要的模式,
工作模式:
nRF24L01 可以設(shè)置為以下幾種主要的模式如圖所示
(圖片來源nrf24l01中文參考手冊):
nRF24L01 在不同模式下的引腳功能:
NRF24L01使用步驟:
該模塊用來無線收發(fā)。而且用的是SPI協(xié)議,所以開發(fā)的對象就很明顯了。就像大家最常用的7PINOLED一樣,通過命令加寄存器地址的讀寫操作進(jìn)行控制收發(fā)的。這里SPI時許就不多介紹,需要的學(xué)習(xí)的可以參考正點(diǎn)原子的嗶站視頻。
具體寄存器的介紹可以參考NRF24L01的中文手冊。這里就不多做介紹(反正都有宏定義的對應(yīng))
先貼NRF24L01.h的代碼`
#ifndef _NRF24L01_H #define _NRF24L01_H#include "sys.h"// CSN A1 CE A0 MOSI A3 SCK A2 IRQ A5 MISO A4#define CSN_Pin GPIO_PIN_1 #define CSN_GPIO_Port GPIOA #define CE_Pin GPIO_PIN_0 #define CE_GPIO_Port GPIOA #define MOSI_Pin GPIO_PIN_3 #define MOSI_GPIO_Port GPIOA #define SCK_Pin GPIO_PIN_2 #define SCK_GPIO_Port GPIOA #define IRQ_Pin GPIO_PIN_5 #define IRQ_GPIO_Port GPIOA #define MISO_Pin GPIO_PIN_4 #define MISO_GPIO_Port GPIOA/****************************************************************************************************/ //NRF24L01寄存器操作命令 #define SPI_READ_REG 0x00 //讀配置寄存器,低5位為寄存器地址 #define SPI_WRITE_REG 0x20 //寫配置寄存器,低5位為寄存器地址 #define RD_RX_PLOAD 0x61 //讀RX有效數(shù)據(jù),1~32字節(jié) #define WR_TX_PLOAD 0xA0 //寫TX有效數(shù)據(jù),1~32字節(jié) #define FLUSH_TX 0xE1 //清除TX FIFO寄存器.發(fā)射模式下用 #define FLUSH_RX 0xE2 //清除RX FIFO寄存器.接收模式下用 #define REUSE_TX_PL 0xE3 //重新使用上一包數(shù)據(jù),CE為高,數(shù)據(jù)包被不斷發(fā)送. #define NOP 0xFF //空操作,可以用來讀狀態(tài)寄存器 //SPI(NRF24L01)寄存器地址 #define CONFIG 0x00 //配置寄存器地址;bit0:1接收模式,0發(fā)射模式;bit1:電選擇;bit2:CRC模式;bit3:CRC使能;//bit4:中斷MAX_RT(達(dá)到最大重發(fā)次數(shù)中斷)使能;bit5:中斷TX_DS使能;bit6:中斷RX_DR使能 #define EN_AA 0x01 //使能自動應(yīng)答功能 bit0~5,對應(yīng)通道0~5 #define EN_RXADDR 0x02 //接收地址允許,bit0~5,對應(yīng)通道0~5 #define SETUP_AW 0x03 //設(shè)置地址寬度(所有數(shù)據(jù)通道):bit1,0:00,3字節(jié);01,4字節(jié);02,5字節(jié); #define SETUP_RETR 0x04 //建立自動重發(fā);bit3:0,自動重發(fā)計(jì)數(shù)器;bit7:4,自動重發(fā)延時 250*x+86us #define RF_CH 0x05 //RF通道,bit6:0,工作通道頻率; #define RF_SETUP 0x06 //RF寄存器;bit3:傳輸速率(0:1Mbps,1:2Mbps);bit2:1,發(fā)射功率;bit0:低噪聲放大器增益 #define STATUS 0x07 //狀態(tài)寄存器;bit0:TX FIFO滿標(biāo)志;bit3:1,接收數(shù)據(jù)通道號(最大:6);bit4,達(dá)到最多次重發(fā)//bit5:數(shù)據(jù)發(fā)送完成中斷;bit6:接收數(shù)據(jù)中斷; #define MAX_TX 0x10 //達(dá)到最大發(fā)送次數(shù)中斷 #define TX_OK 0x20 //TX發(fā)送完成中斷 #define RX_OK 0x40 //接收到數(shù)據(jù)中斷#define OBSERVE_TX 0x08 //發(fā)送檢測寄存器,bit7:4,數(shù)據(jù)包丟失計(jì)數(shù)器;bit3:0,重發(fā)計(jì)數(shù)器 #define CD 0x09 //載波檢測寄存器,bit0,載波檢測; #define RX_ADDR_P0 0x0A //數(shù)據(jù)通道0接收地址,最大長度5個字節(jié),低字節(jié)在前 #define RX_ADDR_P1 0x0B //數(shù)據(jù)通道1接收地址,最大長度5個字節(jié),低字節(jié)在前 #define RX_ADDR_P2 0x0C //數(shù)據(jù)通道2接收地址,最低字節(jié)可設(shè)置,高字節(jié),必須同RX_ADDR_P1[39:8]相等; #define RX_ADDR_P3 0x0D //數(shù)據(jù)通道3接收地址,最低字節(jié)可設(shè)置,高字節(jié),必須同RX_ADDR_P1[39:8]相等; #define RX_ADDR_P4 0x0E //數(shù)據(jù)通道4接收地址,最低字節(jié)可設(shè)置,高字節(jié),必須同RX_ADDR_P1[39:8]相等; #define RX_ADDR_P5 0x0F //數(shù)據(jù)通道5接收地址,最低字節(jié)可設(shè)置,高字節(jié),必須同RX_ADDR_P1[39:8]相等; #define TX_ADDR 0x10 //發(fā)送地址(低字節(jié)在前),ShockBurstTM模式下,RX_ADDR_P0與此地址相等 #define RX_PW_P0 0x11 //接收數(shù)據(jù)通道0有效數(shù)據(jù)寬度(1~32字節(jié)),設(shè)置為0則非法 #define RX_PW_P1 0x12 //接收數(shù)據(jù)通道1有效數(shù)據(jù)寬度(1~32字節(jié)),設(shè)置為0則非法 #define RX_PW_P2 0x13 //接收數(shù)據(jù)通道2有效數(shù)據(jù)寬度(1~32字節(jié)),設(shè)置為0則非法 #define RX_PW_P3 0x14 //接收數(shù)據(jù)通道3有效數(shù)據(jù)寬度(1~32字節(jié)),設(shè)置為0則非法 #define RX_PW_P4 0x15 //接收數(shù)據(jù)通道4有效數(shù)據(jù)寬度(1~32字節(jié)),設(shè)置為0則非法 #define RX_PW_P5 0x16 //接收數(shù)據(jù)通道5有效數(shù)據(jù)寬度(1~32字節(jié)),設(shè)置為0則非法 #define FIFO_STATUS 0x17 //FIFO狀態(tài)寄存器;bit0,RX FIFO寄存器空標(biāo)志;bit1,RX FIFO滿標(biāo)志;bit2,3,保留//bit4,TX FIFO空標(biāo)志;bit5,TX FIFO滿標(biāo)志;bit6,1,循環(huán)發(fā)送上一數(shù)據(jù)包.0,不循環(huán); /**********************************************************************************************************///NRF2401片選信號 #define CE_L HAL_GPIO_WritePin(CE_GPIO_Port,CE_Pin,GPIO_PIN_RESET) #define CE_H HAL_GPIO_WritePin(CE_GPIO_Port,CE_Pin,GPIO_PIN_SET)//SPI時鐘 #define SCK_L HAL_GPIO_WritePin(SCK_GPIO_Port,SCK_Pin,GPIO_PIN_RESET) #define SCK_H HAL_GPIO_WritePin(SCK_GPIO_Port,SCK_Pin,GPIO_PIN_SET)//SPI輸入 #define READ_MISO HAL_GPIO_ReadPin(MISO_GPIO_Port, MISO_Pin)//SPI片選信號 #define CSN_L HAL_GPIO_WritePin(CSN_GPIO_Port,CSN_Pin,GPIO_PIN_RESET) #define CSN_H HAL_GPIO_WritePin(CSN_GPIO_Port,CSN_Pin,GPIO_PIN_SET)//SPI輸出 #define MOSI_L HAL_GPIO_WritePin(MOSI_GPIO_Port,MOSI_Pin,GPIO_PIN_RESET) #define MOSI_H HAL_GPIO_WritePin(MOSI_GPIO_Port,MOSI_Pin,GPIO_PIN_SET)//IRQ中斷腳 #define IRQ_L HAL_GPIO_WritePin(IRQ_GPIO_Port,IRQ_Pin,GPIO_PIN_RESET) #define IRQ_H HAL_GPIO_WritePin(IRQ_GPIO_Port,IRQ_Pin,GPIO_PIN_SET)#define READ_IRQ HAL_GPIO_ReadPin(IRQ_GPIO_Port, IRQ_Pin)//NRF24L01發(fā)送接收數(shù)據(jù)寬度定義 #define TX_ADR_WIDTH 5 //5字節(jié)的地址寬度 #define RX_ADR_WIDTH 5 //5字節(jié)的地址寬度 #define TX_PLOAD_WIDTH 32 //20字節(jié)的用戶數(shù)據(jù)寬度 #define RX_PLOAD_WIDTH 32 //20字節(jié)的用戶數(shù)據(jù)寬度void Init_NRF24L01(void); //NRF24l01初始化 uint8_t SPI_ReadWriteByte(uint8_t TxData) ; //模擬SPI通訊函數(shù) void RX_Mode(void); //配置為接收模式 void TX_Mode(uint8_t addr); //配置為發(fā)送模式 uint8_t NRF24L01_Write_Buf(uint8_t regaddr, uint8_t *pBuf, uint8_t datalen); //寫數(shù)據(jù)區(qū) uint8_t NRF24L01_Read_Buf(uint8_t regaddr, uint8_t *pBuf, uint8_t datalen); //讀數(shù)據(jù)區(qū) uint8_t NRF24L01_Read_Reg(uint8_t regaddr); //讀寄存器 uint8_t NRF24L01_Write_Reg(uint8_t regaddr, uint8_t data); //寫寄存器 uint8_t NRF24L01_Check(void); //檢查NRF24L01是否在位 uint8_t NRF24L01_TxPacket(uint8_t *txbuf); //發(fā)送一個包的數(shù)據(jù) uint8_t NRF24L01_RxPacket(uint8_t *rxbuf); //接收一個包的數(shù)據(jù)#endif為了方便移植到51單片機(jī)等沒有硬件SPI的單片機(jī)(這里也是小編比較懶,不想去找各種引腳束縛自己的擴(kuò)展板布線)所以使用的GPIO時序模擬SPI的時序進(jìn)行通信
首先是相應(yīng)GPIO引腳的初始化
void Init_NRF24L01(void) {GPIO_InitTypeDef GPIO_InitStruct = {0};/* GPIO Ports Clock Enable */__HAL_RCC_GPIOH_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET);/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(GPIOA, CSN_Pin|CE_Pin|MOSI_Pin|SCK_Pin, GPIO_PIN_SET);/*Configure GPIO pin : PC0 */GPIO_InitStruct.Pin = GPIO_PIN_0;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);/*Configure GPIO pins : PAPin PAPin PAPin PAPin */GPIO_InitStruct.Pin = CSN_Pin|CE_Pin|MOSI_Pin|SCK_Pin;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/*Configure GPIO pins : PAPin PAPin */GPIO_InitStruct.Pin = IRQ_Pin|MISO_Pin;GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_PULLUP;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);IRQ_H; //IRQ置高CE_L; //使能NRF24L01CSN_H; //SPI片選取消SCK_L; //時鐘置低}這里是借助CubeMX工具生成的初始化文件復(fù)制過來的。
然后是模擬SPI時序進(jìn)行讀寫的底層代碼:
//模擬SPI讀寫數(shù)據(jù)函數(shù) uint8_t SPI_ReadWriteByte(uint8_t TxData) { uint16_t bit_ctr;for(bit_ctr=0;bit_ctr<8;bit_ctr++) {if(TxData & 0x80)MOSI_H; elseMOSI_L;TxData = (TxData << 1); SCK_H; // delay_us(10);TxData|=READ_MISO;SCK_L; }return(TxData); }寫好底層時序之后就需要通過SPI協(xié)議對24l01進(jìn)行讀寫操作了,這里直接貼所有代碼:(前面的代碼是為了方便理解24L01的初始化步驟,需要移植代碼的直接cv下邊的代碼就行,不過一定要看下去或者去看中文手冊,否則調(diào)試失敗率很高)
#include "NRF24L01.h" #include "delay.h" uint8_t TX_ADDRESS[TX_ADR_WIDTH]={0x34,0x43,0x10,0x10,0x01}; //發(fā)送地址 const uint8_t RX_ADDRESS[RX_ADR_WIDTH]={0x34,0x43,0x10,0x10,0x01}; //接收地址 //初始化NRF24L01IO口//CE->PA2,CSN->PA5,SCK->PA3,MOSI->PA6,MISO->PA4,IRQ->PA7 void Init_NRF24L01(void) {GPIO_InitTypeDef GPIO_InitStruct = {0};/* GPIO Ports Clock Enable */__HAL_RCC_GPIOH_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET);/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(GPIOA, CSN_Pin|CE_Pin|MOSI_Pin|SCK_Pin, GPIO_PIN_SET);/*Configure GPIO pin : PC0 */GPIO_InitStruct.Pin = GPIO_PIN_0;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);/*Configure GPIO pins : PAPin PAPin PAPin PAPin */GPIO_InitStruct.Pin = CSN_Pin|CE_Pin|MOSI_Pin|SCK_Pin;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/*Configure GPIO pins : PAPin PAPin */GPIO_InitStruct.Pin = IRQ_Pin|MISO_Pin;GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_PULLUP;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);IRQ_H; //IRQ置高CE_L; //使能NRF24L01CSN_H; //SPI片選取消SCK_L; //時鐘置低}//模擬SPI讀寫數(shù)據(jù)函數(shù) uint8_t SPI_ReadWriteByte(uint8_t TxData) { uint16_t bit_ctr;for(bit_ctr=0;bit_ctr<8;bit_ctr++) {if(TxData & 0x80)MOSI_H; elseMOSI_L;TxData = (TxData << 1); SCK_H; // delay_us(10);TxData|=READ_MISO;SCK_L; }return(TxData); }//上電檢測NRF24L01是否在位 //寫5個數(shù)據(jù)然后再讀回來進(jìn)行比較, //相同時返回值0,表示在位; //否則返回1,表示不在位. uint8_t NRF24L01_Check(void) {uint8_t buf[5]={0XA5,0XA5,0XA5,0XA5,0XA5};uint8_t buf1[5];uint8_t i; NRF24L01_Write_Buf(SPI_WRITE_REG+TX_ADDR,buf,5);//寫入5個字節(jié)的地址. NRF24L01_Read_Buf(TX_ADDR,buf1,5); //讀出寫入的地址 for(i=0;i<5;i++)if(buf1[i]!=0XA5) break; if(i!=5) return 1; //NRF24L01不在位return 0; //NRF24L01在位 } //通過SPI寫寄存器 uint8_t NRF24L01_Write_Reg(uint8_t reg_addr,uint8_t data) {uint8_t status; CSN_L; //使能SPI傳輸status =SPI_ReadWriteByte(reg_addr); //發(fā)送寄存器號 SPI_ReadWriteByte(data); //寫入寄存器的值CSN_H; //禁止SPI傳輸 return(status); //返回狀態(tài)值 } //讀取SPI寄存器值 ,regaddr:要讀的寄存器 uint8_t NRF24L01_Read_Reg(uint8_t reg_addr) {uint8_t reg_val; CSN_L; //使能SPI傳輸 SPI_ReadWriteByte(reg_addr); //發(fā)送寄存器號reg_val=SPI_ReadWriteByte(0);//讀取寄存器內(nèi)容CSN_H; //禁止SPI傳輸 return(reg_val); //返回狀態(tài)值 } //在指定位置讀出指定長度的數(shù)據(jù) //*pBuf:數(shù)據(jù)指針 //返回值,此次讀到的狀態(tài)寄存器值 uint8_t NRF24L01_Read_Buf(uint8_t reg_addr,uint8_t *pBuf,uint8_t data_len) {uint8_t status,i; CSN_L; //使能SPI傳輸status=SPI_ReadWriteByte(reg_addr); //發(fā)送寄存器值(位置),并讀取狀態(tài)值 for(i=0;i<data_len;i++)pBuf[i]=SPI_ReadWriteByte(0);//讀出數(shù)據(jù)CSN_H; //關(guān)閉SPI傳輸return status; //返回讀到的狀態(tài)值 } //在指定位置寫指定長度的數(shù)據(jù) //*pBuf:數(shù)據(jù)指針 //返回值,此次讀到的狀態(tài)寄存器值 uint8_t NRF24L01_Write_Buf(uint8_t reg_addr, uint8_t *pBuf, uint8_t data_len) {uint8_t status,i; CSN_L; //使能SPI傳輸status = SPI_ReadWriteByte(reg_addr); //發(fā)送寄存器值(位置),并讀取狀態(tài)值for(i=0; i<data_len; i++)SPI_ReadWriteByte(*pBuf++); //寫入數(shù)據(jù) CSN_H; //關(guān)閉SPI傳輸return status; //返回讀到的狀態(tài)值 } //啟動NRF24L01發(fā)送一次數(shù)據(jù) //txbuf:待發(fā)送數(shù)據(jù)首地址 //返回值:發(fā)送完成狀況 uint8_t NRF24L01_TxPacket(uint8_t *tx_buf) {uint8_t state; CE_L;NRF24L01_Write_Buf(WR_TX_PLOAD,tx_buf,TX_PLOAD_WIDTH);//寫數(shù)據(jù)到TX BUF 32個字節(jié)CE_H; //啟動發(fā)送 while(READ_IRQ != 0); //等待發(fā)送完成state=NRF24L01_Read_Reg(STATUS); //讀取狀態(tài)寄存器的值 NRF24L01_Write_Reg(SPI_WRITE_REG+STATUS,state); //清除TX_DS或MAX_RT中斷標(biāo)志if(state&MAX_TX) //達(dá)到最大重發(fā)次數(shù){NRF24L01_Write_Reg(FLUSH_TX,0xff); //清除TX FIFO寄存器 return MAX_TX; }if(state&TX_OK) //發(fā)送完成{return TX_OK;}return 0xff; //其他原因發(fā)送失敗 }//啟動NRF24L01發(fā)送一次數(shù)據(jù) //txbuf:待發(fā)送數(shù)據(jù)首地址 //返回值:0,接收完成;其他,錯誤代碼 uint8_t NRF24L01_RxPacket(uint8_t *rx_buf) {uint8_t state; state=NRF24L01_Read_Reg(STATUS); //讀取狀態(tài)寄存器的值 NRF24L01_Write_Reg(SPI_WRITE_REG+STATUS,state); //清除TX_DS或MAX_RT中斷標(biāo)志if(state&RX_OK) //接收到數(shù)據(jù){NRF24L01_Read_Buf(RD_RX_PLOAD,rx_buf,RX_PLOAD_WIDTH);//讀取數(shù)據(jù)NRF24L01_Write_Reg(FLUSH_RX,0xff); //清除RX FIFO寄存器 return 0; } return 1; //沒收到任何數(shù)據(jù) }//該函數(shù)初始化NRF24L01到RX模式 //設(shè)置RX地址,寫RX數(shù)據(jù)寬度,選擇RF頻道,波特率和LNA HCURR //當(dāng)CE變高后,即進(jìn)入RX模式,并可以接收數(shù)據(jù)了 void RX_Mode(void) {CE_L; //寫RX節(jié)點(diǎn)地址NRF24L01_Write_Buf(SPI_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH);//使能通道0的自動應(yīng)答 NRF24L01_Write_Reg(SPI_WRITE_REG+EN_AA,0x01); //使能通道0的接收地址 NRF24L01_Write_Reg(SPI_WRITE_REG+EN_RXADDR,0x01);//設(shè)置RF通信頻率 NRF24L01_Write_Reg(SPI_WRITE_REG+RF_CH,40); //選擇通道0的有效數(shù)據(jù)寬度 NRF24L01_Write_Reg(SPI_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);//設(shè)置TX發(fā)射參數(shù),0db增益,2Mbps,低噪聲增益開啟 NRF24L01_Write_Reg(SPI_WRITE_REG+RF_SETUP,0x0f);//配置基本工作模式的參數(shù);PWR_UP,EN_CRC,16BIT_CRC,PRIM_RX接收模式 NRF24L01_Write_Reg(SPI_WRITE_REG+CONFIG, 0x0f); //CE為高,進(jìn)入接收模式 CE_H; } //該函數(shù)初始化NRF24L01到TX模式 //設(shè)置TX地址,寫TX數(shù)據(jù)寬度,設(shè)置RX自動應(yīng)答的地址,填充TX發(fā)送數(shù)據(jù), //選擇RF頻道,波特率和LNA HCURR PWR_UP,CRC使能 //當(dāng)CE變高后,即進(jìn)入RX模式,并可以接收數(shù)據(jù)了 //CE為高大于10us,則啟動發(fā)送. void TX_Mode(uint8_t addr) { CE_L; TX_ADDRESS[4] = addr; //注意這里是修改地址最后一位 一對多通信的時候改變發(fā)送地址,達(dá)到用不同的地址發(fā)送給不同的從機(jī)通信//寫TX節(jié)點(diǎn)地址 NRF24L01_Write_Buf(SPI_WRITE_REG+TX_ADDR,(uint8_t*)TX_ADDRESS,TX_ADR_WIDTH); //設(shè)置TX節(jié)點(diǎn)地址,主要為了使能ACK NRF24L01_Write_Buf(SPI_WRITE_REG+RX_ADDR_P0,(uint8_t*)RX_ADDRESS,RX_ADR_WIDTH); //使能通道0的自動應(yīng)答 NRF24L01_Write_Reg(SPI_WRITE_REG+EN_AA,0x01); //使能通道0的接收地址 NRF24L01_Write_Reg(SPI_WRITE_REG+EN_RXADDR,0x01); //設(shè)置自動重發(fā)間隔時間:500us + 86us;最大自動重發(fā)次數(shù):10次NRF24L01_Write_Reg(SPI_WRITE_REG+SETUP_RETR,0x1a);//設(shè)置RF通道為40NRF24L01_Write_Reg(SPI_WRITE_REG+RF_CH,40); //設(shè)置TX發(fā)射參數(shù),0db增益,2Mbps,低噪聲增益開啟 NRF24L01_Write_Reg(SPI_WRITE_REG+RF_SETUP,0x0f); //配置基本工作模式的參數(shù);PWR_UP,EN_CRC,16BIT_CRC,PRIM_RX發(fā)送模式,開啟所有中斷NRF24L01_Write_Reg(SPI_WRITE_REG+CONFIG,0x0e); // CE為高,10us后啟動發(fā)送CE_H; }NRF24L01模塊使用步驟
1:我建議這里借助一個無線轉(zhuǎn)串口進(jìn)行調(diào)試:
插入24L01之后借助串口助手的AT指令進(jìn)行設(shè)置接受發(fā)送地址。(通信雙方的接受和發(fā)送地址一致)
2 就是一些基本參數(shù)設(shè)置了,這個可以參考中文手冊進(jìn)行更改,或者參考上方代碼盡量保持一致。
3 就是需要改的地方了,在上述代碼中信頻通道我選擇的是60,(一共有0-255)個通道。當(dāng)時為了解決與電腦通信和單片機(jī)相互通信之間干擾問題。這里如果需要借助上述模塊進(jìn)行調(diào)試的話,就將60改回0即可。
4:NRF24L01的發(fā)送接收地址默認(rèn)都是5個0XFF。這里借助AT指令改成代碼上的發(fā)送接收地址或者將代碼上的改回0XFF即可進(jìn)行通信。
主函數(shù)示例
int main(void) {u8 i,flag; u16 times=0; u8 NRF_buf[32];u8 RX_buf[32];u8 TX_buf[32];u8 rx_flag,len;HAL_Init(); //初始化HAL庫 Stm32_Clock_Init(96,4,2,4); //設(shè)置時鐘,96Mhzdelay_init(96); //初始化延時函數(shù)LED_Init(); //初始化LED uart_init(115200); //初始化串口115200KEY_Init();Init_NRF24L01();while(1){if(NRF24L01_Check()){printf("NRF24L01 is Not work!\r\n");HAL_Delay(500);}elsebreak;}printf("NRF24L01 is working!\r\n");RX_Mode(); //只收不發(fā)while(1){if(KEY_Scan(1)==KEY0_PRES){TX_Mode(0x01); //{0x34,0x43,0x10,0x10,0xaa}TX_buf[0]=5;TX_buf[1]=0x11;TX_buf[2]=0x01;TX_buf[3]=0x02;TX_buf[4]=0x03;TX_buf[5]=0x04; NRF24L01_TxPacket(TX_buf);RX_Mode(); }if(!NRF24L01_RxPacket(RX_buf)){len=RX_buf[0];for(i=0;i<=len;i++){NRF_buf[i]=RX_buf[i];}HAL_UART_Transmit(&UART1_Handler,NRF_buf,len+1,1000);}} }這里演示通過按鍵控制發(fā)送和將接受的數(shù)據(jù)回傳示例。
結(jié)果演示
好了這個模塊的分享到這就結(jié)束了。通過該模塊進(jìn)行無線透傳還是挺方便的,一對一,一對多都可以進(jìn)行,方法也比較多。歡迎大家相互探討。
代碼放在開源群了,**群號(709997214)**也歡迎大家加入相互學(xué)習(xí)?;蛘咄ㄟ^鏈接下載。https://download.csdn.net/download/m0_55977534/86026119
總結(jié)
以上是生活随笔為你收集整理的NRF24L01的学习浅析(通过软件模拟SPI)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python爬取豆瓣读书_爬取豆瓣读书.
- 下一篇: 简单网络管理协议SNMP通讯基础篇-熊健