本文最后修改时间:2017年10月16日 03:45
一、本节简介
本节以simple_peripheral工程为例,介绍如何使用定时器启动周期事件。
二、实验平台
1)CC2640R2F平台
①协议栈版本:CC2640R2 SDK v1.40.00.45
②编译软件:CCS7.3.0.00019
③硬件平台:香瓜CC2640R2F开发板
④仿真器:香瓜XDS100V3下载器
三、版权声明
1)作者:甜甜的大香瓜
2)声明:喝水不忘挖井人,转载请注明出处。
3)纠错/业务合作:[email protected]
4)香瓜BLE之CC2640R2F群:557278427
5)本文出处:原创连载资料《简单粗暴学蓝牙5》
6)完整开源资料下载地址(电脑端打开):
https://shop217632629.taobao.com/?spm=2013.1.1000126.d21.hd2o8i
7)香瓜CC2640R2F开发板购买链接:
https://item.taobao.com/item.htm?spm=a1z10.1-c-s.w4023-16963296339.8.21bfc58419sWKt&id=558653143169
8)香瓜XDS100V3下载器购买链接:
https://item.taobao.com/item.htm?spm=a230r.1.14.1.1d150040zvJBco&id=558356989143&ns=1&abbucket=6#detail
四、实验前提
1、在进行本文步骤前,请先阅读以下章节:
1)《简单粗暴学蓝牙5》的“第一章至第四章”章节。
2、在进行本文步骤前,请先实现以下章节:
1)《简单粗暴学蓝牙5》的“第三章 软件的安装及使用”章节。
2) 《简单粗暴学蓝牙5》的《香瓜CC2640R2F之LED》:http://blog.csdn.net/feilusia/article/details/78087346
3) 《简单粗暴学蓝牙5》的《香瓜CC2640R2F之自定义按键》:http://blog.csdn.net/feilusia/article/details/78239447
五、基础知识
1、为什么要用定时器来启动事件?
答:由于蓝牙通信的实时性要求较高,如果在协议栈中使用了“for、delay”等延时代码,则很容易出现“无广播、蓝牙连接断开”等异常现象。
因此工程师在开发过程中禁止使用延时代码。
取而代之的是用协议栈提供的定时器,如:点亮1个led后,启动2S的定时器,在2S后执行熄灭该led的定时器处理函数。
2、什么是任务(TASK)、事件(EVENT)、消息(MESSAGE)?
答:
举个简单的例子:
如果协议栈是一栋楼,则任务是楼层,事件是房间,消息是包裹。香瓜在顶层的7楼8号房间等待接收包裹。
而快递员携一堆包裹一楼开始派送,一层一层往上,最终到7楼,再一间一间地判断是否为8号房间,是8号房间则将包裹给香瓜。
以上例子要注意几点:
1)越底层的任务优先级越高。
2)每个事件可占有的时间是有限的,如果用了延时代码导致事件时间过长,协议栈的正常运作将会被破坏,会造成“无广播、蓝牙连接断开”等异常现象。
3)任务与任务之间、事件与事件之间,都是通过消息进行传递信息。
4)通常一个工程中我们不需要增减任务,只需要增减事件(如增加led闪烁时间、增加周期性广播事件)。
六、硬件原理
暂无
七、实验步骤
1、定义周期事件
1)定义周期事件的宏(simple_peripheral.c中)
//GUA
#define SBP_GUA_PERIODIC_EVT Event_Id_02 //香瓜周期事件
#define SBP_GUA_ALL_EVENTS SBP_GUA_PERIODIC_EVT //所有事件的集合
//GUA
注意:
①由于协议栈本身使用了Event_Id_00和Event_Id_01,则香瓜从Event_Id_02开始使用。
②如果有多个事件,需要通过“|”写到SBP_GUA_ALL_EVENTS事件中,如“SBP_GUA_PERIODIC_EVT | SBP_GUA_PERIODIC_2_EVT”。
2)添加周期事件的处理(simple_peripheral.c的SimpleBLEPeripheral_taskFxn中)
//GUA
//香瓜周期事件
if (events & SBP_GUA_PERIODIC_EVT)
{
//再次启动定时器
//Util_startClock(&GUA_periodicClock);
//香瓜周期处理函数
GUA_performPeriodicTask();
}
//GUA
紧接着其他事件之后即可。
定时器默认只执行一次,如果希望重复进入定时器事件,则可把上方代码中香瓜注释的语句利用起来。
3)添加周期事件的执行权限(simple_peripheral.c的SimpleBLEPeripheral_taskFxn中)
将
events = Event_pend(syncEvent, Event_Id_NONE, SBP_ALL_EVENTS,
ICALL_TIMEOUT_FOREVER);
替换成
//GUA
events = Event_pend(syncEvent, Event_Id_NONE, SBP_ALL_EVENTS | SBP_GUA_ALL_EVENTS,
ICALL_TIMEOUT_FOREVER);
//GUA
如果没有这一步,香瓜周期事件将被过滤掉而无法执行。
1)定义周期事件的处理函数(simple_peripheral.c中)
//GUA
//**********************************************************************
//name: GUA_performPeriodicTask
//introduce: 香瓜周期事件的处理函数
//parameter: none
//return: none
//author: 甜甜的大香瓜
//email: [email protected]
//QQ group: 香瓜BLE之CC2640R2F(557278427)
//shop:
//https://shop217632629.taobao.com/?spm=2013.1.1000126.d21.hd2o8i
//changetime: 2017.10.15
//**********************************************************************
static void GUA_performPeriodicTask(void)
{
GUA_Led_Set(GUA_LED_NO_ALL, GUA_LED_MODE_OFF); //LED全灭
}
//GUA
这里将LED灯全部熄灭。
2)声明周期事件的处理函数(simple_peripheral.c中)
//GUA
static void GUA_performPeriodicTask(void);
//GUA
1)定义定时器结构体数据(simple_peripheral.c中)
//GUA
static Clock_Struct GUA_periodicClock;
//GUA
//GUA
#define SBP_GUA_PERIODIC_EVT_PERIOD 100 //香瓜定时时间
//GUA
这里设置为100ms。
3)初始化定时事件(simple_peripheral.c的SimpleBLEPeripheral_init函数末尾中)
//GUA
//初始化定时器
Util_constructClock(&GUA_periodicClock, SimpleBLEPeripheral_clockHandler,
SBP_GUA_PERIODIC_EVT_PERIOD, 0, false, SBP_GUA_PERIODIC_EVT);
//GUA
注意:这里仅仅是对定时器初始化函数,还需要一个“Util_startClock”函数(启动定时器函数)。必须两个都有,定时器才能被启动起来。
本文中的“Util_startClock”函数在下文的按键处理函数中被调用。
4、启动定时器(替换simple_peripheral.c的GUA_HandleKeys函数)
//GUA
//**********************************************************************
//name: GUA_HandleKeys
//introduce: 应用层按键处理函数
//parameter: GUA_Keys:键值
//return: none
//author: 甜甜的大香瓜
//email: [email protected]
//QQ group: 香瓜BLE之CC2640R2F(557278427)
//shop:
//https://shop217632629.taobao.com/?spm=2013.1.1000126.d21.hd2o8i
//changetime: 2017.10.08
//**********************************************************************
static void GUA_HandleKeys(uint8 GUA_Keys)
{
//UP按键
if(GUA_Keys & GUA_KEY_UP_VALUE)
{
//LED
GUA_Led_Set(GUA_LED_NO_1, GUA_LED_MODE_ON); //LED1亮
//启动定时器
Util_startClock(&GUA_periodicClock);
}
//DOWN按键
if(GUA_Keys & GUA_KEY_DOWN_VALUE)
{
//LED
GUA_Led_Set(GUA_LED_NO_2, GUA_LED_MODE_ON); //LED2亮
//启动定时器
Util_startClock(&GUA_periodicClock);
}
//LEFT按键
if(GUA_Keys & GUA_KEY_LEFT_VALUE)
{
//LED
GUA_Led_Set(GUA_LED_NO_3, GUA_LED_MODE_ON); //LED3亮
//启动定时器
Util_startClock(&GUA_periodicClock);
}
//RIGHT按键
if(GUA_Keys & GUA_KEY_RIGHT_VALUE)
{
//LED
GUA_Led_Set(GUA_LED_NO_4, GUA_LED_MODE_ON); //LED4亮
//启动定时器
Util_startClock(&GUA_periodicClock);
}
//SELECT按键
if(GUA_Keys & GUA_KEY_SELECT_VALUE)
{
//LED
GUA_Led_Set(GUA_LED_NO_ALL, GUA_LED_MODE_ON); //LED全亮
//启动定时器
Util_startClock(&GUA_periodicClock);
}
}
//GUA
5个按键都可以点亮对应LED、启动一次定时器事件。
暂无
九、实验结果
仿真并全速运行,分别按下5个按键,现象分别为LED1闪烁一次、LED2闪烁一次、LED3闪烁一次、LED4闪烁一次、所有LED闪烁一次。
也就是按键将对应LED点亮后,启动了100ms定时器事件熄灭所有LED。
因此,实验成功。