当用W_TX_PAYLOAD命令对发送端TX FIFO写数据时,将数据打包后,数据包中包控制字段NO_ACK 标志位复位。接收端接收到一帧有效数据后, 产生RX_DR中断后,会自动发送一帧ACK信号,发送端接收到ACK信号,则自动清除TX FIFO数据并产生TX_DS发射中断,表明此次通信成功。
接收端在发送ACK信号时,取接收管道地址作为目标地址来发送ACK信号,所以发送端需要设置接收管道0地址与自身发送地址相同,以便接收ACK信号。
如果发送端在ARD时间内没有接收到ACK信号,则重新发送上一帧数据。当重发次数达到最大,仍没有收到确认信号时,发送端产生MAX_RT中断。MAX_RT中断在清除之前不能进行下一步的数据发送。所有中断通过对状态寄存器进行写操作来清除。PLOS_CNT寄存器在每产生一个MAX_RT中断后加1,用来记录当前频段下,丢失的数据包的数量。ARC_CNT寄存器记录当前数据重发的次数,在发送一包新数据时使其复位。最大重发次数与ARD时间通过SETUP_RETR寄存器来进行配置。接收端开启自动回复ACK信号由EN_AA寄存器来控制。
发送端每当发射一个新数据包,数据对应的PID自动加1,因此发送的相邻的两个数据包中,PID应互不相同。如果链路中连续几帧数据丢失,接收端接收到的连续两帧数据的PID可能相同。
接收端如果发现接收到数据与上一帧数据PID相同,则比对CRC,如果CRC也相同,则判断为上一帧数据的重发,将数据丢弃,并重新回复ACK信号。图4.4发送端第一次数据发送没有接收到ACK信号,进行重发后,接收到ACK信号,数据通信成功完成。
这里只介绍与ACK模式相关的寄存器配置,默认理解为其他配置都正确的情况下。
发送方的必要配置
nRF24L01+的ACK自动应答功能,原理是在接收方收到数据后立刻自动回复给发送方一个ACK确认数据包,发送方如果收到确认的数据包,认为发送成功,否则认为本次失败,是否再次发送,决定于自动重发的配置。
那带来的疑问是,接收方收到数据后,在回复的时候,是怎样知道发送方的地址的呢?数据包中并没有携带地址,如果携带会多占用5个字节,影响了传输有效数据的相对速率。设计团队最后使用的是在发送时,先将发送方的接收通道0的接收地址设置为要发送的目标地址,这样执行完发送就立刻等待接收,并自己的地址是与目标地址一样的。接收方收到数据回复ACK的时候,就不需要知道发送方的地址,按照自己的地址作为目标地址发出即可。因自己处在发送状态,所以自己不会接收,而发送方这时刚好处在接收状态,地址刚好是接收方的地址,也是接收方回复时的目标地址,所以发送方可以收到回复的ACK数据。因此下面的这行配置必需存在:
spi_write_buf(RX_ADDR_P0, TX_ADDRESS, 5); //接收通道0地址和发射地址相同,等待接收来自接收方的ACK数据
ACK模式的整个工作过程中,自动重发功能为确保数据有效到达起了很大作用。因为无线电信号很难在任何环境下都十分稳定,也极容易受到各种干扰,那么如果一次发送没有收到ACK数据,就可以认为本次发送失败。接下来稍等一下可以再次发送,经过多次尝试,成功率就大大增加了。所以就要启用自动重发功能,当达到重发次数的上限的时候,仍然没有收到ACK数据,则宣告本轮发送彻底失败。因此下面的配置也是必需存在的:
spi_write_reg(SETUP_RETR, 0x15); //自动重发延时等待500us,自动重发5次,根据自己需要设置
SETUP_RETR寄存器的说明见下图(0x15的二进制是00010101):
接收方的必要配置
接收方为了可以在收到数据后,执行自动回复功能,需要开启相应的控制寄存器,否则无法实现自动回复,因为下面这行配置是必需存在的:
spi_write_reg(EN_AA, 0x01); //使能接收通道0的自动应答
如果启用了ACK功能,那么CRC校验功能就必须启用,因为需要避免接收到重复的数据包产生多次接收成功和造成多次回复的现象。因此下面的配置也是必需存在的:
spi_write_reg(CONFIG, 0x0F); //CRC使能,16位CRC校验,开机,接收模式
CONFIG寄存器的说明见下图(0x0F的二进制是00001111):
发送方先置为发送模式,以上介绍的发送模式的寄存器也在置为发送模式时配置完毕。
接下来使用W_TX_PAYLOAD命令写入待发送的数据,参考代码如下:
CE = 0; //CE拉低,使能24L01配置
spi_write_buf(WR_TX_PLOAD, RF24Buf, TX_PLOAD_WIDTH); //写数据到TX FIFO,TX_PLOAD_WIDTH个字节
CE = 1; //CE置高,使能发送
模块在发送完发送缓冲区的数据后,自动立刻转入接收状态,并将自己的地址临时修改为刚才发送的目标地址(即接收方地址,因为接收方回复的时候,它的目标地址会是这个),等待接收方回复ACK,收到ACK后产生发送成功TX_DS(0x20)中断。
如果在SETUP_RETR寄存器设置的时间间隔内没有收到ACK回复,将再次发送,直到收到ACK或达到SETUP_RETR寄存器设置的最大发送次数。如达到最大发送次数则产生MAX_RT(0x10)中断,表示已经尝试发送到最大次数仍然没有成功。
以上状态都可通过读状态寄存器STATUS得到(其实单片机每次与模块通信,SPI指令返回的都是这个寄存器的值),下图是STATUS寄存器的说明:
有关nRF24L01+的ACK模式的调试重点就介绍到这里,其他关于nRF24L01+的问题请看本人博客的其他文章。