完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
一、MCU与NRF24L01通讯
采用SPI通讯协议,速率最大为10M,与普通SPI元器件稍有不同的是,多了一个CE引脚,用来开启接收、发送,以及使器件进入待机模式。具体看IC DATASHEET说明。 写寄存器指令格式为:1、SPI写寄存器地址 + 0x20 2、SPI写参数 读寄存器指令格式为:1、SPI写寄存器地址 2、SPI读参数 但少数几个指令,只需写入一个参数,如: 读STATUS寄存器: 不能使用NOP指令,读取出来参数不正确。 应使用读普通寄存器的方式,STATUS寄存器地址为0x07; 二、数据的发送 当设置芯片的寄存器,“CE”引脚需要为低电平。 用到以下几个寄存器: 1、将接收端地址写入发送地址寄存器“TX_ADDR” 2、将接收端地址写入PIPE0通道地址寄存器“RX_ADDR_P0”,开启自动应答后,PIPE0将接收接收端的应答信号。 3、使能“EN_AA”寄存器开启自动应答,使能“EN_RXADDR”中PIPE0对应的bit。 4、设置重发寄存器“SETUP_RETR”,设置重发次数以及时间间隔。 5、设置发送频道的频率“RF_CH”,以及发送功率、速率“RF_SETUP” 6、设置配置寄存器“CONFIG”,开启中断以及设置发送。 如果以上寄存器设置完毕,拉低“CE”将需要发送的数据通过“WR_TX_PLOAD”指令写入TX_FIFO,"CE"拉高“10us”以上即可 开启发送。以上寄存器设置完后,不必每次设置,接下来的发送只要不断通过“WR_TX_PLOAD”写数据至TX_FIFO即可。 发送完毕后,根据发送情况产生2种中断:“TX_DS”中断以及“MAX_RT”中断。 1、对于“TX_DS”中断,可在处理标志位后,开启下一帧传输或进行其他处理。 2、对于“MAX_RT”中断,需清除TX_FIFO。 三、数据的接收 1、设置接收通道,以及通道的地址“RX_ADDR_P0”~“RX_ADDR_P5” 2、设置接收通道接收数据的字节数“RX_PW_P0”~“RX_PW_P5” 3、设置“EN_AA”、“EN_RXADDR”、“RF_CH”、“RF_SETUP”、“CONFIG”等寄存器 4、拉高“CE”开启接收。 注意:1、假设需要开启PIPE3,接收数据。那么PIPE0~2也必须开启。即,不能单独开启后面的通道,而关闭前面的通道。 2、地址传入芯片是低字节先行。例如: 设定P0地址为:0x01,0x02,0x03,0x04,0x05 写入地址的顺序为:0x05,0x04,0x03,0x02,0x01 3、单对单传输,在“RX_DR”中断中接收数据一般不会有问题,如果是6发送,1接收。可能会出现,中断中数据尚 未接收完毕,再次产生RX_DR中断。第二次产生的中断MCU是检测不到的。此时应将接收数据的操作放于中 断外。 四、程序 1、FREERTOS模块 /** ****************************************************************************** * File Name : freertos.c * Description : Code for freertos applications ****************************************************************************** * This notice applies to any and all portions of this file * that are not between comment pairs USER CODE BEGIN and * USER CODE END. Other portions of this file, whether * inserted by the user or by software development tools * are owned by their respective copyright owners. * * Copyright (c) 2018 STMicroelectronics International N.V. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted, provided that the following conditions are met: * * 1. Redistribution of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. Neither the name of STMicroelectronics nor the names of other * contributors to this software may be used to endorse or promote products * derived from this software without specific written permission. * 4. This software, including modifications and/or derivative works of this * software, must execute solely and exclusively on microcontroller or * microprocessor devices manufactured by or for STMicroelectronics. * 5. Redistribution and use of this software other than as permitted under * this license is void and will automatically terminate your rights under * this license. * * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "FreeRTOS.h" #include "task.h" #include "cmsis_os.h" /* USER CODE BEGIN Includes */ #include "stdio.h" #include "usart.h" #include "bsp_NRF24L01.h" #include "bsp_key.h" /* USER CODE END Includes */ /* Variables -----------------------------------------------------------------*/ osThreadId defaultTaskHandle; osThreadId Task_KEYSCANHandle; osThreadId Task_NRF2401Handle; osMutexId Mutex_USARTHandle; /* USER CODE BEGIN Variables */ /* USER CODE END Variables */ /* Function prototypes -------------------------------------------------------*/ void StartDefaultTask(void const * argument); void Task_KEYSCAN(void const * argument); void Task_NRF2401(void const * argument); void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */ /* USER CODE BEGIN FunctionPrototypes */ /* USER CODE END FunctionPrototypes */ int fputc(int c, FILE * f) { HAL_UART_Transmit(&huart1,(uint8_t *)&c,1,1000);//发送串口 return c; } void MX_FREERTOS_Init(void) { osMutexDef(Mutex_USART); Mutex_USARTHandle = osMutexCreate(osMutex(Mutex_USART)); /* Create the thread(s) */ /* definition and creation of defaultTask */ osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128); defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL); /* definition and creation of Task_KEYSCAN */ osThreadDef(Task_KEYSCAN, Task_KEYSCAN, osPriorityLow, 0, 128); Task_KEYSCANHandle = osThreadCreate(osThread(Task_KEYSCAN), NULL); /* definition and creation of Task_NRF2401 */ osThreadDef(Task_NRF2401, Task_NRF2401, osPriorityBelowNormal, 0, 256); Task_NRF2401Handle = osThreadCreate(osThread(Task_NRF2401), NULL); } //GPIO_9外部中断回调函数 void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { uint8_t STATUS_Temp; if(GPIO_Pin == NRF2401_IRQ_Pin) { STATUS_Temp = NRF24L01_Read_REG(NRF24_RREG + STATUS); if(NRF_Dev->Mode == NRF_RXMode) { if(STATUS_Temp&0x40) //接收数据中断 { RX_Handle( STATUS_Temp>>1&0x07 ); } } else { if(STATUS_Temp&0x20) //数据发送成功中断 { TX_DSHandle(); } else //此次中断为发送失败中断 { TX_RTHandle(); } } NRF24L01_Write_REG(NRF24_WREG + STATUS,STATUS_Temp); //清除STATUS寄存器中 //的中断位 } } /* StartDefaultTask function */ void StartDefaultTask(void const * argument) { NRFStructInit(); //初始化NRF24L01 for(;;) { osDelay(1); } /* USER CODE END StartDefaultTask */ } /* StartTask02 function */ void Task_KEYSCAN(void const * argument) { for(;;) { ScanKey(); osDelay(50); } } /* NRF2401_TXRX function */ void Task_NRF2401(void const * argument) { uint32_t i; for(;;) { if(KeySingle(KEY_0)) //KEY0被单次触发,发送数据 { printf("rn发送模式rn"); for(i=0;i<6;i++) { printf("发送数据至接收端通道:%drn",i); NRF_Dev->TX_S->TXPIPE = i; TX_Mode(); TX_Package(); osDelay(10); //等待printf函数输出完毕,实际发送数据可取消此延时 while(NRF_Dev->IRQ_S->TxFinish == 0 && NRF_Dev->IRQ_S->TxMAXRT == 0); NRF_Dev->IRQ_S->TxMAXRT = 0; NRF_Dev->IRQ_S->TxFinish = 0; } } if(KeySingle(KEY_1)) //KEY1被单次触发,切换为接收模式 { printf("接收模式"); RX_Mode(); } osDelay(1); } } /* USER CODE BEGIN Application */ /* USER CODE END Application */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 2、NRF24L01模块 /************************************************************** * NRF24L01程序模块 * * 测试板为原子战舰V3,使用外设为SPI1,SPI分频系数为8分频 * **************************************************************/ #include "bsp_NRF24L01.h" //收发端地址相反,否则由于地址问题无法通讯 //#define TX_Device #ifdef TX_Device //接收端6通道地址 uint8_t NRF_TXAddr[TXADRR_NUM][5] = { {0x0,0x11,0x11,0x11,0x11}, {0x1,0x11,0x11,0x11,0x11}, {0x2,0x11,0x11,0x11,0x11}, {0x3,0x11,0x11,0x11,0x11}, {0x4,0x11,0x11,0x11,0x11}, {0x5,0x11,0x11,0x11,0x11}, }; //发送端(本机)6通道接收地址 uint8_t NRF_RXAddr[6][5] = { {0x0,0x22,0x22,0x22,0x22}, {0x1,0x22,0x22,0x22,0x22}, {0x2,0x22,0x22,0x22,0x22}, {0x3,0x22,0x22,0x22,0x22}, {0x4,0x22,0x22,0x22,0x22}, {0x5,0x22,0x22,0x22,0x22}, }; #else uint8_t NRF_TXAddr[TXADRR_NUM][5] = { {0x0,0x22,0x22,0x22,0x22}, {0x1,0x22,0x22,0x22,0x22}, {0x2,0x22,0x22,0x22,0x22}, {0x3,0x22,0x22,0x22,0x22}, {0x4,0x22,0x22,0x22,0x22}, {0x5,0x22,0x22,0x22,0x22}, }; uint8_t NRF_RXAddr[6][5] = { {0x0,0x11,0x11,0x11,0x11}, {0x1,0x11,0x11,0x11,0x11}, {0x2,0x11,0x11,0x11,0x11}, {0x3,0x11,0x11,0x11,0x11}, {0x4,0x11,0x11,0x11,0x11}, {0x5,0x11,0x11,0x11,0x11}, }; #endif //数据发送缓冲数组 uint8_t NRF_TXBuff[32] = "NRF24L01通讯测试"; //发送数据size管理数组 uint8_t NRF_TXPxSize[TXADRR_NUM] = {32,32,32,32,32,32}; //接收数据缓存数组 uint8_t NRF_RXBuff[6][32]; //接收数据size管理数组 uint8_t NRF_RXPxSize[6] = {32,32,32,32,32,32}; //NRF管理结构体 NRF_Struct NRF_S, *NRF_Dev = &NRF_S; NRF_TXStruct NRF_TXS; NRF_RXStruct NRF_RXS; NRF_IRQStruct NRF_IRQS; /** * @brief NRF24L01管理结构体初始化 * * @Note 默认开启6个通道, * 发送字节数为32字节 * 6个通道接收字节数位32字节 * * @retval None */ void NRFStructInit(void) { NRF_Dev->RX_S = &NRF_RXS; NRF_Dev->TX_S = &NRF_TXS; NRF_Dev->IRQ_S = &NRF_IRQS; NRF_Dev->Mode = NRF_RXMode; NRF_Dev->RX_S->PIPEx = 5; NRF_Dev->RX_S->Size = NRF_RXPxSize; NRF_Dev->RX_S->ADDR = (uint8_t *)&NRF_RXAddr; NRF_Dev->RX_S->Buff = (uint8_t *)&NRF_RXBuff; NRF_Dev->TX_S->TXPIPE = 0; NRF_Dev->TX_S->ReCount = 15; NRF_Dev->TX_S->ReTime = 1; NRF_Dev->TX_S->Size = NRF_TXPxSize; NRF_Dev->TX_S->RF_Ch = 40; NRF_Dev->TX_S->RF_DR = DR_2Mbps; NRF_Dev->TX_S->RF_PWR = PWR_0dBm; NRF_Dev->TX_S->ADDR = (uint8_t *)&NRF_TXAddr; NRF_Dev->TX_S->Buff = NRF_TXBuff; NRF_Dev->IRQ_S->TxFinish = 0; NRF_Dev->IRQ_S->TxMAXRT = 0; RX_Mode(); //初始化为接收模式 } //SPI与NRF2401读写通信 uint8_t NRF24L01_RW(uint8_t d_send) { uint8_t d_read; if(HAL_SPI_TransmitReceive(&hspi1,&d_send,&d_read,1,0xFFFFFF)!=HAL_OK) d_read=0xff; return d_read; } // NRF24L01写SPI指令 void SPI_WReg(uint8_t reg) { NRF24L01_CE_L NRF24L01_Write_REG(reg, 0); NRF24L01_CE_H } //SPI读取NRF2401寄存器数据 uint8_t NRF24L01_Read_REG(uint8_t reg) { uint8_t status; NRF24L01_CS_L NRF24L01_RW(reg); status = NRF24L01_RW(0); NRF24L01_CS_H return status; } //SPI写NRF2401寄存器数据 uint8_t NRF24L01_Write_REG(uint8_t reg,uint8_t value) { uint8_t status; NRF24L01_CS_L status = NRF24L01_RW(reg); NRF24L01_RW(value); NRF24L01_CS_H return status; } //SPI连续读取NRF2401寄存器数据 uint8_t NRF24L01_Read_Buff(uint8_t reg,uint8_t *pBuf,uint8_t Count) { uint8_t status,i; NRF24L01_CS_L status = NRF24L01_RW(reg); for(i=0;i pBuf = NRF24L01_RW(0); } NRF24L01_CS_H return status; } //SPI连续写NRF2401寄存器数据 uint8_t NRF24L01_Write_Buff(uint8_t reg,uint8_t *pBuf,uint8_t Count) { uint16_t j = 720; uint8_t status,i; NRF24L01_CS_L status = NRF24L01_RW(reg); while(j--); //短暂延时 for(i=0;i status = NRF24L01_RW(*pBuf++); } NRF24L01_CS_H return status; } //SPI与NRF2401通讯自检 //通过则代表MCU SPI通讯NRF2401成功 //可用于测试器件之间的连接 uint8_t NRF24L01_Check(void) { uint8_t buf[5]={0x01,0x02,0x03,0x04,0x05}; uint8_t buf1[5]; uint8_t i; NRF24L01_Write_Buff(NRF24_WREG+TX_ADDRReg,buf,5); //开机第一次写入不成功 NRF24L01_Write_Buff(NRF24_WREG+TX_ADDRReg,buf,5); /*写入5个字节的地址. */ NRF24L01_Read_Buff(TX_ADDRReg,buf1,5); /*读出写入的地址 */ for(i=0;i<5;i++) /*比较*/ { if(buf1 != i+1) break; } if(i==5) return SUCCESS ; //MCU与NRF成功连接 else return ERROR ; //MCU与NRF不正常连接 } /** * @brief NRF24L01设置为发送模式 * * @retval None */ void TX_Mode(void) { //发送地址不能大于发送地址二维数组个数上限,发送size不能大于32 if( NRF_Dev->TX_S->TXPIPE > TXADRR_NUM -1 || NRF_Dev->TX_S->Size[NRF_Dev->TX_S->TXPIPE] > 32 ) return ; NRF_Dev->Mode = NRF_TXMode; NRF24L01_CE_L NRF24L01_Write_Buff(NRF24_WREG + TX_ADDRReg, (uint8_t *)NRF_Dev->TX_S->ADDR + NRF_Dev->TX_S->TXPIPE*5, 5); //设置发送地址 NRF24L01_Write_Buff(NRF24_WREG + RX_ADDR_P0, (uint8_t *)NRF_Dev->TX_S->ADDR + NRF_Dev->TX_S->TXPIPE*5, 5); //设置本机地址,P0接收应答 NRF24L01_Write_REG(NRF24_WREG + EN_AA, 0x01); // Enable Auto.Ack:Pipe0 NRF24L01_Write_REG(NRF24_WREG + EN_RXADDR, 0x01); // Enable Pipe0 NRF24L01_Write_REG(NRF24_WREG + SETUP_RETR, NRF_Dev->TX_S->ReCount + (NRF_Dev->TX_S->ReTime<<4)); // 500us + 86us, 10 retrans... NRF24L01_Write_REG(NRF24_WREG + RF_CH, NRF_Dev->TX_S->RF_Ch); // Select RF channel NRF24L01_Write_REG(NRF24_WREG + RF_SETUP, NRF_Dev->TX_S->RF_DR<<3 | NRF_Dev->TX_S->RF_PWR<<1); // TX_PWR:0dBm, Datarate:2Mbps, NRF24L01_Write_REG(NRF24_WREG + CONFIG, 0x0e); // Set PWR_UP bit, enable CRC(2 bytes) } void TX_Package(void) { NRF_Dev->Mode = NRF_TXMode; NRF24L01_CE_L NRF24L01_Write_Buff(WR_TX_PLOAD, (uint8_t *)NRF_Dev->TX_S->Buff , NRF_Dev->TX_S->Size[NRF_Dev->TX_S->TXPIPE]); // Writes data to TX payload NRF24L01_CE_H } /** * @brief NRF24L01设置为接收模式 * * @retval None */ void RX_Mode(void) { uint8_t i,j = 5; NRF_Dev->Mode = NRF_RXMode; NRF24L01_CE_L for(i=0;i { if(i>1) j = 1; NRF24L01_Write_Buff(NRF24_WREG + RX_ADDR_P0 + i, (uint8_t *)NRF_Dev->RX_S->ADDR + 5*i, j); //设置接收通道以及通道的地址 NRF24L01_Write_REG(NRF24_WREG + RX_PW_P0 + i, NRF_Dev->RX_S->Size); //设置接收通道接收数据的长度 } NRF24L01_Write_REG(NRF24_WREG + EN_AA, ( 2< NRF24L01_Write_REG(NRF24_WREG + EN_RXADDR, ( 2< NRF24L01_Write_REG(NRF24_WREG + RF_CH, NRF_Dev->TX_S->RF_Ch); // Select RF channel NRF24L01_Write_REG(NRF24_WREG + RF_SETUP, NRF_Dev->TX_S->RF_DR<<3 | NRF_Dev->TX_S->RF_PWR<<1); // TX_PWR:0dBm, Datarate:2Mbps, NRF24L01_Write_REG(NRF24_WREG + CONFIG, 0x0f); // Set PWR_UP bit, enable CRC(2 bytes) NRF24L01_CE_H } /** * @brief NRF24L01接收处理函数 * * @param reg: NRF2401状态寄存器的值 * @arg 0 - 5 * @retval None */ void RX_Handle(uint8_t reg) { if( reg < 6 ) //获取接收数据pipe编号,溢出则不进行接收处理 { NRF24L01_Read_Buff(NRF24_RREG + RD_RX_PLOAD, (uint8_t *)NRF_Dev->RX_S->Buff + reg*32, NRF_Dev->RX_S->Size[reg]); //接收数据 SPI_WReg(FLUSH_RX); //清除RX FIFO printf("rn数据来自通道%drn",reg); printf("%srn",(uint8_t *)NRF_Dev->RX_S->Buff + reg*32); } } /** * @brief NRF24L01发送成功处理函数 * * @retval None */ void TX_DSHandle(void) { NRF_Dev->IRQ_S->TxFinish = 1; } /** * @brief NRF24L01达到最大重发数处理函数 * * @retval None */ void TX_RTHandle(void) { SPI_WReg(FLUSH_TX); //重发送溢出,需清除TX FIFO,否则再次触发发送 NRF_Dev->IRQ_S->TxMAXRT = 1; } 3、NRF24L01头文件定义 #ifndef __bsp_NRF24L01_H__ #define __bsp_NRF24L01_H__ #include "stm32f1xx_hal.h" #include "main.h" #include "spi.h" #define TXADRR_NUM 6 #define vu8 volatile uint8_t #define vu16 volatile uint16_t #define vu32 volatile uint32_t #define DR_1Mbps 0 #define DR_2Mbps 1 #define PWR_0dBm 3 #define PWR_6dBm 2 #define PWR_16dBm 1 #define PWR_18dBm 0 typedef struct { vu8 RF_PWR; //发射功率 vu8 RF_DR; //发射速率 vu8 RF_Ch; //发射通道 vu8 TXPIPE; //发送地址 vu8 ReCount; //重发送次数 vu8 ReTime; //重发送时间 vu8 *Size; //发送数据字节数 vu8 *Buff; //发送数据指针 vu8 *ADDR; //发送地址指针 }NRF_TXStruct; typedef struct { vu8 PIPEx; //接收通道开启 0~5 vu8 *Size; //接收字节数 vu8 *Buff; //接收缓存指针 vu8 *ADDR; //接收通道地址指针 }NRF_RXStruct; typedef struct { vu8 TxMAXRT; //重发送中断标志位 vu8 TxFinish; //发送完成中断标志位 }NRF_IRQStruct; typedef struct { vu8 Mode; NRF_IRQStruct *IRQ_S; NRF_TXStruct *TX_S; NRF_RXStruct *RX_S; }NRF_Struct; extern NRF_Struct *NRF_Dev; #define NRF_TXMode 0 #define NRF_RXMode 1 /************************NRF引脚定义*********************/ #define NRF24L01_CS_L HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET); #define NRF24L01_CS_H HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET); #define NRF24L01_CE_L HAL_GPIO_WritePin(NRF2401_CSN_GPIO_Port, NRF2401_CSN_Pin, GPIO_PIN_RESET); #define NRF24L01_CE_H HAL_GPIO_WritePin(NRF2401_CSN_GPIO_Port, NRF2401_CSN_Pin, GPIO_PIN_SET); /************************SPI 接口寄存器定义*********************/ #define NRF24_RREG 0x00 // Define read command to register #define NRF24_WREG 0x20 // Define write command to register #define RD_RX_PLOAD 0x61 // Define RX payload register address #define WR_TX_PLOAD 0xA0 // Define TX payload register address #define FLUSH_TX 0xE1 // Define flush TX register command #define FLUSH_RX 0xE2 // Define flush RX register command #define REUSE_TX_PL 0xE3 // Define reuse TX payload register command #define NOP 0xFF // Define No Operation, might be used to read status /**********************NRF2401功能寄存器定义********************/ #define CONFIG 0x00 // 'Config' register address #define EN_AA 0x01 // 'Enable Auto Acknowledgment' register address #define EN_RXADDR 0x02 // 'Enabled RX addresses' register address #define SETUP_AW 0x03 // 'Setup address width' register address #define SETUP_RETR 0x04 // 'Setup Auto. Retrans' register address #define RF_CH 0x05 // 'RF channel' register address #define RF_SETUP 0x06 // 'RF setup' register address #define STATUS 0x07 // 'Status' register address #define OBSERVE_TX 0x08 // 'Observe TX' register address #define CD 0x09 // 'Carrier Detect' register address #define RX_ADDR_P0 0x0A // 'RX address pipe0' register address #define RX_ADDR_P1 0x0B // 'RX address pipe1' register address #define RX_ADDR_P2 0x0C // 'RX address pipe2' register address #define RX_ADDR_P3 0x0D // 'RX address pipe3' register address #define RX_ADDR_P4 0x0E // 'RX address pipe4' register address #define RX_ADDR_P5 0x0F // 'RX address pipe5' register address #define TX_ADDRReg 0x10 // 'TX address' register address #define RX_PW_P0 0x11 // 'RX payload width, pipe0' register address #define RX_PW_P1 0x12 // 'RX payload width, pipe1' register address #define RX_PW_P2 0x13 // 'RX payload width, pipe2' register address #define RX_PW_P3 0x14 // 'RX payload width, pipe3' register address #define RX_PW_P4 0x15 // 'RX payload width, pipe4' register address #define RX_PW_P5 0x16 // 'RX payload width, pipe5' register address #define FIFO_STATUS 0x17 // 'FIFO Status Register' register address void NRFStructInit(void); uint8_t NRF24L01_RW(uint8_t d_send); uint8_t NRF24L01_Read_REG(uint8_t reg); uint8_t NRF24L01_Write_REG(uint8_t reg,uint8_t value); uint8_t NRF24L01_Read_Buff(uint8_t reg,uint8_t *pBuf,uint8_t Count); uint8_t NRF24L01_Write_Buff(uint8_t reg,uint8_t *pBuf,uint8_t Count); uint8_t NRF24L01_Check(void); void RX_Mode(void); void TX_Mode(void); void SPI_WReg(uint8_t reg); void RX_Handle(uint8_t reg); void TX_DSHandle(void); void TX_RTHandle(void); void TX_Package(void); #endif 注意:1、程序基于STM32CUBEMX生成,编译环境为MDK,硬件环境为F1原子战舰V3。 2、使用程序,接收与发送端地址不同,具体使用宏定义“#define TX_Device”即可切换地址。 3、两块板子烧好程序,上电后,先按下KEY1,将其中一个板子转换为接收模式,另一个板子开启发送。 开启两个串口助手,观察到现象为: 五、速度测试 器件本身选定的是2Mbps的速度,那么我们能做的就是,将MCU的SPI通讯速率提升上去。所以程序作了如下改动。 1、不使用HAL的SPI库进行通讯,将SPI通讯函数改为: //SPI与NRF2401读写通信 uint8_t NRF24L01_RW(uint8_t d_send) { uint8_t d_read; for(d_read = 0; d_read<8; d_read++); SPI1->DR = d_send; for(d_read = 0; d_read<8; d_read++); return SPI1->DR; } 2、FreeRTOS中发送任务,改为使用PIPE0连续发送10,000个32byte的数据包,数据总量为:312.5Kb 需要注意的是,HAL库是在SPI通讯函数中使能SPI1外设,所以平时SPI1外设时没有使能的,需要我们手动使能 /* NRF2401_TXRX function */ void Task_NRF2401(void const * argument) { uint32_t i; SPI1->CR1 |= 0x0040; //使能SPI1 SPI1->DR = 0xff; //dummy write for(;;) { if(KeySingle(KEY_0)) //KEY0被单次触发,发送数据 { printf("rn发送模式rn"); TX_Mode(); for(i=0;i<10000;i++) { TX_Package(); while(NRF_Dev->IRQ_S->TxFinish == 0 && NRF_Dev->IRQ_S->TxMAXRT == 0); NRF_Dev->IRQ_S->TxMAXRT = 0; NRF_Dev->IRQ_S->TxFinish = 0; } } if(KeySingle(KEY_1)) //KEY1被单次触发,切换为接收模式 { printf("接收模式"); RX_Mode(); } osDelay(1); } } 3、接收中断处理函数中,加一个缓存标志“i”记录接收数据包的个数 void RX_Handle(uint8_t reg) { volatile static uint32_t i=0; i++; if( reg < 6 ) //获取接收数据pipe编号,溢出则不进行接收处理 { NRF24L01_Read_Buff(NRF24_RREG + RD_RX_PLOAD, (uint8_t *)NRF_Dev->RX_S->Buff + reg*32, NRF_Dev->RX_S->Size[reg]); //接收数据 SPI_WReg(FLUSH_RX); //清除RX FIFO } } 测试结果: 完整地接收到10000个数据包,按下输出按键同时,手机进行计时。。。别问我为什么不开个定时器,我懒。。。。 测量了几次,时间约为6.5S,据此计算,通信速率为:10000*32/1024/6.5 = 48Kb/s 听说网上有人不开启自动应答可以达到65Kb/s的,反正我是开了自动应答。。。不开启的就懒得测了。 六、距离测试 跟距离有关的因素很多,我们能通过程序调整的有:1、发射功率 2、发射速率 3、频道 所以将初始化参数更改如下: void NRFStructInit(void) { NRF_Dev->RX_S = &NRF_RXS; NRF_Dev->TX_S = &NRF_TXS; NRF_Dev->IRQ_S = &NRF_IRQS; NRF_Dev->Mode = NRF_RXMode; NRF_Dev->RX_S->PIPEx = 5; NRF_Dev->RX_S->Size = NRF_RXPxSize; NRF_Dev->RX_S->ADDR = (uint8_t *)&NRF_RXAddr; NRF_Dev->RX_S->Buff = (uint8_t *)&NRF_RXBuff; NRF_Dev->TX_S->TXPIPE = 0; NRF_Dev->TX_S->ReCount = 15; NRF_Dev->TX_S->ReTime = 15; NRF_Dev->TX_S->Size = NRF_TXPxSize; NRF_Dev->TX_S->RF_Ch = 80; NRF_Dev->TX_S->RF_DR = DR_1Mbps; NRF_Dev->TX_S->RF_PWR = PWR_0dBm; NRF_Dev->TX_S->ADDR = (uint8_t *)&NRF_TXAddr; NRF_Dev->TX_S->Buff = NRF_TXBuff; NRF_Dev->IRQ_S->TxFinish = 0; NRF_Dev->IRQ_S->TxMAXRT = 0; RX_Mode(); //初始化为接收模式 } 未更改参数前,超过2米通讯会出现中断。 参数更改后,无障碍下7米距离通讯正常。更远则由于环境限制未测试 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1632 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1559 浏览 1 评论
985 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
688 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1605 浏览 2 评论
1869浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
653浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
523浏览 3评论
540浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
509浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-25 15:11 , Processed in 0.942311 second(s), Total 79, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号