【CW32模块使用】NRF24L01无线2.4G模块

NRF24L01是一款工作在2.4-2.5GHz世界通用ISM频段的单片收发芯片, 使用4线SPI通讯端口,通讯速率最高可达8Mbps,适合与各种MCU连接,编程简单;输出功率、频道选择和协议的设置可以通过SPI接口设置极低的电流消耗,当工作在发射模式下发射功率为6dBm时电流消耗为9.0mA接受模式为12.3mA掉电模式和待机模式下电流消耗模式更低。

一、模块来源

模块实物展示:


资料链接:https://pan.baidu.com/s/1CUQ3SOdnmD8xSXMdR4YopA
资料提取码:1234

二、规格参数

工作电压:1.9~3.6V

供电电流:900 ~ 12.3mA

最大数据传输率:2000 Kbps

控制方式:SPI

管脚数量:8 Pin(2.54mm间距排针)

以上信息见厂家资料文件

三、移植过程

我们的目标是将例程移植至CW32F030C8T6开发板上【实现无线的数据传输的功能】。首先要获取资料,查看数据手册应如何实现读取数据,再移植至我们的工程。

3.1查看资料

接收方式

NRF24L01的接收端是靠IRQ引脚进行判断,当IRQ为高电平时,说明接收到了数据,IRQ为1则是正在等待数据。因此可以根据IRQ引脚来决定接收的方式。这里提供轮询方式和中断方式。

轮询方式接收

采用轮询方式会阻碍其他任务的运行,因接收数据要时时刻刻判断IRQ引脚是否为高电平,会一直占用MCU的时间。为了解决因为没有接收到数据就卡死问题以及防止错过数据没有接收问题,在等待数据的过程中,加入了超时判断,当一定的时间内没有接收到数据,则结束等待接收,去运行其他任务。

中断方式接收

采用中断方式接收数据,是通过将IRQ引脚设置为外部中断功能。当检测到IRQ引脚有变化时,则接收数据。根据24L01的要求,当接收完数据后,必须清除接收的FIFO。

3.2引脚选择

引脚说明

硬件SPI与软件SPI相比,硬件SPI是靠硬件上面的SPI控制器,所有的时钟边缘采样,时钟发生,还有时序控制,都是由硬件完成的。它降低了CPU的使用率,提高了运行速度。软件SPI就是用代码控制IO输出高低电平,模拟SPI的时序,这种方法通信速度较慢,且不可靠。

想要使用硬件SPI驱动,需要确定使用的引脚是否有SPI外设功能。可以通过用户手册146页进行查看。

当前使用的是硬件SPI接口,而NRF24L01我们需要与它发送数据也需要接收数据,故使用的是4线的SPI,使用到了时钟线SCK、主机输出从机输入线MOSI、主机输入从机输出线MISO和软件控制的片选线NSS。所以除了这些引脚需要使用硬件SPI功能的引脚外,其他引脚都可以使用开发板上其他的GPIO。这里选择使用PA5/PA6/PA7的SPI复用功能 。其他对应接入的引脚请按照你的需要。这里选择的引脚见右表。

有SPI功能的引脚

模块接线图

3.3移植至工程

移植步骤中的导入.c和.h文件与【CW32模块使用】DHT11温湿度传感器相同,只是将.c和.h文件更改为drv_spi.c与drv_spi.h。这里不再过多讲述,移植完成后面修改相关代码。

在drv_spi.c中,修改为如下代码。

/*
 * Change Logs:
 * Date           Author       Notes
 * 2024-06-21     LCKFB-LP    first version
 */

#include "drv_spi.h"



/** 硬件SPI */
#define SPI_WAIT_TIMEOUT       ((uint16_t)0xFFFF)

/**
  * @brief :SPI初始化(硬件)
  * @param :无
  * @note  :无
  * @retval:无
  */
void drv_spi_init( void )
{
        GPIO_InitTypeDef GPIO_InitStruct1;             // GPIO初始化结构体
        GPIO_InitTypeDef GPIO_InitStruct2;             // GPIO初始化结构体

        SPI_GPIO_RCC();                                // 使能GPIO时钟
        RCC_SPI_HARDWARE_ENABLE();                     // 使能SPI1时钟

        // GPIO复用为SPI1
        BSP_SPI_AF_SCK();
        BSP_SPI_AF_MISO();
        BSP_SPI_AF_MOSI();

        GPIO_InitStruct1.Pins = SPI_NSS_GPIO_PIN|
                                                        SPI_CLK_GPIO_PIN|
                                                        SPI_MOSI_GPIO_PIN;      // GPIO引脚
        GPIO_InitStruct1.Mode = GPIO_MODE_OUTPUT_PP;    // 推挽输出
        GPIO_InitStruct1.Speed = GPIO_SPEED_HIGH;       // 输出速度高
        GPIO_Init(SPI_GPIO_PORT, &GPIO_InitStruct1);    // 初始化

        GPIO_InitStruct2.Pins = SPI_MISO_GPIO_PIN;      // GPIO引脚
        GPIO_InitStruct2.Mode = GPIO_MODE_INPUT_PULLUP; // 上拉输入
        GPIO_Init(SPI_GPIO_PORT, &GPIO_InitStruct2);    // 初始化

        spi_set_nss_high();  // 片选拉高

        SPI_InitTypeDef  SPI_InitStructure; // SPI 初始化结构体

        SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;    // 双线全双工
        SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                         // 主机模式
        SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                     // 帧数据长度为8bit
        SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;                            // 时钟空闲电平为低
        SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;                          // 第1个边沿采样
        SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                             // 片选信号由SSI寄存器控制
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;    // 波特率为PCLK的8分频
        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;                    // 最高有效位 MSB 收发在前
        SPI_InitStructure.SPI_Speed = SPI_Speed_Low;                          // 低速SPI

        SPI_Init(PORT_SPI, &SPI_InitStructure);   // 初始化
        SPI_Cmd(PORT_SPI, ENABLE);   // 使能SPI1
}

/**
  * @brief :SPI收发一个字节
  * @param :
  * @TxByte: 发送的数据字节
  * @note  :非堵塞式,一旦等待超时,函数会自动退出
  * @retval:接收到的字节
  */
uint16_t drv_spi_read_write_byte( uint8_t TxByte )
{
        uint16_t l_Data = 0;
        uint16_t l_WaitTime = 0;

    while(RESET == SPI_GetFlagStatus(PORT_SPI, SPI_FLAG_TXE))//等待发送缓冲区为空
        {
                if( SPI_WAIT_TIMEOUT == ++l_WaitTime )
                {
                        break;                        //如果等待超时则退出
                }
        }
        l_WaitTime = SPI_WAIT_TIMEOUT / 2;                //重新设置接收等待时间(因为SPI的速度很快,正常情况下在发送完成之后会立即收到数据,等待时间不需要过长)
        SPI_SendData(PORT_SPI, TxByte);//发送数据

    while(RESET == SPI_GetFlagStatus(PORT_SPI, SPI_FLAG_RXNE))//等待接收缓冲区非空
        {
                if( SPI_WAIT_TIMEOUT == ++l_WaitTime )
                {
                                break;                        //如果等待超时则退出
                }
        }
    l_Data = SPI_ReceiveData(PORT_SPI);//读取接收数据

        return l_Data;                //返回
}

/**
  * @brief :SPI收发字符串
  * @param :
  * @ReadBuffer: 接收数据缓冲区地址
  * @WriteBuffer:发送字节缓冲区地址
  * @Length:字节长度
  * @note  :非堵塞式,一旦等待超时,函数会自动退出
  * @retval:无
  */
void drv_spi_read_write_string( uint8_t* ReadBuffer, uint8_t* WriteBuffer, uint16_t Length )
{
    spi_set_nss_low( );//拉低片选
        while( Length-- )
        {
                *ReadBuffer = drv_spi_read_write_byte( *WriteBuffer ); //收发数据
                ReadBuffer++;
                WriteBuffer++;                                //读写地址加1
        }
    spi_set_nss_high( );//拉高片选
}

在drv_spi.h中,修改为如下代码。

/*
 * Change Logs:
 * Date           Author       Notes
 * 2024-06-21     LCKFB-LP    first version
 */

#ifndef __DRV_SPI_H__
#define __DRV_SPI_H__

#include "board.h"


//SPI引脚定义
#define SPI_GPIO_RCC()           __RCC_GPIOA_CLK_ENABLE() // GPIO时钟

#define SPI_GPIO_PORT            CW_GPIOA

#define SPI_CLK_GPIO_PIN         GPIO_PIN_5
#define SPI_MISO_GPIO_PIN        GPIO_PIN_6
#define SPI_MOSI_GPIO_PIN        GPIO_PIN_7
#define SPI_NSS_GPIO_PIN         GPIO_PIN_4


#define spi_set_nss_high( )      GPIO_WritePin(SPI_GPIO_PORT, SPI_NSS_GPIO_PIN, GPIO_Pin_SET)   //片选置高
#define spi_set_nss_low( )       GPIO_WritePin(SPI_GPIO_PORT, SPI_NSS_GPIO_PIN, GPIO_Pin_RESET) //片选置低



/******** 硬件SPI修改此次 ********/
#define RCC_SPI_HARDWARE_ENABLE()         __RCC_SPI1_CLK_ENABLE()
#define PORT_SPI                          CW_SPI1

//GPIO AF
#define BSP_SPI_AF_SCK()                  PA05_AFx_SPI1SCK()
#define BSP_SPI_AF_MISO()                 PA06_AFx_SPI1MISO()
#define BSP_SPI_AF_MOSI()                 PA07_AFx_SPI1MOSI()


void drv_spi_init( void );
uint16_t drv_spi_read_write_byte( uint8_t TxByte );
void drv_spi_read_write_string( uint8_t* ReadBuffer, uint8_t* WriteBuffer, uint16_t Length );

#endif

在NRF24L01.c中,修改如下代码。

/*
 * Change Logs:
 * Date           Author       Notes
 * 2024-06-21     LCKFB-LP    first version
 */

#include "NRF24L01.h"
#include "stdio.h"


const char *g_ErrorString = "RF24L01 is not find !...";


void drv_delay_500Ms( unsigned int ms)
{
        while(ms--)
        {
                delay_ms(500);
        }
}

/**
  * @brief :NRF24L01读寄存器
  * @param :
           @Addr:寄存器地址
  * @note  :地址在设备中有效
  * @retval:读取的数据
  */
uint8_t NRF24L01_Read_Reg( uint8_t RegAddr )
{
    uint8_t btmp;

    RF24L01_SET_CS_LOW( );       //片选

    drv_spi_read_write_byte( NRF_READ_REG | RegAddr );    //读命令 地址
    btmp = drv_spi_read_write_byte( 0xFF );               //读数据

    RF24L01_SET_CS_HIGH( );      //取消片选

    return btmp;
}

/**
  * @brief :NRF24L01读指定长度的数据
  * @param :
  *                        @reg:地址
  *                        @pBuf:数据存放地址
  *                        @len:数据长度
  * @note  :数据长度不超过255,地址在设备中有效
  * @retval:读取状态
  */
void NRF24L01_Read_Buf( uint8_t RegAddr, uint8_t *pBuf, uint8_t len )
{
    uint8_t btmp;

    RF24L01_SET_CS_LOW( );                        //片选

    drv_spi_read_write_byte( NRF_READ_REG | RegAddr );        //读命令 地址
    for( btmp = 0; btmp < len; btmp ++ )
    {
        *( pBuf + btmp ) = drv_spi_read_write_byte( 0xFF );        //读数据
    }
    RF24L01_SET_CS_HIGH( );                //取消片选
}

/**
  * @brief :NRF24L01写寄存器
  * @param :无
  * @note  :地址在设备中有效
  * @retval:读写状态
  */
void NRF24L01_Write_Reg( uint8_t RegAddr, uint8_t Value )
{
    RF24L01_SET_CS_LOW( );                //片选

    drv_spi_read_write_byte( NRF_WRITE_REG | RegAddr );        //写命令 地址
    drv_spi_read_write_byte( Value );                        //写数据

    RF24L01_SET_CS_HIGH( );                //取消片选
}

/**
  * @brief :NRF24L01写指定长度的数据
  * @param :
  *                        @reg:地址
  *                        @pBuf:写入的数据地址
  *                        @len:数据长度
  * @note  :数据长度不超过255,地址在设备中有效
  * @retval:写状态
  */
void NRF24L01_Write_Buf( uint8_t RegAddr, uint8_t *pBuf, uint8_t len )
{
    uint8_t i;

    RF24L01_SET_CS_LOW( );                //片选

    drv_spi_read_write_byte( NRF_WRITE_REG | RegAddr );        //写命令 地址
    for( i = 0; i < len; i ++ )
    {
        drv_spi_read_write_byte( *( pBuf + i ) );                //写数据
    }

    RF24L01_SET_CS_HIGH( );                //取消片选
}

/**
  * @brief :清空TX缓冲区
  * @param :无
  * @note  :无
  * @retval:无
  */
void NRF24L01_Flush_Tx_Fifo ( void )
{
    RF24L01_SET_CS_LOW( );                //片选

    drv_spi_read_write_byte( FLUSH_TX );        //清TX FIFO命令

    RF24L01_SET_CS_HIGH( );                //取消片选
}

/**
  * @brief :清空RX缓冲区
  * @param :无
  * @note  :无
  * @retval:无
  */
void NRF24L01_Flush_Rx_Fifo( void )
{
    RF24L01_SET_CS_LOW( );                //片选

    drv_spi_read_write_byte( FLUSH_RX );        //清RX FIFO命令

    RF24L01_SET_CS_HIGH( );                //取消片选
}

/**
  * @brief :重新使用上一包数据
  * @param :无
  * @note  :无
  * @retval:无
  */
void NRF24L01_Reuse_Tx_Payload( void )
{
    RF24L01_SET_CS_LOW( );                //片选

    drv_spi_read_write_byte( REUSE_TX_PL );                //重新使用上一包命令

    RF24L01_SET_CS_HIGH( );                //取消片选
}

/**
  * @brief :NRF24L01空操作
  * @param :无
  * @note  :无
  * @retval:无
  */
void NRF24L01_Nop( void )
{
    RF24L01_SET_CS_LOW( );                //片选

    drv_spi_read_write_byte( NOP );                //空操作命令

    RF24L01_SET_CS_HIGH( );                //取消片选
}

/**
  * @brief :NRF24L01读状态寄存器
  * @param :无
  * @note  :无
  * @retval:RF24L01状态
  */
uint8_t NRF24L01_Read_Status_Register( void )
{
    uint8_t Status;

    RF24L01_SET_CS_LOW( );                //片选

    Status = drv_spi_read_write_byte( NRF_READ_REG + STATUS );        //读状态寄存器

    RF24L01_SET_CS_HIGH( );                //取消片选

    return Status;
}

/**
  * @brief :NRF24L01清中断
  * @param :
           @IRQ_Source:中断源
  * @note  :无
  * @retval:清除后状态寄存器的值
  */
uint8_t NRF24L01_Clear_IRQ_Flag( uint8_t IRQ_Source )
{
    uint8_t btmp = 0;

    IRQ_Source &= ( 1 << RX_DR ) | ( 1 << TX_DS ) | ( 1 << MAX_RT );        //中断标志处理
    btmp = NRF24L01_Read_Status_Register( );                        //读状态寄存器

    RF24L01_SET_CS_LOW( );                        //片选
    drv_spi_read_write_byte( NRF_WRITE_REG + STATUS );        //写状态寄存器命令
    drv_spi_read_write_byte( IRQ_Source | btmp );                //清相应中断标志
    RF24L01_SET_CS_HIGH( );                        //取消片选

    return ( NRF24L01_Read_Status_Register( ));                        //返回状态寄存器状态
}

/**
  * @brief :读RF24L01中断状态
  * @param :无
  * @note  :无
  * @retval:中断状态
  */
uint8_t RF24L01_Read_IRQ_Status( void )
{
    return ( NRF24L01_Read_Status_Register( ) & (( 1 << RX_DR ) | ( 1 << TX_DS ) | ( 1 << MAX_RT )));        //返回中断状态
}

 /**
  * @brief :读FIFO中数据宽度
  * @param :无
  * @note  :无
  * @retval:数据宽度
  */
uint8_t NRF24L01_Read_Top_Fifo_Width( void )
{
    uint8_t btmp;

    RF24L01_SET_CS_LOW( );                //片选

    drv_spi_read_write_byte( R_RX_PL_WID );        //读FIFO中数据宽度命令
    btmp = drv_spi_read_write_byte( 0xFF );        //读数据

    RF24L01_SET_CS_HIGH( );                //取消片选

    return btmp;
}

 /**
  * @brief :读接收到的数据
  * @param :无
  * @note  :无
  * @retval:
           @pRxBuf:数据存放地址首地址
  */
uint8_t NRF24L01_Read_Rx_Payload( uint8_t *pRxBuf )
{
    uint8_t Width, PipeNum;

    PipeNum = ( NRF24L01_Read_Reg( STATUS ) >> 1 ) & 0x07;        //读接收状态
    Width = NRF24L01_Read_Top_Fifo_Width( );                //读接收数据个数

    RF24L01_SET_CS_LOW( );                //片选
    drv_spi_read_write_byte( RD_RX_PLOAD );                        //读有效数据命令

    for( PipeNum = 0; PipeNum < Width; PipeNum ++ )
    {
        *( pRxBuf + PipeNum ) = drv_spi_read_write_byte( 0xFF );                //读数据
    }
    RF24L01_SET_CS_HIGH( );                //取消片选
    NRF24L01_Flush_Rx_Fifo( );        //清空RX FIFO

    return Width;
}

 /**
  * @brief :发送数据(带应答)
  * @param :
  *                        @pTxBuf:发送数据地址
  *                        @len:长度
  * @note  :一次不超过32个字节
  * @retval:无
  */
void NRF24L01_Write_Tx_Payload_Ack( uint8_t *pTxBuf, uint8_t len )
{
    uint8_t btmp;
    uint8_t length = ( len > 32 ) ? 32 : len;                //数据长达大约32 则只发送32个

    NRF24L01_Flush_Tx_Fifo( );                //清TX FIFO

    RF24L01_SET_CS_LOW( );                        //片选
    drv_spi_read_write_byte( WR_TX_PLOAD );        //发送命令

    for( btmp = 0; btmp < length; btmp ++ )
    {
        drv_spi_read_write_byte( *( pTxBuf + btmp ) );        //发送数据
    }
    RF24L01_SET_CS_HIGH( );                        //取消片选
}

 /**
  * @brief :发送数据(不带应答)
  * @param :
  *                        @pTxBuf:发送数据地址
  *                        @len:长度
  * @note  :一次不超过32个字节
  * @retval:无
  */
void NRF24L01_Write_Tx_Payload_NoAck( uint8_t *pTxBuf, uint8_t len )
{
    if( len > 32 || len == 0 )
    {
        return ;                //数据长度大于32 或者等于0 不执行
    }

    RF24L01_SET_CS_LOW( );        //片选
    drv_spi_read_write_byte( WR_TX_PLOAD_NACK );        //发送命令
    while( len-- )
    {
        drv_spi_read_write_byte( *pTxBuf );                        //发送数据
                pTxBuf++;
    }
    RF24L01_SET_CS_HIGH( );                //取消片选
}

 /**
  * @brief :在接收模式下向TX FIFO写数据(带ACK)
  * @param :
  *                        @pData:数据地址
  *                        @len:长度
  * @note  :一次不超过32个字节
  * @retval:无
  */
void NRF24L01_Write_Tx_Payload_InAck( uint8_t *pData, uint8_t len )
{
    uint8_t btmp;

        len = ( len > 32 ) ? 32 : len;                //数据长度大于32个则只写32个字节

    RF24L01_SET_CS_LOW( );                        //片选
    drv_spi_read_write_byte( W_ACK_PLOAD );                //命令
    for( btmp = 0; btmp < len; btmp ++ )
    {
        drv_spi_read_write_byte( *( pData + btmp ) );        //写数据
    }
    RF24L01_SET_CS_HIGH( );                        //取消片选
}

 /**
  * @brief :设置发送地址
  * @param :
  *                        @pAddr:地址存放地址
  *                        @len:长度
  * @note  :无
  * @retval:无
  */
void NRF24L01_Set_TxAddr( uint8_t *pAddr, uint8_t len )
{
        len = ( len > 5 ) ? 5 : len;                                        //地址不能大于5个字节
    NRF24L01_Write_Buf( TX_ADDR, pAddr, len );        //写地址
}

 /**
  * @brief :设置接收通道地址
  * @param :
  *                        @PipeNum:通道
  *                        @pAddr:地址存肥着地址
  *                        @Len:长度
  * @note  :通道不大于5 地址长度不大于5个字节
  * @retval:无
  */
void NRF24L01_Set_RxAddr( uint8_t PipeNum, uint8_t *pAddr, uint8_t Len )
{
    Len = ( Len > 5 ) ? 5 : Len;
    PipeNum = ( PipeNum > 5 ) ? 5 : PipeNum;                //通道不大于5 地址长度不大于5个字节

    NRF24L01_Write_Buf( RX_ADDR_P0 + PipeNum, pAddr, Len );        //写入地址
}

 /**
  * @brief :设置通信速度
  * @param :
  *                        @Speed:速度
  * @note  :无
  * @retval:无
  */
void NRF24L01_Set_Speed( nRf24l01SpeedType Speed )
{
        uint8_t btmp = 0;

        btmp = NRF24L01_Read_Reg( RF_SETUP );
        btmp &= ~( ( 1<<5 ) | ( 1<<3 ) );

        if( Speed == SPEED_250K )                //250K
        {
                btmp |= ( 1<<5 );
        }
        else if( Speed == SPEED_1M )   //1M
        {
                   btmp &= ~( ( 1<<5 ) | ( 1<<3 ) );
        }
        else if( Speed == SPEED_2M )   //2M
        {
                btmp |= ( 1<<3 );
        }

        NRF24L01_Write_Reg( RF_SETUP, btmp );
}

 /**
  * @brief :设置功率
  * @param :
  *                        @Speed:速度
  * @note  :无
  * @retval:无
  */
void NRF24L01_Set_Power( nRf24l01PowerType Power )
{
    uint8_t btmp;

        btmp = NRF24L01_Read_Reg( RF_SETUP ) & ~0x07;
    switch( Power )
    {
        case POWER_F18DBM:
            btmp |= PWR_18DB;
            break;
        case POWER_F12DBM:
            btmp |= PWR_12DB;
            break;
        case POWER_F6DBM:
            btmp |= PWR_6DB;
            break;
        case POWER_0DBM:
            btmp |= PWR_0DB;
            break;
        default:
            break;
    }
    NRF24L01_Write_Reg( RF_SETUP, btmp );
}

 /**
  * @brief :设置频率
  * @param :
  *                        @FreqPoint:频率设置参数
  * @note  :值不大于127
  * @retval:无
  */
void RF24LL01_Write_Hopping_Point( uint8_t FreqPoint )
{
    NRF24L01_Write_Reg(  RF_CH, FreqPoint & 0x7F );
}

/**
  * @brief :NRF24L01检测
  * @param :无
  * @note  :无
  * @retval:无
  */
void NRF24L01_check( void )
{
        uint8_t i;
        uint8_t error = 0;
        uint8_t buf[5]={ 0XA5, 0XA5, 0XA5, 0XA5, 0XA5 };
        uint8_t read_buf[ 5 ] = { 0 };

        while( 1 )
        {
                NRF24L01_Write_Buf( TX_ADDR, buf, 5 );       //写入5个字节的地址
                NRF24L01_Read_Buf( TX_ADDR, read_buf, 5 );   //读出写入的地址
                for( i = 0; i < 5; i++ )
                {
                        if( buf[ i ] != read_buf[ i ] )
                        {
                                break;
                        }
                }

                if( 5 == i )
                {
                        break;
                }
                else
                {
                        error++;
                        if( error >= 3 )
                        {
                                break;
                        }
                        //测试错误
                        printf("NRF24L01 ERROR  FILE:NRF24L01.C  LINE = %d\r\n",__LINE__);
                }
                drv_delay_500Ms( 4 );
        }
    printf("Successful configuration\r\n");
}

 /**
  * @brief :设置模式
  * @param :
  *                        @Mode:模式发送模式或接收模式
  * @note  :无
  * @retval:无
  */
void RF24L01_Set_Mode( nRf24l01ModeType Mode )
{
    uint8_t controlreg = 0;
        controlreg = NRF24L01_Read_Reg( CONFIG );

    if( Mode == MODE_TX )
        {
                controlreg &= ~( 1<< PRIM_RX );
        }
    else
        {
                if( Mode == MODE_RX )
                {
                        controlreg |= ( 1<< PRIM_RX );
                }
        }

    NRF24L01_Write_Reg( CONFIG, controlreg );
}

/**
  * @brief :NRF24L01发送一次数据
  * @param :
  *                        @txbuf:待发送数据首地址
  *                        @Length:发送数据长度
  * @note  :无
  * @retval:
  *                        MAX_TX:达到最大重发次数
  *                        TX_OK:发送完成
  *                        0xFF:其他原因
  */
uint8_t NRF24L01_TxPacket( uint8_t *txbuf, uint8_t Length )
{
        uint8_t l_Status = 0;
        uint16_t l_MsTimes = 0;

        RF24L01_SET_CS_LOW( );                //片选
        drv_spi_read_write_byte( FLUSH_TX );
        RF24L01_SET_CS_HIGH( );

        RF24L01_SET_CE_LOW( );
        NRF24L01_Write_Buf( WR_TX_PLOAD, txbuf, Length );        //写数据到TX BUF 32字节  TX_PLOAD_WIDTH
        RF24L01_SET_CE_HIGH( );                        //启动发送
        while( 0 != RF24L01_GET_IRQ_STATUS( ))
        {
                delay_ms( 5 );
//        printf("error-1\r\n");
                if( 500 == l_MsTimes++ )                                                //500ms还没有发送成功,重新初始化设备
                {

                        NRF24L01_Gpio_Init_transmit( );

                        RF24L01_Init( );
                        RF24L01_Set_Mode( MODE_TX );
                        break;
                }
        }
        l_Status = NRF24L01_Read_Reg(STATUS);                                                //读状态寄存器
        NRF24L01_Write_Reg( STATUS, l_Status );                                                //清除TX_DS或MAX_RT中断标志

        if( l_Status & MAX_TX )        //达到最大重发次数
        {
                NRF24L01_Write_Reg( FLUSH_TX,0xff );        //清除TX FIFO寄存器
                return MAX_TX;
        }
        if( l_Status & TX_OK )        //发送完成
        {
                return TX_OK;
        }

        return 0xFF;        //其他原因发送失败
}


void key_gpio_config(void)
{
        RF24L01_CE_GPIO_RCC_ENABLE();      // 使能GPIO时钟

        GPIO_InitTypeDef GPIO_InitStruct;                    // GPIO初始化结构体

        GPIO_InitStruct.Pins  = RF24L01_IRQ_GPIO_PIN;        // GPIO引脚
        GPIO_InitStruct.Mode  = GPIO_MODE_INPUT_PULLUP;             // 上拉输入
        GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;             // 速度高
        GPIO_InitStruct.IT    = GPIO_IT_FALLING;             // 下降沿触发中断
        GPIO_Init(RF24L01_GPIO_PORT, &GPIO_InitStruct);      // 初始化

        // 清除PA0中断标志
        GPIOA_INTFLAG_CLR(BSP_KEY_EXTI_PIN);
        // 使能NVIC
        NVIC_EnableIRQ(BSP_KEY_EXTI_IRQN);

}

 /**
  * @brief :RF24L01引脚初始化
  * @param :无
  * @note  :无
  * @retval:无
  */
void NRF24L01_Gpio_Init_receive( void )
{
        RF24L01_CE_GPIO_RCC_ENABLE(); // GPIO时钟使能

        //CE推挽输出
        GPIO_InitTypeDef  GPIO_InitStructure;

        GPIO_InitStructure.Pins = RF24L01_CE_GPIO_PIN;
        GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
        GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
        GPIO_Init(RF24L01_GPIO_PORT, &GPIO_InitStructure);

        IRQ上拉输入
//        gpio_mode_set(RF24L01_IRQ_GPIO_PORT, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP,RF24L01_IRQ_GPIO_PIN);
//    gpio_output_options_set(RF24L01_IRQ_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,RF24L01_IRQ_GPIO_PIN);
//    gpio_bit_set(RF24L01_IRQ_GPIO_PORT,RF24L01_IRQ_GPIO_PIN);
//        IRQ外部中断方式
        key_gpio_config();

        RF24L01_SET_CE_LOW( );
        RF24L01_SET_CS_HIGH( );
}



/************************************************
函数名称 : BSP_KEY_EXTI_IRQHandler
功    能 : 中断处理函数
参    数 : 无
返 回 值 : 无
作    者 : LCEDA
*************************************************/
extern uint8_t g_RF24L01RxBuffer[30];

extern uint32_t flag;

void Buff_Clear(void)
{
        for(int i = 0; i < 30; i++)
        {
                g_RF24L01RxBuffer[i] = 0;
        }
}

void BSP_KEY_EXTI_IRQHANDLER(void)
{
  if(RF24L01_GPIO_PORT->ISR_f.BSP_KEY_EXTI_JUDGE)   // 中断标志位为1,按键按下
  {
                if(GPIO_ReadPin(RF24L01_GPIO_PORT, RF24L01_IRQ_GPIO_PIN) == GPIO_Pin_RESET)  // IRQ为低电平
                {
            NRF24L01_RxPacket(g_RF24L01RxBuffer);  //接收数据
//            printf("data = %s",g_RF24L01RxBuffer );//输出数据


            RF24L01_SET_CS_LOW( );                //片选
            drv_spi_read_write_byte( FLUSH_RX );//清除RX FIFO寄存器
            RF24L01_SET_CS_HIGH( );
                }
        else// IRQ为高电平
        {

                }
                GPIOA_INTFLAG_CLR(BSP_KEY_EXTI_PIN); // 清除标志位
   }
}

/**
  * @brief :NRF24L01接收数据
  * @param :
  *                        @rxbuf:接收数据存放地址
  * @note  :无
  * @retval:接收的数据个数
  */
uint8_t NRF24L01_RxPacket( uint8_t *rxbuf )
{
        uint8_t l_Status = 0, l_RxLength = 0;

        l_Status = NRF24L01_Read_Reg( STATUS );                //读状态寄存器
        NRF24L01_Write_Reg( STATUS,l_Status );                //清中断标志
        if( l_Status & RX_OK)        //接收到数据
        {
                l_RxLength = NRF24L01_Read_Reg( R_RX_PL_WID );                //读取接收到的数据个数
                NRF24L01_Read_Buf( RD_RX_PLOAD,rxbuf,l_RxLength );        //接收到数据
                NRF24L01_Write_Reg( FLUSH_RX,0xff );                                //清除RX FIFO
                return l_RxLength;
        }
        return 0;                                //没有收到数据
}

 /**
  * @brief :RF24L01引脚初始化
  * @param :无
  * @note  :无
  * @retval:无
  */
void NRF24L01_Gpio_Init_transmit( void )
{
        RF24L01_CE_GPIO_RCC_ENABLE(); // GPIO使能时钟

        //CE推挽输出
        GPIO_InitTypeDef  GPIO_InitStructure;

        GPIO_InitStructure.Pins = RF24L01_CE_GPIO_PIN;
        GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
        GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
        GPIO_Init(RF24L01_GPIO_PORT, &GPIO_InitStructure);

//        GPIO_InitStructure.Pins = RF24L01_IRQ_GPIO_PIN;
//        GPIO_InitStructure.Mode = GPIO_MODE_INPUT_PULLUP;
//        GPIO_Init(RF24L01_GPIO_PORT, &GPIO_InitStructure);
//
//        GPIO_WritePin( RF24L01_GPIO_PORT, RF24L01_IRQ_GPIO_PIN,GPIO_Pin_SET);

        key_gpio_config();

        RF24L01_SET_CE_LOW( );
        RF24L01_SET_CS_HIGH( );
}


 /**
  * @brief :RF24L01模块初始化
  * @param :无
  * @note  :无
  * @retval:无
  */
void RF24L01_Init( void )
{
    uint8_t addr[5] = {INIT_ADDR};

    RF24L01_SET_CE_HIGH( );
    NRF24L01_Clear_IRQ_Flag( IRQ_ALL );
#if DYNAMIC_PACKET == 1

    NRF24L01_Write_Reg( DYNPD, ( 1 << 0 ) );         //使能通道1动态数据长度
    NRF24L01_Write_Reg( FEATRUE, 0x07 );
    NRF24L01_Read_Reg( DYNPD );
    NRF24L01_Read_Reg( FEATRUE );

#elif DYNAMIC_PACKET == 0

    L01_WriteSingleReg( L01REG_RX_PW_P0, FIXED_PACKET_LEN );        //固定数据长度

#endif        //DYNAMIC_PACKET

    NRF24L01_Write_Reg( CONFIG,     /*( 1<<MASK_RX_DR ) |*/                //接收中断*/
                                      ( 1 << EN_CRC ) |     //使能CRC 1个字节
                                      ( 1 << PWR_UP ) );    //开启设备
    NRF24L01_Write_Reg( EN_AA, ( 1 << ENAA_P0 ) );                   //通道0自动应答
    NRF24L01_Write_Reg( EN_RXADDR, ( 1 << ERX_P0 ) );                //通道0接收
    NRF24L01_Write_Reg( SETUP_AW, AW_5BYTES );                             //地址宽度 5个字节
    NRF24L01_Write_Reg( SETUP_RETR, ARD_4000US |
                        ( REPEAT_CNT & 0x0F ) );                 //重复等待时间 250us
    NRF24L01_Write_Reg( RF_CH, 00 );                                     //初始化通道
    NRF24L01_Write_Reg( RF_SETUP, 0x26 );

    NRF24L01_Set_TxAddr( &addr[0], 5 );                      //设置TX地址
    NRF24L01_Set_RxAddr( 0, &addr[0], 5 );                   //设置RX地址
}

四、移植验证

将发送端代码烧入开发板,接收端代码烧入另一个开发板。

main.c代码如下:

/*
 * Change Logs:
 * Date           Author       Notes
 * 2024-06-21     LCKFB-LP    first version
 */
#include "board.h"
#include "stdio.h"
#include "bsp_uart.h"
#include "NRF24L01.h"
#include "drv_spi.h"

#define RECEIVING_MODE        1 // 1:接收模式 0:发送模式

uint8_t g_RF24L01RxBuffer[30];

int32_t main(void)
{

        board_init();

        uart1_init(115200);

        //SPI初始化
        drv_spi_init( );

        #if RECEIVING_MODE

        NRF24L01_Gpio_Init_receive( );
        //检测nRF24L01
        NRF24L01_check( );
        //NRF初始化
        RF24L01_Init( );
        RF24L01_Set_Mode( MODE_RX );//NRF接收模式        .
        printf("MODE_RX\r\n");

        while(1)
        {
                if( 0 != g_RF24L01RxBuffer[0])
                {
                        printf("Data = %s\r\n",g_RF24L01RxBuffer);
                        Buff_Clear();
                }
        }

        #else

        NRF24L01_Gpio_Init_transmit( );
        //检测nRF24L01
        NRF24L01_check( );
        //NRF初始化
        RF24L01_Init( );
        RF24L01_Set_Mode( MODE_TX );//NRF发送模式        .
        printf("MODE_TX\r\n");

        while(1)
        {
                NRF24L01_TxPacket((uint8_t*)"hello LCKFB!\r\n",13);//NRF发送数据
                printf("Send\r\n");
                delay_ms(200);
        }

        #endif
}

上电现象:一个开发板烧录接收模式的代码,一个开发板烧录发送模式的代码。

模块移植成功案例代码:

链接:https://pan.baidu.com/s/1KReODFKFa4vjTN8qfsaNrQ?pwd=LCKF

提取码:LCKF

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值