NRF24L01+模块双向通信(带负载数据的ACK配置)

目录

一、步骤总览:

二、具体实现步骤:

        1、 在项目中新建NRF24L01.c和NRF24L01.h文件:

        2、 定义相关变量:

        3、 创建NRF24L01_CE使能与失能函数:

         4 、创建NRF24L01_IRQ中断函数:

         5、创建NRF24L01+模块初始化函数;

         6、创建写NRF24L01+寄存器的值(单个字节)函数:

        7、创建读NRF24L01+寄存器的值(单个字节)函数:

        8、创建写NRF24L01+寄存器的值(多个字节)函数:

        9、创建读NRF24L01+寄存器的值(多个字节)函数:

         10、创建NRF24L01+发射模式初始化函数:

        11、创建NRF24L01+接收模式初始化函数:

        12、创建NRF24L01+发射数据函数:

        13、创建NRF24L01+接收数据函数:

        14、发射端调用NRF24L01_TxPacket函数:

        15、 接收端调用NRF24L01_RxPacket函数就可以实现双向通信了。


        NRF24L01模块的引脚定义:

一、步骤总览:

        1、 在项目中新建NRF24L01.c和NRF24L01.h文件;

        2、 定义相关变量;

        3、 创建NRF24L01_CE使能与失能函数;

        4 、创建NRF24L01_IRQ中断函数;

        5、创建NRF24L01+模块初始化函数;

        6、创建写NRF24L01+寄存器的值(单个字节)函数;

        7、创建读NRF24L01+寄存器的值(单个字节)函数;

        8、创建写NRF24L01+寄存器的值(多个字节)函数;

        9、创建读NRF24L01+寄存器的值(多个字节)函数;

        10、创建NRF24L01+发射模式初始化函数;

        11、创建NRF24L01+接收模式初始化函数;

        12、创建NRF24L01+发射数据函数;

        13、创建NRF24L01+接收数据函数;

        14、发射端调用NRF24L01_TxPacket函数;

        15、接收端调用NRF24L01_RxPacket函数。

         👉👉NRF24L01头文件里的宏定义:

#ifndef __NRF24L01_H
#define __NRF24L01_H


extern uint8_t RX_AckData[];




/*****SPI命令*****/

#define  R_Register              0x00     //读寄存器命令需要加上寄存器地址
#define  W_Register              0x20     //写寄存器命令需要加上寄存器地址 
#define  R_RX_Payload            0x61     //从FIFO中读收到的数据, 1-32字节,读出后FIFO数据被 
                                          //删除。适用于接收模式

#define  W_TX_Payload            0xA0     //写发射负载数据,大小为1-32字节,适用于发射模式。
#define  Flush_TX                0xE1     //清空TX FIFO,适用于发射模式。
#define  Flush_RX                0xE2     //清空RX FIFO,适用于接收模式
#define  Reuse_TX_PL             0xE3     //适用于发送方,清空TX FIFO或对FIFO写入新的数据后不            
                                          //能使用该命令。

#define  R_RX_PL_WID             0x60     //读取收到的数据字节数。
#define  W_ACK_Payload           0xA8     //适用于接收方,通过PIPE PPP将数据通过ACK的形式发出 
                                          //去,最多允许三帧数据存于FIFO中

#define  W_TX_Payload_NOACK      0xB0     //适用于发射模式,
                                          //使用这个命令同时需要将AUTOACK位置1。

#define  NOP                     0xFF     //无操作。可用于返回STATUS值。


/*****NRF24L01寄存器地址******/
#define  Config                 0x00     //配置寄存器
#define  EN_AA                  0x01     //使能自动确认
#define  EN_RXADDR              0x02     //使能接收数据管道地址
#define  SETUP_AW               0x03     //地址宽度配置
#define  SETUP_RETR             0x04     //自动重发配置
#define  RF_CH                  0x05     //射频信道
#define  RF_SETUP               0x06     //射频配置
#define  STATUS                 0x07     //状态寄存器(SPI操作开始,
                                         //状态寄存器值通过MISO串行输出)。

#define  OBSERVE_TX             0x08     //发射结果统计
#define  RSSI                   0x09     //接收信号强度检测
#define  RX_ADDR_P0             0x0A     //数据管道0的接收地址,最大宽度为5bytes(LSByte最先写 
                                         //入,通过SETUP_AW配置地址宽度) 。

#define  RX_ADDR_P1             0x0B     //数据管道1的接收地址,最大宽度为5bytes(LSByte最先写 
                                         //入,通过SETUP_AW配置地址宽度) 。

#define  RX_ADDR_P2             0x0C     //数据管道2的接收地址的最低字节,接收地址高字节与 
                                         //RX_ADDR_P1[39:8]相同

#define  RX_ADDR_P3             0x0D     //数据管道3的接收地址的最低字节,接收地址高字节与 
                                         //RX_ADDR_P1[39:8]相同

#define  RX_ADDR_P4             0x0E     //数据管道4的接收地址的最低字节,接收地址高字节与 
                                         //RX_ADDR_P1[39:8]相同

#define  RX_ADDR_P5             0x0F     //数据管道5的接收地址的最低字节,接收地址高字节与 
                                         //RX_ADDR_P1[39:8]相同

#define  TX_ADDR                0x10     //发射方的发射地址(LSByte最先写入),如果发射放需要收 
                                         //ACK确认信号,则需要配置RX_ADDR_P0的值等于 
                                         //TX_ADDR,并使能ARQ。

#define  RX_PW_P0               0x11     //
#define  RX_PW_P1               0x12     //
#define  RX_PW_P2               0x13     //
#define  RX_PW_P3               0x14     //
#define  RX_PW_P4               0x15     //
#define  RX_PW_P5               0x16     //
#define  FIFO_STATUS            0x17     //FIFO状态
#define  DYNPD                  0x1C     //使能动态负载长度
#define  FEATURE                0x1D     //特征寄存器
                                      


void NRF24L01_CE(uint8_t Value);
uint8_t NRF24L01_IRQ(void);


void NRF24L01_Init(void);
uint8_t NRF24L01_Write_Reg(uint8_t Reg, uint8_t Value);
uint8_t NRF24L01_Write_Buf(uint8_t Reg, uint8_t *pBuf, uint8_t Length);
uint8_t NRF24L01_Read_Reg(uint8_t Reg);
uint8_t NRF24L01_Read_Buf(uint8_t Reg, uint8_t *pBuf, uint8_t Length);

void NRF24L01_TX_Mode(void);
void NRF24L01_RX_Mode(void);

uint8_t NRF24L01_TxPacket(uint8_t *pTxData);
uint8_t NRF24L01_RxPacket(uint8_t *pRxData);




#endif

二、具体实现步骤:

        1、 在项目中新建NRF24L01.c和NRF24L01.h文件:

        2、 定义相关变量:

#include "stm32f10x.h"                  // Device header
#include "MySPI.h"                      //SPI
#include "NRF24L01.h"                   //NRF24L01+



/*这个数组定义在发射端,用于接收从接收端返回的数据*/
uint8_t RX_AckData[4];                                  //定义读取随ACK返回发射端的负载数组


/*定义5位的通信地址,收发双方需要保持一致*/
uint8_t TX_ADDRESS[] = {0xA5, 0xA5, 0xA5, 0xA5, 0xA5};  


/*这个数组定义在接收端,用于回传数据给发射端*/
uint8_t TX_AckData[4] = {0x11, 0x12, 0x13, 0x14};       //定义随ACK返回发射端的数据

        3、 创建NRF24L01_CE使能与失能函数:

/**
  * 函数功能:NRF24L01_CE使能与失能
  * 入口参数:Value:0失能  1使能
  * 返 回 值:无
  */
void NRF24L01_CE(uint8_t Value)
{
    GPIO_WriteBit(GPIOB, GPIO_Pin_0, (BitAction)Value);  //控制CE引脚高低电平
}

         4 、创建NRF24L01_IRQ中断函数:

/**
  * 函数功能:读取NRF24L01_IRQ中断的状态
  * 入口参数:无
  * 返 回 值:0或1  低电平有效
  */
uint8_t NRF24L01_IRQ(void)
{
    uint8_t i;
    i = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1); //读取IRQ引脚的高低电平
    return i;
}


         5、创建NRF24L01+模块初始化函数;

/**
  * 函    数:NRF24L01+无线模块初始化
  * 参    数:无
  * 返 回 值:无
  */
void NRF24L01_Init(void)
{
    /*调用SPI初始化函数*/
    MySPI_Init();               
    
    /*开启GPIOB时钟*/
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    
    /*NRF24L01使能引脚CE初始化*/
    GPIO_InitTypeDef GPIO_InitStructure;               
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    /*NRF24L01中断引脚初始化*/
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;     
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    GPIO_SetBits(GPIOB, GPIO_Pin_1);   //IRQ高电平
    GPIO_ResetBits(GPIOB, GPIO_Pin_0); //CE脚低电平
}

         6、创建写NRF24L01+寄存器的值(单个字节)函数:

/**
  * 函数功能:写NRF24L01+寄存器的值(单个字节)
  * 入口参数:Reg  :寄存器地址。
  * 入口参数:Value:需要写入的数据。
  * 返 回 值:状态寄存器的值。
  */
uint8_t NRF24L01_Write_Reg(uint8_t Reg, uint8_t Value)
{
    uint8_t Status;               //定义接收状态寄存器的变量
    
    MySPI_Start();                //SPI开始
    Status = MySPI_SwapData(Reg); //发送寄存器地址,并接收返回值。
    MySPI_SwapData(Value);        //写入数据,不需要返回值。
    MySPI_Stop();                 //SPI停止
    
    return Status;                //返回返回值
}

        7、创建读NRF24L01+寄存器的值(单个字节)函数:

/**
  * 函数功能:读NRF24L01+单个寄存器的值(单个字节)
  * 入口参数:Reg:需要读取的寄存器地址
  * 返 回 值:寄存器里的数据
  */
uint8_t NRF24L01_Read_Reg(uint8_t Reg)
{
    uint8_t Value;                  //用于接收读取值
     
    MySPI_Start();                  //SPI开始
    MySPI_SwapData(Reg);            //发送需要读取的寄存器的地址
    Value = MySPI_SwapData(0xFF);   //读取寄存器的值
    MySPI_Stop();                   //SPI停止
    
    return Value;                   //返回数据
}

        8、创建写NRF24L01+寄存器的值(多个字节)函数:

/**
  * 函数功能:写NRF24L01+寄存器的值(多个字节)
  * 入口参数:Reg:   NRF24L01+寄存器地址
             pBuf:  数组数据的首元素
             Length:写入的数量
  * 返 回 值:
  */
uint8_t NRF24L01_Write_Buf(uint8_t Reg, uint8_t *pBuf, uint8_t Length)
{
    uint8_t Status;                 //接收寄存器返回值
    uint8_t i;                      //重复写寄存器次数
                            
    MySPI_Start();                  //SPI开始 
    Status = MySPI_SwapData(Reg);   //指定需要写的寄存器首地址
    for (i = 0; i < Length; i++)    //连续写入数据
    {
        MySPI_SwapData(pBuf[i]);    
    }
    MySPI_Stop();                   //SPI停止
    
    return Status;                  //返回寄存器数值
}

        9、创建读NRF24L01+寄存器的值(多个字节)函数:

/**
  * 函数功能:读NRF24L01+寄存器的值(多个字节)
  * 入口参数:Reg   :NRF24L01+寄存器地址
             pBuf  :读回来的数据存放的地址
             Length:读取长度
  * 返 回 值:寄存器状态值
  */
uint8_t NRF24L01_Read_Buf(uint8_t Reg, uint8_t *pBuf, uint8_t Length)
{
    uint8_t Status;                      //定义接收状态寄存器数值变量
    uint8_t i;                           //定义读取次数变量
    
    MySPI_Start();                       //SPI开始
    Status = MySPI_SwapData(Reg);        //发送寄存器位置,并接收寄存器状态值
    for (i = 0; i < Length; i++)         //连续读取多次
    {
        pBuf[i] = MySPI_SwapData(0xFF);  //读到的数据存到pBuf为首地址的数组中
    }
    MySPI_Stop();                        //SPI停止
    
    return Status;                       //返回寄存器状态
}

         10、创建NRF24L01+发射模式初始化函数:

/**
  * 函数功能:发送模式初始化
  * 入口参数:无
  * 返 回 值:无
  */
void NRF24L01_TX_Mode(void)
{
    NRF24L01_CE(0);                                           //失能NRF24L01
    
    NRF24L01_Write_Reg(W_Register + SETUP_AW, 0x03);            //设置通信地址宽度5bytes
    NRF24L01_Write_Buf(W_Register + TX_ADDR, TX_ADDRESS, 5);    //写入发送地址,5字节
    NRF24L01_Write_Buf(W_Register + RX_ADDR_P0, TX_ADDRESS, 5); //接收通道0地址和发射地址相同,用于接收ACK
    NRF24L01_Write_Reg(W_Register + EN_AA, 0x01);               //使能数据管道0自动确认
    NRF24L01_Write_Reg(W_Register + EN_RXADDR, 0x01);           //使能接收数据管道0
    NRF24L01_Write_Reg(W_Register + FEATURE, 0x06);             //使能动态负载长度和使能ACK负载(带负载数据的ACK包)
    NRF24L01_Write_Reg(W_Register + DYNPD, 0x01);               //使能接收通道0动态负载长度
    NRF24L01_Write_Reg(W_Register + SETUP_RETR, 0xFF);          //自动重发延时500us,自动重发次数5次。
    NRF24L01_Write_Reg(W_Register + RF_CH, 0x40);               //射频信道
    NRF24L01_Write_Reg(W_Register + RF_SETUP, 0x03);            //射频配置速率2Mbps,发射功率4dBm
    NRF24L01_Write_Reg(W_Register + Config, 0x0E);              //配置寄存器
    
    NRF24L01_CE(1);                                           //使能NRF24L01
}

        11、创建NRF24L01+接收模式初始化函数:

/**
  * 函数功能:NRF24L01接收模式初始化
  * 入口参数:无
  * 返 回 值:无
  */
void NRF24L01_RX_Mode(void)
{
    NRF24L01_CE(0);                                                //失能NRF24L01
    
    NRF24L01_Write_Reg(W_Register + SETUP_AW, 0x03);               //配置通信地址长度 5个字节
    NRF24L01_Write_Buf(W_Register + RX_ADDR_P0, TX_ADDRESS, 5);    //配置接收地址
    NRF24L01_Write_Reg(W_Register + FEATURE, 0x06);                //使能动态负载长度和使能ACK负载(带负载数据的ACK包)
    NRF24L01_Write_Reg(W_Register + DYNPD, 0x01);                  //使能接收管道0动态负载
    NRF24L01_Write_Reg(W_Register + RX_PW_P0, 32);                 //接收数据管道0数据长度
    NRF24L01_Write_Reg(W_Register + EN_AA, 0x01);                  //使能数据管道0自动确认
    NRF24L01_Write_Reg(W_Register + EN_RXADDR, 0x01);              //使能接收数据管道0地址
    NRF24L01_Write_Reg(W_Register + RF_CH, 0x40);                  //射频信道64
    NRF24L01_Write_Reg(W_Register + RF_SETUP, 0x03);               //发射功率4dBm, 速率2Mbps
    NRF24L01_Write_Reg(W_Register + Config, 0x0F);                 //接收模式
    
    NRF24L01_CE(1);                                                //使能NRF24L01
}

        12、创建NRF24L01+发射数据函数:

/**
  * 函数功能:NRF24L01发射数据
  * 入口参数:pTxData:要发送数据的首地址
  * 返 回 值:发送成功or不成功
  */
uint8_t NRF24L01_TxPacket(uint8_t *pTxData)
{
    uint8_t Status;                                   //定义状态寄存器变量
    uint8_t FIFO_Status;                              //定义FIFO状态寄存器变量
    uint32_t i = 10000;                               //定义防卡死变量
    
    /*写入发射的数据*/
    NRF24L01_CE(0);                                   //NRF24L01失能
    NRF24L01_Write_Buf(W_TX_Payload, pTxData, 32);    //写入发送的数据
    NRF24L01_CE(1);                                   //NRF24L01使能
    
    /*等待发射中断*/
    while (NRF24L01_IRQ() == 1)                       //等待发送完成中断, 低电平有效
    {
        i--;
        if (i < 10)
        {
            break;
        }
    }
    
    /*读取状态寄存器状态*/
    Status = NRF24L01_Read_Reg(STATUS);                          //读取状态寄存器
    FIFO_Status = NRF24L01_Read_Reg(FIFO_STATUS);                //读取FIFO状态寄存器
    NRF24L01_Write_Reg(W_Register+STATUS, Status);               //清空状态寄存器
    NRF24L01_Write_Reg(W_Register+FIFO_STATUS, FIFO_Status);     //清空FIFO状态寄存器
    
    /*清空TX_FIFO*/
    NRF24L01_Write_Reg(Flush_TX, 0xFF);                          
    
//    /*打印状态寄存器的状态*/
//    Serial_Printf("Status:     %X  \r\nFOFI_Status:%X\r\n", Status, FIFO_Status);
//    Serial_Printf("\r\n");

    /*读取随ACK返回的负载数据*/
    if (Status & 0x40)                                            //读取随ACK返回的负载
    {
        NRF24L01_Read_Buf(R_RX_Payload, RX_AckData, 32);          //读取随ACK返回的负载
        NRF24L01_Write_Reg(Flush_RX, 0xFF);                       //清空接收FIFO寄存器  
    }
    
    /*返回发射状态*/
    if ((Status & 0x10))                                          //达到最大重发次数中断位,发送失败
    {
        return 0x10;                                              //返回发送状态
    }
    if ((Status & 0x20))                                          //发射完成中断位, 发送成功
    {
        return 0x20;                                              //返回发送成功状态
    }
    return 0xFF;                                                  //返回其它错误状态
}

        13、创建NRF24L01+接收数据函数:

/**
  * 函数功能:NRF24L01接收数据
  * 入口参数:pRxDATA:接收地址
  * 返 回 值:接收状态
  */
uint8_t NRF24L01_RxPacket(uint8_t *pRxData)
{
    
    uint8_t Statu;                                                    
    if (NRF24L01_IRQ() == 0)                                          //等待中断引脚低电平
    {
        Statu = NRF24L01_Read_Reg(STATUS);                            //读取状态寄存器
        NRF24L01_Write_Reg(W_Register + STATUS, Statu);               //清空状态寄存器
//      NRF24L01_Write_Reg(Flush_TX, 0xFF);                           //清空ACK负载数据
        if ((Statu & 0x40))                                           //收到接收中断后开始读数据
        {

            NRF24L01_Write_Buf(W_ACK_Payload + 0x00, TX_AckData, 32);  //写入随ACK返回的负载(返回数据到发射端)
            NRF24L01_Read_Buf(R_RX_Payload, pRxData, 32);              //开始读取RX_FIFO数据
            NRF24L01_Write_Reg(Flush_RX, 0xFF);                        //清空RX_FIFO
          
            return 1;                                                  //返回1
        }
    }   
    return 0;                                                          //返回0
}

        14、发射端调用NRF24L01_TxPacket函数

     

   15、 接收端调用NRF24L01_RxPacket函数就可以实现双向通信了。

  • 17
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值