NRF24L012.4G模块

datasheet

NRF24L01模块资料:https://download.csdn.net/download/acktomas/11135884

1. 相关案例:

使用Arduinon开发板连接RF24L01实现控制伺服电机:
https://www.yiboard.com/thread-970-1-1.html
如何使用Arduino UNO、操纵杆模块和NRF24L01模块控制伺服电机:
https://www.yiboard.com/thread-1095-1-1.html
如何使用多个NRF24L01模块搭建一个Arduino无线网络
https://www.yiboard.com/thread-985-1-1.html

2. nRF24L01通信的常识

  1. 用5根线的SPI接口向2401发送数据或指令。
  2. 芯片在每次上电的时候都需要进行一番配置。这些配置数据,就是所谓的指令了。
  3. 配置完成后知道芯片处在哪个模式。并且知道它将要转向哪个模式。
  4. 通讯协议。
  5. 观察现象。

好了,小牛们一定急切想知道自己的程序问题出在哪里了,再小白一点的一定想急切的知道如何配置才能让它工作。更小白一点的一定想知道这个芯片的各个模式之间是怎么联系的。又是如何进行相互转化的。别急,一个一个说。

1. 发送模式。

发送模式要经历几个变化。

  1. 上电,上电完了芯片其实还是在powerDown模式,因为芯片为了省电,它需要通过软件来控制开机或关机。powerDown模式就是所谓的待机模式了。这个模式理所当然是最省电的。它除了省电以外还能干吗呢?配置!对最重要的配置。就是可以通过SPI口向它发送数据,它是可以接收到的,并且可以正确写入到指定的寄存器中的。一般我们在初始化一开始就可以配置了,而此时芯片正是处在这个模式。

  2. 我们的目标是要把它配置的能发送数据,而且能被目标设备正确接收。所以这中间涉及的寄存器(当然是2401里自带的寄存器区了)有:

    1. 发送到的目标地址。 说地址其实是虚的,它就相当于一个钥匙和一把锁一样。当你在接收设备里边规定了一个地址以后,那么接收到的数据只有带了这个地址的包才会被正确接收。所以说这里的发送目标地址就是接收设备里的本机地址。只要设计时两个地址相同,就不会接收不到。
    2. @接收到的地址。 这个名字起的不是很好哈,有点误导人。说白了就是一个本机地址了。在纯发射机里,它并不是必要的。因为它从来不接收数据~~~这里写上,是因为:发射模式还有个东西,就是自动应答功能,(当然也是通过配置才能启用的,不配置则不会自动应答,也就不需要知道本机地址了)。
    3. 说到自动应答,那就先说它吧。一般我们会想,发送出一帧数据后是不是应该等待另一方回应个数据呀?想法是好的,但我说了,有通讯协议在控制。因为我们这里只想设计成一直发送而不管对方是否收到。所以自动应答可以不去配置,让它开机默认即可。但实际上我们的通讯协议可能很复杂,肯定不会是一直在发送。并且,它发送完一帧后,确实应该转为接收模式来等待对方发送应答数据过来。我们人为的当然可以自己来个模式跳转,但是有自动应答了,也就是说,当你设定开启自动应答了,那么在它发送完一包数据后,芯片会立即转为接收模式了。 《在这里我也仍有一点没理解,就是,当它收到应答后会变成什么模式呢,是自动再回到发送模式还是停留在接收模式。》
    4. 有自动应答了,那么就不能少了自动重发功能了。为什么呢。首先理解为什么会自动重发,就因为它处在自动应答模式时,通过接收数据来判定上次的数据是否有接收者成功接收了,就像我送出了一封信,如果你没有回信我是不是会想你可能没收到信,我需要再发一次。就是这个道理 。自动重发寄存器8位被分成两个4位的小区域,高4位存的是重发间隔时间,也就是说总共可以设定为16种不同的间隔,在这个间隔时间过后仍没有回应才再次重发。低4位好说,就是存一个最大重发次数。则最大可以设为15,即重发15次后仍然没回应那就不理你了,不再重发了。并且还会产生一个中断呢。最后再讲中断部分。 这里应该注意的是,当自动应答功能禁止时,就没有自动重发了,不管你设了重发多少次都不管用了。所以是互相影响的。还有就是重发次数设为0次,则相当于禁自动重发了,这不是显然的么。嘿嘿。
    5. 最基本的配置,,频率。这个芯片不光能以2.4Ghz的载波发射呢,它的带宽为2.4G----2.512G呢。这中间有一百多M的频带,可以划分成2M一个的信道。这个寄存器中的值就标明你想工作在哪个信道上啦,只有设置为同频的设备才能接收的到很容易理解吧。比如你设为10信道,则10*2=20M即发送时所用的载波频率就是2400+20=2420MHz。当然也只有设为2420M的接收设备才能接收的到了。
    6. 功率,数据速率。这是什么呢?原来2401里边也有自动增益控制部分,我们可以设定一个合适的功率来发射数据,第一可以在能耗上有利,另一方面对通信距离的控制也是很重要的。比如我只想在2米内能够通信,但2401最大的通信距离可以达到上百米,显然需要降发射功率来降低通信距离。可选的功率值有 0Dbm,-6dBm, -12dBm,-18dBm, 显然0在这里是最大的发射功率了。开发时尽可能设为0.如果设为0时,接收者都接收不到数据,那肯定是芯片坏了,就不用考虑降低功耗来通信了。这四档功率,通信距离从远到近,从几十米到几cm.并且在通信过程中还可以动态更改这个功率值,以达到最佳匹配的效果。数据速率是什么呢,刚开始我跟SPI接口的速率搞混了,想着,一个4M的单片机跟芯片通信速率怎么可能到这么高的。其实不是,这个速率就是加在载波上的数据的码率了。有两个可选值,1Mb/s,2Mb/s.也就是说,1秒钟能发送出去多少个高低电平。

以上这些配置命令之后就可以通过简单的指令转向发送模式了。下面就看一下,配置的伪指令吧:

  1. sendCommand(TxAddress_5) .因为地址是3到5字节可选的,这里选择了5字节的地址
  2. sendCommand(LocalAddress_5),本机地址如果想要开启自动应答则必需与发射地址相同,即LocalAddress==TxAddress…不开启则不需要相等。
  3. sendCommand(EnableAutoAck_0),因为芯片自带了6个通道,可以同时工作同时接收不同的数据,所以这里的自动应答也有相应的6个bit位来分别控制。这里只允许通道0自动应答。
  4. sendCommand(EnableAutoTransmit) .只要上边一句配置开了自动应答,这句就应答生效。即自动重发.
  5. sendCommand(RF_CH). 这一句设置发射频率。即设定信道。一般默认的就是0信道了,也即2.4G的载波。
  6. sendCommand(RF_Power). 设定发射速率,还有发射功率就设成0dBM吧。

以上这些是发射模式的必要配置了。如果不涉及接收,那么现在就可以转向发射模式。
7. sendCommand(Config); 通过 config寄存器中的开机控制位 powerup=1,转向空闲模式,config^0=0.转向发射模式。
8. sendCommand(TxBuffer);  填充发送数据到缓冲区里边。
9. CE=1;  这是一个引脚,用来控制从空闲模式向发送或接收模式跳转的.仅将相应位设为发送或接收模式不行,芯片现在只欠东风了,就是CE=1并保持最少10us时间后。就会开始发送数据了。

一个帧数据发送完成后会产生中断。这些中断是可以屏蔽的,就像单片机的中断允许控制一样。控制位在config寄存器中。

这里还可能产生另一个中断,就是重发次数达到上限了,你设了重发3次,那么重发3次以后还没收到应答就产生中断了。同样也是可屏蔽的。

1.5 补充spi一点知识

1. SPI读写时序

空闲状态SCK为0,CPOL=0;数据在时钟第一个跳变沿采集,CPHA=0;

  • Cn:SPI命令位
  • Sn:STATUS寄存器位
  • Dn:数据位(MSB,多字节传输时,低字节在前)
    在这里插入图片描述

2. 工作模式

NRF24L01工作模式,由CE和CONFIG寄存器(0x00)的PWR_UP(第1位)和PRIM_RX(第0位)共同控制:

NRF24L01工作模式PWR_UP位状态PRIM_RX位状态CE引脚电平FIFO寄存器状态
接收模式111-
发送模式101数据在TX FIFO寄存器中
发送模式101 ----> 0停留在发送模式,直至发送完
待机模式II101TX FIFO为空
待机模式I1-0无数据传输
掉电模式0---
2.1 收发模式

收发模式有Enhanced ShockBurstTM收发模式、ShockBurstTM收发模式和直接模式三种,收发模式由器件配置字决定。

Enhanced ShockBurstTM收发模式

发送数据时,自动加上字头和CRC校验码,在发送模式下,置CE为高,至少10us,将使能发送过程;接收数据时,自动把字头和CRC校验码移去。

在接收端,确认收到数据后记录地址,并以此地址为目标地址发送应答信号。在发送端,通道0被用作接收应答信号,故通道0的接收地址与发送地址端地址相等,以确保接收到正确应答信号。

Enhanced ShockBurstTM发送流程:

A. 把地址和要发送的数据按时序送入NRF24L01;
B. 配置CONFIG寄存器,使之进入发送模式;
C. MCU把CE置高(至少10us),激发Enhanced ShockBurstTM发射;
D. Enhanced ShockBurstTM发射:a)给射频前端供电;
b)射频数据打包(加字头、CRC校验码);
c)高速发射数据包;
d)发射完成,NRF24L01进入空闲状态

Enhanced ShockBurstTM接收流程:

A. 配置接收地址和要接收的数据包大小;
B. 配置CONFIG寄存器,使之进入接收模式,把CE置高;
C. 130us后,NRF24L01进入监视状态,等待数据包的到来;
D. 当接收到正确的数据包(正确的地址和CRC校验码),NRF24L01自动移去字头、地址和CRC校验位
E. NRF24L01通过把STATUS寄存器的RX_DR置位(STATUS一般引起MCU中断)通知MCU;
F. MCU把数据从FIFO读出(0x61指令);
G. 所有数据读取完毕后,可清除STATUS寄存器;NRF24L01可以进入四中主要的模式之一。

3. SPI指令

常用SPI指令

指令名称指令格式操作
R_REGISTER000A AAAA读寄存器。AAAAA为要读取的寄存器地址
W_REGISTER001A AAAA写寄存器。AAAAA为要写入的寄存器地址
R__RX_PAYLOAD0110 0001读 RX 有效数据,1-32字节。 读操作从字节0开始,当读RX有效数据完成后,FIFO寄存器中的使有效数据将被清除。接收模式下用。
W_TX_PAYLOAD1010 0000写TX有效数据,1-32字节。写操作从0字节开始,发送模式下用。
FLUSH_TX1110 0001清除TX FIFO寄存器。发送模式下用
FLUSH_RX1110 0010清除RX FIFO寄存器。接收模式下用

在这里插入图片描述

3. NRF24L01一对多通信方法

原文地址:
如果你还搞不通2个NRF24L01之间的通信,请看瑞生写的这两篇文章《新手如何快速搞通NRF24L01通信》《NRF24L01中文资料_原理_程序详解》

搞通了2个NRF24L01的互相通信,一对多实际上就非常容易了。你要记住,一对多通信,实际上同一时刻也是一对一通信。一次通信只需几个毫秒,如果一个和一个通信完以后,再和另外一个通信,然后再和另外一个通信……这中间如果没有延时程序的话,对于人的反应来说,就是同时进行的。这个原理就和操作系统一样,同一时刻,既可以打字聊天,又可以看电影。

下面视频是瑞生做的一个项目,是一对五,共用到6个NRF24L01模块,一个盒子里有一个。

视频地址:http://v.youku.com/v_show/id_XOTUwMDM4NTg4.html

上面这个视频的实例,如果只看NRF24L01的话,可以总结为下面的图示:
在这里插入图片描述
我们知道,2个NRF24L01通信需要具备4个条件设置相同。

  • 发射接收数据宽度相同(最大32个字节)
  • 发射接收地址相同(5个8位地址)
  • 发射接收频道相同(0~125)
  • 发射接收速率相同(2M 1M 250K)
    现在假设,主机和5个从机的这四个条件全部设置相同,如果主机发送数据的话,理论上5个从机会收到数据,实际上由于干扰,不会都收到。而且,这时候,如果从机1给主机发送数据的话,从机2~5也会收到数据。所以这样做是不行的!

一对多,有两种方式,一种是修改为不同的频道,一种是修改为不同的地址,也可以修改为不同的频道+不同的地址。

上面视频中用到的,是修改为不同的频道,例如,从机1的频道是10,从机2的频道是30,从机3的频道是50,从机4的频道是70,从机5的频道是90(注意,频道的值可以是0~125,共126个频道),频道接近的话,有可能出问题,例如从机1的频道是20,如果设置从机2的频道是21的话,主机给从机1发送数据时,从机2也有可能受到数据。所以要向上面一样,频道距离拉开一些。这时候,有人会产生疑问,如果我有几十个从机,频道岂不是很接近了,恭喜你,答对了。如果有几个从机的话,建议不要用不同的频道,而同一频道不同的地址,由于地址是5字节的,所以理论上可以有上亿个从机。

从机的频道定义好了,那么主机的程序该怎么写呢?这个很容易。例如,主机要和从机1通信,自己就把频道改为从机1一样的频道10,然后就可以发送数据,这时候,从机2~5由于频道不同,是收不到数据的。同样,主机要和从机2通信,就把自己的频道改为和从机2一样的频道30,然后就可以发送数据了。到了这个时候了,还会有童鞋问,我怎么就知道我要和谁通信?该怎么改呢?这样的童鞋还不少,那我就给你解释下吧。我都不好意思说了,太简单了。假设我的主机有5个按键,按下按键1,给从机1发送数据;按下按键2,给从机2发送数据……以此类推。那么,主机程序就是下面这个样子的:

if(KEY==0)//按下KEY1
{
  NRF_CE=0;	//拉低CE引脚
  NRF24L01_Write_Reg(WRITE_REG+RF_CH,10);//修改为从机1的频道
  NRF_CE=1;	//拉高CE引脚
  NRF24L01_TxPacket(rece_buf);//发送数据
}
else if(KEY2==0)//按下KEY2
{
  NRF_CE=0;	//拉低CE引脚
  NRF24L01_Write_Reg(WRITE_REG+RF_CH,30);//修改为从机2的频道
  NRF_CE=1;	//拉高CE引脚
  NRF24L01_TxPacket(rece_buf);//发送数据
}
else if(KEY2==0)//按下KEY3
{
  NRF_CE=0;	//拉低CE引脚
  NRF24L01_Write_Reg(WRITE_REG+RF_CH,50);//修改为从机3的频道
  NRF_CE=1;	//拉高CE引脚
  NRF24L01_TxPacket(rece_buf);//发送数据
}
else if(KEY2==0)//按下KEY4
{
  NRF_CE=0;	//拉低CE引脚
  NRF24L01_Write_Reg(WRITE_REG+RF_CH,70);//修改为从机4的频道
  NRF_CE=1;	//拉高CE引脚
  NRF24L01_TxPacket(rece_buf);//发送数据
}
else if(KEY2==0)//按下KEY5
{
  NRF_CE=0;	//拉低CE引脚
  NRF24L01_Write_Reg(WRITE_REG+RF_CH,90);//修改为从机5的频道
  NRF_CE=1;	//拉高CE引脚
  NRF24L01_TxPacket(rece_buf);//发送数据
}

话说到这份上,有的童鞋还会有疑问:“那如果我的5个从机要给主机发送数据怎么办?按照你上面的程序,主机的频道是不定的,一会儿这个,一会那个的,从机要想和主机通信的时候,我怎么判断现在主机的频道和现在从机的频道相同,不相同不能通信啊!”。真有童鞋这么问,还不是少数,这个问题,稍微动一下脑筋就想出来了。请看下面解决方案:

假设有5个大棚,1个机房,机房要无线采集5个大棚的温度。每个大棚里,都有一个电路板,板子上有温度传感器+单片机+NRF24L01,单片机通过温度传感器采集到温度以后,就通过NRF24L01发送到机房。这个例子,正好是上面童鞋问到的,大棚要给机房发送温度。

解决思路是:主机修改为从机1的频道以后,发送数据命令,从机收到命令后,发送温度数据给主机,主机再回应从机收到数据;然后主机再把频道修改为从机2的频道,发送数据命令,从机收到命令后,发送温度数据给主机,主机再回应从机收到数据….以此类推。

有的人听了以后,感觉好麻烦,实际上机房按照上面的描述收集5个机房的温度,也就是一眨眼的功夫。

假设机房每隔5分钟采集一次大棚温度,示例程序如下:

main()
{
  //各种初始化配置
  while(1)
  {
    delay()//延时5分钟(每5分钟采集一次数据)

    NRF_CE=0; //拉低CE引脚
    NRF24L01_Write_Reg(WRITE_REG+RF_CH,10);//修改为从机1的频道
    NRF_CE=1; //拉高CE引脚
    rece_buf[0]=0x66;//这是我规定的从机发送温度命令
    NRF24L01_TxPacket(rece_buf);//告诉从机我要你给我发温度数据
    NRF24L01_RX_Mode();// 配置为接收模式
    while(IRQ==1);//等待发来数据
    NRF24L01_RxPacket(rece_buf);//接收温度数据
    wendu[0]=rece_buf[1];//把采集到的温度数据给了wendu[0]变量
    NRF24L01_TX_Mode();//配置为发送模式
    rece_buf[0]=0x88;//这是我规定的主机接收到温度的回应数据
    NRF24L01_TxPacket(rece_buf);//告诉从机1我收到数据了

    NRF_CE=0; //拉低CE引脚
    NRF24L01_Write_Reg(WRITE_REG+RF_CH,30);//修改为从机2的频道
    NRF_CE=1; //拉高CE引脚
    rece_buf[0]=0x66;//这是我规定的从机发送温度命令
    NRF24L01_TxPacket(rece_buf);//告诉从机我要你给我发温度数据
    NRF24L01_RX_Mode();// 配置为接收模式
    while(IRQ==1);//等待发来数据
    NRF24L01_RxPacket(rece_buf);//接收温度数据
    wendu[1]=rece_buf[1];//把采集到的温度数据给了wendu[1]变量
    NRF24L01_TX_Mode();//配置为发送模式
    rece_buf[0]=0x88;//这是我规定的主机接收到温度的回应数据
    NRF24L01_TxPacket(rece_buf);//告诉从机1我收到数据了

    NRF_CE=0; //拉低CE引脚
    NRF24L01_Write_Reg(WRITE_REG+RF_CH,50);//修改为从机3的频道
    NRF_CE=1; //拉高CE引脚
    rece_buf[0]=0x66;//这是我规定的从机发送温度命令
    NRF24L01_TxPacket(rece_buf);//告诉从机我要你给我发温度数据
    NRF24L01_RX_Mode();// 配置为接收模式
    while(IRQ==1);//等待发来数据
    NRF24L01_RxPacket(rece_buf);//接收温度数据
    wendu[2]=rece_buf[1];//把采集到的温度数据给了wendu[2]变量
    NRF24L01_TX_Mode();//配置为发送模式
    rece_buf[0]=0x88;//这是我规定的主机接收到温度的回应数据
    NRF24L01_TxPacket(rece_buf);//告诉从机1我收到数据了

    NRF_CE=0; //拉低CE引脚
    NRF24L01_Write_Reg(WRITE_REG+RF_CH,70);//修改为从机4的频道
    NRF_CE=1; //拉高CE引脚
    rece_buf[0]=0x66;//这是我规定的从机发送温度命令
    NRF24L01_TxPacket(rece_buf);//告诉从机我要你给我发温度数据
    NRF24L01_RX_Mode();// 配置为接收模式
    while(IRQ==1);//等待发来数据
    NRF24L01_RxPacket(rece_buf);//接收温度数据
    wendu[3]=rece_buf[1];//把采集到的温度数据给了wendu[3]变量
    NRF24L01_TX_Mode();//配置为发送模式
    rece_buf[0]=0x88;//这是我规定的主机接收到温度的回应数据
    NRF24L01_TxPacket(rece_buf);//告诉从机1我收到数据了

    NRF_CE=0; //拉低CE引脚
    NRF24L01_Write_Reg(WRITE_REG+RF_CH,90);//修改为从机5的频道
    NRF_CE=1; //拉高CE引脚
    rece_buf[0]=0x66;//这是我规定的从机发送温度命令
    NRF24L01_TxPacket(rece_buf);//告诉从机我要你给我发温度数据
    NRF24L01_RX_Mode();// 配置为接收模式
    while(IRQ==1);//等待发来数据
    NRF24L01_RxPacket(rece_buf);//接收温度数据
    wendu[4]=rece_buf[1];//把采集到的温度数据给了wendu[4]变量
    NRF24L01_TX_Mode();//配置为发送模式
    rece_buf[0]=0x88;//这是我规定的主机接收到温度的回应数据
    NRF24L01_TxPacket(rece_buf);//告诉从机1我收到数据了
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值