STM32F103C8T6实验代码之NRF24L01P 多发一收

这篇具有很好参考价值的文章主要介绍了STM32F103C8T6实验代码之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

连线如下:
STM32F103C8T6实验代码之NRF24L01P 多发一收

代码格式

关于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通道的关系。
STM32F103C8T6实验代码之NRF24L01P 多发一收
这个通道我就不详细描述,给出我用的地址:

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。

总结

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

STM32F103C8T6实验代码之NRF24L01P 多发一收
四个通道,每个通道的前三位分别是111,222,333,444。后续根据项目的需求进行改动。
如果对NRF24L01P的原理和寄存器等知识可以参考其他人的博客,希望这篇博客可以让大家快速上手多路通信的代码。
自己写的工程如下,希望给大家参考:
链接: NRF24L01四发一收基于STM32F103C8T6完成文章来源地址https://www.toymoban.com/news/detail-459921.html

到了这里,关于STM32F103C8T6实验代码之NRF24L01P 多发一收的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32F103C8T6系统板

    1.电源部分 2.复位 3.晶振 4. 电源电路——防反接 有关二极管 漫谈二极管防电源反接电路 本次采用上图右下角的NMOS防反接电路。 电源电路——电源芯片 AMS1117是AMS公司的 ,LM1117是NS(美国国家半导体)的,LM1117要贵很多,所以一般的用AMS1117就可以了。 (以下分析参考STM32F10

    2024年02月02日
    浏览(60)
  • STM32F103C8T6串口通信

      首先来看一下需要操作的函数,以及配置的步骤: 图1                                                  图2   Code: usart.c #include \\\"usart.h\\\" void ustart_Init(void ) { GPIO_InitTypeDef GPIO_Init_Ustar ; // 定义输出端口TX的结构体对象 USART_InitTypeDef USTART_Init; // 定义串口初始化结构体对象

    2024年02月16日
    浏览(42)
  • 正点原子stmf103zet6代码移植为stm32f103c8t6(库函数版)

    目录 1、打开正点原子的工程模板template, 点击魔术棒  2、 修改芯片型号 为stm32f103c8

    2024年02月01日
    浏览(43)
  • STM32F103C8T6串口调试篇

    项目开发中,当出现bug时,由于不知道某个变量的值,所以很难定位问题,针对此问题,串口调试脱颖而出。通过串口printf()实时将需要显示的信息打印出来,这样就很方便的定位问题。 串口设置方法 1.购买调试器pwlink2。参考STM32F103C8T6程序烧录方法_stm32f103c8t6如何烧录_流

    2024年02月12日
    浏览(54)
  • [STM32F103C8T6]ADC转换

    什么是ADC转换? ADC转换的全称是: Analog-to-Digital Converter ,指模拟 / 数字转换器 ADC的性能指标: ADC分辨率: SSA与VREF-一起接到地,DDA与VREF+接到3.3v,所以ADC转换的范围是0---3.3v 所以最后的ADC转换值应该是我们的测量值*分辨率    分辨率 = 3.3v/2^12 = (3.3/4096)   12位的转换器所

    2024年02月06日
    浏览(40)
  • STM32F103C8T6 按键扫描输入

    第一章 STM32F103C8T6 点亮LED灯 系列文章目录 前言 一、原理  1.按键类型  2.按键消抖 3.IO口输入配置 1)模拟输出 2)浮空输入模式 3)下拉输入模式(PULL DOWN) 4)上拉输入模式(PULL UP) 二、代码部分 main.c key.c key.h 总结         上一章我们成功入门了STM32F103C8T6,今天我们来

    2023年04月23日
    浏览(69)
  • STM32F103C8T6移植FreeRTOS

    根据自己开发板型号下载地址:STM32相关内容下载地址 SDK直接下载地址:STM32直接下载地址 下载参考博客 FreeROTS下载地址 选用V9.0.0 版本 个人创建目录如下,可做参考 keil目录 链接头文件 • 修改堆栈大小 • 修改中断函数名 去掉stm32f10x_it.c终端函数 增加FreeRTOS中断 特别解释

    2024年02月12日
    浏览(46)
  • stm32f103c8t6的外部中断

    在单片机中存在着中断系统,这个系统的逻辑和功能在51单片机中已经有所了解。 1.在32单片机中的内核有一个nvic 里面存放许多优先级的设定,外接许多中断源,比如“exti、tim、adc、usart等”接入之后,nvic再通过中断优先级进行排队,再内接入cpu中进行处理,这样子大大减少

    2024年02月09日
    浏览(43)
  • STM32F103C8T6 点亮LED灯

    一、开发板介绍 二、程序实现 1.配置函数 2.程序源码 main.c LED.c LED.h 总结​​​​​​​ 前言         今天我们开始来学习一下STM32F103Z8T6 点灯。这块芯片可用的IO口资源十分丰富,可用的通用IO口为32个 (注意:是在使用ST_LINK 和 J_LINK的情况下) 。这块芯片的操作方法与正

    2024年02月05日
    浏览(73)
  • STM32F103C8T6制作USB键盘

            1、原因:电脑每次开机都需要输入登录密码,感觉很麻烦,就想着能不能用单片机做一个USB键盘,按一下自动给电脑发一串密码实现开机。后来又想,其实不用按键也行,用延时,延时到电脑开机再发送密码就好了,于是便有了这个制作。         2、 功能:将做好

    2024年01月22日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包