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板子介绍

    STM32简介 STM32是ST公司基于ARM Cortex-M内核开发的32位微控制器 STM32常应用在嵌入式领域,如智能车、无人机、机器人、无线通信、物联网、工业控制、娱乐电子产品等 STM32功能强大、性能优异、片上资源丰富、功耗低,是一款经典的嵌入式微控制器。  STM32F103C8T6 F1XX片上资源

    2024年02月11日
    浏览(57)
  • 功耗测评 | STM32F103C8T6

    STM32F103C8T6 MCU越来越广泛的应用在生产生活的各个领域,外接丰富的传感器、功能模块、通信模块、显示存储等可以形成各种可样的产品项目应用。对于功耗要求比较高的产品,一般会选择STM32L系列的MCU,但是从功耗的评测角度,逻辑上是基本相似的。 在很多应用场合中都对

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

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

    2024年02月01日
    浏览(56)
  • STM32F103C8T6移植FreeRTOS

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

    2024年02月12日
    浏览(56)
  • 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日
    浏览(78)
  • STM32F103C8T6串口调试篇

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

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

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

    2024年02月09日
    浏览(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日
    浏览(47)
  • STM32F103C8T6制作USB键盘

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

    2024年01月22日
    浏览(47)
  • 自制STM32F103C8T6最小系统板

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 记录自己绘制第一块STM32F103C8T6最小系统板,包括原理图的绘制,pcb图的绘制和布局,以及器材的选购。 提示:有任何问题和交流可以加q:2874160799, 我基本上不看评论和私信。 根据ST官方手册,查看引脚

    2024年02月07日
    浏览(55)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包