nRF24L01 采用 QFN20 封裝,有 20 個引腳,以下是各引腳的詳細介紹:
1. 電源引腳
? VDD:電源輸入端,一般接 + 3V 電源,為芯片提供工作電壓,供電電壓范圍為 1.9V~3.6V。
? VSS:電源地引腳,接地,為芯片提供電氣參考電位。
? VDD_PA:為功率放大器供電,輸出為 1.8V,給射頻功率放大器提供所需的電源。
? DVDD:去耦電路電源正極端,用于連接去耦電容,為芯片內部電路提供穩定的電源。
2. SPI 接口引腳
? CSN:SPI 片選信號引腳,低電平有效。當 CSN 為低電平時,芯片被選中,微處理器可以通過 SPI 接口對 nRF24L01 進行配置和數據傳輸。
? SCK:SPI 時鐘引腳,用于同步 SPI 數據傳輸,由微處理器提供時鐘信號,決定數據傳輸的速率和時序。
? MOSI:主設備輸出從設備輸入引腳,微處理器通過該引腳將數據發送到 nRF24L01 芯片中,進行寄存器配置、發送數據等操作。
? MISO:主設備輸入從設備輸出引腳,nRF24L01 通過該引腳將數據返回給微處理器,如返回寄存器的值、接收的數據等。
3. 控制與狀態引腳
? CE:使能發射或接收引腳,數字輸入。在 CSN 為低的情況下,CE 協同 CONFIG 寄存器共同決定 nRF24L01 的狀態,用于選擇芯片的工作模式,如發射模式、接收模式、待機模式等。
? IRQ:中斷標志位引腳,數字輸出,低電平觸發。當狀態寄存器中 TX_DS(數據發送完成中斷位)、RX_DR(接收數據中斷位)或 MAX_RT(達到最多次重發中斷位)為高時觸發中斷,通知微處理器進行相應的處理。
4. 晶體振蕩器引腳
? XC2:晶體振蕩器 2 腳,模擬輸出,用于連接外部晶體振蕩器的一端,與 XC1 共同構成晶體振蕩電路,為芯片提供時鐘信號。
? XC1:晶體振蕩器 1 腳 / 外部時鐘輸入腳,模擬輸入,可連接外部晶體振蕩器的另一端,也可以作為外部時鐘信號的輸入引腳。
5. 天線接口引腳
? ANT1:天線接口 1,用于連接天線,實現射頻信號的發射和接收。
? ANT2:天線接口 2,同樣用于連接天線,與 ANT1 共同作用,提高射頻信號的傳輸性能。
6. 參考電流輸入引腳
? IREF:參考電流輸入引腳,模擬輸入,用于輸入參考電流,為芯片內部的電路提供基準電流。
- ADC 配置:
/* ADC 及引腳 定義 */
#define ADC_ADCX_CHY_GPIO_PORT GPIOA
#define ADC_ADCX_CHY_GPIO_PIN GPIO_PIN_5
#define ADC_ADCX_CHY_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOC_CLK_ENABLE();\
}while(0) /* PA 口時鐘使能 */
#define ADC_ADCX ADC1
#define ADC_ADCX_CHY ADC_CHANNEL_5 /* 通道 Y, 0 <= Y <= 16 */
/* ADC1 時鐘使能 */
#define ADC_ADCX_CHY_CLK_ENABLE() do{ __HAL_RCC_ADC1_CLK_ENABLE();}while(0)
ADC_HandleTypeDef hadc;
void ADC_Init(void)
{
????????__HAL_RCC_ADC1_CLK_ENABLE();// 使能ADC時鐘
????// ?配置ADC結構體參數
????hadc.Instance = ADC1; ?// 選擇使用ADC1,
hadc.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
????// 時鐘預分頻,這里將APB2時鐘(PCLK)除以4作為ADC時鐘,
hadc.Init.Resolution = ADC_RESOLUTION_12B; // 分辨率設置為12位,這意味著ADC轉換結果的范圍是0 - 4095
hadc.Init.ScanConvMode = DISABLE; // 禁用掃描模式,因為我們只處理單個通道
hadc.Init.ContinuousConvMode = ENABLE;
// 啟用連續轉換模式,ADC會不斷進行轉換,而不是只進行一次
hadc.Init.DiscontinuousConvMode = DISABLE; // 禁用不連續轉換模式
hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
// 不使用外部觸發轉換,即采用軟件觸發
?hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START; // 軟件觸發ADC轉換
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT; // 數據右對齊,轉換結果的低12位有效
hadc.Init.NbrOfConversion = 1; // 轉換通道數量為1
hadc.Init.DMAContinuousRequests = DISABLE; // 禁用DMA連續請求,這里不使用DMA傳輸
hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV; // 單個轉換結束標志
????// 3. 初始化ADC
if (HAL_ADC_Init(&hadc) != HAL_OK)
????{
????????Error_Handler();// 初始化失敗處理
????}
????ADC_ChannelConfTypeDef sConfig;// 4. 配置ADC通道
sConfig.Channel = ADC_CHANNEL_0; ?// 選擇ADC通道0,可根據實際連接的引腳修改
????sConfig.Rank = 1; // 通道轉換順序為第1個
????sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
????// 采樣時間設置為3個ADC時鐘周期,可根據需要調整
????if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
????{
????????????????Error_Handler();// 通道配置失敗處理
????}
}
// 錯誤處理函數示例
void Error_Handler(void)
{
????while (1)
????{
????????// 可以添加錯誤提示代碼,如點亮LED等
????}
}
音頻信號采集,模擬信號轉換為數字信號
uint16_t adc_value;
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
????if (hadc->Instance == ADC1)
????{
????????adc_value = HAL_ADC_GetValue(hadc);
????????// 在這里可以對采集到的數字音頻信號進行進一步處理
GPIO_InitTypeDef gpio_init_struct;
ADC_ADCX_CHY_CLK_ENABLE(); /* 使能 ADCx 時鐘 */
ADC_ADCX_CHY_GPIO_CLK_ENABLE(); /* 開啟 GPIO 時鐘 */
/* AD 采集引腳模式設置,模擬輸入 */
gpio_init_struct.Pin = ADC_ADCX_CHY_GPIO_PIN;
gpio_init_struct.Mode = GPIO_MODE_ANALOG;
gpio_init_struct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(ADC_ADCX_CHY_GPIO_PORT, &gpio_init_struct);
????}
}
編碼與調制
#include "nrf24l01.h"
void ASK_Modulate(uint16_t data)
{
????// 將數字信號轉換為適合ASK調制的形式,例如0對應低電平,非0對應高電平
????uint8_t modulated_data = (data == 0)? 0 : 1;
????// 發送調制后的數據到nRF24L01
????NRF24L01_TxPacket(&modulated_data);
}
無線傳輸
#include "stm32f4xx_hal.h"
#include "nrf24l01.h"
// 定義nRF24L01相關引腳
#define NRF24L01_CE_Pin GPIO_PIN_0
#define NRF24L01_CE_GPIO_Port GPIOA
#define NRF24L01_CSN_Pin GPIO_PIN_1
#define NRF24L01_CSN_GPIO_Port GPIOA
#define NRF24L01_IRQ_Pin GPIO_PIN_2
#define NRF24L01_IRQ_GPIO_Port GPIOA
// 定義SPI句柄
extern SPI_HandleTypeDef hspi1;
// 初始化nRF24L01相關GPIO引腳
static void NRF24L01_GPIO_Init(void)
{
????GPIO_InitTypeDef GPIO_InitStruct
= {0};
????__HAL_RCC_GPIOA_CLK_ENABLE();
????// 配置CE引腳
????GPIO_InitStruct
.Pin = NRF24L01_CE_Pin;
????GPIO_InitStruct
.Mode = GPIO_MODE_OUTPUT_PP;
????GPIO_InitStruct
.Pull = GPIO_NOPULL;
????GPIO_InitStruct
.Speed = GPIO_SPEED_FREQ_LOW;
????HAL_GPIO_Init(NRF24L01_CE_GPIO_Port, &GPIO_InitStruct);
????// 配置CSN引腳
????GPIO_InitStruct
.Pin = NRF24L01_CSN_Pin;
????GPIO_InitStruct
.Mode = GPIO_MODE_OUTPUT_PP;
????GPIO_InitStruct
.Pull = GPIO_NOPULL;
????GPIO_InitStruct
.Speed = GPIO_SPEED_FREQ_LOW;
????HAL_GPIO_Init(NRF24L01_CSN_GPIO_Port, &GPIO_InitStruct);
????// 配置IRQ引腳
????GPIO_InitStruct
.Pin = NRF24L01_IRQ_Pin;
????GPIO_InitStruct
.Mode = GPIO_MODE_INPUT;
????GPIO_InitStruct
.Pull = GPIO_NOPULL;
????HAL_GPIO_Init(NRF24L01_IRQ_GPIO_Port, &GPIO_InitStruct);
????// 初始化CE和CSN引腳電平
????HAL_GPIO_WritePin(NRF24L01_CE_GPIO_Port, NRF24L01_CE_Pin, GPIO_PIN_RESET);
????HAL_GPIO_WritePin(NRF24L01_CSN_GPIO_Port, NRF24L01_CSN_Pin, GPIO_PIN_SET);
}
// 向nRF24L01寫寄存器
static void NRF24L01_Write_Reg(uint8_t reg, uint8_t value)
{
????HAL_GPIO_WritePin(NRF24L01_CSN_GPIO_Port, NRF24L01_CSN_Pin, GPIO_PIN_RESET);
????HAL_SPI_Transmit(&hspi1, ?, 1, 100);
????HAL_SPI_Transmit(&hspi1, &value, 1, 100);
????HAL_GPIO_WritePin(NRF24L01_CSN_GPIO_Port, NRF24L01_CSN_Pin, GPIO_PIN_SET);
}
// 從nRF24L01讀寄存器
static uint8_t NRF24L01_Read_Reg(uint8_t reg)
{
????uint8_t value;
????HAL_GPIO_WritePin(NRF24L01_CSN_GPIO_Port, NRF24L01_CSN_Pin, GPIO_PIN_RESET);
????HAL_SPI_Transmit(&hspi1, ?, 1, 100);
????HAL_SPI_Receive(&hspi1, &value, 1, 100);
????HAL_GPIO_WritePin(NRF24L01_CSN_GPIO_Port, NRF24L01_CSN_Pin, GPIO_PIN_SET);
????return value;
}
// 初始化nRF24L01
void NRF24L01_Init(void)
{
????// 初始化相關GPIO引腳
????NRF24L01_GPIO_Init();
????// 延時一段時間等待nRF24L01上電穩定
????HAL_Delay(100);
????// 配置為發射模式(可根據需要修改為接收模式)
????NRF24L01_Write_Reg(NRF24L01_REG_CONFIG, 0x0E); // 使能CRC,2字節CRC校驗,上電,發射模式
????// 設置通道頻率
????NRF24L01_Write_Reg(NRF24L01_REG_RF_CH, 0x40); // 通道76
????// 設置數據速率和發射功率
????NRF24L01_Write_Reg(NRF24L01_REG_RF_SETUP, 0x0F); // 2Mbps速率,最大發射功率
????// 設置接收地址寬度
????NRF24L01_Write_Reg(NRF24L01_REG_SETUP_AW, 0x03); // 5字節地址寬度
????// 設置自動重發時間和次數
????NRF24L01_Write_Reg(NRF24L01_REG_SETUP_RETR, 0x1A); // 自動重發延遲500us,重發次數10次
????// 設置接收通道0地址
????uint8_t rx_addr_p0[5] = {0xE7, 0xE7, 0xE7, 0xE7, 0xE7};
????HAL_GPIO_WritePin(NRF24L01_CSN_GPIO_Port, NRF24L01_CSN_Pin, GPIO_PIN_RESET);
????HAL_SPI_Transmit(&hspi1, (uint8_t *)&NRF24L01_CMD_WRITE_REG + NRF24L01_REG_RX_ADDR_P0, 1, 100);
????HAL_SPI_Transmit(&hspi1, rx_addr_p0, 5, 100);
????HAL_GPIO_WritePin(NRF24L01_CSN_GPIO_Port, NRF24L01_CSN_Pin, GPIO_PIN_SET);
????// 設置發射地址
????uint8_t tx_addr[5] = {0xE7, 0xE7, 0xE7, 0xE7, 0xE7};
????HAL_GPIO_WritePin(NRF24L01_CSN_GPIO_Port, NRF24L01_CSN_Pin, GPIO_PIN_RESET);
????HAL_SPI_Transmit(&hspi1, (uint8_t *)&NRF24L01_CMD_WRITE_REG + NRF24L01_REG_TX_ADDR, 1, 100);
????HAL_SPI_Transmit(&hspi1, tx_addr, 5, 100);
????HAL_GPIO_WritePin(NRF24L01_CSN_GPIO_Port, NRF24L01_CSN_Pin, GPIO_PIN_SET);
????// 設置接收通道0數據長度
????NRF24L01_Write_Reg(NRF24L01_REG_RX_PW_P0, 1); // 1字節數據長度
????// 清除中斷標志
????NRF24L01_Write_Reg(NRF24L01_REG_STATUS, 0x70);
}int main(void)
{
????// 初始化ADC、nRF24L01等
????ADC_Init();
????NRF24L01_Init();
????while (1)
????{
????????// 啟動ADC轉換
????????HAL_ADC_Start_IT(&hadc);
????????// 等待ADC轉換完成,在中斷中獲取adc_value
????????// 對采集到的音頻數據進行編碼和ASK調制并發送
????????ASK_Modulate(adc_value);
????}
}
DAC 實驗數模轉換器
typedef struct
{
?DAC_TypeDef *Instance; /* DAC 寄存器基地址 */
?__IO HAL_DAC_StateTypeDef State; /* DAC 工作狀態 */
?HAL_LockTypeDef Lock; /* DAC 鎖定對象 */
?DMA_HandleTypeDef *DMA_Handle1; /* 通道 1 的 DMA 處理句柄指針 */
?DMA_HandleTypeDef *DMA_Handle2; /* 通道 2 的 DMA 處理句柄指針 */
?__IO uint32_t ErrorCode; /* DAC 錯誤代碼 */
} DAC_HandleTypeDef;
typedef struct
{
??uint32_t Trigger; ????//指定DAC觸發源
DAC_TRIGGER_NONE:不使用觸發源,通過軟件觸發。
DAC_TRIGGER_T6_TRGO:使用定時器 6 的觸發輸出(TRGO)作為觸發源。
DAC_TRIGGER_T3_TRGO:使用定時器 3 的觸發輸出(TRGO)作為觸發源。
??uint32_t OutputBuffer; ?//指定DAC輸出緩沖狀態
DAC_OUTPUTBUFFER_ENABLE:使能輸出緩沖,提高輸出驅動能力。
DAC_OUTPUTBUFFER_DISABLE:禁用輸出緩沖。
} DAC_InitTypeDef;
MSP 初始化函數 HAL_DAC_MspInit,
void HAL_DAC_MspInit(DAC_HandleTypeDef* hdac);
DAC 的通道參數初始化函數:
HAL_StatusTypeDef HAL_DAC_ConfigChannel(DAC_HandleTypeDef *hdac,
DAC_ChannelConfTypeDef *sConfig, uint32_t Channel);
typedef struct
{
?uint32_t DAC_Trigger; /* DAC 觸發源的選擇 */
?uint32_t DAC_OutputBuffer; /* 啟用或者禁用 DAC 通道輸出緩沖區 */
} DAC_ChannelConfTypeDef;
使能啟動 DAC 轉換通道函數,
HAL_StatusTypeDef HAL_DAC_Start(DAC_HandleTypeDef *hdac, uint32_t Channel);
DAC 的通道輸出值函數,其聲明如下:
HAL_StatusTypeDef HAL_DAC_SetValue(DAC_HandleTypeDef *hdac, uint32_t Channel,
uint32_t Alignment, uint32_t Data);
Channel選擇輸出通道, DAC_CHANNEL_1或DAC_CHANNEL_2
DAC 讀取通道輸出值函數:
uint32_t HAL_DAC_GetValue(DAC_HandleTypeDef *hdac, uint32_t Channel);
啟動 DAC 使用 DMA 方式傳輸函數,
HAL_StatusTypeDef HAL_DAC_Start_DMA(DAC_HandleTypeDef *hdac, uint32_t Channel,
uint32_t *pData, uint32_t Length, uint32_t Alignment);
形參 3 是使用 DAC 輸出數據緩沖區的指針。
形參 4 是 DAC 輸出數據的長度。
形參 5 是指定 DAC 通道的數據對齊方式,有:DAC_ALIGN_8B_R(8 位右對齊)、
DAC_ALIGN_12B_L(12 位左對齊)和 DAC_ALIGN_12B_R(12 位右對齊)三種方式
停止 DAC 的 DMA 方式函數,其聲明如下:
HAL_StatusTypeDef HAL_DAC_Stop_DMA(DAC_HandleTypeDef *hdac, uint32_t Channel);
配置主模式下的定時器觸發輸出選擇函數,其聲明如下:
HAL_StatusTypeDef HAL_TIMEx_MasterConfigSynchronization(
TIM_HandleTypeDef *htim, TIM_MasterConfigTypeDef *sMasterConfig);
接收端,無線接收
uint8_t received_data;
void NRF24L01_Receive(void)
{
????if (NRF24L01_RxPacket(&received_data) == 0)
????{
????????// 接收成功,對received_data進行處理
????}
}
解調與解碼
uint16_t ASK_Demodulate(uint8_t data)
{
????// ASK解調,將接收到的數據轉換為數字音頻信號形式
return (data == 0)? 0 : 1000; // 這里假設0對應0,1對應1000,實際需根據編碼情況調整
}
DAC 配置與音頻輸出
DAC_HandleTypeDef hdac;
void DAC_Init(void)
{
????hdac.Instance = DAC;
????hdac.Init.OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
????HAL_DAC_Init(&hdac);
????// 配置DAC通道
????DAC_ChannelConfTypeDef sConfig;
????sConfig.DAC_Channel = DAC_CHANNEL_1;
????sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
????HAL_DAC_ConfigChannel(&hdac, &sConfig);
}
int main(void)
{
????// 初始化nRF24L01、DAC等
????NRF24L01_Init();
????DAC_Init();
????while (1)
????{
????????// 接收無線數據
????????NRF24L01_Receive();
????????// 對接收數據進行ASK解調
????????uint16_t demodulated_data = ASK_Demodulate(received_data);
????????// 通過DAC輸出模擬音頻信號
????????HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, demodulated_data);
????}
}