【STM32】2.4G无线模块nRF24L01驱动编写说明

文章目录

  • 一、nRF24L01+模块介绍
    • 1.运行电压要求
    • 2.模块引脚定义与原理图
  • 二、寄存器配置
    • 1.工作模式说明
    • 2.寄存器命令与地址
    • 3.发送过程
    • 4.接收过程
  • 三、nRF24L01模块配置代码
  • 总结


一、nRF24L01+模块介绍

  nRF24L01+是一款单芯片2.4GHz收发器,适用于超低功耗无线应用。nRF24L01+设计在2.400-2.4835GHz的全球ISM频段内运行。
  要设计一个使用nRF24L01+的无线电系统,只需要一个单片机(微控制器)和一些外部无源组件。
  可以通过串行外设接口(SPI)来操作和配置nRF24L01+。寄存器图包含nRF24L01+中的所有配置寄存器,可通过SPI访问,并可在芯片的所有操作模式下访问。
  nRF24L01+与nRF24L01在线兼容,与nRF2401A、nRF2402、nRF24E1和nRF24E2在线兼容。与nRF24L01相比,nRF24L01+中的互调和宽带阻塞值有了很大改善,在nRF24L01+中添加内部滤波提高了满足射频调节标准的边际。

1.运行电压要求

【STM32】2.4G无线模块nRF24L01驱动编写说明_第1张图片
  3.3V供电即可。

2.模块引脚定义与原理图

【STM32】2.4G无线模块nRF24L01驱动编写说明_第2张图片
【STM32】2.4G无线模块nRF24L01驱动编写说明_第3张图片
  与单片机连接为4线SPI接口,此外需要CE输出口以及IRQ中断输入口。

二、寄存器配置

1.工作模式说明

【STM32】2.4G无线模块nRF24L01驱动编写说明_第4张图片
接收模式(RX mode):接收数据的模块配置成此模式。

发送模式(TX mode):发送数据的模块配置成此模式。数据存在TX FIFO寄存器中。
  a.如果CE保持高位,则清空所有TX FIFO,并执行所有必要的确认和可能的重新传输。只要重新填充TX FIFO,传输就会继续。如果TX FIFO为空时,CE仍然处于高电平,则nRF24L01+进入待机-II模式。在这种模式下,在向TX FIFO上传数据包(UL)后,一旦CSN设置为高,数据包的传输就开始了。
  b.该工作模式下,CE高脉冲至少持续10µs。这就会传输一个数据包。这是正常操作模式。数据包传输后,nRF24L01+进入待机状态-I模式。

掉电模式(Power Down):PWR_UP位寄存器写0

2.寄存器命令与地址

  这里Data Sheet中的篇幅太长(P51&P57-P63),就直接放程序里的定义了。
【STM32】2.4G无线模块nRF24L01驱动编写说明_第5张图片
【STM32】2.4G无线模块nRF24L01驱动编写说明_第6张图片
  其中,配置工作模式需要使用命令:写配置寄存器,加上寄存器地址CONFIG。该寄存器各个位的定义为:
【STM32】2.4G无线模块nRF24L01驱动编写说明_第7张图片
7位:只能写0
6-4位:中断使能设置
3位:CRC校验使能
2位:1or2字节CRC
1位:电源
0位:RX/TX控制
  根据工作模式配置图,注意1和0位的配置,加上CE引脚的电平,就可以配置工作模式。

ep:配置模块为接收RX模式

NRF24L01_Write_Reg(nRF_WRITE_REG + CONFIG, 0x0f); //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式,开启所有中断

  其他寄存器配置参考Data Sheet,形式同上。

3.发送过程

  模块配置为发送模式后,将数据写入发送的数组中,直接启动发送函数,发送函数在读取到发送完毕的中断标志TX_DS后,清除中断标志,以便下次发送。

4.接收过程

  模块配置为接收模式后,当收到其他模块发送的一帧数据,STATUS寄存器的RX_DR位被置1,且触发中断,反馈在IRQ引脚上。读取数据后,需要清除中断标志以及清空RX_FIFO寄存器,否则无法进行下一次的接收。
【STM32】2.4G无线模块nRF24L01驱动编写说明_第8张图片

三、nRF24L01模块配置代码

  使用MCU型号为STM32F103REx,库为HAL库,操作系统rt-thread-2.0.0_beta版本,注意此程序引脚初始化的方式有所不同。
头文件 24L01.h

/**
	********************************************************************
	*	@file			24L01.h
	*	@version       
	*	@date			
	*	@brief
	********************************************************************
	*	@attention
	********************************************************************
	*/
#ifndef _24L01_H_
#define _24L01_H_

#include 
//#include 

/**********  RF通道  ***********/
#define NRF24L01_Channel 	0

/**********  NRF24L01寄存器操作命令  ***********/
#define nRF_READ_REG    0x00  //读配置寄存器,低5位为寄存器地址
#define nRF_WRITE_REG   0x20  //写配置寄存器,低5位为寄存器地址
#define RD_RX_PLOAD     0x61  //读RX有效数据,1~32字节
#define WR_TX_PLOAD     0xA0  //写TX有效数据,1~32字节
#define FLUSH_TX        0xE1  //清除TX FIFO寄存器.发送模式下用
#define FLUSH_RX        0xE2  //清除RX FIFO寄存器.接收模式下用
#define REUSE_TX_PL     0xE3  //重新使用上一包数据,CE为高,数据包被不断发送.
#define NOP             0xFF  //空操作,可以用来读状态寄存器	 
/**********  NRF24L01寄存器地址   *************/
#define CONFIG          0x00  //配置寄存器地址                             
#define EN_AA           0x01  //使能自动应答功能 
#define EN_RXADDR       0x02  //接收地址允许
#define SETUP_AW        0x03  //设置地址宽度(所有数据通道)
#define SETUP_RETR      0x04  //建立自动重发
#define RF_CH           0x05  //RF通道
#define RF_SETUP        0x06  //RF寄存器
#define STATUS          0x07  //状态寄存器
#define OBSERVE_TX      0x08  // 发送检测寄存器
#define RPD             0x09  // 载波检测寄存器
#define RX_ADDR_P0      0x0A  // 数据通道0接收地址
#define RX_ADDR_P1      0x0B  // 数据通道1接收地址
#define RX_ADDR_P2      0x0C  // 数据通道2接收地址
#define RX_ADDR_P3      0x0D  // 数据通道3接收地址
#define RX_ADDR_P4      0x0E  // 数据通道4接收地址
#define RX_ADDR_P5      0x0F  // 数据通道5接收地址
#define TX_ADDR         0x10  // 发送地址寄存器
#define RX_PW_P0        0x11  // 接收数据通道0有效数据宽度(1~32字节) 
#define RX_PW_P1        0x12  // 接收数据通道1有效数据宽度(1~32字节) 
#define RX_PW_P2        0x13  // 接收数据通道2有效数据宽度(1~32字节) 
#define RX_PW_P3        0x14  // 接收数据通道3有效数据宽度(1~32字节) 
#define RX_PW_P4        0x15  // 接收数据通道4有效数据宽度(1~32字节)
#define RX_PW_P5        0x16  // 接收数据通道5有效数据宽度(1~32字节)
#define FIFO_STATUS     0x17  // FIFO状态寄存器
/*——————————————————————————————————————————————————*/

/******  STATUS寄存器中断bit位定义  *******/
#define MAX_TX  	0x10  	  //达到最大发送次数中断
#define TX_OK   	0x20  	  //TX发送完成中断
#define RX_OK   	0x40  	  //接收到数据中断
/*——————————————————————————————————————————————————*/

/*********  24L01发送接收数据宽度定义	  ***********/
#define TX_ADR_WIDTH    5     //5字节地址宽度
#define RX_ADR_WIDTH    5     //5字节地址宽度
#define TX_PLOAD_WIDTH  32    //32字节有效数据宽度
#define RX_PLOAD_WIDTH  32    //32字节有效数据宽度

/* NRF24L01端口定义 */
#define NRF24L01_PWR_gpio        C
#define NRF24L01_PWR_pin         10
#define NRF24L01_PWR_gpio_mode   Out_PP
#define NRF24L01_PWR			 PCout(NRF24L01_PWR_pin)
#define NRF24L01_IRQ_gpio        A
#define NRF24L01_IRQ_pin         8
#define NRF24L01_IRQ_gpio_mode   IPU
#define NRF24L01_IRQ   			 PAin(NRF24L01_IRQ_pin)

#define NRF24L01_CE_gpio         B
#define NRF24L01_CE_pin          11
#define NRF24L01_CE_gpio_mode    Out_PP
#define NRF24L01_CE   			 PBout(NRF24L01_CE_pin)

#define NRF24L01_CSN_gpio        B
#define NRF24L01_CSN_pin         12
#define NRF24L01_CSN_gpio_mode   Out_PP
#define NRF24L01_CSN   			 PBout(NRF24L01_CSN_pin)

#define NRF24L01_SCK_gpio        B
#define NRF24L01_SCK_pin         13
#define NRF24L01_SCK_gpio_mode   Out_PP
#define NRF24L01_SCK   			 PBout(NRF24L01_SCK_pin)

#define NRF24L01_MISO_gpio       B
#define NRF24L01_MISO_pin        14
#define NRF24L01_MISO_gpio_mode  IPU
#define NRF24L01_MISO  			 PBin(NRF24L01_MISO_pin)

#define NRF24L01_MOSI_gpio       B
#define NRF24L01_MOSI_pin        15
#define NRF24L01_MOSI_gpio_mode  Out_PP
#define NRF24L01_MOSI  			 PBout(NRF24L01_MOSI_pin)

/* 变量 */
u8 TX_ADDRESS[TX_ADR_WIDTH] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; //发送地址
u8 RX_ADDRESS[RX_ADR_WIDTH] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; //接收地址
u8 NRF24L01_Recv_buf[32];//第一个字节为数据包长度,且不包含第一个字节
u8 NRF24L01_Send_buf[32];

/* 函数 */
u8   SPI_RW(u8  byte);
u8   NRF24L01_Write_Reg(u8  reg, u8  value);
u8   NRF24L01_Read_Reg(u8  reg);
u8   NRF24L01_Read_Buf(u8  reg, u8  *pBuf, u8  len);
u8   NRF24L01_Write_Buf(u8  reg, u8  *pBuf, u8  len);
u8   NRF24L01_RxPacket(u8  *rxbuf);
u8   NRF24L01_TxPacket(u8  *txbuf);
u8   NRF24L01_Check(void);
void NRF24L01_RT_Init(void);
void NRF24L01_SEND_BUF(u8 *buf);
void NRF24L01_Init(void);
void NRF24L01_Receive(void);
void NRF24L01_Send_online(void);

#endif

源文件 24L01.c

#include "24L01.h"
#include "gpio.h"
#include "flash.h"
#include "delay.h"
#include "24L01_app.h"

/**
	*	@name		  SPI_RW
	*	@brief		发送寄存器地址,并读取状态值
	*	@param		byte 需要发送的1byte数据
	*	@retval		接收到从机返回的数据
	*/
u8 SPI_RW(u8 byte)
{
    u8 bit_ctr;
    for(bit_ctr = 0; bit_ctr < 8; bit_ctr++) // 输出8位
    {
        if((u8)(byte & 0x80) == 0x80)
        {
            NRF24L01_MOSI = 1;    // MSB TO MOSI
        }
        else
        {
            NRF24L01_MOSI = 0;
        }
        byte = (byte << 1);					 // shift next bit to MSB
        NRF24L01_SCK = 1;
        byte |= NRF24L01_MISO;	     // capture current MISO bit
        NRF24L01_SCK = 0;
    }
    return byte;
}

/*********************************************/
/* 函数功能:给24L01的寄存器写值(一个字节) */
/* 入口参数:reg   要写的寄存器地址          */
/*           value 给寄存器写的值            */
/* 出口参数:status 状态值                   */
/*********************************************/
u8 NRF24L01_Write_Reg(u8 reg, u8 value)
{
    u8 status;
    NRF24L01_CE = 0;
	NRF24L01_CSN = 0;                //CSN=0,选择从机,开始发送
    status = SPI_RW(reg);		//发送寄存器地址,并读取状态值
    SPI_RW(value);
    NRF24L01_CSN = 1;                //CSN=1;
    return status;
}

/*************************************************/
/* 函数功能:读24L01的寄存器值 (一个字节)      */
/* 入口参数:reg  要读的寄存器地址               */
/* 出口参数:value 读出寄存器的值                */
/*************************************************/
u8 NRF24L01_Read_Reg(u8 reg)
{
    u8 value;
    NRF24L01_CSN = 0;            //CSN=0;
    SPI_RW(reg);			//发送寄存器值(位置),并读取状态值
    value = SPI_RW(NOP);
    NRF24L01_CSN = 1;            //CSN=1;
    return value;
}

/*********************************************/
/* 函数功能:读24L01的寄存器值(多个字节)   */
/* 入口参数:reg   寄存器地址                */
/*           *pBuf 读出寄存器值的存放数组    */
/*           len   数组字节长度              */
/* 出口参数:status 状态值                   */
/*********************************************/
u8 NRF24L01_Read_Buf(u8 reg, u8 *pBuf, u8 len)
{
    u8 status, u8_ctr;
    NRF24L01_CSN = 0;                   			//CSN=0
    status = SPI_RW(reg);					//发送寄存器地址,并读取状态值
    for(u8_ctr = 0; u8_ctr < len; u8_ctr++)
    {
        pBuf[u8_ctr] = SPI_RW(NOP);    //读出数据
    }
    NRF24L01_CSN = 1;                 			//CSN=1
    return status;        					//返回读到的状态值
}

/**********************************************/
/* 函数功能:给24L01的寄存器写值(多个字节)  */
/* 入口参数:reg  要写的寄存器地址            */
/*           *pBuf 值的存放数组               */
/*           len   数组字节长度               */
/**********************************************/
u8 NRF24L01_Write_Buf(u8 reg, u8 *pBuf, u8 len)
{
    u8 status, u8_ctr;
    NRF24L01_CSN = 0;
    status = SPI_RW(reg);					//发送寄存器值(位置),并读取状态值
    for(u8_ctr = 0; u8_ctr < len; u8_ctr++)
    {
        SPI_RW(*pBuf++);    //写入数据
    }
    NRF24L01_CSN = 1;
    return status;          				//返回读到的状态值
}

/*********************************************/
/* 函数功能:24L01接收一个数据包             */
/* 入口参数:rxbuf 接收数据数组              */
/* 返回值: 0   成功收到数据                 */
/*          1   没有收到数据                 */
/*********************************************/
u8 NRF24L01_RxPacket(u8 *rxbuf)
{
    u8 state;
    state = NRF24L01_Read_Reg(nRF_READ_REG + STATUS);  			//读取状态寄存器的值
    NRF24L01_Write_Reg(nRF_WRITE_REG + STATUS, state);  		//清除TX_DS或MAX_RT中断标志
    if(state & RX_OK)											//接收到数据
    {
        NRF24L01_CE = 0;
        NRF24L01_Read_Buf(RD_RX_PLOAD, rxbuf, RX_PLOAD_WIDTH); 	//读取数据
        NRF24L01_Write_Reg(FLUSH_RX, 0xff);						//清除RX FIFO寄存器
        NRF24L01_CE = 1;
        rt_thread_delay(1);
        return 0;
    }
    return 1;//没收到任何数据
}

/**********************************************/
/* 函数功能:24L01发送一个数据包              */
/* 入口参数:txbuf  发送数据数组              */
/* 返回值; 0x10    达到最大重发次数,发送失败*/
/*          0x20    成功发送完成              */
/*          0xff    发送失败                  */
/**********************************************/
u8 NRF24L01_TxPacket(u8 *txbuf)
{
    u8 state;
    NRF24L01_CE = 0;											//CE拉低,使能24L01配置
    NRF24L01_Write_Buf(WR_TX_PLOAD, txbuf, TX_PLOAD_WIDTH);		//写数据到TX BUF  32个字节
    NRF24L01_CE = 1;											//CE置高,使能发送
    while(NRF24L01_IRQ == 1);									//等待发送完成
    state = NRF24L01_Read_Reg(nRF_READ_REG + STATUS);  			//读取状态寄存器的值
    NRF24L01_Write_Reg(nRF_WRITE_REG + STATUS, state); 			//清除TX_DS或MAX_RT中断标志
    if(state & MAX_TX)											//达到最大重发次数
    {
        NRF24L01_Write_Reg(FLUSH_TX, 0xff);						//清除TX FIFO寄存器
        return MAX_TX; //配对失败返回值
    }
    if(state & TX_OK)											//发送完成
    {
        NRF->pair_ACK = 1;
        return TX_OK; //配对成功返回值
    }
    return 0xff;												//发送失败
}

/********************************************/
/* 函数功能:检测24L01是否存在              */
/* 返回值;  0  存在                        */
/*           1  不存在                      */
/********************************************/
u8 NRF24L01_Check(void)
{
    u8 check_in_buf[5] = {0x11, 0x22, 0x33, 0x44, 0x55};
    u8 check_out_buf[5] = {0x00};
    NRF24L01_SCK = 0;
    NRF24L01_CSN = 1;
    NRF24L01_CE = 0;
    NRF24L01_Write_Buf(nRF_WRITE_REG + TX_ADDR, check_in_buf, 5);
    NRF24L01_Read_Buf(nRF_READ_REG + TX_ADDR, check_out_buf, 5);
    if((check_out_buf[0] == 0x11) && \
            (check_out_buf[1] == 0x22) && \
            (check_out_buf[2] == 0x33) && \
            (check_out_buf[3] == 0x44) && \
            (check_out_buf[4] == 0x55)) { return 0; }
    else { return 1; }
}

/**
	*	@name		NRF24L01_RT_Init
	*	@brief
	*	@param		None
	*	@retval		None
	*/
void NRF24L01_RT_Init(void)
{
	NRF24L01_CE = 0;
	NRF24L01_Write_Reg(nRF_WRITE_REG + CONFIG, 0x0f); 								//配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式,开启所有中断
	NRF24L01_Write_Reg(nRF_WRITE_REG + EN_AA, 0x01);  								//使能通道0的自动应答
	NRF24L01_Write_Reg(nRF_WRITE_REG + EN_RXADDR, 0x01); 							//使能通道0的接收地址
	NRF24L01_Write_Reg(nRF_WRITE_REG + SETUP_RETR, 0x1a); 							//设置自动重发间隔时间:500us + 86us;最大自动重发次数:10次
	NRF24L01_Write_Reg(nRF_WRITE_REG + RF_CH, NRF24L01_Channel);   					//设置RF通道为CHANAL
	NRF24L01_Write_Reg(nRF_WRITE_REG + RF_SETUP, 0x0f); 							//设置TX发射参数,2Mbps,0db增益,低噪声增益开启
	NRF24L01_Write_Buf(nRF_WRITE_REG + RX_ADDR_P0, (u8*)RX_ADDRESS, RX_ADR_WIDTH);	//设置TX节点地址,主要为了使能ACK
	NRF24L01_Write_Buf(nRF_WRITE_REG + TX_ADDR, (u8*)TX_ADDRESS, TX_ADR_WIDTH); 	//写TX节点地址
	NRF24L01_Write_Reg(nRF_WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH); 					//选择通道0的有效数据宽度	
	NRF24L01_Write_Reg(FLUSH_RX, 0xff);												//清除RX FIFO寄存器
	NRF24L01_CE = 1; 																//CE置高,使能发送
}

/**
	*	@name		NRF24L01_SEND_BUF
	*	@brief	2.4G发送数据
	*	@param	buf:数组
	*	@retval	NONE
	*/
void NRF24L01_SEND_BUF(u8 *buf)
{
	NRF24L01_CE = 0;
	NRF24L01_Write_Reg(nRF_WRITE_REG + CONFIG, 0x0e);	//发射模式
	NRF24L01_CE = 1;
	rt_thread_delay(1);
	NRF24L01_TxPacket(buf);	//发送一个数据包
	NRF24L01_CE = 0;
	NRF24L01_Write_Reg(nRF_WRITE_REG + CONFIG, 0x0f);	//接收模式
	NRF24L01_CE = 1;
}

/**
	*	@name		NVIC_Configuration_24l01中断初始化
	*	@brief
	*	@param		None
	*	@retval		None
	*/
static void NVIC_Configuration_24l01(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;

#ifdef  VECT_TAB_RAM
    /* Set the Vector Table base location at 0x20000000 */
    NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else  /* VECT_TAB_FLASH  */
    /* Set the Vector Table base location at 0x08000000 */
    NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif

    /* Configure one bit for preemption priority */
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
    /* Enable the EXTI0 Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

/**
	*	@name		SPI_GPIO_Init
	*	@brief		24l01端口初始化
	*	@param		None
	*	@retval		None
	*/
static void SPI_GPIO_Init(void)
{
	GPIO_Pin_Setup(NRF24L01_PWR_gpio,  NRF24L01_PWR_pin,  NRF24L01_PWR_gpio_mode);	//供电引脚
	GPIO_Pin_Setup(NRF24L01_IRQ_gpio,  NRF24L01_IRQ_pin,  NRF24L01_IRQ_gpio_mode);	//中断引脚
    GPIO_Pin_Setup(NRF24L01_CE_gpio,   NRF24L01_CE_pin,   NRF24L01_CE_gpio_mode);	//模式选择引脚
    GPIO_Pin_Setup(NRF24L01_CSN_gpio,  NRF24L01_CSN_pin,  NRF24L01_CSN_gpio_mode);	//片选引脚
    GPIO_Pin_Setup(NRF24L01_SCK_gpio,  NRF24L01_SCK_pin,  NRF24L01_SCK_gpio_mode);	//时钟信号引脚
	GPIO_Pin_Setup(NRF24L01_MISO_gpio, NRF24L01_MISO_pin, NRF24L01_MISO_gpio_mode);	//数据输入引脚
    GPIO_Pin_Setup(NRF24L01_MOSI_gpio, NRF24L01_MOSI_pin, NRF24L01_MOSI_gpio_mode);	//数据输出引脚
	NVIC_Configuration_24l01();	//中断配置
}

/**
	*	@name		NRF24L01_Init
	*	@brief		2.4G初始化
	*	@param		None
	*	@retval		None
	*/
void NRF24L01_Init(void)
{
    SPI_GPIO_Init();
    NRF24L01_CE = 1;
    NRF24L01_CSN = 1;
    NRF24L01_SCK = 1;
    NRF24L01_MOSI = 1;
    NRF24L01_PWR(1);
    while(NRF24L01_Check())	//等待检测到NRF24L01,程序才会向下执行
    {
		rt_thread_delay(1);
    }
    NRF24L01_RT_Init();
}

  底层驱动完成,配置为接收模式。此处往下皆为接收应用代码,做了地址配对,只有参考性。

24L01_app.h

#define static_addr 	0   				//修改TX_ADDRESS_static
#define dynamic_addr 	1						//由CPUID生成的动态地址
#define NRF24L01_pair_addr	dynamic_addr  	//2.4G地址模式

int NRF24l01_thread_create(u16 stack, u8 priority, u8 delay);

24L01_app.c,此部分为rtthread的线程

#include "sys.h"
#include "24L01.h"
#include "gpio.h"
#include "flash.h"
#include "delay.h"
#include "24L01_app.h"

u8 pair_flag_clear = 0;
u8 pair_flag = 0;
/**
	*	@name		NRF24l01_dynamic_thread_entry
	*	@brief	2.4G无线通信
	*	@param	None
	*	@retval	None
	*/
static void NRF24l01_dynamic_thread_entry(void* parameter)
{
    u8 i;
    static u8 addrset_flash_wipe_once = 0;
    rt_lock(1);
    NRF24L01_Init();	//模块初始化
    NRF24L01_pairFlag_Read();
    NRF24L01_Addr_Init();	//地址初始化,地址部分是为了识别不同设备的数据帧(自定义)
    rt_lock(0);
    while (1)
    {
       /* NRF24L01无线模块接收到数据 */
       if(NRF24L01_IRQ == 0)
       {
          if(NRF24L01_RxPacket(NRF24L01_Recv_buf) == 0)
          {
            if(....)
            {
              /*此处为接收数据处理代码*/
            }
            //地址配对,地址部分是为了识别不同设备的数据帧(自定义)
            else if((NRF24L01_Recv_buf[1] == 0xAA) && (NRF24L01_Recv_buf[2] == 0xBB)) //地址配对
            {
               pair_flag = 1;
               flashDataWrite[0] = 1;
               for(i = 0; i < 6; i++)
               {
                   flashDataWrite[i + 1] = NRF24L01_Recv_buf[i + 3];
               }
               //写入flash
               if(addrset_flash_wipe_once == 0)
               {
                  addrset_flash_wipe_once = 1;    
#if NRF24L01_pair_addr == dynamic_addr
			      rt_lock(1);
			      Flash_Write(0, flashDataWrite, sizeof(flashDataWrite));
			      rt_lock(0);
			      softReset();
#endif
               }
            }
          }
       }
       else
       {
          /* 接收不到数据动作 */
       }
       NRF24L01_addr_config();
       rt_thread_delay(10);
    }
}
/**
	*	@name		NRF24l01_thread_create
	*	@brief  线程初始化
	*	@param	(stack, priority, delay)
	*	@retval	None
	*/
int NRF24l01_thread_create(u16 stack, u8 priority, u8 tick)
{
    rt_err_t result;
    /* 动态线程 控制块指针 */
    rt_thread_t NRF24l01_thread;
    /* 创建动态线程 */
    NRF24l01_thread = rt_thread_create("NRF24l01_thread",
                                       NRF24l01_dynamic_thread_entry, RT_NULL,
                                       stack, priority, tick);
    if (NRF24l01_thread != RT_NULL)
    {
        rt_thread_startup(NRF24l01_thread);
    }	
    return 0;
}
/**
	*	@name		NRF24L01_Addr_Init
	*	@brief	NRF24l01地址初始化
	*	@param	None
	*	@retval	None
	*/
void NRF24L01_Addr_Init(void)
{
    static u8 i;
/* 动态通讯地址 */
#if NRF24L01_pair_addr == dynamic_addr
    /* 如果配对过,使用配对地址 */
    if(pair_flag == 1)
    {
        TX_ADDRESS[0] = flashDataRead[1];
        TX_ADDRESS[1] = flashDataRead[2];
        TX_ADDRESS[2] = flashDataRead[3];
        TX_ADDRESS[3] = flashDataRead[4];
        TX_ADDRESS[4] = flashDataRead[5];
    }
    else
    {
        TX_ADDRESS[0] = 0xFF;
        TX_ADDRESS[1] = 0xFF;
        TX_ADDRESS[2] = 0xFF;
        TX_ADDRESS[3] = 0xFF;
        TX_ADDRESS[4] = 0xFF;
    }

    for(i = 0; i < TX_ADR_WIDTH; i++)
    {
        RX_ADDRESS[i] = TX_ADDRESS[i];
    }
/**
	*	@name		NRF24L01_addr_config
	*	@brief		NRF24l01地址
	*	@param		None
	*	@retval		None
	*/
void NRF24L01_addr_config(void)
{
#if NRF24L01_pair_addr == dynamic_addr
    /* 加长按按键:NRF24L01地址恢复出厂设置全FF */
    if(pair_flag_clear == 1)//pair_flag_clear由其他线程赋值
    {
        pair_flag == 0;
        pair_flag_clear = 0;
        rt_lock(1);
        flashDataWrite[0] = 0;
        Flash_Write(0, flashDataWrite, sizeof(flashDataWrite)); //擦除flash
        rt_lock(0);
        softReset();
    }
#endif
}
/*****************下面是自定义的地址配对的数据帧样式*****************/
/**
	*	@name		NRF24L01_Send_dynamicCommunicationAddress
	*	@brief		NRF24L01发送动态地址
	*	@param		None
	*	@retval		None
	*/
void NRF24L01_Send_dynamicCommunicationAddress(void)
{
    DataLength = 0x08;
    NRF24L01_Send_buf[0] = DataLength;//数据长度
    NRF24L01_Send_buf[1] = Target_Addr;//目标地址
    NRF24L01_Send_buf[2] = Source_Addr;//源地址
    NRF24L01_Send_buf[3] = dynamicCommunicationAddress[0];
    NRF24L01_Send_buf[4] = dynamicCommunicationAddress[1];
    NRF24L01_Send_buf[5] = dynamicCommunicationAddress[2];
    NRF24L01_Send_buf[6] = dynamicCommunicationAddress[3];
    NRF24L01_Send_buf[7] = dynamicCommunicationAddress[4];
    if(pair_flag == 1)
    {
        NRF24L01_Send_buf[8] = 1;
    }
    else
    {
        NRF24L01_Send_buf[8] = 0;
    }
    NRF24L01_SEND_BUF(NRF24L01_Send_buf);
}
/**
	*	@name		Dynamic_Comm_Address
	*	@brief		根据Cpu_Id生成动态通讯地址
	*	@param		None
	*	@retval		None
	*/
u8 dynamicCommunicationAddress[5] = {0};
void Dynamic_Comm_Address(void)
{
    Cpu_Id_Get();
    dynamicCommunicationAddress[0] = (uint8_t)(Cpu_Id[0] & 0x000000FF);
    dynamicCommunicationAddress[1] = (uint8_t)(Cpu_Id[1] & 0x000000FF);
    dynamicCommunicationAddress[2] = (uint8_t)(Cpu_Id[2] & 0x000000FF);
    dynamicCommunicationAddress[3] = (uint8_t)(((Cpu_Id[0] & Cpu_Id[1]) & 0x000FF000) >> 12);
    dynamicCommunicationAddress[4] = (uint8_t)(((Cpu_Id[1] & Cpu_Id[2]) & 0x000FF000) >> 12);
}
/**
	*	@name		Cpu_Id_Get
	*	@brief		获取cpu的id
	*	@param		None
	*	@retval		成功或失败
	*/
u32 Cpu_Id[3] = {0};
void Cpu_Id_Get(void)
{
    Cpu_Id[0] = *(__IO u32*)(0x1FFFF7E8);
    Cpu_Id[1] = *(__IO u32*)(0x1FFFF7EC);
    Cpu_Id[2] = *(__IO u32*)(0x1FFFF7F0);
}
/**
	*	@name		NRF24L01_pairFlag_Read
	*	@brief  读取2.4G地址标志位,初始化时执行
	*	@param	None
	*	@retval	None
	*/
void NRF24L01_pairFlag_Read(void)
{
#if NRF24L01_pair_addr == dynamic_addr
    Flash_Read(0, flashDataRead, sizeof(flashDataRead));
    if(flashDataRead[0] == 1) //读取NRF24L01配对标志位
    {
       pair_flag = 1;
    }
#endif
}

头文件flash.h

#ifndef _flash_H_
#define _flash_H_

#include "stm32f10x_flash.h"

#define  STARTADDR  0x0807F800   //主存储器第255页首地址
//0x08007C00

/* 变量 */
extern  u8  flashDataWrite[6];
extern  u8  flashDataRead[6];

/* 函数 */
void Flash_Write(u32 WriteAddr, u8 *DataToWrite, u8 WriteNum);
void Flash_Read(u32 ReadAddr, u8*DataToRead, u8 ReadNum);

#endif

原文件flash.c

#include "flash.h"

/* 变量 */
volatile FLASH_Status FLASHStatus = FLASH_COMPLETE;
u8 flashDataWrite[6] = {0};//第1个字节为配对标志位,后5个字节为地址
u8 flashDataRead[6] = {0};
/**
*	@name		Flash_Write
*	@brief      向内部flash写入数据
*	@param		WriteAddr:写数据地址偏移量
*				DataToWrite:要写入的数据
*               num:写入数据个数
*	@retval		None*/
void Flash_Write(uint32_t WriteAddr, uint8_t *DataToWrite, uint8_t WriteNum) 
{
    uint32_t addr;
    uint8_t i;
    addr = (uint32_t)STARTADDR + WriteAddr;
    FLASH_Unlock();
    FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
    FLASH_ErasePage(addr);
    for(i = 0; i < WriteNum; i++)
    {
        FLASH_ProgramWord(addr, DataToWrite[i]);
        addr += 4;
    }
    FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
    FLASH_Lock();
}


/**
	*	@name		Flash_Read
	*	@brief      读内部flash的指定地址的N个字节
	*	@param		ReadAddr:指定地址
	*				DataToRead:数据存储指针
	*				ReadNum:读取字节数
	*	@retval		None
	*/
void Flash_Read(uint32_t ReadAddr, uint8_t *DataToRead, uint8_t ReadNum)
{
    uint8_t i;
    uint32_t addr;
    addr = (uint32_t)STARTADDR + ReadAddr;
    for(i = 0; i < ReadNum; i++)
    {
        DataToRead[i] = *(uint32_t*)(addr);
        addr += 4;
    }
}

总结

  此篇作为nRF24L01模块驱动,仅底层驱动有适用性,其他部分代码皆做参考,根据自己需求采用、编写。
  该模块通讯效果不是很好,且有国产型号SI24R1、SI24L01混入,用的时候收发模块不要混用,不然会出现莫名奇妙的问题。

你可能感兴趣的:(STM32系列,stm32,单片机,c语言)