STM32
直播中

王桂英

7年用户 1347经验值
私信 关注
[问答]

请问一下nrf2401模块的接口有哪几种呢

VCC/GND的管脚有何呢?
怎样才能准确知道是哪一种事件触发了IRQ呢?

回帖(1)

侯晓萃

2021-12-17 09:21:18
一、接口介绍

以TB上最常见最便宜的模块为例。







  左边的这个型号最常见,最便宜,大约3/4块钱一个,双排8针,2.54mm间距,模块尺寸比右边那个大;
右边这个也不少,稍贵,大约6/7块钱一个,单排8针,1.27mm间距,带邮票孔,体积非常小巧,做工我感觉要比前一个好些;
除此之外,这两种功能上没任何区别。
都是板载nrf24l01+单芯片,没有PA(射频功率放大)芯片,功率不大,空旷通信距离百米左右。
  根据你自己的实际情况选择:
如果你【对成本不敏感】且【打算自己做板】且【希望板子做的小巧漂亮】,推荐右边这个;
除此之外一律选择左边这个;
   
  根据我自己的经验,列出一些关于硬件使用上的问题(对上面两种型号均适用):



  • 模块供电【一定/必须/不能】超过3.6V,如果你不小心接了5V供电,哪怕就一会儿,请节哀,不要问我是怎么知道的(╥╯^╰╥)。
  • 除VCC和GND之外,其余6个pin却是兼容5V电平的,这也是为什么arduino可以导线直连的方式驱动它的原因。
  • 除【买了便宜到超越底线的模块】之外,不要随便怀疑模块硬件有问题,一个模块能持续多年大量出货且不用升级换代,足以说明模块的稳定性。
  • 所有管脚直连arduino的对应管脚即可,无需【串联】电阻。
  • 用稳压芯片引出的3.3V供电可以直接给模块使用,除供电端极度不稳定之外,几乎不需要并联电容。
  • 如果你用的是带PA的模块,工作电流峰值能达到一百几十毫安,要特别注意供电端的带载能力是否足够。
下面来说说除VCC/GND之外其余6个管脚的作用,可以先看一下上图中的那个管脚功能表,再看下文。
我们的程序要使用nrf24l01+,包括配置工作模式/查询工作状态/发送数据/接收数据,全部是通过这6个管脚来和模块进行交互的。
这6个管脚可以分为3组:
   
  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  
CSN/SCK/MOSI/MISO算一组,是 SPI接口往模块里送数据/从模块里读数据都是使用SPI来进行的。
这里所说的数据有2个含义,即可以是我们打算向外界真实发送的数据,也可以是给这个模块自身的配置数据,也就是它内部各个寄存器的值。
  
从底层来说,这些数据就是一串0101,一打眼没什么区别,直接丢给你你也看不出来。
  那nrf24l01+如何知道这一串0101代表什么含义呢? 当然是约定好协议格式啦:
  
不管这一串bit流有多长,一律按8bit即单字节为基本单元进行格式划分。
nrf24l01+规定,双方在传输字节时,必须高位bit优先输出,即输出顺序是: bit7-bit6-bit5-bit4-bit3-bit2-bit1-bit0。
   
  CSN一旦拉低,模块的SPI接口被使能,同时也代表数据交换【或者叫“一次通信过程”吧】的开始;
主机从MOSI输出的第一个字节被叫做【 命令字 】,这个字节的含义是让模块知道主机想要做什么,例如读寄存器/写寄存器/写入待发送数据/读入已接收数据等等;
  以写寄存器为例子,按照一般逻辑,不能只告诉我你想写寄存器,总还得告诉我你想写哪个吧,即必须还要传给我 寄存器的地址
   
   
二、命令字

   
  nrf24l01+内部一共30个寄存器,编址0x00-0x1D,不多不少;
主机能做的事情也不多,读写寄存器,读写数据等等,总共十多项;
一个字节总共可以表示256种情况,不算少;
  以上3者一结合,为了提高传输效率,于是砖家在设计nrf24l01+命令字的时候取了个巧,将代表【操作类型】的信息和代表【地址属性】的信息整合到一个字节中,即是【 命令字 】。
   
  于是【命令字】从【 编码格式 】上分,一共有两大类:【 只带操作信息不需要地址信息的 】/【 操作信息地址信息都要有的 】。
下图中的3条命令就是这类复合命令字的典型。







  以上图中读寄存器命令  R_REGISTER  为例,
操作码是0x00;
  
寄存器地址用bit4-bit0来表示,前面说过寄存器地址的最大值不过是0x1D, 5个bit足够容纳了。
于是修改0x1D寄存器的命令字应该是: 0x00+0x1D = 0x1D。
  主机端在MOSI脚输出命令字的同时, nrf24l01+也没闲着,通过MISO脚也输出了从机端的第1个字节。
  
这个字节是有意义的,叫做【状态字】,是模块内部名为 STATUS (地址0x07)寄存器数据的副本。
为什么偏偏选这个这个寄存器的值输出呢? 看一下这个寄存器的位值说明:







  上面的位值表示了模块在工作过程中的一些关键性的状态数据,包括:
  
数据是否已经发送成功/是否发送失败/是否收到了外界的新数据/新数据来自哪个pipe/数据缓冲区是否已被写满
  
我们的程序在运行时一定会非常频繁的要获知这些状态,【 状态字 】给我们提供了某种福利:
  
不需要专门使用【命令字(0x00+0x07=0x07)】去读取STATUS,任何一次与模块的交互过程都能立即得到STATUS的值。
  
当然你非要使用读寄存器的方式获取STATUS也是可以的,就是效率低一点儿。
   
  【命令字】和【状态字】过后,从第二个字节开始,后面都是数据字节。而数据字节的流向就只是单向的了。
  
【命令字】按照【 数据流向 】划分的话,可以分为3类:
  
一类是 给nrf2401送数据 ,比如写寄存器/写入待发送数据;
  
一类是 从nrf2401里面拿数据 ,比如读寄存区/读出其他模块发来的数据;
  
最后一类是 没有数据 ,只有命令,比如FLUSH_TX/FLUSH_RX只是通知模块清空内部数据缓冲区,明显不需要提供数据。
  
不存在既要给模块送数据同时也要从模块里读出数据的情况,所以说 数据流向是单向的 。
   
  对于R_REGISTER命令,数据从模块流出,于是有效数据在MISO这根线上,MOSI上的数据就无所谓了;
  
同理,对于W_REGISTER命令,数据从主机流入模块,有效数据在MOSI这根线上,MISO上有啥无所谓;
   
  绝大部分命令只带一个字节的数据就行了,个别情况需要附带多个字节的数据,以W_REGISTER为例:
  
数据通道pipe0的地址最长5个字节,在nrf2401内部只给这个pipe0_adr寄存器分配了1个寄存器地址而不是5个。
  
这个寄存器地址是0x0A,所以我们可以认为0x0A是一个长度为5字节的寄存器。
  
假设我们要给pipe0设置的地址为: 0xA4A3A2A1A0,拆开看从高到低5字节:0xA4 0xA3 0xA2 0xA1 0xA0
   
  前面说过,SPI传输时字节内部高位bit优先输出,而协议规定传输多字节数据时,【低字节优先】输出。
  
于是MOSI信号线上字节流的顺序是这样的: CMD-A0-A1-A2-A3-A4
   
  最后,数据传输完毕,CSN要拉高,即代表模块的SPI断开了主机的连接,也让nrf2401知晓一条命令结束了。
  
这个地方必须提醒,CSN拉高是必须的,哪怕你有很多命令排队等着操作模块,每条命令的写入都要遵守: 【CSN拉低-数据传输-CSN拉高】这条规定。
   
  啰嗦了一大堆话,一张图足以代表一切:
   













  解读一下这张图对我们 写程序 有什么用:



  •       模块要求MOSI/MISO在SCK上升沿的时候输出bit,不管是软件模拟SPI还是硬件SPI要特别注意这一点,尤其是stm32这类SOC当主控时,它的SPI功能非常繁多,   配置SPI工作模式的时候要特别注意  
  •       两条操作命令之间要在CSN高电平时添加适当延时  
  •       上图红框标出的Tcwh,这个时间代表上一条命令结束后,下条命令开始前,必须要有个恢复时间,防止误动作。   
    这个时间不要少于【100纳秒】,保守起见,建议   至少延时【500纳秒】。  
关于SPI接口,最后再说一下SCK时钟频率的问题:
  
nrf2401模块的时钟频率最高可以到10MHz,但保守起见,我们实际使用是建议时钟速度不要超过8M, 留一些余量总是好的 。
  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  
CE 可以单独算一组,这个管脚和 nrf2401射频模块的工作状态 有关。
  
当nrf2401被配置成PTX时,我们通过SPI写入要对外发送的数据之后,模块并不会立即启动发送,
  
我们必须再拉高CE管脚并使其高电平保持至少10微秒(10微秒过后,可以拉低也可以继续保持高电平),
  
模块才会开启射频模块,进入【 发送状态 】,开始发送数据。
   
  当nrf2401被配置成PRX时,同样模块也不会立即启动射频模块进入【接收状态】
  ,
我们必须拉高CE并使其一直保持高电平,模块才会进入【接收状态】开始监听数据。
  
任意时刻,只要CE被拉低了,PRX会立即从【接收状态】退出到待机状态。
   
  这只是CE管脚的基本用处,更多的细节我们后面在讲完【发送/接收缓冲区】以及【工作状态图】之后再说。
   
  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   
三、IRQ

  
IRQ 也单独算一组,这个管脚如其名,是模块用来通知主机【 数据发送/数据接收相关的紧急事件 】的快捷通道。
  
相对于单片机的运行速度来说,nrf2401是比较慢的,8M的SPI时钟下,主机要对外发送32字节数据,
  
只需要不到40微秒就能将数据全部塞给模块,而模块想要将这些数据发送完毕,需要的时间却是要多得多。
   
  主机当然可以在写完数据之后,一遍遍的询问模块数据是否发送完成,但同时主机也不可能去干别的事情了,所以必须要使用中断通知的方式来减轻主机的压力。
  
主机写完数据之后就可以去忙别的了,后续发送过程/成功确认/发送失败确认的一系列工作交给模块自主完成,一旦结果出来之后,模块立即将IRQ管脚拉低。
  
主机端一般会将自己的外部中断管脚和模块的IRQ管脚连在一起,一旦IRQ管脚被模块置为有效,主机端的外部中断会立即触发,然后就可以在中断函数中访问模块,查看发生了什么。
   
  这中 紧急事件只有3种 : 【数据发送成功】/【数据发送失败且已经多次失败】/【收到其他模块发来的新数据】
  
当中任意一个单独发生或任意多个同时发生,都会触发IRQ,所以主机程序在获知中断发生之后,必须在读取一遍模块内部的STATUS寄存器才能准确知道是哪一种事件触发了IRQ。
   
  关于IRQ更细致的问题,后面章节中在讨论。


举报

更多回帖

发帖
×
20
完善资料,
赚取积分