目录
1、 在项目中新建NRF24L01.c和NRF24L01.h文件:
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
}