一、总流程
---> 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代码框架及学习