日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

51822模拟ble广播-实践

發(fā)布時間:2023/12/15 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 51822模拟ble广播-实践 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

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)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。