加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

NRF51822 广播与扫描

(2017-01-09 14:40:02)
分类: 蓝牙

from:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=28852942&id=5752396

解决以下几个问题:

1 SDK9 中的几种广播模型

2 广播超时如何进入睡眠

如何取消广播超时睡眠使其可以无限广播。

 

1 SDK9 中的几种广播模型

Nordci SDK对于广播方面有一个模块。这个模式定义了几种广播模式,当然这些模式并非规范中的广播模式,仅仅是sdk自己定义的一些模式而已。

如下图


http://blog.chinaunix.net/attachment/201609/26/28852942_1474850442GiVL.png广播与扫描" />

Direct模式及直连模式,利用的就是ble中的直连广播,该模式是为了快速重连上刚刚断开的设备,比如利用在快速重连上意外断开的设备,已达到无缝恢复的目的。(实践代码中还分成了)

Fast模式:就是普通的广播,不过连接间隔我们可以设置的快一点。

Slow模式:普通广播,连接间隔设置的慢一点

Idle模式:停止广播。

这四种模式是递进的,比如你设置了启动广播时选择Direct模式,但是如果你并未在初始化时设置Direct模式的相关参数,那么它就会回尝试Fast模式,如果初始化时Fast模式的相关信息也没设置,就会再尝试Slow模式,如果初始化时Slow模式相关信息也没设置最后就直接进入到Idle模式了。

同样的,广播超时后的超时处理就是选择下一个模式再进行广播,比如你Fast模式启动广播成功后,如果超时时间是3分钟,3分钟后,广播超时处理中就是选择尝试Slow模式广播。

其实模式的定义只是给出了一个可以直接利用的模块,比如Fast模式和Slow模式并没有定义所谓的快慢是多少,只是给以一个你可以直接使用的代码模块。比如你的使用场景是希望设备上电后以30ms快速广播20s,如果一直都没有被连接上,30s后切换成200ms的广播3分钟以达到减小功耗目的。

那么在广播初始化的时候就可以忽略Direct模式的相关设置,设置Fast模式使能,并且广播间隔为30ms,超时时间为20s,设置Slow模式使能,并且其广播间隔为200ms,超时时间设置为180s。之后启动Fast模式广播就可以了,当20s超时到期后,就会收到协议栈的BLE timeout事件,sdk中的处理就是切换成Slow模式继续广播。如果Slow模式180s也超时了,协议栈就会上抛Slow timeout事件,最终就停止广播了。

2广播超时后如何进入睡眠:

Main函数中调用了advertising_init来初始化广播参数

http://blog.chinaunix.net/attachment/201609/26/28852942_1474850442Ew2v.png广播与扫描" />

从上图可以看到,sdk中默认只初始化了Fast 这个模式的参数,也就是说当我们用Fast模式启动广播后,当广播超时后。由之前的描述知道Sdk会再选择SLOW模式,但是初始化这里并未设置SLOW模式参数,所以最终会再选择IDLE模式也就是进入睡眠了。分析如下:

 

Main中初始化广播后,启动FAST模式广播

http://blog.chinaunix.net/attachment/201609/26/28852942_1474850443q2y2.png广播与扫描" />

如果一直没有其他设备来连接,当广播超时后,协议栈就会上抛一个TIMEOUT事件,广播模块的事件处理函数会处理这个事件


http://blog.chinaunix.net/attachment/201609/26/28852942_14748504434pP3.png广播与扫描" />
http://blog.chinaunix.net/attachment/201609/26/28852942_1474850443g2eO.png广播与扫描" />

http://blog.chinaunix.net/attachment/201609/26/28852942_14748504443KTe.png广播与扫描" />

可以看到对TIMEOUT的事件处理为先判断是不是广播的TIMEOUT事件。如果是就判断模式,因为是FAST模式启动,所以代码中就会再次启动SLOW模式的广播。

 

再看下启动广播函数,只看相关的几个代码段:

http://blog.chinaunix.net/attachment/201609/26/28852942_14748504446R4O.png广播与扫描" />

下面这段代码就是根据启动广播的模式和初始化时设置的参数来决定真正的广播模式。

第一次启动时,因为是FAST模式启动的,并且初始化函数advertising_init中设置了FAST模式的相关参数,所以确定就是FAST模式,当FAST广播模式超后,上面的代码显示是又启动了SLOW模式,但是advertising_init函数中并未设置SLOW模式的相关参数,从下面的代码中看到最终设置成了IDLE模式。即并未按照要求启动了SLOW广播,因为初始化时没有设置SLOW模式的相关参数。

http://blog.chinaunix.net/attachment/201609/26/28852942_1474850445kIYR.png广播与扫描" />

PS:上图的DIRECT_SLOW这个模式就是利用ble中的Low Duty Cycle Directed Advertising4.0时规范只定义了DIRECT广播类型,就是定向广播,并且广播周期为3.75ms,并且只能持续1.28s4.1开始分成了Low Duty Cycle Directed AdvertisingHigh Duty Cycle Directed AdvertisingHigh Duty Cycle Directed保持了之前的定义即3.5ms周期和最多持续1.28s,而Low Duty Cycle Directed类似普通广播,不过是定向的而已。


函数的最后有如下片段,因为最终设置成了IDLE模式,所以没有启动广播,于是调用了m_evt_handler函数。


http://blog.chinaunix.net/attachment/201609/26/28852942_1474850445rHJH.png广播与扫描" />

这个函数时在广播初始化里面设置的

http://blog.chinaunix.net/attachment/201609/26/28852942_1474850445sV2j.png广播与扫描" />


实现如下

http://blog.chinaunix.net/attachment/201609/26/28852942_14748504460wEq.png广播与扫描" />


sleep_mode_enter
函数的实现就是设置唤醒按键,然后进入深度睡眠    

http://blog.chinaunix.net/attachment/201609/26/28852942_1474850446wq81.png广播与扫描" />

唤醒按键设置了BUTTON0 和BUTTON1  这里的0,1是编号的意思。我用的板子是PCA10028型号,这个板子上有4个按键分别是p0.17  p0.28, p0.19 ,p0.20。对应的编号就是0-3.

这里就是将17 ,18连个引脚设置为唤醒引脚。(17引脚唤醒的同时会删除绑定信息)

http://blog.chinaunix.net/attachment/201609/26/28852942_1474850446ulyj.png广播与扫描" />

http://blog.chinaunix.net/attachment/201609/26/28852942_1474850447114R.png广播与扫描" />

综上:广播初始化中设置了FAST模式广播的相关参数,然后按FAST模式启动广播。当广播超时后,超时时间处理中判断是FAST模式超时,于是再启动SLOW模式广播,但是因为SLOW模式广播的相关参数并没有设置,于是切换成IDLE模式,并且调用了初始化时设置的回调函数。回函数中会设置唤醒按键然后设置深度睡眠。


3如何取消广播超时睡眠使其可以无限广播

 

 

 

http://blog.chinaunix.net/attachment/201609/26/28852942_1474850447M5Z7.png广播与扫描" />

 

扫描

 

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

找到m_scan_param参数定义



http://s9/mw690/003hEzXrzy77QPBiQkMb8&690广播与扫描" TITLE="NRF51822 广播与扫描" />


在实际中如果需要获得扫描响应,需要主机设置为主动扫描。如果仅仅是需要广播数据则设置为被动扫描。主动扫描和被动扫描的区别在于:主动扫描可以获得广播数据和扫描回应数据。而被动扫描只能获得广播数据不能获得扫描数据。

 

不返回扫描回应数据

 

 

Scan_rsp: This is 1 if the packet is a scan response. It is 0 if the packet is a normal advertisement packet.

 

ble_gap_scan_params_t m_scan_params 结构体的成员active0,不得到 扫描回应数据

SCAN_TIMEOUT也设置为0 设备一直扫描 不超时

1.    

2.  static const ble_gap_scan_params_t m_scan_param  

3.   

4.      0,              // Active scanning not set.  //设置为被动扫描  

5.      0,              // Selective scanning not set.  

6.      NULL,           // No whitelist provided.  

7.      SCAN_INTERVAL,  

8.      SCAN_WINDOW,  

9.      0x0000          // No timeout.  

10. };


值的意义依次为:

0,表示只侦听广播,不主动发起scan_req请求。

0,表示侦听所有广播包,不做过滤。

NULL,没有白名单

扫描间隔,和扫描窗口。(比如1s的间隔和0.5s的窗口,那么每1s就会启动侦听,但是只侦听0.5s,只会休眠。等待下一个1s到来)

0,表示没有扫描超时,即设备会一值侦听除非主动关闭扫描

 

  • Active: Perform active scanning, which is sending scan requests to all advertisers asking for their scan response packets in addition to the advertisement packet.
  • Selective: Ignore devices not in our whitelist, which is a list of known devices.
  • Whitelist: Our list of known devices.
  • Interval: How often we start a scan window
  • Scan window: How long we scan every scan interval
  • Timeout: How long the scanner will run before stopping automatically.

 

 

启动广播之后,设备就会不断侦听其他设备的广播。

当收到广播数据后,协议栈会上抛一个BLE_GAP_EVT_ADV_REPORT事件给上层,所以实现一个简单的侦听器,我们直接在事件处理中添加一个 BLE_GAP_EVT_ADV_REPORT事件的分支,并在该分支中提取收到的广播数据就可以了。

 

官方的例子里面已经有针对 BLE_GAP_EVT_ADV_REPORT这个事件的处理了。



http://s9/mw690/003hEzXrzy77QPDGtQs68&690广播与扫描" TITLE="NRF51822 广播与扫描" />


The advertisement report is found inside the event structure: p_gap_evt->params.adv_report. The type of this report is ble_gap_evt_adv_report_t, which is a structure containing the following:

  • peer_addr: The Bluetooth address of the device broadcasting the advertisement
  •    发送广播设备的地址
  • Rssi: Received Signal Strength Indication. The signal strength of the device, in dBm.
  • Scan_rsp: This is 1 if the packet is a scan response. It is 0 if the packet is a normal

  • advertisement packet.

  • 1--扫描回应包  0--正常广播包

  • Advertisement type (Connectable, direct/indirect etc…).

  • Dlen: Length of the advertisement packet.

  • Data: The advertisement packet as a byte array. (uint8_t *)

 

 

The data field is structured in the following way:


[LENGTH_0][TYPE_0][VALUE_0][LENGTH_1][TYPE_1][VALUE_1]   [LENGTH_n][TYPE_n][VALUE_n]

If it contains the name “Hello” as the first value of the packet, it will look like this:


[0x5][0x9][0x48,0x65,0x6c,0x6c ,0x6f]   [LENGTH_n][TYPE_n][VALUE_n]

这个是有问题的应该是[0x6][0x9][0x48,0x65,0x6c,0x6c,0x6f]

length的数据长度包含 type和value值总的长度

0x5 is the length of the name, and 0x9 is the type COMPLETE_LOCAL_NAME. The type codes can be foundhere . They are also defined in ble_gap.h in the nRF SDK. The rest of the values are "Hello" in hex format (ASCII).

 

type

#define BLE_GAP_AD_TYPE_FLAGS                               0x01
#define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE   0x02
#define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE         0x03
#define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_MORE_AVAILABLE   0x04
#define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_COMPLETE         0x05
#define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE  0x06
#define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE        0x07
#define BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME                    0x08
#define BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME                 0x09
#define BLE_GAP_AD_TYPE_TX_POWER_LEVEL                      0x0A
#define BLE_GAP_AD_TYPE_CLASS_OF_DEVICE                     0x0D
#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C               0x0E
#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R         0x0F
#define BLE_GAP_AD_TYPE_SECURITY_MANAGER_TK_VALUE           0x10
#define BLE_GAP_AD_TYPE_SECURITY_MANAGER_OOB_FLAGS          0x11
#define BLE_GAP_AD_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE     0x12
#define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_16BIT       0x14
#define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_128BIT      0x15
#define BLE_GAP_AD_TYPE_SERVICE_DATA                        0x16
#define BLE_GAP_AD_TYPE_PUBLIC_TARGET_ADDRESS               0x17
#define BLE_GAP_AD_TYPE_RANDOM_TARGET_ADDRESS               0x18
#define BLE_GAP_AD_TYPE_APPEARANCE                          0x19
#define BLE_GAP_AD_TYPE_ADVERTISING_INTERVAL                0x1A
#define BLE_GAP_AD_TYPE_LE_BLUETOOTH_DEVICE_ADDRESS         0x1B
#define BLE_GAP_AD_TYPE_LE_ROLE                             0x1C
#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C256            0x1D
#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R256      0x1E
#define BLE_GAP_AD_TYPE_SERVICE_DATA_32BIT_UUID             0x20
#define BLE_GAP_AD_TYPE_SERVICE_DATA_128BIT_UUID            0x21
#define BLE_GAP_AD_TYPE_URI                                 0x24
#define BLE_GAP_AD_TYPE_3D_INFORMATION_DATA                 0x3D
#define BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA          0xFF

代码中就是从广播数据中提取了设备名 然后判断是不是自己要连的那个设备。

 

我们不需要动这些代码,直接在前面添加广播数据的打印就可以了。如图所示


http://s12/mw690/003hEzXrzy77QPEUuCf9b&690广播与扫描" TITLE="NRF51822 广播与扫描" />




打印结果如图所示



http://s10/mw690/003hEzXrzy77QPFTc3T19&690广播与扫描" TITLE="NRF51822 广播与扫描" />



    关于adv data的数据怎么解析,参考教程 ble广播数据解析。

 

广播数据结构体中还有一个scan_rsp 没有使用


http://blog.chinaunix.net/attachment/201607/19/28852942_1468928327BMEm.png广播与扫描" />

这个为是用来区分 当前的广播数据是普通广播数据,还是收到的扫描响应数据(扫描者发送了scan_req,如果广播者可以响应则会回复scan_rsp)

如果需要区分自己判断一下就行了

  

 

 from:http://blog.csdn.net/zwj695535100/article/details/49127035

当使用softdevice时,可以调用函数:sd_ble_gap_tx_power_set

 

[html] view plain copy  print?
  1. uint32_t sd_ble_gap_tx_power_set(int8_t     tx_power)     
  2. Set the radio's transmit power.  
  3.   
  4. Parameters  
  5. [in]    tx_power    Radio transmit power in dBm (accepted values are -40, -30, -20, -16, -12, -8, -4, 0, and dBm).  
  6. Note  
  7. -40 dBm will not actually give -40 dBm, but will instead be remapped to -30 dBm.  
  8. Returns  
  9. NRF_SUCCESS Successfully changed the transmit power.  
  10. NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.  
  11. NRF_ERROR_BUSY The stack is busy, process pending events and retry.  


使用这个函数可以随时随地的更改发射功率,即使已经开始了广播。

在gap_params_init() 函数中调用!!或者在需要的地方调用!!!

 

[html] view plain copy  print?
  1. <</SPAN>span style="color:#253555;">  
  2. static void gap_params_init(void)  
  3.  
  4.     uint32_t                err_code;  
  5.     ble_gap_conn_params_t   gap_conn_params;  
  6.     ble_gap_conn_sec_mode_t sec_mode;  
  7.   
  8.     BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);  
  9.   
  10.     err_code sd_ble_gap_device_name_set(&sec_mode,  
  11.                                           (const uint8_t *)DEVICE_NAME,  
  12.                                           strlen(DEVICE_NAME));  
  13.     APP_ERROR_CHECK(err_code);  
  14.   
  15.     err_code sd_ble_gap_appearance_set(BLE_APPEARANCE_GENERIC_KEYRING);  
  16.     APP_ERROR_CHECK(err_code);  
  17.   
  18.     memset(&gap_conn_params, 0, sizeof(gap_conn_params));  
  19.   
  20.     gap_conn_params.min_conn_interval MIN_CONN_INTERVAL 
  21.     gap_conn_params.max_conn_interval MAX_CONN_INTERVAL 
  22.     gap_conn_params.slave_latency     SLAVE_LATENCY 
  23.     gap_conn_params.conn_sup_timeout  CONN_SUP_TIMEOUT 
  24.   
  25.     err_code sd_ble_gap_ppcp_set(&gap_conn_params);  
  26.     APP_ERROR_CHECK(err_code);  
  27.   
  28.  </</SPAN>span><</SPAN>span style="color:#ff0000;">   err_code sd_ble_gap_tx_power_set(TX_POWER_LEVEL);  
  29.     APP_ERROR_CHECK(err_code);</</SPAN>span><</SPAN>span style="color:#253555;">  
  30. }</</SPAN>span>  


0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有