NRF24L01模塊----6通道通訊測試

一、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("\r\n發送模式\r\n");
				
			for(i=0;i<6;i++)
			{
				printf("發送數據至接收端通道:%d\r\n",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<Count;i++)
	{
	    pBuf[i] = 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<Count;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] != 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<NRF_Dev->RX_S->PIPEx+1;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[i]);               //設置接收通道接收數據的長度	
		
	}
	
	
	NRF24L01_Write_REG(NRF24_WREG + EN_AA, ( 2<<NRF_Dev->RX_S->PIPEx) - 1 );     // Enable Auto.Ack:PipeX
	NRF24L01_Write_REG(NRF24_WREG + EN_RXADDR, ( 2<<NRF_Dev->RX_S->PIPEx) - 1  ); // Enable PipeX

	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("\r\n數據來自通道%d\r\n",reg);
		printf("%s\r\n",(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("\r\n發送模式\r\n");

				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米距離通訊正常。更遠則由於環境限制未測試

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章