在使用CC2530芯片进行ZigBee协议的开发时,我们往往使用TI公司提供的带有ZigBee协议栈的ZStack工程,接下来以其中的SampleApp为例,向其中添加自己需要的定时任务并设置周期和处理流程。
首先,我们以SampleApp中的默认定时任务
SAMPLEAPP_SEND_PERIODIC_MSG_EVT
作为参考,通过IAR软件找到其在SampleApp.h头文件中被定义,并在SampleApp.c中多次被使用,由于该文件就是用户程序运行的主要区域,因此着重分析其在这两个文件中的分布及起到的作用。
以下是对该任务的分析:
// Send Message Timeout
#define SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT 1000 // Every 1 seconds// Application Events (OSAL) – These are bit weighted definitions.(**注意二进制表达**)
#define SAMPLEAPP_SEND_PERIODIC_MSG_EVT 0x0001
在SampleApp.c中的SampleApp_ProcessEvent函数中,第一次用到了该任务。此函数用于处理系统所产生的一些事件和消息。在系统事件ZDO_STATE_CHANGE(网络状态)的处理支路中,使用osal_start_timerEx函数开启了此定时器,具体代码如下:
osal_start_timerEx(SampleApp_TaskID,
SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT);
代码中使用了SampleApp的TaskID,表明该定时器所产生的消息将交由SampleApp中专门负责处理消息的回调函数SampleApp_ProcessEvent进行处理,产生消息时将会传入SAMPLEAPP_SEND_PERIODIC_MSG_EVT的事件信息,并将该定时器超时时间设置为SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT所定义的值。
随后,在SampleApp_ProcessEvent函数中的events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT支路对此任务设置的消息进行处理,从处理的方式可以看到进行了位与运算,即判断events中该事件ID所在的位是否与设定值一致,若一致则进行处理,因此消息ID必须放置在二进制的“bit”中。
在事件处理结束后,通过return (events ^ SAMPLEAPP_SEND_PERIODIC_MSG_EVT)返回了处理的结果,即清除了该事件所在的位,并保留其它位留待后续处理。
接下来我们添加两个自定义的定时任务:
#define SAMPLEAPP_SEND_INFO_MSG_EVT 0x0002
#define SAMPLEAPP_LED_RUN_EVT 0x0004#define SAMPLEAPP_SEND_INFO_MSG_TIMEOUT 10000 // Every 10 seconds
#define SAMPLEAPP_LED_RUN_TIMEOUT 500 // Every 0.5 seconds
分别用于状态信息的发送和LED运行状态的指示。
首先,在SampleApp.h中添加上述宏定义,随后,在SampleApp.c中的SampleApp_Init函数中添加以下初始化定时器的相关函数:
osal_start_timerEx(SampleApp_TaskID,
SAMPLEAPP_SEND_INFO_MSG_EVT,
SAMPLEAPP_SEND_INFO_MSG_TIMEOUT);
osal_start_timerEx(SampleApp_TaskID,
SAMPLEAPP_LED_RUN_EVT,
SAMPLEAPP_LED_RUN_TIMEOUT);
最后,参考已有的定时器用法,在SampleApp_ProcessEvent函数中添加对应的事件处理流程:
if (events & SAMPLEAPP_SEND_INFO_MSG_EVT)
{
// Setup to send message again in normal info
osal_start_timerEx(SampleApp_TaskID, SAMPLEAPP_SEND_INFO_MSG_EVT,
(SAMPLEAPP_SEND_INFO_MSG_TIMEOUT));
//do something
// return unprocessed events 返回未处理的事件
return (events ^ SAMPLEAPP_SEND_INFO_MSG_EVT);
}
if (events & SAMPLEAPP_LED_RUN_EVT)
{
// Setup to led event again
osal_start_timerEx(SampleApp_TaskID, SAMPLEAPP_LED_RUN_EVT,
(SAMPLEAPP_LED_RUN_TIMEOUT));
//do something
// return unprocessed events 返回未处理的事件
return (events ^ SAMPLEAPP_LED_RUN_EVT);
}
值得注意的是,由于OSAL中采用按位设置标志位的方式进行事件的处理,因此设置事件时就需要留意事件ID的选取,必须设置为2的整数次幂,如0x01、0x02、0x04、0x08等,不可设置为0x03或其它非2的整数次幂的值,否则将会导致多个事件同时命中。相对地,我们也可以利用这一特性,通过设置一个全为“1”的事件ID来响应发生的所有事件或使所有事件的处理流程对此做出响应。
总之,OSAL系统为我们所编写的用户程序提供了一个完善而稳定的运行环境,对于它的使用,TI官方所给的示例及注释已十分完备,通过阅读代码,对用户程序进行修改也能够帮助我们对ZigBee和CC2530的使用有更加深入的理解。