说明:
1、蓝牙协议栈版本:1.5.1.1
2、蓝牙IC:CC2540或者CC2541
3、IDE版本:IAR For 8051 10.20.1
4、采用截图的方式,将整个实验过程还原出来,附带行号,便于学习的小伙伴们能依据图文完全重复实验结果。
本文目标:弄清楚广播前的初始化。
正文:
1、了解OSAL:
OSAL直译就是操作系统抽象层。它是一个类操作系统的事件驱动型软件框架。每建立一个任务,都会分配一个唯一任务ID,同时对应一个任务事件处理函数,用来处理不同的事件。然后不断地轮询每个任务,判断其是否有事件需要处理,如此往复。
建立任务,如加粗的SimpleBLEPeripheral_Init( taskID )就是官方例程建立的一个Demo应用任务,该初始化在文件OSAL_SimpleBLEPeripheral.c中:
void osalInitTasks( void )
{
uint8 taskID = 0;
tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);
if (tasksEvents != NULL)
{
osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));
}
else
{
HAL_ASSERT_FORCED();
}
LL_Init( taskID++ );
Hal_Init( taskID++ );
HCI_Init( taskID++ );
#if defined ( OSAL_CBTIMER_NUM_TASKS )
osal_CbTimerInit( taskID );
taskID += OSAL_CBTIMER_NUM_TASKS;
#endif
L2CAP_Init( taskID++ );
GAP_Init( taskID++ );
SM_Init( taskID++ );
GATT_Init( taskID++ );
GAPRole_Init( taskID++ );
GAPBondMgr_Init( taskID++ );
GATTServApp_Init( taskID++ );
SimpleBLEPeripheral_Init( taskID );
}
以上任务集对应一个事件处理函数表,该表中存放的是事件处理函数指针:
![bd89860a8f7078ba24d0ed577218495c.png](https://i-blog.csdnimg.cn/blog_migrate/18d7872230b01b66888e987614c8d9e5.jpeg)
图1(操作文件:OSAL_SimpleBLEPeripheral.c)
2、关注(暂时)两个初始化
![8ade63a81e50d1eb854d241c5417c2e7.png](https://i-blog.csdnimg.cn/blog_migrate/dbd0f5e2a71c3275435430f60fae919a.jpeg)
图2(操作文件:OSAL_SimpleBLEPeripheral.c)
在GAPRole_Init()中会确定gap角色状态为初始态,gap角色为外设等
![4b3b713fbf8297d9494f855f15285c07.png](https://i-blog.csdnimg.cn/blog_migrate/06d01fbd24c91538414141ad0f8c5845.jpeg)
图3(操作文件:peripheral.c)
而在SimpleBLEPeripheral_Init()中则进行各种参数的初始化,详见源码。
3、关注(暂时)两个任务(由OSAL调度执行)
![47f4e1c81c15ee76670f8069c9f3af3e.png](https://i-blog.csdnimg.cn/blog_migrate/51406d2721c676630f4396cf2619cec1.jpeg)
图4(操作文件:OSAL_SimpleBLEPeripheral.c)
这两个任务(所有任务都是)是轮询执行的,OSAL一直在轮询所有的任务,查看是否有需要处理的事件。先说第二个任务SimpleBLEPeripheral_ProcessEvent,这是个OSAL调度任务,会随着系统的运行,不断地产生各类事件来触发不同的执行流程。在外设初始化SimpleBLEPeripheral_Init()的最后会触发启动设备事件,如下图:
![e48a1da060a573d9311dd3a3eb1c0afd.png](https://i-blog.csdnimg.cn/blog_migrate/748d327f408a8c0e6e18058f03c1eb6c.jpeg)
图5(操作文件:simpleBLEPeripheral.c)
于是在SimpleBLEPeripheral_ProcessEvent()中进行了如下处理:
![d57d12fc0fb2aab4c7d953a2b903602e.png](https://i-blog.csdnimg.cn/blog_migrate/e56430bfcd5580daa33dce22972f5a9a.jpeg)
图6(操作文件:simpleBLEPeripheral.c)
即启动设备,启动绑定管理,设置周期运行事件。而设备一旦启动,就执行各类初始化动作,当初始化完成时就会产生SYS_EVENT_MSG事件,并通知OSAL进行相关处理,这就引出了第一个任务GAPRole_ProcessEvent,如下:
![f37ba4e304f782a653ae4a4fb9a6f084.png](https://i-blog.csdnimg.cn/blog_migrate/61ad08112b74355a35a7cd1f744ab5d5.jpeg)
图7(操作文件:peripheral.c)
调用函数gapRole_ProcessOSALMsg()处理消息:
![c02db5da7def3dc02c99ff30eccf04a4.png](https://i-blog.csdnimg.cn/blog_migrate/c8f03705c8cf6c39f0af35df17c65678.jpeg)
图8(操作文件:peripheral.c)
再调用函数gapRole_ProcessGAPMsg()处理gap消息:
![0b0666a6d9b71520b26fc4550905c157.png](https://i-blog.csdnimg.cn/blog_migrate/c1b12df4a92c34b0c050a110e6e0813c.jpeg)
图9(操作文件:peripheral.c)
至此,设备初始化完成,保存密钥、设备地址,并更新广播数据。GAP状态变为GAPROLE_STARTED,触发回调函数peripheralStateNotificationCB(),显示本机地址以及初始化完成标识:
![8c92d82611ee5c184cd112d17b14f35b.png](https://i-blog.csdnimg.cn/blog_migrate/784c879859ae392c61f8917e2df5e96f.jpeg)
图10(操作文件:simpleBLEPeripheral.c)
4、输出提示信息
由于官方例程用LCD进行输出显示,为了学习的各位小伙伴们能更加简单地学习,我们之后的所有实验测试都是基于串口来实现的,这样只要你有个蓝牙模块就可以实现所有我们讲述的例程。
在不改变源码结构的基础上,我们来实现串口输出提示信息。首先在hal_lcd.c中加入引用串口的头文件:
![bce076c1c3e4b43a961a8fc84600e6e4.png](https://i-blog.csdnimg.cn/blog_migrate/11ec3b939052a787cb2e4ca5bb9b66bf.jpeg)
图11(操作文件:hal_lcd.c)
接着,修改LCD显示字符串函数void HalLcdWriteString ( char *str, uint8 option),在该函数最后添加串口输出函数:
![6f1d69b4ae9ab70817ab40c8e66b52f8.png](https://i-blog.csdnimg.cn/blog_migrate/51eb1fb0c1d597e3479b7ebc9022cd5d.jpeg)
图12(操作文件:hal_lcd.c)
5、编译下载
![014f2c2ba92672a5bb0bf5892164265d.png](https://i-blog.csdnimg.cn/blog_migrate/33df19749bdd62fdf6797fc6407d9288.jpeg)
图13(实验结果)
6、扩展说明:
GAP: Generic Access Profile,即通用访问规范(当然还有其他译法,暂且这么翻译)。具体相关概念自己查阅。这里要说明的是,作为初学者,我们只要知道GAP是干嘛的就行,简单来说就是负责设备配置,设备初始化,安全管理,设备发现,建立连接,断开连接等,都是与连接相关的(准备、建立,管理,终止等)。