【IT168 技术】本讲为框架介绍,不会牵涉到太多代码细节。51822的官方SDK其实是没有框架依耐性的。什么叫框架,比如TI的BLE SDK中就有一个操作系统抽象层(OSAL)他是一个轮训的调度。你需要按照他的方式去创建任务等等。

  而51822的SDK本质上只是提供了各种调用接口,比如开启初始化协议栈,初始化一些硬件功能模块,开始广播,发起链接等等。这些接口怎么用完全取决于自己。不过一般固件开发都是一些类似的流程各种资源的初始化,51822也不例外。所以sdk中的作为从机的例子main函数都是类似如下的步骤:

  以官方的串口BLE 为例:

  int main(void)

  {

  leds_init(); //非必须,只是该例子中用到了

  timers_init(); //非必须,只是该例子中用到了

  buttons_init(); //非必须,只是该例子中用到了

  uart_init(); //非必须,只是该例子中用到了串口

  ble_stack_init(); //必须

  gap_params_init(); //必须

  services_init(); //跟自己创建的服务相关,不同的服务细节不同但大体建立

  //过程基本一致,通常在直接使用官 方的例子修改一些参数即可

  advertising_init(); //广播数据初始化,必须

  conn_params_init(); //是情况而定,如果连接后不需要连接参数的协商,该初始化也 //可不要

  sec_params_init(); //安全参数初始化,如果没用到配对绑定相关这个也可以不初始化

  advertising_start(); //开启广播,必须

  // Enter main loop

  for (;;)

  {

  power_manage(); //进入睡眠

  }

  }

  可以看到其实核心必要的只有这5个函数而已。你可以将其他代码全都去掉,只要留下这5个函数设备一样可以运行,手机也能搜到设备并与设备通信。

  这种初始化的方式可以说是与我们一般的单片机开发没有区别。

  那么初始化之后呢。以前的裸板单片机开发我们就是进入一个while循环执行一些周而复始的事,后面为了降低功耗开始在while(1)循环中加个睡眠代码让没有工作时芯片处于睡眠状态,并依靠中断来唤醒从而处理到来的事物。

  而上面的51822的main函数最后也是一个for{}循环,power_manage(); 内部代码其实就是一个睡眠指令。Main函数到这里就已经没了,最后其实就是一个循环睡眠。这里看不到任何任务(task),只有睡眠。那么可想而知,51822的协议栈实现应该是基于”事件唤醒”的,也就是没事的时候睡眠,有事的时候唤醒工作而后继续睡眠。那么那些处理事件的代码都是在哪里的?

  那协议栈到底是怎么运作的?我希望创建一个服务在哪里添加?手机发送来的数据在哪里?我怎么发送数据给手机?

  下面一一解释这些问题:

  协议栈如何运作?

  要明白协议栈怎么运作,首先就要理解51822的协议栈是基于100%的事件驱动的。就是说协议栈向app发送的任何数据都是基于事件的。

  比如设备收到手机发来的链接请求,或是手机发过来的数据等等。协议栈首先收到这些数据后做一些处理,然后将这些数据(比如链接请求,或是普通数据等)打包成一个结构体,并附上事件ID,比如BLE_GAP_EVT_CONNECTED或BLE_GATTS_EVT_WRITE来分别告诉上层app这个事件结构体代表的事件。

  比如BLE_GAP_EVT_CONNECTED代表链接事件,那么这个事件结构体中包含的数据就是连接参数等数据。而BLE_GATTS_EVT_WRITE代表写事件,那么结构体中的数据就是对端设备(比如手机)写给板子的数据。

  比如uart的demo中dispatch派发函数

static void ble_evt_dispatch(ble_evt_t * p_ble_evt)

{

ble_conn_params_on_ble_evt(p_ble_evt);

ble_nus_on_ble_evt(&m_nus, p_ble_evt);

on_ble_evt(p_ble_evt);

}

  在任何与BLE相关的事件被协议栈上抛上来给app时,ble_evt_dispatch就会被调用。从而将事件抛给各个服务函数或处理模块,这里是将事件抛给了

  连接参数管理处理函数ble_conn_params_on_ble_evt

  Uart服务的事件处理函数ble_nus_on_ble_evt (nus为Nordicuart server)

  通用的事件处理函数on_ble_evt

  不同的事件在事件结构体ble_evt_t中通过id来区别。不同是事件处理函数通常也只是处理自己感情去的事件,我们来看看ble_nus_on_ble_evt事件处理函数的内部

  voidble_nus_on_ble_evt(ble_nus_t * p_nus, ble_evt_t * p_ble_evt)

  {

  if ((p_nus == NULL) || (p_ble_evt == NULL))

  {

  return;

  }

  switch (p_ble_evt->header.evt_id)

  {

  caseBLE_GAP_EVT_CONNECTED:

  on_connect(p_nus, p_ble_evt);

  break;

  caseBLE_GAP_EVT_DISCONNECTED:

  on_disconnect(p_nus, p_ble_evt);

  break;

  caseBLE_GATTS_EVT_WRITE:

  on_write(p_nus, p_ble_evt);

  break;

  default:

  // No implementation needed.

  break;

  }

  }

  可以看到,uart服务事件处理函数只关心三个事件,链接事件,断开链接事件以及写事件(对端设备发数据过来),不同的事件再针对做不同的,这个就由开发人员自己来实现了。比如对于连接事件通常应该记录下事件结构体中的连接句柄,因为后续的BLE操作基本都要基于连接句柄(可以看做是两个设备通信的信道ID,实际为链路层中的数据接入地址概念)。

  PS: 事件是交给dispatch来派发给各个服务以及模块的,对于更底层的事件又是如何交给dispatch函数的过程请参考群公告中的 51822教程-协议栈概述教程。

  解决了所谓的事件驱动再来解决:如果希望创建一个服务在哪里添加?

  在main函数的初始化过程中有一个services_init();这个函数的内部就是添加服务,添加特征值等代码。

  函数内部其实就是注册了一会回调函数nus_data_handler(该函数会在手机发数据给板子时将数据从电脑串口打印出来) 然后再执行真正的初始化函数ble_nus_init。

  该函数的内部又会调用sd_ble_gatts_service_add这个协议栈的api接口来添加服务。

  后面也会调用sd_ble_gatts_characteristic_add这个协议栈的api接口来添加特征值。

  层次关系如下:

  也就是说完成一个完整的服务建立函数其实只要sd_ble_gatts_service_add()和sd_ble_gatts_characteristic_add ()这两个核心函数。

  通常建立服务并不需要自己去从头写过。而是直接赋值官方的这个services_init()函数,然后做一些小改动就可以。比如修改一下uuid, 修改一下读/写属性,多添加一个特征值等。要修改的其实很少。

  下面解决最后两个问题:手机发送来的数据在哪里?我怎么发送数据给手机?

  要搞清楚这两个问题,先来看一下群里常问的几个与上面相关的问题:

  问:手机发给51822设备的数据在哪个函数里出来的?

  答:

  没有函数

  协议栈会抛上来一个事件结构体

  收到的数据在结构体中

  问:蓝牙上传函数,与下发函数都是一样的吗?都是服务API函数?

  答:

  只有上传函数 是服务器用来将数据传给客户端的。

  下发数据 是蓝牙芯片收到数据后,协议栈会拋上来一个有数据的事件结 构体。具体参看示例代码中的 dispatch派发程序中各个事件处理函数对各 种事件的数据。

  问:sd_ble_gatts_hvx()这个函数是 蓝牙的发送函数,有知道蓝牙的接收函数 ?

  答:

  蓝牙没有接收函数,蓝牙的数据接收在底层,接收完后会返回事件给上层的 ble_evt_dispatch 分发函数,它将事件分发给各个服务或者事件处理函数。 服 务或处理函数会捕获是否存在写事件case BLE_GATTS_EVT_WRITE: 存在就做 相应的处理。收到的数据都在返回的事件结构体里

  其实看完这三个问题基本上上面的问题其实已经解决差不多了。作为从设备,BLE的发送数据给手机是有API接口的,就是上面问到的sd_ble_gatts_hvx(),可以通过参数来设置是以通知方式发送还是指示方式发送(通知不需要回复确认,指示需要)。但是手机发过来数据却是没有接收函数,为什么?因为协议栈是基于事件驱动的!所以收到数据后协议栈会给上层app一个写事件(指示对端设备写数据过来了),而写过来的数据时在这个事件结构体中。我们只要提取出来就行了。所以没有接收函数API。

  从另一方面也可以解释为什么没有接收数据函数。因为发送数据时”同步的”,是主动调用的,在往想发送数据的时候。但是接收数据时”异步的”,数据可能随时到来,总不来一直调用一个函数然后原地等待数据到来吧,如果数据不来岂不是什么事都干不了了。所以接收是基于事件驱动的。有数据来再转过去处理。

  用个图来解释下:

  如果还是觉得有点抽象,回到前面看看协议栈运作讲解部分。应该更能体会所谓的事件驱动。

原文地址:http://blog.chinaunix.net/uid-28852942-id-5335038.html

BLE-NRF51822教程3-sdk程序框架剖析相关推荐

  1. VC++基于MFC的程序框架剖析(前言)

    目录 基于MFC的程序框架剖析 MFC类组织结构图:层次结构图 接上:VC++MFC应用程序向导 接下:VC++MFC程序中的WinMain函数(一) 基于MFC的程序框架剖析 MFC库是开发Wind ...

  2. 微信小程序云开发教程-微信小程序框架的介绍

    同学们大家好,我是小伊同学,今天我们来学习微信小程序框架. 微信小程序实质上是一款基于web技术的应用程序,他和我们平常所接触到的前端网页是大同小异的.相同点在于他们使用的开发语言,代码结构以及代码的 ...

  3. 精品教程---Android应用程序框架

      下载源码 1.Android资源文件... 1 (1) anim.. 2 (2) drawable. 2 (3) layout2 (4) menu. 2 (5) values. 2 (6) raw ...

  4. Directx11 教程(2) 基本的windows应用程序框架(2)

    Directx11 教程(2) 基本的windows应用程序框架(2) 原文:Directx11 教程(2) 基本的windows应用程序框架(2) 在本教程中,我们把前面一个教程的代码,进行封装.把 ...

  5. 《ArcGIS Engine+C#实例开发教程》第一讲桌面GIS应用程序框架的建立

    原文:<ArcGIS Engine+C#实例开发教程>第一讲桌面GIS应用程序框架的建立 摘要:本讲主要是使用MapControl.PageLayoutControl.ToolbarCon ...

  6. 美团小程序框架mpvue入门教程

    美团小程序框架mpvue入门教程 自打写了 美团小程序框架mpvue蹲坑指南, 一发不可收拾,今天趁周末空闲,来写个mpvue(没朋友)的简单入门教程,本教程只针对新手,老鸟勿喷. 另外,我还专门为本 ...

  7. 好程序员技术教程分享JavaScript运动框架

    好程序员技术教程分享JavaScript运动框架,有需要的朋友可以参考下. JavaScript的运动,即让某元素的某些属性由一个值变到另一个值的过程.如让div的width属性由200px变到400 ...

  8. mpvue 微信小程序api_mpVue 小程序框架 SDK

    mpVue 小程序框架 SDK 接入mpVue小程序框架需要「微信授权」和「集成SDK」. 微信小程序授权 登录「诸葛io分析平台」后,进入「数据接入」-「微信小程序」开始微信小程序授权,点击「开始授 ...

  9. vue 美团框架_美团小程序框架mpvue入门教程

    美团小程序框架mpvue入门教程 本教程只针对新手,老鸟勿喷. 另外,我还专门为本文做了一个简单的项目,如果懒得从头开始搭项目的童鞋,可以直接去我的 github上克隆到本地, 安装一下依赖,即可直接 ...

最新文章

  1. 继续过中等难度.0309
  2. python vs java的rsa加密
  3. 判断均匀平面波的极化形式_测瑞通|怎样判断电波暗室的性能?
  4. 如何给对方邮箱发照片_朋友圈如何发心形拼图九宫格照片?
  5. mac 下修改 jenkins 端口以及Jenkins的启动、关闭与更新
  6. 普通人,如何实现年收入百万?
  7. python实现翻转给定列表中的元素
  8. Ubuntu4.04 安装Mesos
  9. 微信小程序Axure元件库
  10. sonar下载地址使用
  11. nvme固件升级 linux,Intel NVME SSD 固件升级步骤
  12. 精简版XP安装IIS
  13. Shader 优化相关资料整理
  14. win10您的计算机配置文件,Win10系统开机登录提示无法加载用户配置文件如何解决...
  15. 16、 基于STM32单片机WIFI控制家电插座
  16. 四轴飞行器基本组成及其飞行原理详解
  17. python编写英文字符频率统计小程序
  18. 腾讯裁员,裁出“财务自由”
  19. java-php-python-ssm职工工资管理系统计算机毕业设计
  20. 怎么设置指定号码打不进来_如何屏蔽某个电话号码,让它永远打不进来??

热门文章

  1. android数据回传多个页面_Android Day06四大组件之Activity多页面跳转和数据传递
  2. java 文件编码 查询系统_javaweb垃圾分类查询系统、ssm+mysql
  3. adb shell 小米手机_如何在Android手机上进行自动化测试
  4. r语言解析html,R语言爬虫入门-rvest教程
  5. osg节点函数功能汇总
  6. c语言中1B是多少,C语言1、C语言中,运算对象必须是整型的运算符是【】A./B-查字典问答网...
  7. iOS App 目录结构
  8. 消息队列中数据丢失了怎么办
  9. 【初窥javascript奥秘之闭包】叶大侠病都好了,求不踩了:)
  10. [翻译]NUnit---String Collection File Directory Assert (七)