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;

}

 

 

蓝牙数据白化:

这里注意白化是不分广播状态或者是连接状态,它的移位寄存器的初始值为信道通道号,并且最高位一定置 1,也就是初始值的第7bit位一定是1。例如,广播通道 channel是37(0x25), 那么初始值就是 37。

白化算法:

uint8_t  reverseBits(uint8_t input) 
{
	uint8_t temp = 0;
	if (input & 0x80) temp |= 0x01;
	if (input & 0x40) temp |= 0x02;
	if (input & 0x20) temp |= 0x04;
	if (input & 0x10) temp |= 0x08;
	if (input & 0x08) temp |= 0x10;
	if (input & 0x04) temp |= 0x20;
	if (input & 0x02) temp |= 0x40;
	if (input & 0x01) temp |= 0x80;
	return temp;
}


uint8_t  bleWhitenStart(uint8_t chan) 
{
	return reverseBits(chan) | 2;
}

void bleWhiten(uint8_t* data, uint8_t len, uint8_t whitenChannel)   //白化信道
{


	// Implementing whitening with LFSR
	uint8_t   m;
	uint8_t  chanel;
	
	chanel = bleWhitenStart(whitenChannel);
	while (len--) {
		for (m = 1; m; m <<= 1) 
		{
			if (chanel & 0x80) {
				chanel ^= 0x11;
				(*data) ^= m;
			}
			chanel <<= 1;
		}
		data++;
	}
}

 

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值