STM32F103C8T6实验代码之NRF24L01P 多发一收
创始人
2025-05-31 00:15:15
0

NRF24L01P的多发一收

  • NRF24L01P简介
    • 模块硬件
    • 代码格式
  • 多通道(多发一收)
    • 单通道通信
    • 多发一收
      • 主机的接收模式函数
      • 主机的接收数据包函数
      • 从机的发送模式函数
  • 总结

NRF24L01P简介

NRF24L01P射频芯片,比NRF24L01具有更高的可靠性,更多的功
率等级,以及更远的传输距离和更低的功率。此外还内置RFX2401功放芯片,
内建LNA,接收灵敏度 提高10dBm,工作在2.4GHz~2.5GHz的ISM频段。
电压:最小值=1.9V;典型值=3.0V;最大值=3.6V;
如果要接入5V,需要使用电阻进行分压,可通过U=RI进行计算。 工作温度:-40℃——85℃。典型值=27℃

模块硬件

模块一共有8个引脚:

  1. +3.3v
  2. CE:数字信号输入,模式控制线。在 CSN为低的情况下,CE 协同CONFIG 寄存器共同决定NRF24L01 的状态
  3. CSN:数字信号输入 ,SPI片选线,低电平使能
  4. SCK:数字信号输入 ,SPI时钟线
  5. MOSI:数字信号输入,SPI数据线,主机输出,从机输入
  6. MISO:数字信号输出,SPI数据线,主机输入,从机输出
  7. IRQ:数字信号输出,中断信号线,在达到最大重发次数数据发送完成收到数据时变低
  8. GND

连线如下:
在这里插入图片描述

代码格式

关于NRF24L01的函数,有一下几个函数:

void NRF24L01_Init(void);						//初始化
void NRF24L01_RX_Mode_init(void);			    //接受模式
void NRF24L01_TX_Mode(void);					//发送模式u8 NRF24L01_Write_Buf(u8 reg, u8 *pBuf, u8 u8s);//写数据区
u8 NRF24L01_Read_Buf(u8 reg, u8 *pBuf, u8 u8s);	//读数据区		  
u8 NRF24L01_Read_Reg(u8 reg);					//读寄存器
u8 NRF24L01_Write_Reg(u8 reg, u8 value);		//写寄存器
u8 NRF24L01_Check(void);						//检测24l01是否存在
u8 NRF24L01_TxPacket(u8 *txbuf);				//发送数据包
u8 NRF24L01_RxPacket_init(u8 *RxData_Buf0,u8 *RxData_Buf1,u8 *RxData_Buf2,u8 *RxData_Buf3);				//接受数据包,这个函数可以接受四个数据通道的数据

多通道(多发一收)

多通道是在单通道的基础上进行代码的修改,所以首先要对单通道的通信进行了解

单通道通信

单通道通信的代码流程大概如下:
GPIO口初始化
SPI初始化
NRF24L01P初始化
NRF24L01P检查
NRF24L01P配置为 接收/发送
使用 接收/发送数据包接收数据

部分代码如下:
1.初始化 NRF24L01

void NRF24L01_Init(void)
{ 	GPIO_InitTypeDef GPIO_InitStructure;SPI_InitTypeDef  SPI_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOA, ENABLE);	 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;				 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);	GPIO_SetBits(GPIOB,GPIO_Pin_12);//ÉÏÀ­				GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_1;   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_SetBits(GPIOA,GPIO_Pin_1|GPIO_Pin_0);			 		 SPI2_Init();    		SPI_Cmd(SPI2, DISABLE);SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;		SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;		SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;		SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;		SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;		SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;	SPI_InitStructure.SPI_CRCPolynomial = 7;	SPI_Init(SPI2, &SPI_InitStructure);  SPI_Cmd(SPI2, ENABLE); NRF24L01_CE=0; 			NRF24L01_CSN=1;			}

2.NRF24L01检查函数

u8 NRF24L01_Check(void)
{u8 buf[5]={0XA5,0XA5,0XA5,0XA5,0XA5};u8 i;SPI2_SetSpeed(SPI_BaudRatePrescaler_16); NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,buf,5);	NRF24L01_Read_Buf(TX_ADDR,buf,5); for(i=0;i<5;i++)if(buf[i]!=0XA5)break;	 							   if(i!=5)return 1;	return 0;		 
}	 	 

3.发送模式

void NRF24L01_TX_Mode(void)
{														 NRF24L01_CE=0;	    NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(u8*)TxAddr0,TX_ADR_WIDTH);NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RxAddr0,RX_ADR_WIDTH); NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);    NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01); NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);    NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);  NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);    NRF24L01_CE=1;
} 

4.接收模式

void NRF24L01_RX_Mode(void)
{NRF24L01_CE=0;	  NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RxAddr0,RX_ADR_WIDTH);NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);   NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);	     	  NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P0,TX_PLOAD_WIDTH);NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f); NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);NRF24L01_CE = 1; 
}						 

这里简单介绍了一下这几个函数,还有很多函数由于篇幅原因没有列出,下面来说一下代码要怎么改才能完成多发一收

多发一收

多发一收,最主要的是要改三个部分:
1.主机的接收模式函数
2.主机的接收数据包函数
3.从机的发送模式函数

主机的接收模式函数

这个函数首先要改接收的地址,如果是四个通道就要改四个通道的地址。其次要将自动应答和接收地址的0x01改为0x0f。最后再改通道的有效数据宽度。代码如下:

void NRF24L01_RX_Mode_init()
{NRF24L01_CE=0;	  NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RxAddr0,RX_ADR_WIDTH);//写RX节点地址NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P1,(u8*)RxAddr1,RX_ADR_WIDTH);//写RX节点地址NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P2,(u8*)RxAddr2,1);//写RX节点地址NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P3,(u8*)RxAddr3,1);//写RX节点地址NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x0f);    //使能通道0的自动应答    NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x0f);//使能通道0的接收地址  	 NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);	     //设置RF通信频率		  NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);//选择通道0的有效数据宽度 NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P1,RX_PLOAD_WIDTH);//选择通道1的有效数据宽度 NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P2,RX_PLOAD_WIDTH);//选择通道2的有效数据宽度 NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P3,RX_PLOAD_WIDTH);//选择通道3的有效数据宽度 NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);//设置TX发射参数,0db增益,2Mbps,低噪声增益开启   NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);//配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式 NRF24L01_CE = 1; //CE为高,进入接收模式 
}					 

首先说一下第一个改的地方

  	NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RxAddr0,RX_ADR_WIDTH);//写RX节点地址NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P1,(u8*)RxAddr1,RX_ADR_WIDTH);//写RX节点地址NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P2,(u8*)RxAddr2,1);//写RX节点地址NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P3,(u8*)RxAddr3,1);//写RX节点地址

这里的RxAddr0,RxAddr1,RxAddr2,RxAddr3,是自己设的地址,但是还要注意一个问题是2,3,4通道与1通道的关系。
在这里插入图片描述
这个通道我就不详细描述,给出我用的地址:

const u8 TxAddr0[TX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x01};   
const u8 TxAddr1[TX_ADR_WIDTH]= {0xC2,0xC2,0xC2,0xC2,0xC2};   
const u8 TxAddr2[TX_ADR_WIDTH] = {0xC3,0xC2,0xC2,0xC2,0xC2};   
const u8 TxAddr3[TX_ADR_WIDTH]=  {0xC4,0xC2,0xC2,0xC2,0xC2};   
const u8 TxAddr4[TX_ADR_WIDTH] = {0xC5,0xC2,0xC2,0xC2,0xC2};   
const u8 TxAddr5[TX_ADR_WIDTH]=  {0xC6,0xC2,0xC2,0xC2,0xC2};     const u8 RxAddr0[RX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x01};  
const u8 RxAddr1[RX_ADR_WIDTH]= {0xC2,0xC2,0xC2,0xC2,0xC2};  
const u8 RxAddr2[1] ={0xC3};
const u8 RxAddr3[1] ={0xC4};
const u8 RxAddr4[1] ={0xC5};
const u8 RxAddr5[1] ={0xC6};

关于第二个改的地方:

NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x0f);    //使能通道0的自动应答    
NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x0f);//使能通道0的接收地址  	 

这里改成0x0f即可,具体原因参考以下博客
链接: NRF24l01的多对一通信

第三个改的地方

  	NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);//选择通道0的有效数据宽度 NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P1,RX_PLOAD_WIDTH);//选择通道1的有效数据宽度 NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P2,RX_PLOAD_WIDTH);//选择通道2的有效数据宽度 NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P3,RX_PLOAD_WIDTH);//选择通道3的有效数据宽度  

主机的接收数据包函数

这里主要改的地方是对接收到通道号的判别

u8 NRF24L01_RxPacket_init(u8 *RxData_Buf0,u8 *RxData_Buf1,u8 *RxData_Buf2,u8 *RxData_Buf3)
{u8 sta;		u8 RX_P_NO;	SPI2_SetSpeed(SPI_BaudRatePrescaler_8); //spi速度为9Mhz(24L01的最大SPI时钟为10Mhz)   sta=NRF24L01_Read_Reg(STATUS);  //读取状态寄存器的值  RX_P_NO=sta&0x0e; 	NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta); //清除TX_DS或MAX_RT中断标志if(sta&RX_OK)//接收到数据{switch(RX_P_NO){case 0x00:	{NRF24L01_Read_Buf(RD_RX_PLOAD,RxData_Buf0,RX_PLOAD_WIDTH);break;}//读取数据case 0x02:  {NRF24L01_Read_Buf(RD_RX_PLOAD,RxData_Buf1,RX_PLOAD_WIDTH);break;}case 0x04:  {NRF24L01_Read_Buf(RD_RX_PLOAD,RxData_Buf2,RX_PLOAD_WIDTH);break;}case 0x06:  {NRF24L01_Read_Buf(RD_RX_PLOAD,RxData_Buf3,RX_PLOAD_WIDTH);break;}default : break;	}NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,0xff);NRF24L01_CSN=0;NRF24L01_Write_Reg(FLUSH_RX,0xff);//清除RX FIFO寄存器 NRF24L01_CSN=1;return 0;}	   
return 1;
}	

主要目的是得到接收的数据时判断是哪个通道的数据,之后传入数组。

从机的发送模式函数

void NRF24L01_TX_Mode(void)
{														 NRF24L01_CE=0;	    NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(u8*)TxAddr3,TX_ADR_WIDTH);//**********************************NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RxAddr3,TX_ADR_WIDTH);//**********************************NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x0f);    NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x0f); NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);       NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f); NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);   NRF24L01_CE=1;
}

这里主要改的地方只有一处

NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(u8*)TxAddr3,TX_ADR_WIDTH);//**********************************NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RxAddr3,TX_ADR_WIDTH);//**********************************

这里只需要将TxAddr3改成所需要的通道即可,如TxAddr0,TxAddr1,TxAddr2。

总结

到此为止就对多发一收进行配置完成了,具体原理部分由于篇幅受限没有讲解,因为网上大部分都是原理讲解部分,而对代码部分的讲解较少,所以写了这篇,放出通信结果图:

在这里插入图片描述
四个通道,每个通道的前三位分别是111,222,333,444。后续根据项目的需求进行改动。
如果对NRF24L01P的原理和寄存器等知识可以参考其他人的博客,希望这篇博客可以让大家快速上手多路通信的代码。
自己写的工程如下,希望给大家参考:
链接: NRF24L01四发一收基于STM32F103C8T6完成

相关内容

热门资讯

linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
C++ 机房预约系统(六):学... 8、 学生模块 8.1 学生子菜单、登录和注销 实现步骤: 在Student.cpp的...
JAVA多线程知识整理 Java多线程基础 线程的创建和启动 继承Thread类来创建并启动 自定义Thread类的子类&#...
【洛谷 P1090】[NOIP... [NOIP2004 提高组] 合并果子 / [USACO06NOV] Fence Repair G ...
国民技术LPUART介绍 低功耗通用异步接收器(LPUART) 简介 低功耗通用异步收发器...
城乡供水一体化平台-助力乡村振... 城乡供水一体化管理系统建设方案 城乡供水一体化管理系统是运用云计算、大数据等信息化手段࿰...
程序的循环结构和random库...   第三个参数就是步长     引入文件时记得指明字符格式,否则读入不了 ...
中国版ChatGPT在哪些方面... 目录 一、中国巨大的市场需求 二、中国企业加速创新 三、中国的人工智能发展 四、企业愿景的推进 五、...
报名开启 | 共赴一场 Flu... 2023 年 1 月 25 日,Flutter Forward 大会在肯尼亚首都内罗毕...
汇编00-MASM 和 Vis... Qt源码解析 索引 汇编逆向--- MASM 和 Visual Studio入门 前提知识ÿ...
【简陋Web应用3】实现人脸比... 文章目录🍉 前情提要🌷 效果演示🥝 实现过程1. u...
前缀和与对数器与二分法 1. 前缀和 假设有一个数组,我们想大量频繁的去访问L到R这个区间的和,...
windows安装JDK步骤 一、 下载JDK安装包 下载地址:https://www.oracle.com/jav...
分治法实现合并排序(归并排序)... 🎊【数据结构与算法】专题正在持续更新中,各种数据结构的创建原理与运用✨...
在linux上安装配置node... 目录前言1,关于nodejs2,配置环境变量3,总结 前言...
Linux学习之端口、网络协议... 端口:设备与外界通讯交流的出口 网络协议:   网络协议是指计算机通信网...
Linux内核进程管理并发同步... 并发同步并发 是指在某一时间段内能够处理多个任务的能力,而 并行 是指同一时间能够处理...
opencv学习-HOG LO... 目录1. HOG(Histogram of Oriented Gradients,方向梯度直方图)1...
EEG微状态的功能意义 导读大脑的瞬时全局功能状态反映在其电场结构上。聚类分析方法一致地提取了四种头表面脑电场结构ÿ...
【Unity 手写PBR】Bu... 写在前面 前期积累: GAMES101作业7提高-实现微表面模型你需要了解的知识 【技...