来自:https://blog.csdn.net/blog_xu/article/details/80597028
无线数据解决冲撞的最好的办法就是从源头避免,这就需要在发送数据之前检测当前信道是否有其他数据正在发送,如当前信道正在被占用,采用一定的退避算法,例如简单的延时来避免空中的数据冲突。
提供了以下两种方案:
1、读取当前信道的RSSI(Received Signal Strength indicator)信号强度
2、检测当前信道是否存在有效前导码(Preamble)
一、如何获取当前RSSI
Silicon Labs提供了两种方法:
1、GET_MODEM_STATUS命令来获取CURR_RSSI和LATCH_RSSI
2、直接读取(Fast Response Register A) 快速响应寄存器。
u8 si4463_read_rssi(void) {
u8 send_data = 0x50, frr[4];
SPI1_CSN_L;
SPI_Write(&send_data, 1);
get_data_group(frr, 4);
SPI1_CSN_H;
return frr[0];
}
注意事项:
1.需要配置MODEM_RSSI_CONTROL=0x02( Latches at sync detect当同步字检测到之后锁存RSSI)
其目的是确定锁存的 RSSI 值没有超出阈值。如果锁存的 RSSI 超出阈值,则不会发生中断,数据包的接收继续正常进行。如果锁存的 RSSI 低于阈值,则芯片转换为 START_RX:RXTIMEOUT_STATE,并生成 INVALID_PREAMBLE中断(如果启用)。利用跳频时,接收器调到下一频率的其中一个条件是 INVALID_PREAMBLE。
2.RSSI阈值控制MODEM_RSSI_THRESH默认值为0xFF(理解为最大值)
3.GPIO快速输出RSSI阈值信号,是通过空闲信道检测(CCA)
CCA(空闲信道评估)信号是可以输出到其中一个 GPIO(在 API 文档中查找 GPIO_PIN_CFG)的信号之一。如果当前 RSSI
值高于 MODEM_RSSI_THRESH 中给出的阈值,则它会变高电平,如果当前 RSSI
值低于此阈值,则它会变低电平。只要接收器打开,此信号就会不断更新。
二、检测当前信道前导码
前导码配置:
#define RF_PREAMBLE_TX_LENGTH_9 0x11, 0x10, 0x09, 0x00, 0x08, 0x14, 0x00, 0x0F, 0x31, 0x00, 0x00, 0x00, 0x00
有如下配置:
PREAMBLE_TX_LENGTH = 0x08 Byte;前导码为八字节传输
RX_THRESH[6:0] - default:0x14 ; 当检测到14bits有效位则表示前导码被检测到
RX_PREAMBLE_TIMEOUT[3:0] - default:0xF ;
STANDARD_PREAM[1:0] - default:0x1 = Use standard preamble of 1010
PATTERN_31_24[7:0] - default:0x00 = Preambles always sent bits 0–31 timewise。前导码按时间顺序发送
程序代码如下:
u8 si4463_detect_preamble(u8 ch) {
IWDG_ReloadCounter();
u8 API_Write[7];
API_Write[0] = CMD_GET_INT_STATUS;
API_Write[1] = 0xFB; //其他位状态保留
API_Write[2] = 0x00; //清除MODEM_CLR_PEND
API_Write[3] = 0xFF;
send_command(ch, API_Write, 4);
get_response(ch, API_Write, 8);
if (API_Write[4] & 0x02) {
//If set, PREAMBLE_DETECT interrupt is pending
return 1;
}
return 0;
}
实际测试经验:
MODE_PEND中断挂起比MODEM_STATUS置位要快;因此我检测的是PEND
前导检测中断或无效的前导码会同时出现置位;我的做法是直接根据前导码中断,则等待后再次检测
三、根据GPIO快速读取当前信道是否有前导码存在
1、配置gpio:
//GPIO0用来检测是否存在有效前导码;GPIO1用来检测是否存在无效的前导码(实测作用不大)
u8 API_Write[8] = {0x13, 0x40|24, 0x40|25, 0x00, 0x00, 0x00, 0x00, 0x00};
set_cmd(API_Write, 8);
检测程序代码段
#define valid_preamble GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_8)
while (valid_preamble && retry > 0) {
//实测每个有效数据包的持续时间为5ms
rt_thread_delay(6*RT_TICK_PER_SECOND/1000);
if (waitms > 20)
waitms -= 6;
retry--;
}
实际压测结果:
从节点源头上避免了数据冲突,可以增大信道的通讯量
如还有其他小概率性丢数据情况,请添加两到三次的重发机制
网关侧会出现广播数据与节点数据同时发,会出现冲突现象
两个节点之间的数据间隔15ms也会导致数据丢失
实际压力测试丢包率为0.2%
---------------------
作者:blog_xu
来源:CSDN
原文:https://blog.csdn.net/blog_xu/article/details/80597028
版权声明:本文为博主原创文章,转载请附上博文链接!