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

理论部分主要介绍了BLE广播包的 数据包格式,知道了数据包格式只需要按照格式要求设置数据包然后发送,那么BLE扫描者就能将这个数据包解析成ble广播包了。

这里我们用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

//链路层信道编号 37:2402MHz, 38:2426MHz, 39:2480MHz

NRF_RADIO->FREQUENCY = 2;

NRF_RADIO->TXPOWER = 0x04;

NRF_RADIO->MODE = 0x03;   //ble_1Mbit

另外根据手册说明 还有一个校准值的设置,如下图手册中的描述

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,应该是要用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

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,如果设置成普通广播的话,手机可能会发扫描包,因为这里没有做扫描回应,手机就会过滤该设备,导致手机搜不到设备。

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

nrf_gpio_cfg_output(22);

nrf_gpio_pin_clear(22);

while(1){

nrf_delay_ms(50);

send_data();

}

return 0;

}

51822模拟ble广播-实践相关推荐

  1. 51822模拟ble广播-理论

    http://blog.chinaunix.net/uid/28852942/cid-219646-list-1.html 这讲教程介绍如何使用51822的radio部分来模拟实现ble广播功能,并使 ...

  2. android BLE Peripheral 手机模拟设备发出BLE广播 BluetoothLeAdvertiser

    android 从4.3系统开始可以连接BLE设备,这个大家都知道了.iOS是从7.0版本开始支持BLE.android 进入5.0时代时,开放了一个新功能,手机可以模拟设备发出BLE广播, 这个新功 ...

  3. android BLE Peripheral 模拟 ibeacon 发出ble 广播

    原文地址: https://www.cnblogs.com/CharlesGrant/p/7155211.html Android对外模模式(peripheral)的支持: 从Android 5.0+ ...

  4. 使用C#进行蓝牙开发-接收BLE广播

    使用BluetoothLEAdvertisementWatcher类来接收附近的蓝牙广播,这个是UWP的类,关于如何在WPF或者命令行程序中使用这个类,随便一搜就有了,很简单,.NET6之后简单设置一 ...

  5. 蓝牙4.0 BLE 广播包解析

    本文转自:蓝牙4.0BLE抓包(二) – 广播包解析 - 强光手电 - 博客园 感谢原创作者! SleepingBug评论:这篇文档写的相当好,受教了,多谢了! 所有图片水印均是CSDN自动标上的,并 ...

  6. ble理论(13) BT4.2 ble 广播详解

    文章目录 1.BLE 广播基本知识 1.1 BLE广播信道 1.2 BLE广播数据结构 1.3 广播间隔 1.4 广播类型 1.41 非定向可连接 广播 事件(ADV_IND) 1.4.2 定向可连接 ...

  7. Android的BLE广播数据包介绍和解析---BLE--Android系列, 蓝牙技术BLE

    目录 一.引言 二.广播的类型 三.广播数据格式 四.广播数据解析 五.总结 一.引言 理解和分析这个数据包结构(这里面也涉及广播间隔时间的设置,设备广播数据间隔设置长了,会影响设备被发现的效率:设置 ...

  8. 【蓝牙开发 - BLE】BLE广播包

    前言 对于BLE相关的知识学习,在实际开发中,大部分的开发人员不需要接触到底层的蓝牙协议,更多的是原厂提供的BLE收发或者广播包相关设置等接口,是不涉及到原理部分的内容. 而对于希望进一步的学习蓝牙知 ...

  9. 如何掌握SWAT模型在水文水资源、面源污染模拟中的实践技术?

    目前,水环境问题逐渐成为制约社会经济和环境可持续发展的重要因素.根据国内外研究表明,受全球环境变化和经济快速发展的影响,面源污染已逐渐成为水环境污染的第一因素.但面源污染由于具有排放分散.隐蔽,排污随 ...

最新文章

  1. php 通过exec 创建git分支失败
  2. sql 查询慢的48个原因分析
  3. python中fit什么意思_使用Logit()和fit()在python中进行逻辑回归
  4. jQuery-强大的jQuery选择器 (详解)
  5. bnuoj 1065 简单的问题(位运算)
  6. 创建型模式(五):Singleton(单例模式)
  7. NLP基础|中英文词向量评测理论与实践
  8. P5169 xtq的异或和(FWT+线性基)
  9. Amazon.com 和 store.apple.com 哪个的购物体验更好?
  10. 使用CAShapeLayer与UIBezierPath画出想要的图形
  11. IMPLEMENT_DYNCREATE(CFileView, CView)
  12. android小米手机拍照功能,小米手机 调用相机拍照后无法返回问题
  13. php 人民币换算美金,美元汇率换算_美国人民币换算器
  14. 作品交流:数字通信同步技术资源下载
  15. 【福利】邀请博主,赢取大奖
  16. 基于javaweb的高校运动会管理系统(java+ssm+jsp+js+jquery+mysql)
  17. 0117 - 深耕 iBooks 标注导入
  18. python存储mp3信息_【Python】 获取MP3信息replica
  19. 1-20的两个数把和告诉A,积告诉B,A说不知道是多少,B也说不知道,这时A说我知道了,B接着说我也知道了,问这两个数是多少?
  20. ps一键滤镜网红文艺小清新VSCO全滤镜插件安装教程

热门文章

  1. php编码和c语言,急求windows下用c语言开发PHP扩展时,在C语言里把字符串转成utf-8编码再打印的方法。...
  2. 深信服上网管理设备恢复出厂设置方法
  3. linux prel安装_Linux下Perl的安装(转)
  4. powerdesigner显示工具面板_10分钟看懂Photoshop 绘画(画笔面板1-3)
  5. 现代通用计算机的雏,1834年巴贝奇设计的( )是现代通用计算机的雏形 答案:分析机...
  6. java 删除某一个学生_java编写一个程序,实现功能(定义一个类学生表示学生1. 增加学生2显示 3. 修改 4. 删除5查找某...
  7. 自定义 URL Scheme 完全指南
  8. anaconda如何更改环境配置_Anaconda环境配置2020-08-27
  9. Linux篇 | 多网卡绑定技术 binding 和 网络组nmcli
  10. rsync定时任务引起cpu负载高