拓展模块使用教程和心得(二):2.4G通信模块nRF24L01及周边知识

您所在的位置:网站首页 无线模块使用教程图解大全 拓展模块使用教程和心得(二):2.4G通信模块nRF24L01及周边知识

拓展模块使用教程和心得(二):2.4G通信模块nRF24L01及周边知识

2024-04-10 03:07| 来源: 网络整理| 查看: 265

成就更好的自己

课设用到了nRF24L01模块,设计和调试前后出现一些问题,开一篇博客说一下理论方面和使用中的问题

目录

元件介绍

工作模式及理论知识

与MCU通信方式:SPI通信

nRF24L01之间的无线通信

细枝末节知识点

一对一通信源码加注释

调试时的问题

题外话

 

元件介绍:

宽电压工作范围,1.9V~3.6V,输入引脚可承受5V电压输入

工作温度范围,-40℃~+80℃

调制方式:GFSK/FSK

工作频率范围,2.400GHz~2.525GHz

发射功率可选择为0dBm、-6dBm、-12dBm和-18dBm

数据传输速率支持1Mbps、2Mbps [1]

极少外围器件,降低系统应用成本

低功耗设计,接收时工作电流12.3mA,0dBm功率发射时11.3mA,掉电模式时仅为900nA

126个通讯通道,6个数据通道,满足多点通讯和调频需要

增强型“ShockBurst”工作模式,硬件的CRC校验和点对多点的地址控制

数据包每次可传输1~32Byte的数据

4线SPI通讯端口,通讯速率最高可达8Mbps,适合与各种MCU连接,编程简单可通过软件设置工作频率、通讯地址、传输速率和数据包长度

MCU可通过IRQ引脚块判断是否完成数据接收和数据发送

芯片引脚(QFN20 4x4mm封装):

典型应用电路:

 

一般用到的也都是制作好的成品模块,如下:

对应的引脚定义及功能如下:

CE:模块控制线,CSN为低时,CE协同CONFIG寄存器共同决定NRF24L01状态(发送或接收模式)

CSN:SPI片选线,控制是否激活配置模式

SCK: SPI时钟线

MOSI:SPI数据线(主机输出从机输入)

MISO:SPI数据线(主机输入从机输出)

IRQ:中断信号线。中断时变为低电平,在以下三种情况变低:Tx FIFO发完并且收到ACK(使能ACK情况下)、Rx FIFO收到数据、达到最大重发次数

 

 

工作模式及理论知识:

按照博主的理解,言简意赅的说一下

Nrf24L01一般使用只在这3个模式下:

待机模式

接收模式

发送模式(细分为准备发送和正在发送两种模式)

且在上面三种模式下,只有待机模式和准备发送模式下才能对nRF内部各寄存器进行修改

 

与MCU通信方式:SPI通信

所采用的通信协议如下:

每次通讯由两部分内容组成:指令格式+数据

而且指令格式也由两部分组成:命令+寄存器地址(有时候寄存器地址为空,只有命令,是因为有的命令默认对指定的寄存器操作,理解不了的看下图)

综上所示,每次通信为命令+寄存器地址+数据;

下图为指令格式(命令+寄存器地址)

如果是写寄存器的话,指令格式后的数据是由主机发出的

如果是读寄存器的话,指令格式后的数据由nRF24L01发出

nFR寄存器太多,就不一一介绍了,我会在代码段介绍几个常用的寄存器

 

nRF24L01之间的无线通信

上面讲的都是主机与nRF24L01的总线通信,是对Nrf24L01的设置和数据传输,下面讲解nRF24L01之间的无线通信和数据收发

nrf发送数据是以包来发送

前导码和CRC不用管,具体看中间两部分:

地址:地址也就是接收到通道的地址,,1个nRF有6个通道,每个通道有有自己的一个地址

如果是能了自动应答,那么我们得将发送地址(TX_ADDR) 和接受应答信号的通道地址(RX_ADDR_P0)设置为一样的。

数据:接收至少1字节,最多32字节,作为一次通信的数据包,这个是需要设置的,这个接收的数据有效宽度需要与发射端的发射数据宽度一致,否则会出现各种问题;

一次完整的发送数据流程如下:

发送流程:发送方根据发送地址(TX_ADDR)发送到接收方(RX_ADDR_P0)接收方收到数据后以接收通道的地址(RX_ADDR_P0)为发送地址发送应答信号给发送方(这个应答信号为自动发送不需要人为发送)。

例如:发送方TX_ADDR=0x10=接收方接收通道地址(以通道0为例:RX_ADDR_P0)=发送端接收通道地址(以通道0为例:RX_ADDR_P0),  总的来说就是接受方发送地址和接受应答信号的通道地址和接受方地址要一致。

多机组网只需要使能接收方全部通道并且分配好地址就ok了。

对于地址的分配要注意:

通道0和通道1的地址为5字节可随意给值。

其他2~5高4字节与通道1高四字节相同(通用高4字节)我们只能修改他的左后一个字节地址

 

细枝末节知识点:

IRQ引脚一般接到普通IO口上,有时候为了确保实时性和对接收的数据尽快处理,会把IRQ接到外部中断上,在中断服务子函数处理数据;

IRQ产生低电平的条件是1.发送数据成功(开应答的必须要收到应答后才算完成)2.接收数据成功3.发送数据达到最大重发次数,且可以设置这三个条件发生后是否产生中断;

博主在开始的时候一直以为发送方的数据只要在32字节内,接收方都会接受,而且全都放入RX_FIFO寄存器(临时存放已经接受的数据的寄存器),只不过读RX_FIFO寄存器时读的是有效长度的数据,但是实际情况是只会让有效长度的数据进入RX_FIFO寄存器;所以一定要保证发送接收双方的数据长度一致,否则会影响数据帧中CRC部分的数据进而导致通信失败;

写入寄存器的时候记得拉低CE引脚;

nRF24L01的最多互通节点数量是多少呢?答案是无数个;

 

一对一通信源码加注释:

平台:STM32F103C8T6

头文件: #include "stm32f10x.h" #include "sys.h" typedef unsigned char uint8; typedef unsigned int uint16; /********************** 引脚别名定义 ***********************/ #define NRF_CE GPIO_Pin_3 //使能控制 #define NRF_CS GPIO_Pin_4 //模拟SPI片选 #define SPI_CLK GPIO_Pin_5 //模拟SPI时钟 #define SPI_MOSI GPIO_Pin_7 //模拟SPI主出从入 #define SPI_MISO GPIO_Pin_6 //模拟SPI主入从出 #define NRF_IRQ GPIO_Pin_2 //中断 #define NRF_IRQ_STATUS GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2) #define CE_LOW PAout(3)=0 //带位定义,使用会报错,修改为原始库函数GPIO_ResetBits即可 #define CE_HIGH PAout(3)=1 //同上 #define CS_LOW PAout(4)=0 //同上 #define CS_HIGH PAout(4)=1 //同上 //无线收发地址宽度(字节数) #define TX_ADDR_WIDTH 5 #define RX_ADDR_WIDTH 5 //无线收发数据长度(字节数) #define TX_PLOAD_WIDTH 1 #define RX_PLOAD_WIDTH 1 //无线收发中断标志 #define MAX_TX 0x10 //达到最大发送次数中断 #define TX_OK 0x20 //TX发送完成中断 #define RX_OK 0x40 //接收到数据中断 /****************************************************************************************************/ //NRF24L01寄存器操作命令(共11个) #define SPI_READ_REG 0x00 //读配置寄存器,低5位为寄存器地址 #define SPI_WRITE_REG 0x20 //写配置寄存器,低5位为寄存器地址 #define RD_RX_PLOAD 0x61 //读RX有效数据(低字节先出),1~32字节 #define WR_TX_PLOAD 0xA0 //写TX有效数据,1~32字节 #define FLUSH_TX 0xE1 //清除TX FIFO寄存器.发射模式下用 #define FLUSH_RX 0xE2 //清除RX FIFO寄存器.接收模式下用 #define REUSE_TX_PL 0xE3 //重新使用上一包数据,CE为高,数据包被不断发送 #define RD_RX_PL_WID 0x60 //读RX有效数据(高字节先出),1~32字节 #define W_ACK_PLOAD 0xA0 //发送寄存器,写入数据可发送出去 #define W_TX_PLOAD_NACK 0xB0 //发送寄存器,写入数据可发送出去,但不应答 #define RF_NOP 0xFF //空操作,可以用来读状态寄存器 //NRF24L01寄存器地址(共24个) #define CONFIG 0x00 //配置寄存器地址;bit0:1接收模式,0发射模式;bit1:电选择;bit2:CRC模式;bit3:CRC使能; //bit4:中断MAX_RT(达到最大重发次数中断)使能;bit5:中断TX_DS使能;bit6:中断RX_DR使能 #define EN_AA 0x01 //使能自动应答功能 bit0~5,对应通道0~5 #define EN_RXADDR 0x02 //接收地址允许,bit0~5,对应通道0~5 #define SETUP_AW 0x03 //设置地址宽度(所有数据通道):bit1,0:00,3字节;01,4字节;02,5字节; #define SETUP_RETR 0x04 //建立自动重发;bit3:0,自动重发计数器;bit7:4,自动重发延时 250*x+86us #define RF_CH 0x05 //RF通道,bit6:0,工作通道频率; #define RF_SETUP 0x06 //RF寄存器;bit5,bit3:传输速率(00:1Mbps,01:2Mbps,10:250Kbps);bit2:1,发射功率;bit0:低噪声放大器增益 #define STATUS 0x07 //状态寄存器;bit0:TX FIFO满标志;bit3:1,接收数据通道号(最大:6);bit4,达到最多次重发 //bit5:数据发送完成中断;bit6:接收数据中断; #define OBSERVE_TX 0x08 //发送检测寄存器,bit7:4,数据包丢失计数器;bit3:0,重发计数器 #define CD 0x09 //载波检测寄存器,bit0,载波检测; #define RX_ADDR_P0 0x0A //数据通道0接收地址,最大长度5个字节,低字节在前 #define RX_ADDR_P1 0x0B //数据通道1接收地址,最大长度5个字节,低字节在前 #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 //发送地址(低字节在前),ShockBurstTM模式下,RX_ADDR_P0与此地址相等 #define RX_PW_P0 0x11 //接收数据通道0有效数据宽度(1~32字节),设置为0则非法 #define RX_PW_P1 0x12 //接收数据通道1有效数据宽度(1~32字节),设置为0则非法 #define RX_PW_P2 0x13 //接收数据通道2有效数据宽度(1~32字节),设置为0则非法 #define RX_PW_P3 0x14 //接收数据通道3有效数据宽度(1~32字节),设置为0则非法 #define RX_PW_P4 0x15 //接收数据通道4有效数据宽度(1~32字节),设置为0则非法 #define RX_PW_P5 0x16 //接收数据通道5有效数据宽度(1~32字节),设置为0则非法 #define FIFO_STATUS 0x17 //FIFO状态寄存器;bit0,RX FIFO寄存器空标志;bit1,RX FIFO满标志;bit2,3,保留 //bit4,TX FIFO空标志;bit5,TX FIFO满标志;bit6,1,循环发送上一数据包.0,不循环; /****************************************************************************************************/ extern void NRF24L01_INIT(void); extern void Set_TXMode(void); extern void Set_RXMode(void); extern uint8 NRF24L01_TXPacket(uint8 *txbuf); extern uint8 NRF24L01_RXPacket(uint8 *rxbuf);

 

发射模式配置:

1.写入发送地址和接受应答通道地址

2.使能应答通道

3.使能接收地址

4.设置自动重发时间和重发次数

5.设置通信频道

6.设置发射参数(功率,增益等)

7.设置模式(发送还是接受)

注意在配置发送或者接受时候要先让其工作再待机模式即CE要先置0.

/***************************************************************************** * 函 数:void NRF24L01_TX_Mode(void) * 功 能:NRF24L01发送模式配置 * 参 数:无 * 返回值:无 * 备 注:无 *****************************************************************************/ void Set_TXMode(void) { CE_LOW; //写TX节点地址 NRF24L01_Write_Buf(SPI_WRITE_REG+TX_ADDR,(uint8*)TX_ADDRESS,TX_ADDR_WIDTH); //设置RX节点地址,使能ACK(应答) NRF24L01_Write_Buf(SPI_WRITE_REG+RX_ADDR_P0,(uint8*)RX_ADDRESS,RX_ADDR_WIDTH); //使能通道0的自动应答 NRF24L01_Write_Reg(SPI_WRITE_REG+EN_AA,0x01); //使能通道0的接收地址 NRF24L01_Write_Reg(SPI_WRITE_REG+EN_RXADDR,0x01); //设置自动重发间隔时间:750us+86us ;最大自动重发次数:5次 NRF24L01_Write_Reg(SPI_WRITE_REG+SETUP_RETR,0x25); //设置RF通道工作频率 NRF24L01_Write_Reg(SPI_WRITE_REG+RF_CH,40); //设置TX发射参数,0db增益,250Kbps,低噪声增益开启 NRF24L01_Write_Reg(SPI_WRITE_REG+RF_SETUP,0x26); //设置为发送模式PTX,使能PWR_UP、EN_CRC,使能CRC为2字节 ,开启RX_DR、TX_DS、MAX_RT中断引脚 NRF24L01_Write_Reg(SPI_WRITE_REG+CONFIG,0x0e); CE_HIGH; delay_ms(12); }

 

接收模式配置:

1.接收通道地址

2.接收通道有效数据宽度

3.使能通道自动应答

4.使能接受通道地址

5.设置通信频道

6.设置参数

7.配置工作模式

/***************************************************************************** * 函 数:void NRF24L01_RX_Mode(void) * 功 能:NRF24L01接收模式配置 * 参 数:无 * 返回值:无 * 备 注:无 *****************************************************************************/ void Set_RXMode(void) { CE_LOW; //写RX节点地址 NRF24L01_Write_Buf(SPI_WRITE_REG+RX_ADDR_P0,(uint8 *)RX_ADDRESS,RX_ADDR_WIDTH); //使能通道0的自动应答 NRF24L01_Write_Reg(SPI_WRITE_REG+EN_AA,0x01); //使能通道0的接收地址 NRF24L01_Write_Reg(SPI_WRITE_REG+EN_RXADDR,0x01); //设置RF通道工作频率 NRF24L01_Write_Reg(SPI_WRITE_REG+RF_CH,40); //选择通道0的有效数据宽度 NRF24L01_Write_Reg(SPI_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH); //设置TX发射参数,0db增益,250Kbps,低噪声增益开启 NRF24L01_Write_Reg(SPI_WRITE_REG+RF_SETUP,0x26); //设置为接收模式PRX,使能PWR_UP、EN_CRC,使能CRC为2字节,开启RX_DR、TX_DS、MAX_RT中断引脚 NRF24L01_Write_Reg(SPI_WRITE_REG+CONFIG, 0x0f); //CE为高,进入接收模式 CE_HIGH; }

 

发送一帧数据(1~32字节):

1.向fifo中写入数据,等待IRQ发送完成中断

2.读取状态寄存器中的值

3.将读取到的状态寄存器中的值写入状态寄存器

4,.判断之前读取到的状态寄存器中得值判断是发送完成还是发送失败

5.清空fifo寄存器

/***************************************************************************** * 函 数:uint8_t NRF24L01_TX_Packet(uint8_t *txbuf) * 功 能:NRF24L01发送一次数据 * 参 数:*txbuf:等待发送数据的首地址 * 返回值:MAX_TX:最大重发次数;TX_OK:发送完成;0xFF:发送失败 * 备 注:无 *****************************************************************************/ uint8 NRF24L01_TXPacket(uint8_t *buf) { uint8 state; CE_LOW; NRF24L01_Write_Buf(WR_TX_PLOAD, buf, TX_PLOAD_WIDTH);//写数据到txbuf,32字节 CE_HIGH;//启动发送 while(NRF_IRQ_STATUS!=0);//等待发送完成 state = NRF24L01_Read_Reg(STATUS);//读取状态寄存器的值 NRF24L01_Write_Reg(SPI_WRITE_REG+STATUS, state);//清除TX_DS or MAX_RT的中断标志 if(state&MAX_TX)//达到最大重发次数 { NRF24L01_Write_Reg(FLUSH_TX, 0XFF);//清除TX FIFO 寄存器 return MAX_TX; } if(state&TX_OK) //发送完成 { return TX_OK; } return 0xFF;//发送失败 }

 

接收一帧数据(1~32字节):

1.读取状态寄存器中的值

2.将读取到的状态寄存器中的值写入状态寄存器

4.判断状态寄存器中得值,是否接受成功(成功就读取fifo中的数据,并且清空fifo)

/***************************************************************************** * 函 数:uint8_t NRF24L01_RX_Packet(uint8_t *rxbuf) * 功 能:NRF24L01接收一次数据 * 参 数:*rxbuf:等待接收数据的首地址 * 返回值:0:接收成功;1:接收数据失败 * 备 注:无 *****************************************************************************/ uint8 NRF24L01_RXPacket(uint8_t *buf) { uint8 state; CE_HIGH; while(NRF_IRQ_STATUS!=0); CE_LOW; state = NRF24L01_Read_Reg(STATUS);//读取状态寄存器的值 NRF24L01_Write_Reg(SPI_WRITE_REG+STATUS, state);//清除TX_DS or MAX_RT的中断标志 if(state&RX_OK)//接收到数据 { NRF24L01_Read_Buf(RD_RX_PLOAD,buf,RX_PLOAD_WIDTH);//读取数据 NRF24L01_Write_Reg(FLUSH_RX,0xFF);//清除RX FIFO寄存器 return RX_OK; } return 0;//没有接收到数据 }

 

前置读写函数: /***************************************************************************** * 函 数:uint8_t NRF24L01_Write_Reg(uint8_t res,uint8_t value) * 功 能:从寄存器写入一字节数据 * 参 数:res:寄存器地址;value:写入的值 * 返回值:status:读取的寄存器状态值 * 备 注:无 *****************************************************************************/ uint8 NRF24L01_Write_Reg(uint8_t regaddr,uint8_t dat) { uint8 status; CS_LOW; status = SPI_RW(regaddr); SPI_RW(dat); CS_HIGH; return status; //返回寄存器状态值 } /***************************************************************************** * 函 数:uint8_t NRF24L01_Read_Reg(uint8_t res) * 功 能:从寄存器读取一字节数据 * 参 数:res:寄存器地址 * 返回值:ret:读取的值 * 备 注:无 *****************************************************************************/ uint8 NRF24L01_Read_Reg(uint8_t regaddr) { uint8 dat; CS_LOW; SPI_RW(regaddr); dat = SPI_RW(0xFF); //在读取数据前稳定MISO的电平,防止触发slave设备 CS_HIGH; return dat; } /***************************************************************************** * 函 数:uint8_t NRF24L01_Read_Buf(uint8_t res,uint8_t len,uint8_t *pBuf) * 功 能:在指定位置读取一定长度的数据 * 参 数:res:指定位置;len:数据长度;*pBuf:指定数据的首地址 * 返回值:status:寄存器的状态 * 备 注:无 *****************************************************************************/ uint8 NRF24L01_Read_Buf(uint8_t regaddr,uint8_t *pBuf,uint8_t len) { uint8 status,temp; CS_LOW; status = SPI_RW(regaddr); for(temp=0;temp


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3