CC2640学习笔记(2)——运行流程

一、总流程

---> main()
---> 初始化硬件模块、系统任务及建立自定义app任务
---> 进入SimpleBLEPeripheral_createTask()【自定义app任务】
---> 进入回调函数SimpleBLEPeripheral_taskFxn()
---> 初始化app任务SimpleBLEPeripheral_init()
---> 处理(消息)事件及定时任务

1.1 打开SimpleBLEPeripheral例程

C:\ti\simplelink\ble_cc26xx_2_01_00_44423\Projects\ble\SimpleBLEPeripheral\CC26xx\IAR\SimpleBLEPeripheral.eww

1.2 main.c

1.2.1 初始化PIN 与 ICall 模块

// 初始化硬件GPIO口
    PIN_init(BoardGpioInitTable);
// 初始化ICall软件模块,用于app和stack之间的通信
    ICall_init();

1.2.2 建立 2 个系统必要任务程序

 // 启动远程任务,对应的ICall的入口点,包含stack任务,优先级5
    ICall_createRemoteTasks();
    
// 初始化GAPRole任务,管理蓝牙设备角色等事务,优先级3
    GAPRole_createTask();

1.2.3 建立用户自定义app任务

// 初始化app任务,以后用户要添加一个自定义任务,都要这样添加
    SimpleBLEPeripheral_createTask();

1.2.4 完整代码

int main()
{
    // 初始化硬件GPIO口
    PIN_init(BoardGpioInitTable);

#ifndef POWER_SAVING
    /* Set constraints for Standby, powerdown and idle mode */
    Power_setConstraint(Power_SB_DISALLOW);
    Power_setConstraint(Power_IDLE_PD_DISALLOW);
#endif // POWER_SAVING
    
    // 初始化ICall软件模块,用于app和stack之间的通信
    ICall_init();

    // 启动远程任务,对应的ICall的入口点,包含stack任务,优先级5(越大越优先)
    ICall_createRemoteTasks();
    
    // 初始化GAPRole任务,管理蓝牙设备角色等事务,优先级3
    GAPRole_createTask();
    
    // 初始化app任务,以后用户要添加一个自定义任务,都要这样添加
    SimpleBLEPeripheral_createTask();

#ifdef FEATURE_OAD
    {
      uint8_t counter;
      uint32_t *vectorTable =  (uint32_t*) 0x20000000;
#if defined(__IAR_SYSTEMS_ICC__)
      uint32_t *flashVectors = &__vector_table;
#elif defined(__TI_COMPILER_VERSION__)
      uint32_t *flashVectors = &ti_sysbios_family_arm_m3_Hwi_resetVectors;
#endif //Compiler.
      
      // Write image specific interrupt vectors into RAM vector table.
      for(counter = 0; counter < 15; ++counter)
      {
        *vectorTable++ = *flashVectors++;
      }
    }
#endif //FEATURE_OAD
    
    // 开启操作系统,永不返回
    BIOS_start();

    // 防止编译器警告用,代码无法执行到这里
    return 0;
}

接下来, 我们不看系统调度, 直接来看 SimpleBLEPeripheral_createTask() 这个任务即可。

1.3 simpleBLEPeripheral.c

app任务,以后用户要添加一个自定义任务,都要像这样模仿

1.3.1 SimpleBLEPeripheral_createTask

void SimpleBLEPeripheral_createTask(void)
{
  // 创建一个任务结构体
  Task_Params taskParams;

  // 配置任务
  Task_Params_init(&taskParams);
  taskParams.stack = sbpTaskStack;
  taskParams.stackSize = SBP_TASK_STACK_SIZE;  // 堆栈大小,在开发中需要适当增大
  taskParams.priority = SBP_TASK_PRIORITY;     // 优先级,数值越小优先级越低
  
  // SimpleBLEPeripheral_taskFxn是任务回调函数,此函数不会返回
  Task_construct(&sbpTask, SimpleBLEPeripheral_taskFxn, &taskParams, NULL);
}

1.3.2 SimpleBLEPeripheral_taskFxn

static void SimpleBLEPeripheral_taskFxn(UArg a0, UArg a1)
{
  // app任务初始化函数
  SimpleBLEPeripheral_init();

  // 死循环运行app任务
  for (;;)
  {
   ....
  // 这里是处理收到(消息) 事件与定时器事件的地方
   ....
  }
}

二、处理(消息)事件流程

2.1 处理app事件

在上述1.3.2死循环体中

 // 如果RTOS队列不为空,处理APP消息
if (!Queue_empty(appMsgQueue))
{
    sbmEvt_t *pMsg = (sbmEvt_t *)Util_dequeueMsg(appMsgQueue);
    if (pMsg)
    {
        // 处理APP消息
       SimpleBLEPeripheral_processAppMsg(pMsg);

        // 释放内存
        ICall_free(pMsg);
    }
}

2.1.1 SimpleBLEPeripheral_processAppMsg

在上述1.3.2死循环体中,处理APP消息的函数,用户自定义处理事件往这里加(如按键事件处理)

static void SimpleBLEPeripheral_processAppMsg(sbpEvt_t *pMsg)
{
  switch (pMsg->hdr.event)
  {
    // BLE连接状态机部分
    case SBP_STATE_CHANGE_EVT:
      SimpleBLEPeripheral_processStateChangeEvt((gaprole_States_t)pMsg->hdr.state);
      break;

    // BLE传输的事件处理,比如收到数据等等
    case SBP_CHAR_CHANGE_EVT:
      SimpleBLEPeripheral_processCharValueChangeEvt(pMsg->hdr.state);
      break;

    default:
      // Do nothing.
      break;
  }
}

2.2 处理定时器事件

在上述1.3.2死循环体中

if (events & SBM_PERIODIC_EVT)  // 我们APP建立的定时器事件,相当于自定义的定时器
{
    events &= ~SBM_PERIODIC_EVT;

    Util_startClock(&periodicClock);

    // 执行定时任务
    SimpleBLEMulti_performPeriodicTask();
}

三、BLE初始化流程

---> ICall_registerApp注册,必须首先调用
---> 设置GAP层,例如广播间隔等参数
---> 设置GAPRole,例如是否开启广播等、连接参数等
---> 设置配对与绑定,例如是否开启绑定,以及绑定模式
---> 添加服务,设置服务参数并注册服务回调函数
---> 启动设备
---> 其他硬件配置


3.1 ICall_registerApp注册

ICall_registerApp() 函数就是注册当前app任务,只有注册之后, ICall 的接口才会辨认我们这个 app 的消息与事件操作。

// ******************************************************************
// N0 STACK API CALLS CAN OCCUR BEFORE THIS CALL TO ICall_registerApp
// ******************************************************************
// Register the current thread as an ICall dispatcher application
// so that the application can send and receive messages.
ICall_registerApp(&selfEntity, &sem);

3.2 设置GAP层

如果你是广播者工程, 这一条语句是可以忽略的

// Setup the GAP
GAP_SetParamValue(TGAP_CONN_PAUSE_PERIPHERAL, DEFAULT_CONN_PAUSE_PERIPHERAL);

设置广播间隔

// Set advertising interval
{
    uint16_t advInt = DEFAULT_ADVERTISING_INTERVAL;  // 广播间隔,间隔越大功耗越低   

    GAP_SetParamValue(TGAP_LIM_DISC_ADV_INT_MIN, advInt);
    GAP_SetParamValue(TGAP_LIM_DISC_ADV_INT_MAX, advInt);
    GAP_SetParamValue(TGAP_GEN_DISC_ADV_INT_MIN, advInt);
    GAP_SetParamValue(TGAP_GEN_DISC_ADV_INT_MAX, advInt);
}

3.3 设置GAP Role

 // Setup the GAP Peripheral Role Profile
  {
    // For all hardware platforms, device starts advertising upon initialization
    uint8_t initialAdvertEnable = TRUE;          // 开机广播

    // By setting this to zero, the device will go into the waiting state after
    // being discoverable for 30.72 second, and will not being advertising again
    // until the enabler is set back to TRUE
    uint16_t advertOffTime = 0;

    uint8_t enableUpdateRequest = DEFAULT_ENABLE_UPDATE_REQUEST;
    uint16_t desiredMinInterval = DEFAULT_DESIRED_MIN_CONN_INTERVAL;// 传输数据延时1~2秒或者反应不灵敏,更改这两个参数为最小值8,可实现快速反应,不过功耗也就上去了
    uint16_t desiredMaxInterval = DEFAULT_DESIRED_MAX_CONN_INTERVAL;
    uint16_t desiredSlaveLatency = DEFAULT_DESIRED_SLAVE_LATENCY;
    uint16_t desiredConnTimeout = DEFAULT_DESIRED_CONN_TIMEOUT;

    // Set the GAP Role Parameters
    GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t),
                         &initialAdvertEnable);
    GAPRole_SetParameter(GAPROLE_ADVERT_OFF_TIME, sizeof(uint16_t),
                         &advertOffTime);

    GAPRole_SetParameter(GAPROLE_SCAN_RSP_DATA, sizeof(scanRspData),
                         scanRspData);
    GAPRole_SetParameter(GAPROLE_ADVERT_DATA, sizeof(advertData), advertData);

    GAPRole_SetParameter(GAPROLE_PARAM_UPDATE_ENABLE, sizeof(uint8_t),
                         &enableUpdateRequest);
    GAPRole_SetParameter(GAPROLE_MIN_CONN_INTERVAL, sizeof(uint16_t),
                         &desiredMinInterval);
    GAPRole_SetParameter(GAPROLE_MAX_CONN_INTERVAL, sizeof(uint16_t),
                         &desiredMaxInterval);
    GAPRole_SetParameter(GAPROLE_SLAVE_LATENCY, sizeof(uint16_t),
                         &desiredSlaveLatency);
    GAPRole_SetParameter(GAPROLE_TIMEOUT_MULTIPLIER, sizeof(uint16_t),
                         &desiredConnTimeout);
  }

上述宏定义

// Advertising interval when device is discoverable (units of 625us, 160=100ms)
#define DEFAULT_ADVERTISING_INTERVAL          160       // 广播间隔,间隔越大功耗越低

// Limited discoverable mode advertises for 30.72s, and then stops
// General discoverable mode advertises indefinitely
#define DEFAULT_DISCOVERABLE_MODE             GAP_ADTYPE_FLAGS_GENERAL

// Minimum connection interval (units of 1.25ms, 80=100ms) if automatic
// parameter update request is enabled
#define DEFAULT_DESIRED_MIN_CONN_INTERVAL     80        // 最小连接间隔

// Maximum connection interval (units of 1.25ms, 800=1000ms) if automatic
// parameter update request is enabled
#define DEFAULT_DESIRED_MAX_CONN_INTERVAL     800       // 最大连接间隔

// Slave latency to use if automatic parameter update request is enabled
#define DEFAULT_DESIRED_SLAVE_LATENCY         0         // 可忽略连接间隔的次数,默认是不忽略

// Supervision timeout value (units of 10ms, 1000=10s) if automatic parameter
// update request is enabled
#define DEFAULT_DESIRED_CONN_TIMEOUT          1000      // 连接超时时间,连接iOS时此参数必须小于6S

// Whether to enable automatic parameter update request when a connection is
// formed
#define DEFAULT_ENABLE_UPDATE_REQUEST         FALSE     // 使能连接参数更新请求

// Connection Pause Peripheral time value (in seconds)
#define DEFAULT_CONN_PAUSE_PERIPHERAL         6         // 有时当CC2640断开连接时,主机端过10S才会断开,此时将此数值改小可让主机快速发现断开连接

3.4 设置配对与绑定

// Setup the GAP Bond Manager
{
    uint32_t passkey = 0; // passkey "000000" 无需密码直接配对的意思
    uint8_t pairMode = GAPBOND_PAIRING_MODE_WAIT_FOR_REQ;
    uint8_t mitm = TRUE;
    uint8_t ioCap = GAPBOND_IO_CAP_DISPLAY_ONLY;
    uint8_t bonding = TRUE;

    GAPBondMgr_SetParameter(GAPBOND_DEFAULT_PASSCODE, sizeof(uint32_t),
                            &passkey);
    GAPBondMgr_SetParameter(GAPBOND_PAIRING_MODE, sizeof(uint8_t), &pairMode);
    GAPBondMgr_SetParameter(GAPBOND_MITM_PROTECTION, sizeof(uint8_t), &mitm);
    GAPBondMgr_SetParameter(GAPBOND_IO_CAPABILITIES, sizeof(uint8_t), &ioCap);
    GAPBondMgr_SetParameter(GAPBOND_BONDING_ENABLED, sizeof(uint8_t), &bonding);
}

3.5 添加服务,初始化GATT属性

// 以下是添加服务,初始化GATT属性,一般来说,要增加新的服务就需要添加一条类似的函数
// 下面增加了4个服务,用手机APP可以发现这些服务
// Initialize GATT attributes
GGS_AddService(GATT_ALL_SERVICES);           // GAP
GATTServApp_AddService(GATT_ALL_SERVICES);   // GATT attributes
DevInfo_AddService();                        // Device Information Service

#ifndef FEATURE_OAD
SimpleProfile_AddService(GATT_ALL_SERVICES); // Simple GATT Profile
#endif //!FEATURE_OAD

3.6 设置服务的初始值

设置这5个profile的初始值,其实不设置也没关系,可省略

// Setup the SimpleProfile Characteristic Values
{
    uint8_t charValue1 = 1;
    uint8_t charValue2 = 2;
    uint8_t charValue3 = 3;
    uint8_t charValue4 = 4;
    uint8_t charValue5[SIMPLEPROFILE_CHAR5_LEN] = { 1, 2, 3, 4, 5 };

    SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR1, sizeof(uint8_t),
                               &charValue1);
    SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR2, sizeof(uint8_t),
                               &charValue2);
    SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR3, sizeof(uint8_t),
                               &charValue3);
    SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR4, sizeof(uint8_t),
                               &charValue4);
    SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR5, SIMPLEPROFILE_CHAR5_LEN,
                               charValue5);
}

// 注册SimpleProfile回调函数
SimpleProfile_RegisterAppCBs(&SimpleBLEPeripheral_simpleProfileCBs);

3.7 启动设备

// 开启设备
VOID GAPRole_StartDevice(&SimpleBLEPeripheral_gapRoleCBs);

// 注册配对与绑定的回调函数
VOID GAPBondMgr_Register(&simpleBLEPeripheral_BondMgrCBs);

// Register with GAP for HCI/Host messages
GAP_RegisterForMsgs(selfEntity);
  
// Register for GATT local events and ATT Responses pending for transmission
GATT_RegisterForMsgs(selfEntity);

3.8 其他硬件配置

#if defined FEATURE_OAD
#if defined (HAL_IMAGE_A)
  LCD_WRITE_STRING("BLE Peripheral A", LCD_PAGE0);
#else
  LCD_WRITE_STRING("BLE Peripheral B", LCD_PAGE0);
#endif // HAL_IMAGE_A
#else
  LCD_WRITE_STRING("BLE Peripheral", LCD_PAGE0);
#endif // FEATURE_OAD

到这里, BLE初始化完毕,现在也已经执行广播了,用你的手机 APP便可以发现参考CC2640学习笔记1


• 由 Leung 写于 2018 年 12 月 5 日

• 参考:AMOMCU-CC2650DK快速入门-v1.52-2017.06.12[提取码y89c]
    CC2640之第一个工程Simple_peripheral代码框架及学习

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,265评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,078评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,852评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,408评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,445评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,772评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,921评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,688评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,130评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,467评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,617评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,276评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,882评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,740评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,967评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,315评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,486评论 2 348

推荐阅读更多精彩内容