51822模拟ble广播-实践
http://blog.chinaunix.net/uid-28852942-id-5745469.html
理論部分主要介紹了BLE廣播包的 數(shù)據(jù)包格式,知道了數(shù)據(jù)包格式只需要按照格式要求設(shè)置數(shù)據(jù)包然后發(fā)送,那么BLE掃描者就能將這個數(shù)據(jù)包解析成ble廣播包了。
這里我們用51822的radio來實現(xiàn)ble的廣播包。
下圖是51822空中包的格式。
Preamble:?該部分會根據(jù)接入地址而自動設(shè)置,不需要我們?nèi)ピO(shè)置
ADDRESS:由BASE和PREFIX組成,就是前面理論部分說的接入地址,對于廣播? 信道的數(shù)據(jù)包來說,接入地址總是0x8E89BED6。注意這個不是ble的廣播地????? 址,廣播地址是在廣播數(shù)據(jù)負(fù)載中的,而且是6字節(jié),這里的接入地址是4????? 字節(jié)
S0,LENGTH,S1,PAYLOAD:這四個部分組成了理論部分介紹的 PDU。S0,LENGTH,S1這三個部分是可選的。理論部分介紹過PDU有2部分組成,2字節(jié)的header和payload所以我們可以使用S0,LENGTH來作為header,不使用s1,然后payload剛好就作為payload。 當(dāng)然你也可以S0,LENGTH,S1一個都不使用,是使用payload,那么就將payload的前兩字節(jié)按照理論部分中的2字節(jié)header設(shè)置,剩下的當(dāng)做應(yīng)用負(fù)載payload。
CRC:我們需要設(shè)置一下 CRC的字節(jié)數(shù),以及生成式,并且使之值計算的部分不包括前導(dǎo)和ADDRESS部分。
?
首先設(shè)置接入地址ADDRESS,因為廣播數(shù)據(jù)是在廣播信道中發(fā)送的,所以使用的是固定的接入地址0x8E89BED6. 51822有8個邏輯地址0-7,并且8個邏輯地址對應(yīng)的實際地址可以設(shè)置,對應(yīng)關(guān)系如下。也就是通過設(shè)置BASE0,BASE1,和PREFIX0,PREFIX1,四個寄存器,我們能分別設(shè)置8個邏輯地址的實際地址。
因為這里用的是廣播信道的固定地址,所以我們將 8個邏輯地址的實際地址全部都設(shè)置成0x8E89BED6,然后設(shè)置發(fā)送地址為 邏輯地址0就行了。因為數(shù)據(jù)發(fā)送是LSByte先發(fā)送,而51822發(fā)送ADDRESS是先發(fā)送BASE再發(fā)送PREFIX,所以我們需要將PREFIX設(shè)置成高位字節(jié)0x8E,低位3字節(jié)設(shè)置到BASE中。
?
?????? NRF_RADIO->BASE0 = (0x89BED600);
?????? NRF_RADIO->BASE1 = (0x89BED600);?
?????? NRF_RADIO->PREFIX0 = 0x8E8E8E8E;
?????? NRF_RADIO->PREFIX1 = 0x8E8E8E8E;
?
?????? NRF_RADIO->TXADDRESS = 0; //使用邏輯地址0
然后是理論中介紹的PDU部分的設(shè)置,即51822中的S0,LENGTH,S1,PAYLOAD,我們使用S0,LENGTH來當(dāng)做header,PAYLOAD就是PDU中的payload.并且設(shè)置S0,LENGTH都為1字節(jié), 然后設(shè)置BLE可以發(fā)送的最大應(yīng)用數(shù)據(jù)?(51822發(fā)送的包組成中的payload的長度)為37字節(jié),因為理論部分說過PDU為2-39字節(jié),2為2字節(jié)頭,所以payload最長為37字節(jié)。并且設(shè)置接入地址的長度,上面已經(jīng)設(shè)置了為4字節(jié)。設(shè)置發(fā)送順序為LSB(規(guī)范要求)。
然后使能白化功能,白化是為了將原始信息中轉(zhuǎn)換為高度隨機的Bit序列,避免出現(xiàn)太長連續(xù)的bit0或bit 1從而導(dǎo)致接收出錯。是規(guī)范要求
?
設(shè)置如下:
?????? //8bit長度的LENGTH? 1字節(jié)長度的S0,不需要s1,因為廣播格式里面負(fù)載數(shù)? //據(jù)前面只需要2字節(jié)頭,一個是報頭,一個是長度。
NRF_RADIO->PCNF0 = (8<<0) | (1<<8);
?????? //最大長度37,沒有靜態(tài)長度,基礎(chǔ)地址為3字節(jié),所以加一字節(jié)頭后為四 //字節(jié),就是藍(lán)牙規(guī)范中接入地址.字節(jié)序為小端(CRC不在這里設(shè)置)
?????? //使能數(shù)據(jù)白化
NRF_RADIO->PCNF1 = (37<<0) | (3<<16) | (1<<25) ;
?????? //白化0x25;?????? 初始值由報文所在鏈路層信道號決定,我們在37好廣播信道上廣播
NRF_RADIO->DATAWHITEIV = 0x25;
?
對于應(yīng)用負(fù)載payload,理論部分說過我們使用 不可連接廣播,
定義一個數(shù)組用來存放將要廣播的數(shù)據(jù),然后將數(shù)據(jù)指針指設(shè)置為改buff地址
static uint8_t adv_array[31] = {0};
NRF_RADIO->PACKETPTR = (uint32_t)&adv_array[0];
?
然后設(shè)置廣播應(yīng)用數(shù)據(jù),如下函數(shù)所示
?
//廣播地址
uint8_t device_add[6]={0xFF,0x01,0x02,0x03,0x04,0xff};
//廣播數(shù)據(jù),第一個0x01為flag設(shè)置成只支持BLE,
//第二個0x09為設(shè)備名,名字隨便寫的
uint8_t adv_data[10] = {0x02,0x01,0x04, 0x06,0x09,0x4e,0x6f,0x48,0x52,0x3d};
?
void set_advdata(void){
?????? //adv_array的前兩字節(jié)為 header 即S0和LENGTH
?????? //PDU Type設(shè)置為ADV_NONCONN_IND,如果設(shè)置成普通廣播的話,手機可能 //會發(fā)掃描包,因為這里沒有做掃描回應(yīng),手機就會過濾該設(shè)備,導(dǎo)致手機?????? //搜不到設(shè)備。
?????? adv_array[0] = 2;?????? ?????????????
?????? adv_array[1] = 0;//最后再計算長度
??????
?????? memcpy(adv_array+2, device_add, 6);
?????? memcpy(adv_array+2+6, adv_data, sizeof(adv_data));
??????
?????? adv_array[1] = 6+sizeof(adv_data);
}
然后需要將 radio的發(fā)送指針寄存器賦值為 adv_array.那么發(fā)送的時候就會自動將這個數(shù)組里的數(shù)據(jù)發(fā)送出去了
?????? NRF_RADIO->PACKETPTR = (uint32_t)&adv_array[0];
?
?
?
對于CRC,需要設(shè)置其字節(jié)數(shù),生成式,和初始值。設(shè)置如下
?????? //3字節(jié)crc,計算不包括接入地址部分和前導(dǎo)部分
NRF_RADIO->CRCCNF = (3<<0) | (1<<8);????
?????? //crc多項式為 x^24+x^10+x^9+x^6+x^4+x^3+x^1+x^0
NRF_RADIO->CRCPOLY = 0x100065b
?????? //廣播信道的數(shù)據(jù)包中crc初始值為0x555555
NRF_RADIO->CRCINIT =? 0x555555;???
?
這個里 BLE廣播相關(guān)的規(guī)范設(shè)置都設(shè)置完了。
我們還需要設(shè)置一下,廣播的信道。我們在37號廣播信道上廣播。
設(shè)置一下發(fā)射功率,以及模式選擇為Ble_1Mbit
?????? //鏈路層信道編號 37:2402MHz, 38:2426MHz, 39:2480MHz
NRF_RADIO->FREQUENCY = 2;??????
NRF_RADIO->TXPOWER = 0x04;
NRF_RADIO->MODE = 0x03;?? //ble_1Mbit
?
另外根據(jù)手冊說明 還有一個校準(zhǔn)值的設(shè)置,如下圖手冊中的描述
?????? NRF_RADIO->OVERRIDE4 = 1<<31;
?????? NRF_RADIO->OVERRIDE0 = NRF_FICR->BLE_1MBIT[0];
?????? NRF_RADIO->OVERRIDE1 = NRF_FICR->BLE_1MBIT[1];
?????? NRF_RADIO->OVERRIDE2 = NRF_FICR->BLE_1MBIT[2];
?????? NRF_RADIO->OVERRIDE3 = NRF_FICR->BLE_1MBIT[3];
?????? NRF_RADIO->OVERRIDE4 = NRF_FICR->BLE_1MBIT[4];
實際使用中,我查看了FICR中的OVERRIDEEN?的值,兩個指示位都為0,應(yīng)該是要用FICR中的校準(zhǔn)值覆蓋RADIO中的校準(zhǔn)值,不過代碼實現(xiàn)中我屏蔽了設(shè)置也能收到廣播。
最后就是發(fā)送數(shù)據(jù)的實現(xiàn)了
函數(shù)實現(xiàn)很簡單,直接啟動就可以了,radio會自動將上面設(shè)置的NRF_RADIO->PACKETPTR指向的數(shù)組數(shù)據(jù)發(fā)送出去
void send_data(void){
??????
?????? NRF_RADIO->EVENTS_READY = 0;
?????? NRF_RADIO->TASKS_TXEN = 1;???????????????????? //啟動發(fā)送使能
?????? while(NRF_RADIO->EVENTS_READY == 0){}?????? //等待準(zhǔn)備好
??????
?????? NRF_RADIO->EVENTS_END = 0;
?
?????? NRF_RADIO->TASKS_START = 1;???? ?????? //開始發(fā)送?
?????? while(NRF_RADIO->EVENTS_END == 0)//等待發(fā)送完成
??????
?????? NRF_RADIO->EVENTS_DISABLED = 0;
?????? NRF_RADIO->TASKS_DISABLE = 1;
?????? while(NRF_RADIO->EVENTS_DISABLED == 0){}//等待停止完成
}
?
下面貼出整體代碼
?
#include "nrf51.h"
#include "nrf_gpio.h"
#include <stdio.h>
#include <string.h>
#include "nrf_delay.h"
?
uint8_t adv_data[10] = {0x02,0x01,0x04,?? 0x06,0x09,0x4e,0x6f,0x48,0x52,0x3d};
uint8_t device_add[6]={0xFF,0x01,0x02,0x03,0x05,0xff};
?
static uint8_t adv_array[37] = {0};
?
void ?init_clock(void){
?????? NRF_CLOCK->XTALFREQ = 0xff;???????????? //16M
?????? NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
?????? NRF_CLOCK->TASKS_HFCLKSTART = 1;
?????? while(NRF_CLOCK->EVENTS_HFCLKSTARTED == 0){? ? ?
?????? }????? //等待啟振完成? ??
}
?
?
void radio_init(void){
?????? //這里設(shè)置8個邏輯地址的實際地址,因為我們只是做廣播,所以把全部地址都設(shè)置成0x8E89BED6,
?????? NRF_RADIO->BASE0 = (0x89BED600);
?????? NRF_RADIO->BASE1 = (0x89BED600);?
?????? NRF_RADIO->PREFIX0 = 0x8E8E8E8E;
?????? NRF_RADIO->PREFIX1 = 0x8E8E8E8E;
?
?????? NRF_RADIO->TXADDRESS = 0; //使用邏輯地址0
??????
?????? NRF_RADIO->CRCCNF = (3<<0) | (1<<8);???? //3字節(jié)crc,計算不包括接入地址部分
?????? NRF_RADIO->CRCPOLY = 0x100065b;//crc多項式為 x^24+x^10+x^9+x^6+x^4+x^3+x^1+x^0
?????? NRF_RADIO->CRCINIT =? 0x555555;??? //廣播信道的數(shù)據(jù)包中crc初始值為0x555555
?????? NRF_RADIO->PACKETPTR = (uint32_t)&adv_array[0];
?????? NRF_RADIO->FREQUENCY = 2;?????? //鏈路層信道編號 37:2402MHz, 38:2426MHz, 39:2480MHz
?????? NRF_RADIO->TXPOWER = 0x04;
?????? NRF_RADIO->MODE = 0x03;?? //ble_1Mbit
??????
?????? //8bit長度的LENGTH? 1字節(jié)長度的S0,不需要s1,因為廣播格式里面負(fù)載數(shù) 據(jù)前面只需要2字節(jié)頭,一個是報頭,一個是長度。?????? NRF_RADIO->PCNF0 = (8<<0) | (1<<8);
?????? //payload最大長度37,沒有靜態(tài)長度,基礎(chǔ)地址為3字節(jié),所以加一字節(jié)頭后為四字節(jié),就是藍(lán)牙規(guī)范中接入地址.字節(jié)序為小端(CRC不在這里設(shè)置)
?????? //使能數(shù)據(jù)白化
?????? NRF_RADIO->PCNF1 = (31<<0) | (3<<16) | (1<<25) ;
?????? NRF_RADIO->DATAWHITEIV = 0x25;//0x25;??????? //初始值由報文所在鏈路層信道號決定,這里為37
?????????????
?????? NRF_RADIO->OVERRIDE4 = 1<<31;
?????? NRF_RADIO->OVERRIDE0 = NRF_FICR->BLE_1MBIT[0];
?????? NRF_RADIO->OVERRIDE1 = NRF_FICR->BLE_1MBIT[1];
?????? NRF_RADIO->OVERRIDE2 = NRF_FICR->BLE_1MBIT[2];
?????? NRF_RADIO->OVERRIDE3 = NRF_FICR->BLE_1MBIT[3];
?????? NRF_RADIO->OVERRIDE4 = NRF_FICR->BLE_1MBIT[4];
}
?
void set_advdata(void){
?????? adv_array[0] = 2;?????? //PDU Type為ADV_NONCONN_IND,如果設(shè)置成普通廣播的話,手機可能會發(fā)掃描包,因為這里沒有做掃描回應(yīng),手機就會過濾該設(shè)備,導(dǎo)致手機搜不到設(shè)備。
?????? adv_array[1] = 0;//最后再計算長度
??????
?????? memcpy(adv_array+2, device_add, 6);
?????? memcpy(adv_array+2+6, adv_data, sizeof(adv_data));
??????
?????? adv_array[1] = 6+sizeof(adv_data);
}
?
void send_data(void){
??????
?????? NRF_RADIO->EVENTS_READY = 0;
?????? NRF_RADIO->TASKS_TXEN = 1;
?????? while(NRF_RADIO->EVENTS_READY == 0){}?????? //等待準(zhǔn)備好
??????
?????? NRF_RADIO->EVENTS_END = 0;
?
?????? NRF_RADIO->TASKS_START = 1;???????????
?????? while(NRF_RADIO->EVENTS_END == 0)//等待發(fā)送完成
??????
?????? NRF_RADIO->EVENTS_DISABLED = 0;
?????? NRF_RADIO->TASKS_DISABLE = 1;
?????? while(NRF_RADIO->EVENTS_DISABLED == 0){}//等待停止完成
}
?
int main(void){
?????? uint32_t data;
??????
?????? init_clock();
?????? radio_init();
?????? set_advdata();
??????
?????? nrf_gpio_cfg_output(22);
?????? nrf_gpio_pin_clear(22);
??????
?????? while(1){
????????????? nrf_delay_ms(50);
????????????? send_data();
?????????????
?????? }
?????? return 0;
}
總結(jié)
以上是生活随笔為你收集整理的51822模拟ble广播-实践的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BLE-NRF51822教程3-sdk程
- 下一篇: 51822模拟ble广播-理论