nrf5x radio射頻模擬ble廣播數據

  轉載於:http://blog.chinaunix.net/uid-28852942-id-5745469.html

這裏我們用51822的radio來實現ble的廣播包。

下圖是51822空中包的格式。


Preamble: 該部分會根據接入地址而自動設置,不需要我們去設置

ADDRESS:由BASE和PREFIX組成,就是前面理論部分說的接入地址,對於廣播  信道的數據包來說,接入地址總是0x8E89BED6。注意這個不是ble的廣播地      址,廣播地址是在廣播數據負載中的,而且是6字節,這裏的接入地址是4      字節

S0,LENGTH,S1,PAYLOAD:這四個部分組成了理論部分介紹的 PDU。S0,LENGTH,S1這三個部分是可選的。理論部分介紹過PDU有2部分組成,2字節的header和payload所以我們可以使用S0,LENGTH來作爲header,不使用s1,然後payload剛好就作爲payload。 當然你也可以S0,LENGTH,S1一個都不使用,是使用payload,那麼就將payload的前兩字節按照理論部分中的2字節header設置,剩下的當做應用負載payload。

CRC:我們需要設置一下 CRC的字節數,以及生成式,並且使之值計算的部分不包括前導和ADDRESS部分。

 

首先設置接入地址ADDRESS,因爲廣播數據是在廣播信道中發送的,所以使用的是固定的接入地址0x8E89BED6. 51822有8個邏輯地址0-7,並且8個邏輯地址對應的實際地址可以設置,對應關係如下。也就是通過設置BASE0,BASE1,和PREFIX0,PREFIX1,四個寄存器,我們能分別設置8個邏輯地址的實際地址。

因爲這裏用的是廣播信道的固定地址,所以我們將 8個邏輯地址的實際地址全部都設置成0x8E89BED6,然後設置發送地址爲 邏輯地址0就行了。因爲數據發送是LSByte先發送,而51822發送ADDRESS是先發送BASE再發送PREFIX,所以我們需要將PREFIX設置成高位字節0x8E,低位3字節設置到BASE中。

       NRF_RADIO->BASE0 = (0x89BED600);

       NRF_RADIO->BASE1 = (0x89BED600); 

       NRF_RADIO->PREFIX0 = 0x8E8E8E8E;

       NRF_RADIO->PREFIX1 = 0x8E8E8E8E;

       NRF_RADIO->TXADDRESS = 0; //使用邏輯地址0

然後是理論中介紹的PDU部分的設置,即51822中的S0,LENGTH,S1,PAYLOAD,我們使用S0,LENGTH來當做header,PAYLOAD就是PDU中的payload.並且設置S0,LENGTH都爲1字節, 然後設置BLE可以發送的最大應用數據 (51822發送的包組成中的payload的長度)爲37字節,因爲理論部分說過PDU爲2-39字節,2爲2字節頭,所以payload最長爲37字節。並且設置接入地址的長度,上面已經設置了爲4字節。設置發送順序爲LSB(規範要求)。

然後使能白化功能,白化是爲了將原始信息中轉換爲高度隨機的Bit序列,避免出現太長連續的bit0或bit 1從而導致接收出錯。是規範要求

設置如下:

       //8bit長度的LENGTH  1字節長度的S0,不需要s1,因爲廣播格式裏面負載數  //據前面只需要2字節頭,一個是報頭,一個是長度。

NRF_RADIO->PCNF0 = (8<<0) | (1<<8);

       //最大長度37,沒有靜態長度,基礎地址爲3字節,所以加一字節頭後爲四 //字節,就是藍牙規範中接入地址.字節序爲小端(CRC不在這裏設置)

       //使能數據白化

NRF_RADIO->PCNF1 = (37<<0) | (3<<16) | (1<<25) ;

       //白化0x25;       初始值由報文所在鏈路層信道號決定,我們在37好廣播信道上廣播

NRF_RADIO->DATAWHITEIV = 0x25;

//對於應用負載payload,理論部分說過我們使用 不可連接廣播,

//定義一個數組用來存放將要廣播的數據,然後將數據指針指設置爲改buff地址

static uint8_t adv_array[31] = {0};

NRF_RADIO->PACKETPTR = (uint32_t)&adv_array[0];



//然後設置廣播應用數據,如下函數所示



//廣播地址

uint8_t device_add[6]={0xFF,0x01,0x02,0x03,0x04,0xff};

//廣播數據,第一個0x01爲flag設置成只支持BLE,

//第二個0x09爲設備名,名字隨便寫的

uint8_t adv_data[10] = {0x02,0x01,0x04, 0x06,0x09,0x4e,0x6f,0x48,0x52,0x3d};



void set_advdata(void){

       //adv_array的前兩字節爲 header 即S0和LENGTH

       //PDU Type設置爲ADV_NONCONN_IND,如果設置成普通廣播的話,手機可能 //會發掃描包,因爲這裏沒有做掃描迴應,手機就會過濾該設備,導致手機       //搜不到設備。

       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的發送指針寄存器賦值爲 adv_array.那麼發送的時候就會自動將這個數組裏的數據發送出去了

      NRF_RADIO->PACKETPTR = (uint32_t)&adv_array[0];



//CRC,需要設置其字節數,生成式,和初始值。設置如下

       //3字節crc,計算不包括接入地址部分和前導部分

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

       //廣播信道的數據包中crc初始值爲0x555555

NRF_RADIO->CRCINIT =  0x555555;   

 

//這個裏 BLE廣播相關的規範設置都設置完了。

//我們還需要設置一下,廣播的信道。我們在37號廣播信道上廣播。

//設置一下發射功率,以及模式選擇爲Ble_1Mbit     

NRF_RADIO->FREQUENCY = 2;       //鏈路層信道編號 37:2402MHz, 38:2426MHz, 39:2480MHz

NRF_RADIO->TXPOWER = 0x04;

NRF_RADIO->MODE = 0x03;   //ble_1Mbit

 


實際使用中,我查看了FICR中的OVERRIDEEN 的值,兩個指示位都爲0,應該是要用FICR中的校準值覆蓋RADIO中的校準值,不過代碼實現中我屏蔽了設置也能收到廣播。


 

最後就是發送數據的實現了

函數實現很簡單,直接啓動就可以了,radio會自動將上面設置的NRF_RADIO->PACKETPTR指向的數組數據發送出去

void send_data(void)
{   
       NRF_RADIO->EVENTS_READY = 0;

       NRF_RADIO->TASKS_TXEN = 1;                     //啓動發送使能

       while(NRF_RADIO->EVENTS_READY == 0){}       //等待準備好
     
       NRF_RADIO->EVENTS_END = 0;

       NRF_RADIO->TASKS_START = 1;            //開始發送 

       while(NRF_RADIO->EVENTS_END == 0)//等待發送完成
     
       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){

       //這裏設置8個邏輯地址的實際地址,因爲我們只是做廣播,所以把全部地址都設置成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字節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;    //廣播信道的數據包中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字節長度的S0,不需要s1,因爲廣播格式裏面負載數據前面只需要2字節頭,一個是報頭,一個是長度。

       NRF_RADIO->PCNF0 = (8<<0) | (1<<8);

       //payload最大長度37,沒有靜態長度,基礎地址爲3字節,所以加一字節頭後爲四字節,就是藍牙規範中接入地址.字節序爲小端(CRC不在這裏設置)

       //使能數據白化

       NRF_RADIO->PCNF1 = (31<<0) | (3<<16) | (1<<25) ;

       NRF_RADIO->DATAWHITEIV = 0x25;//0x25;        //初始值由報文所在鏈路層信道號決定,這裏爲37

             

}



void set_advdata(void){

       adv_array[0] = 2;       //PDU Type爲ADV_NONCONN_IND,如果設置成普通廣播的話,手機可能會發掃描包,因爲這裏沒有做掃描迴應,手機就會過濾該設備,導致手機搜不到設備。

       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){}       //等待準備好

      

       NRF_RADIO->EVENTS_END = 0;



       NRF_RADIO->TASKS_START = 1;           

       while(NRF_RADIO->EVENTS_END == 0)//等待發送完成

      

       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();

       while(1){

              nrf_delay_ms(50);

              send_data();     

       }

       return 0;

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章