页面加载中,请稍候
来源:电子工程世界发布时间:2021-08-10143浏览
询问 AI


NRF_RADIO->RXADDRESSES = 1; enable address 0
NRF_RADIO->FREQUENCY = 2; 2402MHz, CH37
NRF_RADIO->DATAWHITEIV = 37;
NRF_RADIO->MODE = (RADIO_MODE_MODE_Ble_1Mbit << RADIO_MODE_MODE_Pos);
NRF_RADIO->PREFIX0 = 0x8E;
NRF_RADIO->BASE0 = 0x89BED600;
LFLEN=6 bits, S0LEN=1Byte, S1LEN=2bit
NRF_RADIO->PCNF0 = 0x00020106;
STATLEN=6, MAXLEN=37, BALEN=3, ENDIAN=0 (little), WHITEEN=1
NRF_RADIO->PCNF1 = 0x02030025;
NRF_RADIO->CRCCNF = 0x103; only PDU, 3 octets
NRF_RADIO->CRCINIT = 0x555555; for advertising packet
NRF_RADIO->CRCPOLY = 0x100065b;
set receive buffer
NRF_RADIO->PACKETPTR = (uint32_t)pkt_buf;
启动接收过程或发送过程要通过nRF51的task型寄存器。先看下RADIO部分的状态转移图:


当收到END event时,表示收到了一个数据包(地址匹配有效),然后可以访问CRCSTATUS寄存器判断CRC校验是否正确。若CRC有错,可能是数据包被干扰破坏,或者格式不正确。接收数据包的S0、LENGTH、S1、PAYLOAD字段存放到RAM中,稍有变化的是LENGTH和S1字段都被扩展成了字节存储。
我写了一个循环来持续接收数据包,进行37信道的监听。使用双缓冲区轮流存放收到的数据包,以便一边解析数据一边接收。
for(;;)
{
NRF_RADIO->PACKETPTR = (uint32_t)pkt_buf1;
NRF_RADIO->EVENTS_END = 0;
NRF_RADIO->TASKS_START = 1;
if(crcok2)
show_pkt(pkt_buf2);
else
uart_wstr(.");
if(NRF_RADIO->EVENTS_END)
uart_wstr(!");
while(! NRF_RADIO->EVENTS_END)
{}
crcok1=NRF_RADIO->CRCSTATUS;
NRF_RADIO->CRCINIT = 0x555555;for advertising packet
NRF_RADIO->PACKETPTR = (uint32_t)pkt_buf2;
NRF_RADIO->EVENTS_END = 0;
NRF_RADIO->TASKS_START = 1;
if(crcok1)
show_pkt(pkt_buf1);
else
uart_wstr(.");
if(NRF_RADIO->EVENTS_END)
uart_wstr(!");
while(! NRF_RADIO->EVENTS_END)
{}
crcok2=NRF_RADIO->CRCSTATUS;
}
通过对PDU第一个字节的低4位,可以判断数据包类型,然后识别余下数据。
staticinlinevoidshow_pkt(volatileuint8_t *buf)
{
switch(buf[0]&0xF)
{
case6: ADV_SCAN_IND
uart_wstr(s");
add_log(buf);
break;
case0: ADV_IND
uart_wstr(A");
add_log(buf);
break;
case2: ADV_NONCONN_IND
uart_wstr(n");
add_log(buf);
break;
case4: SCAN_RESP
uart_wstr(R");
break;
case1: ADV_DIRECT_IND
uart_wstr(i");
break;
case3: SCAN_REQ
uart_wstr(+");
break;
case5: CONN_REQ
uart_wstr(C");
break;
default:
uart_wstr(?");
break;
}
}
如果是包含advertising数据的包,可以将地址、数据记录下来,待收集一段时间后进行统计。
voidadd_log(uint8_t *buf)
{
inti;
for(i=0;i<32;i++)
{
if(adv_log.count)not blank
{
if(memcmp(adv_log.addr, buf+3, 6)==0&& adv_log.type==buf[0])match
{
adv_log.count++;
return;
}
}
elseadd entry
{
memcpy(adv_log.addr, buf+3, 6);
adv_log.type = buf[0];
adv_log.len = buf[1]-6;
memcpy(adv_log.payload, buf+9, adv_log.len);
adv_log.count=1;
return;
}
}
}
这样就可以发现周围的一部分BLE设备了。现在我的程序只是接收,没有主动发起“扫描”。但是我的程序收到了许多主动扫描的包,表明附近有设备在持续进行疯狂扫描……

使用一个包含名称的advertising数据,调用上面的函数。设备地址是04:8B:C6:29:5A:37, 写在发送函数中了。
voidradio_adv_tx(uint8_t *pdu, uint8_t len)
{
uint8_t txpkt[40];
NRF_RADIO->EVENTS_READY = 0;
NRF_RADIO->TASKS_TXEN = 1;
while(NRF_RADIO->EVENTS_READY == 0);
now in TXIDLE state
txpkt[0]=0x42;private TX address, non-connectable
if(len>31)
len=31;
txpkt[1]=len+6;
txpkt[2]=0;
txpkt[3]=0x37; txpkt[4]=0x5A; txpkt[5]=0x29;
txpkt[6]=0xC6; txpkt[7]=0x8B; txpkt[8]=0x04;
memcpy(txpkt+9, pdu, len);
NRF_RADIO->PACKETPTR = (uint32_t)txpkt;
NRF_RADIO->EVENTS_END = 0;
NRF_RADIO->TASKS_START = 1;
while(! NRF_RADIO->EVENTS_END)
{}
}
定期(比如1秒)发送一次,在手机上用BLE扫描工具可以发现这个设备。当然现在仅仅广播了一个名称而已,要添加自定的传感器数据也很简单,不过要注意31个字节长度的限制。
constuint8_t dummy_adv[]={0x02,0x01,0x06,flags
15,0x09,'A','D','V','_','D','e','m','o',' ','5','1','8','2','2'};
radio_adv_tx(dummy_adv,sizeof(dummy_adv));

新闻来源:电子工程世界,文中所述为作者独立观点,不代表icspec立场。更多精彩资讯请下载icspec App。如对本稿件有异议,请联系微信客服specltkj。
暂无评论哦,快来评论一下吧!

4 天前

2026-07-02