一、NRF2401无线通信模块使用记录

news2025/3/4 14:58:12

一、电路引脚图

在这里插入图片描述

1、引脚说明:

在这里插入图片描述

2、引脚标号:

找到1号引脚,与原理图对号入座。
在这里插入图片描述

3、cubemx初始化配置:

在这里插入图片描述
在这里插入图片描述

5、驱动文件

配置spi,并构建发送与接收函数接口

.h


#define TX_ADR_WIDTH 	5  	//发射地址宽度
#define TX_PLOAD_WIDTH  32   //发射数据通道有效数据宽度0~32Byte 
#define RX_ADR_WIDTH    5
#define RX_PLOAD_WIDTH  32

#define CHANAL 40	//频道选择 

// SPI(nRF24L01) commands ,	NRF的SPI命令宏定义,详见NRF功能使用文档
#define NRF_READ_REG    0x00  // Define read command to register
#define NRF_WRITE_REG   0x20  // Define write command to register
#define RD_RX_PLOAD 0x61  // Define RX payload register address
#define WR_TX_PLOAD 0xA0  // Define TX payload register address
#define FLUSH_TX    0xE1  // Define flush TX register command
#define FLUSH_RX    0xE2  // Define flush RX register command
#define REUSE_TX_PL 0xE3  // Define reuse TX payload register command
#define NOP         0xFF  // Define No Operation, might be used to read status register

// SPI(nRF24L01) registers(addresses) ,NRF24L01 相关寄存器地址的宏定义
#define CONFIG      0x00  // 'Config' register address
#define EN_AA       0x01  // 'Enable Auto Acknowledgment' register address
#define EN_RXADDR   0x02  // 'Enabled RX addresses' register address
#define SETUP_AW    0x03  // 'Setup address width' register address
#define SETUP_RETR  0x04  // 'Setup Auto. Retrans' register address
#define RF_CH       0x05  // 'RF channel' register address
#define RF_SETUP    0x06  // 'RF setup' register address
#define STATUS      0x07  // 'Status' register address
#define OBSERVE_TX  0x08  // 'Observe TX' register address
#define CD          0x09  // 'Carrier Detect' register address
#define RX_ADDR_P0  0x0A  // 'RX address pipe0' register address
#define RX_ADDR_P1  0x0B  // 'RX address pipe1' register address
#define RX_ADDR_P2  0x0C  // 'RX address pipe2' register address
#define RX_ADDR_P3  0x0D  // 'RX address pipe3' register address
#define RX_ADDR_P4  0x0E  // 'RX address pipe4' register address
#define RX_ADDR_P5  0x0F  // 'RX address pipe5' register address
#define TX_ADDR     0x10  // 'TX address' register address
#define RX_PW_P0    0x11  // 'RX payload width, pipe0' register address
#define RX_PW_P1    0x12  // 'RX payload width, pipe1' register address
#define RX_PW_P2    0x13  // 'RX payload width, pipe2' register address
#define RX_PW_P3    0x14  // 'RX payload width, pipe3' register address
#define RX_PW_P4    0x15  // 'RX payload width, pipe4' register address
#define RX_PW_P5    0x16  // 'RX payload width, pipe5' register address
#define FIFO_STATUS 0x17  // 'FIFO Status Register' register address

#define MAX_RT      0x10 //达到最大重发次数中断标志位
#define TX_DS		0x20 //发送完成中断标志位	  // 

#define RX_DR		0x40 //接收到数据中断标志位


uint8_t SPI_NRF_WriteBuf(uint8_t reg ,uint8_t *pBuf,uint8_t bytes);
uint8_t SPI_NRF_ReadBuf(uint8_t reg,uint8_t *pBuf,uint8_t bytes);
uint8_t SPI_NRF_ReadReg(uint8_t reg);
uint8_t SPI_NRF_WriteReg(uint8_t reg,uint8_t dat);
extern  uint8_t RX_BUF[RX_PLOAD_WIDTH];		//接收数据缓存
extern uint8_t TX_BUF[TX_PLOAD_WIDTH];		//发射数据缓存
extern uint8_t TX_ADDRESS[TX_ADR_WIDTH];  // 定义一个静态发送地址
extern  uint8_t RX_ADDRESS[RX_ADR_WIDTH];
void NRF_RX_Mode(void);
void NRF_TX_Mode(void);
uint8_t NRF_Check(void);
uint8_t NRF_Tx_Dat(uint8_t *txbuf);
uint8_t NRF_Rx_Dat(uint8_t *rxbuf);

.c

uint8_t SPIx_ReadWriteByte(SPI_HandleTypeDef* hspi,uint8_t byte)
{
  uint8_t d_read,d_send=byte;
  if(HAL_SPI_TransmitReceive(hspi,&d_send,&d_read,1,0xFF)!=HAL_OK)
  {
    d_read=0xFF;
  }
  return d_read; 
}
/**
  * @brief   用于向NRF特定的寄存器写入数据
  * @param   
  *		@arg reg:NRF的命令+寄存器地址
  *		@arg dat:将要向寄存器写入的数据
  * @retval  NRF的status寄存器的状态
  */
uint8_t SPI_NRF_WriteReg(uint8_t reg,uint8_t dat)
{
	uint8_t status;
	CS_L();
	status =SPIx_ReadWriteByte(&hspi1,reg);
	SPIx_ReadWriteByte(&hspi1,dat);
	CS_H();
	return status;
}

/**
  * @brief   用于从NRF特定的寄存器读出数据
  * @param   
  *		@arg reg:NRF的命令+寄存器地址
  * @retval  寄存器中的数据
  */
uint8_t SPI_NRF_ReadReg(uint8_t reg)
{
	uint8_t val;
	CS_L();
	SPIx_ReadWriteByte(&hspi1,reg);
	val=SPIx_ReadWriteByte(&hspi1,0xff);
	CS_H();
	return val;
}	

/**
  * @brief   用于向NRF的寄存器中写入一串数据
  * @param   
  *		@arg reg : NRF的命令+寄存器地址
  *		@arg pBuf:用于存储将被读出的寄存器数据的数组,外部定义
  * 	@arg bytes: pBuf的数据长度
  * @retval  NRF的status寄存器的状态
  */
uint8_t SPI_NRF_ReadBuf(uint8_t reg,uint8_t *pBuf,uint8_t bytes)
{
	uint8_t status,u8_ctr;	       
  	CS_L();         //使能SPI传输
	  status=SPIx_ReadWriteByte(&hspi1,reg);
	
  //发送寄存器值(位置),并读取状态值   	   
 	for(u8_ctr=0;u8_ctr<bytes;u8_ctr++)//读出数据
	 pBuf[u8_ctr]=SPIx_ReadWriteByte(&hspi1,0xff);
  	CS_H();     //关闭SPI传输
  	return status;        //返回读到的状态值
}

/**
  * @brief   用于向NRF的寄存器中写入一串数据
  * @param   
  *		@arg reg : NRF的命令+寄存器地址
  *		@arg pBuf:存储了将要写入写寄存器数据的数组,外部定义
  * 	@arg bytes: pBuf的数据长度
  * @retval  NRF的status寄存器的状态
  */
uint8_t SPI_NRF_WriteBuf(uint8_t reg ,uint8_t *pBuf,uint8_t bytes)
{
uint8_t status,u8_ctr;	    
 	CS_L();          //使能SPI传输
		status= SPIx_ReadWriteByte(&hspi1,reg);
  	//发送寄存器值(位置),并读取状态值
  	for(u8_ctr=0; u8_ctr<bytes; u8_ctr++)
	{
		SPIx_ReadWriteByte(&hspi1,(*pBuf++)); //写入数据	 
	}	
	CS_H();        //关闭SPI传输
  	return status;          //返回读到的状态值
	
}

 uint8_t RX_BUF[RX_PLOAD_WIDTH];		//接收数据缓存
 uint8_t TX_BUF[TX_PLOAD_WIDTH];		//发射数据缓存
 uint8_t TX_ADDRESS[TX_ADR_WIDTH] = {0x34,0x43,0x10,0x10,0x01};  // 定义一个静态发送地址
 uint8_t RX_ADDRESS[RX_ADR_WIDTH] = {0x34,0x43,0x10,0x10,0x01};
/**
  * @brief  配置并进入接收模式
  * @param  无
  * @retval 无
  */
void NRF_RX_Mode(void)
{
	CE_L();	

   SPI_NRF_WriteBuf(NRF_WRITE_REG+RX_ADDR_P0,RX_ADDRESS,RX_ADR_WIDTH);//写RX节点地址,在配置时有RX_ADDR_P0~RX_ADDR_P5个通道,每个通道的RX_ADDRESS都一样根据需求自己设定

   SPI_NRF_WriteReg(NRF_WRITE_REG+EN_AA,0x01);    //使能通道0的自动应答 ,b‘0 ,0 0 0 1’ ,为0通道    

   SPI_NRF_WriteReg(NRF_WRITE_REG+EN_RXADDR,0x01);//使能通道0的接收地址    

   SPI_NRF_WriteReg(NRF_WRITE_REG+RF_CH,CHANAL);      //设置RF通信频率    

   SPI_NRF_WriteReg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);//选择通道0的有效数据宽度      

   SPI_NRF_WriteReg(NRF_WRITE_REG+RF_SETUP,0x0f); //设置TX发射参数,0db增益,2Mbps,低噪声增益开启   

   SPI_NRF_WriteReg(NRF_WRITE_REG+CONFIG, 0x0f);  //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式 

/*CE拉高,进入接收模式*/	
  CE_H();
 HAL_Delay(1);
}    

/**
  * @brief  配置发送模式
  * @param  无
  * @retval 无
  */
void NRF_TX_Mode(void)
{  
	CE_L();		

   SPI_NRF_WriteBuf(NRF_WRITE_REG+TX_ADDR,TX_ADDRESS,TX_ADR_WIDTH);    //写TX节点地址 

   SPI_NRF_WriteBuf(NRF_WRITE_REG+RX_ADDR_P0,RX_ADDRESS,RX_ADR_WIDTH); //设置TX节点地址,主要为了使能ACK   

   SPI_NRF_WriteReg(NRF_WRITE_REG+EN_AA,0x01);     //使能通道0的自动应答    

   SPI_NRF_WriteReg(NRF_WRITE_REG+EN_RXADDR,0x01); //使能通道0的接收地址  

   SPI_NRF_WriteReg(NRF_WRITE_REG+SETUP_RETR,0x1a);//设置自动重发间隔时间:500us + 86us;最大自动重发次数:10次

   SPI_NRF_WriteReg(NRF_WRITE_REG+RF_CH,CHANAL);       //设置RF通道为CHANAL

   SPI_NRF_WriteReg(NRF_WRITE_REG+RF_SETUP,0x0f);  //设置TX发射参数,0db增益,2Mbps,低噪声增益开启   
	
   SPI_NRF_WriteReg(NRF_WRITE_REG+CONFIG,0x0e);    //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,发射模式,开启所有中断

/*CE拉高,进入发送模式*/	
  CE_H();
	 HAL_Delay(1);
   // HAL_Delay(0xffff); //CE要拉高一段时间才进入发送模式
}

/**
  * @brief  主要用于NRF与MCU是否正常连接
  * @param  无
  * @retval SUCCESS/ERROR 连接正常/连接失败
  */
static uint8_t buf[5]={0xC2,0xC2,0xC2,0xC2,0xC2};
uint8_t buf1[5]={0};
uint8_t NRF_Check(void)
{
	
	uint8_t buf[5]={0XA5,0XA5,0XA5,0XA5,0XA5};
	uint8_t i;
  
	SPI_NRF_WriteBuf(NRF_WRITE_REG+TX_ADDR,buf,5);//写入5个字节的地址.	
	memset(buf,0,5);
	SPI_NRF_ReadBuf(TX_ADDR,buf,5); //读出写入的地址  
	for(i=0;i<5;i++)if(buf[i]!=0XA5)break;	 							   
	if(i!=5)return 1;//检测24L01错误	
	return 0;		 //检测到24L01

}

/**
  * @brief   用于向NRF的发送缓冲区中写入数据
  * @param   
  *		@arg txBuf:存储了将要发送的数据的数组,外部定义	
  * @retval  发送结果,成功返回TXDS,失败返回MAXRT或ERROR
  */
uint8_t NRF_Tx_Dat(uint8_t *txbuf)
{
	uint8_t state;  
	
		CE_L();

  	SPI_NRF_WriteBuf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);//写数据到TX BUF  32个字节
 		 CE_H();//启动发送	   
	while(READ_IRQ()!=0);//等待发送完成
	state=SPI_NRF_ReadReg(STATUS);  //读取状态寄存器的值	   
	SPI_NRF_WriteReg(NRF_WRITE_REG+STATUS,state); //清除TX_DS或MAX_RT中断标志
	if(state&MAX_RT)//达到最大重发次数
	{
		SPI_NRF_WriteReg(FLUSH_TX,0xff);//清除TX FIFO寄存器 
		printf("state&(MAX_RT) %0x \n ",state&(MAX_RT) );
		printf("state %0x \n",state);
		return MAX_RT; 
	}
	if(state&TX_DS)//发送完成
	{
		return TX_DS;
	}
	return 0xff;//其他原因发送失败

} 

/**
  * @brief   用于从NRF的接收缓冲区中读出数据
  * @param   
  *		@arg rxBuf :用于接收该数据的数组,外部定义	
  * @retval 
  *		@arg 接收结果
  */
uint8_t NRF_Rx_Dat(uint8_t *rxbuf)
{
	uint8_t state; 
	
	 /*等待接收中断*/
	
	state=SPI_NRF_ReadReg(STATUS);  //读取状态寄存器的值    	 
	SPI_NRF_WriteReg(NRF_WRITE_REG+STATUS,state); //清除TX_DS或MAX_RT中断标志
	if(state&RX_DR)//接收到数据
	{
		SPI_NRF_ReadBuf(RD_RX_PLOAD,rxbuf,RX_PLOAD_WIDTH);//读取数据
		SPI_NRF_WriteReg(FLUSH_RX,0xff);//清除RX FIFO寄存器 
		return 0; 
	}	   
	return 1;//没收到任何数据

}

自测调用

  /*检测 NRF 模块与 MCU 的连接*/
void Self_Test(void)
{
  /*判断连接状态*/  
  if(NRF_Check() == SUCCESS)	   
    printf("\r\n NRF1与MCU连接成功! \r\n");  
  else	  
    printf("\r\n NRF1与MCU连接失败,请重新检查接线。\r\n");

  NRF_RX_Mode();  // NRF1 进入接收模式
  while(1)
  {
    /* 等待 NRF1 接收数据 */
    /* 判断接收状态 */
    if(NRF_Rx_Dat(rxbuf) == 0)
    {
      printf("\r\n NRF1 接收数据为: \r\n"); 
 //     for(i=0;i<32;i++)
 //    {	
 //       printf(" %d ",rxbuf[i]); 
 //    }
       printf("\n %s ",rxbuf); 
    }
    
    /* NRF1 发送数据 */	
    if ( get_date(rs_buf) == 1)  // 获取发送数据,开始送数据
    { 
      /* 发送数据 */
      NRF_TX_Mode(); 
      status = NRF_Tx_Dat(rs_buf);
      /* 发送数据的状态 */
       if(status == TX_DS)
      {
        printf("\r\nNRF1 发送数据成功\r\n");
        
      }
      else
      {
        printf("\r\nNRF1 发送数据失败  %d\r\n", status);
      }
      memset(rs_buf,0,u_size);
      //再次开启接收,并等候接收。
      printf("\r\nNRF1 进入接收模式\r\n"); 
      NRF_RX_Mode();
    }

  }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2309544.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

NVIDIA GPU 架构详解:Pascal、Volta、Turing、Ampere、Ada、Hopper、Blackwell

目录 1. Pascal&#xff08;帕斯卡&#xff09;架构&#xff08;2016&#xff09;关键技术性能特性代表产品应用场景 2. Volta&#xff08;伏特&#xff09;架构&#xff08;2017&#xff09;关键技术性能特性代表产品应用场景 3.Turing&#xff08;图灵&#xff09;架构&#…

初阶数据结构(C语言实现)——3顺序表和链表(2)

2.3 数组相关面试题 原地移除数组中所有的元素val&#xff0c;要求时间复杂度为O(N)&#xff0c;空间复杂度为O(1)。OJ链接 力扣OJ链接-移除元素删除排序数组中的重复项。力扣OJ链接-删除有序数组中的重复项合并两个有序数组。力扣OJ链接-合并两个有序数组 2.3.1 移除元素 1…

IP-----BGP协议

7.BGP协议 1.BGP的所属分类 2.BGP的特性 3.BGP的数据包 4.BGP的6种状态机 5.BGP的工作过程 6.BGP的路由黑洞 1.BGP路由黑洞 2.解决方法 7.BGP的防环 1.EBGP水平分割 2.IBGP水平分割 1.解决IBGP环路的规则 2.解决IBGP水平分割问题 3.作用 8.BGP的基础配置 1.查看…

【String】917. 仅仅反转字母

917. 仅仅反转字母 - 力扣&#xff08;LeetCode&#xff09; 使用双指针&#xff0c;一个指针指向s的开始&#xff0c;一个指向s的末尾&#xff0c;同时遍历即可。

python3使用selenium打开火狐并全屏

序言 本来桌面端全屏这种东西现在用electron或者tauri来做软件的全屏&#xff0c;但是奈何今天拿到了一块早些年的nx板子&#xff0c;arm架构的&#xff0c;系统有点老&#xff0c;装node只能到16版本&#xff0c;装了半天终于搞好了&#xff0c;发现这个系统没法隐藏系统的顶…

探秘基带算法:从原理到5G时代的通信变革【二】Viterbi解码

文章目录 二、关键算法原理剖析2.1 Viterbi 解码2.1.1 卷积码与网格图基础**卷积码****网格图****生成多项式****理想情况下解码过程** 2.1.2 Viterbi 算法核心思想2.1.3 路径度量与状态转移机制2.1.4 算法流程与关键步骤详解2.1.5 译码算法举例与复杂度分析2.1.6 算法代码示例…

金融项目实战

测试流程 测试流程 功能测试流程 功能测试流程 需求评审制定测试计划编写测试用例和评审用例执行缺陷管理测试报告 接口测试流程 接口测试流程 需求评审制定测试计划分析api文档编写测试用例搭建测试环境编写脚本执行脚本缺陷管理测试报告 测试步骤 测试步骤 需求评审 需求评…

命令行参数和环境变量 ─── linux第13课

目录 命令行参数 命令行参数列表: 如何实现命令行参数传递到此进程 环境变量 基本概念 常见环境变量 查看环境变量方法 ​编辑 环境变量如何写入 总结: 测试PATH 命令行参数 同一个程序,可以根据命令行参数的不同,表现不同功能 比如:指令中的选项的实现. ls -al…

基于 openEuler 22.09 的 OpenStack Yoga 部署

openEuler 虚拟化环境部署 使用 VMWare Workstation 创建三台 2 CPU、8G内存、100 GB硬盘 的虚拟机 主机 IP 作用 Controller 192.168.184.110 控制节点 Compute 192.168.184.111 计算节点 Storage 192.168.184.112 存储节 一 基础配置 1.1 配置 yum 源 由于 op…

【Linux实践系列】:用c语言实现一个shell外壳程序

&#x1f525;本文专栏&#xff1a;Linux Linux实践项目 &#x1f338;博主主页&#xff1a;努力努力再努力wz 那么今天我们就要进入Linux的实践环节&#xff0c;那么我们之前学习了进程控制相关的几个知识点&#xff0c;比如进程的终止以及进程的等待和进程的替换&#xff0c;…

conda安装及超详细避坑实战

1. Anaconda介绍。 Anaconda是一站式数据科学与机器学习平台&#xff0c;专为开发者、数据分析师设计,并带有python中超过180个科学包及其依赖项。通过 Anaconda&#xff0c;您可以轻松管理数据环境、安装依赖包&#xff0c;快速启动数据分析、机器学习项目。 Anaconda集成了…

LM studio 加载ollama的模型

1.LM 下载&#xff1a; https://lmstudio.ai/ 2.ollama下载&#xff1a; https://ollama.com/download 3.打开ollama&#xff0c;下载deepseek-r1。 本机设备资源有限&#xff0c;选择7B的&#xff0c;执行ollama run deepseek-r1:7b 4.windows chocolatey下载&#xff1a; P…

深入探索像ChatGPT这样的大语言模型-02-POST training supervised finetuning

参考 【必看珍藏】2月6日&#xff0c;安德烈卡帕西最新AI普及课&#xff1a;深入探索像ChatGPT这样的大语言模型&#xff5c;Andrej Karpathy fineweb知乎翻译介绍 fineweb-v1原始连接 fineweb中文翻译版本 Chinese Fineweb Edu数据集 查看网络的内部结果&#xff0c;可以参…

Kaldi环境配置与Aishell训练

一、项目来源 代码来源&#xff1a;kaldi-asr/kaldi: kaldi-asr/kaldi is the official location of the Kaldi project. (github.com) 官网文档&#xff1a;Kaldi: The build process (how Kaldi is compiled) (kaldi-asr.org) 踩着我的同门李思成-CSDN博客填上的坑kaldi环境…

数据集/API 笔记:新加坡PSI(空气污染指数)API

data.gov.sg 数据范围&#xff1a;2016年2月 - 2025年3月 1 获取API方式 curl --request GET \--url https://api-open.data.gov.sg/v2/real-time/api/psi 2 返回数据 API 的数据结构可以分为 3 大部分&#xff1a; 区域元数据&#xff08;regionMetadata&#xff09; →…

【GPU使用】如何在物理机和Docker中指定GPU进行推理和训练

我的机器上有4张H100卡&#xff0c;我现在只想用某一张卡跑程序&#xff0c;该如何设置。 代码里面设置 import os # 记住要写在impot torch前 os.environ[CUDA_VISIBLE_DEVICES] "0, 1"命令行设置 export CUDA_VISIBLE_DEVICES0,2 # Linux 环境 python test.py …

【Java项目】基于SpringBoot的CSGO赛事管理系统

【Java项目】基于SpringBoot的CSGO赛事管理系统 技术简介&#xff1a;采用SpringBoot框架、Java语言、MySQL数据库等技术实现。 系统简介&#xff1a;CSGO赛事管理系统是一个基于B/S架构的管理系统&#xff0c;主要功能包括前台和后台管理模块。前台系统功能模块分为&#xf…

MIPI接口:(4)MIPI CSI-2协议详解(上)

1. 什么是CSI&#xff1f; CSI&#xff08;Camera Serial Interface&#xff09;是MIPI联盟早期制定的摄像头接口标准&#xff0c;主要用于连接摄像头和处理器。 CSI-2是CSI的第二代版本&#xff0c;在原有基础上进行了全面优化&#xff1a; &#xff08;1&#xff09;分层架…

防火墙旁挂组网双机热备负载均衡

一&#xff0c;二层交换网络&#xff1a; 使用MSTPVRRP组网形式 VLAN 2--->SW3为主,SW4 作为备份 VLAN 3--->SW4为主,SW3 作为备份 MSTP 设计 --->SW3 、 4 、 5 运行 实例 1 &#xff1a; VLAN 2 实例 2 &#xff1a; VLAN 3 SW3 是实例 1 的主根&#xff0c;实…

视频教育网站开源系统的部署安装 (roncoo-education)服务器为ubuntu22.04.05

一、说明 前端技术体系&#xff1a;Vue3 Nuxt3 Vite5 Vue-Router Element-Plus Pinia Axios 后端技术体系&#xff1a;Spring Cloud Alibaba2021 MySQL8 Nacos Seata Mybatis Druid redis 后端系统&#xff1a;roncoo-education&#xff08;核心框架&#xff1a;S…