Z-Stack中OSAL定时器事件触发流程分析---转载

合集下载

实验教程八---zstack操作系统原理之任务调度实验

实验教程八---zstack操作系统原理之任务调度实验
初始化所有任务与各任务对应的事件清除所有任务的事增加任务初始uint8osalseteventuint8taskiduint16eventflagtaskid任务ideventflag事件触发事件精简os中与任务调度相关的函数api事件可以预先定义好但不知道会在哪个确定时间点被触发
无线传感器网络实验教程
精简OS中与任务调度相关的数据结构

任务---事件映射表

任务事件对应位由用户程序自己定义; 例如: #define TEST_EVENT_EVT 0x0001 #define TEST_TIMER_EVT 0x0002
精简OS中与任务调度相关的函数API

void OS_IntTasks( void )

参数:


精简OS中与任务调度相关的函数API

void OS_Scan( void );

功能:该函数执行一些扫描任务,例如按键,LED 等
精简OS中与任务调度相关的函数API

void OS_Start( void );

功能:OS的主循环
源代码分析
精简OS中与任务调度相关的数据结构

任务ID

uint8 taskId;
这个声明引入了 OSEventHandle类型 uint8 testOSTaskID 作为函数指针的同义 字,该函数有两个 当前系统中的任务数 uint8、uint16类型的参 const uint8 TaskCont; 数以及一个 uint16类 型的返回值。 任务---处理函数映射表
OSAL的主要功能




任务的登记,加载, 初始化及启动任务调 度 任务之间的信息传递 任务同步 中断操作 定时器功能 内存单元管理

zstack按键程序分析

zstack按键程序分析

本文来自飞比论坛,作者:xingqing帖子地址:/bbs/viewthread.php?tid=393膜拜大作,虚心学习。

看了outm an的关于Rem oTI的教程,受益匪浅,然后找了下以前学习所做的笔记,共享出来,大家共同学习,如果有哪里理解错误请大家给我指出来:Rem oTI遥控板子上按键的发射程序,整个流程及其相对应的程序我都贴上了,好了,首先上个图:很不幸的是,从刚开始分析我就没留意这个图,造成我花了很长时间来想这个按键的流程,看他的流程,已经很明白了:开始(start),所有的列配置为输出,所有的行配置为中断使能输入,这里很简单就是个矩阵键盘,51中是用查询法来检测按键,这里只不过用的是中断方式来触发而已,然后调用消除抖动定时器(start key de-bounce tim er),当定时器溢出的时候,开始扫描按键,如果没有检测到按键,那么有返回到开始之下,重新来,如果有按键被检测到,这时候启动轮询定时器,启动这个定时器的原因是为了能够连发,如果你按下这个键一直不放那么就是靠这个定时器,来实现连发的,连发的时间间隔这个值我们是可以改动的,如果这个时候又检测不到按键了,那么又回到开始之下,当你再次按键的时候是靠中断来触发的。

有很多人觉得读取按键还有无线发送按键命令是在端口0的中断处理函数中进行的,其实不是这样的,中断中只是给这个任务添加了一个定时器而已这里先插一句:分析程序的时候我们要忽略次要的,看主要的。

以上是整个按键的流程了,下面分析下具体的程序:凡是要找个开始,不用说肯定先看主函数,:int m ain(void){/* Initialize hardware 初始化硬件,选择时钟,还有灯的方向选择*/HAL_BOARD_INIT();/* Initialze the HAL driver 初始化板上的硬件*/HalDriverInit();/* Initialize NV system 初始化nv系统????*/osal_nv_init(NULL);/* Initialize MAC 被封掉了 */MAC_InitRf4ce();/* Initialize the operating system 初始化操作系统*/osal_init_system();/* Enable interrupts 使能总中断*/HAL_ENABLE_INTERRUPTS();/* Setup Keyboard callback 这里是选择了按键的检测方式*///最重要的是指向了按键回调函数HalKeyConfig(RSA_KEY_INT_ENABLED, RSA_KeyCbac k);/* Start OSAL 进入操作系统,不能返回 */osal_start_system(); // No Return from herereturn 0;}以上我已经做了注释了,这个主函数很简单,下面看看具体跟按键相关的程序:函数HalDriverInit中,有这么一句/* KEY */#if (defined HAL_KEY) && (HAL_KEY == TRUE)HalKeyInit();#endif我们再看看这个HalKeyInit();函数到底做了什么,void HalKeyInit( void ){#if (HAL_KEY == TRUE)/* Initialize previous key to 0 初始化先前的键值为0*/halKeySavedKeys = HAL_KEY_CODE_NOKEY;//列端口1除了P1_1没有使用之外其他都用到了,设置为普通的IO,方向输出HAL_KEY_COL_SEL &= (uint8) ~HAL_KEY_COL_BITS; // set pin function to GPIOHAL_KEY_COL_DIR |= HAL_KEY_COL_BITS; // set pin direction to output//以下几句是在选择他的触发方式,上升沿触发还是下降沿触发,如果学过单片机的同学//这个应该不是问题if (HAL_KEY_ROW_PULLDOWN)//如果是下拉的话,进来设置所有的引脚为高电平{HAL_KEY_COL_PORT |= HAL_KEY_COL_BITS; // output high on all colum ns}else//如果是上拉,进来设置所有的引脚为低电平{HAL_KEY_COL_PORT &= (uint8) ~HAL_KEY_COL_BITS; // output low on all colum ns }//行端口0设置为普通的IO(所有端口都用到了),方向输入HAL_KEY_ROW_SEL &= ~(HAL_KEY_ROW_BITS); // set pin function to GPIOHAL_KEY_ROW_DIR &= ~(HAL_KEY_ROW_BITS); // set pin direction to input// pull down setup if necessary 如果有必要的话设置为下拉if (HAL_KEY_ROW_PULLDOWN){HAL_KEY_ROW_INP |= HAL_KEY_ROW_PDUPBIT;//设置端口0为下拉}//以下三句程序现在不用管他是做什么用的,后面我们会看到他的作用,/* Initialize callback function 这个要好好关注下,开始的时候这个回调时空的 */pHalKeyProcessFunction = NULL;//这里初始化回调函数是空的/* Start with key is not configured */HalKeyConfigured = FALSE;//起始的时候键值没有被配置halKeyTim erRunning = FALSE;#endif /* HAL_KEY */}上面这个函数只是对按键的初始化,注意这里初始化只是将按键配置成了:普通的IO口,列为输出,行为输入,并没有让行的中断使能,再就是对回调函数的清空,这个回调是重点,要注意!!!!在osal_init_system这个函数中,osalInitTasks这个函数,具体程序如下:void osalInitTasks( void ){uint8 taskID = 0;//注意这里任务ID是从0开始的/*这里返回的是分配内存空间的首地址,注意这个首地址的上一个地址就是他的内存控制头,关于他内存的分配可以看看我的下一教程*/tasksEvents = (uint16 *)osal_m em_alloc( sizeof( uint16 ) * tasksCnt);//分配了足够的空间osal_m em set( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));//全部初始化为0m acTaskInit( taskID++ ); //添加m ac层的任务被封掉了RCN_Init( taskID++ ); //添加RCN的任务RCN:RF4CE network layer 被封掉了RTI_Init( taskID++ ); //添加RTI的任务R TI:Rem oTI appli cation fram eworkRSA_Init( taskID++ ); //添加RSA的任务Hal_Init( taskID ); //添加硬件抽象层的任务,这里就是对按键处理任务的添加}还有一个数组要十分注意的是:// The order in this table m ust be identi cal to the task initialization calls below in osalInitTask.//这里的顺序很重要,要和osalInitTasks这里添加任务的顺序一样const pTaskEventHandlerFn tasksArr[] ={m acEventLoop,RCN_ProcessEvent,RTI_ProcessEvent,RSA_ProcessEvent,Hal_ProcessEvent};这个数组的顺序和上面的taskID要对应上,也就是说他给每个处理函数排了个队,并且给他们编了个号,而且有个标志位,这个标志位很重要,标志位是靠下层触发的(这句话现在看有点不明白,看到最后的时候你会明白),究竟怎么触发的我们先不用管,还是举个例子吧,比如无线接收到数据了,你要从下层传到上层,最后就是靠下层触发这些标志位,这样上层才知道有事情发生了,通过taskID 找到你相应的函数,这样比较简单,系统在轮询事件的时候是按照这个顺序来走了,你的taskID和相应的程序对不上号那不就乱了吗,简单说下,以后详再说。

Z-Stack分析

Z-Stack分析

ZigBee协议栈TI Z-Stack分析2007年4月,德州仪器推出业界领先的ZigBee协议栈(Z-Stack)。

Z-Stack 符合ZigBee 2006规范,支持多种平台,包括基于CC2420收发器以及TI MSP430超低功耗单片机的平台,CC2430的SOC平台C51RF-3-PK等。

Z-Stack包含了网状网络拓扑的几近于全功能的协议栈,在竞争激烈的ZigBee领域占有很重要地位。

ZigBee stack应用开发相关概念ZigBee术语一、属性属性Attribute是一个反映物理数量或状态的数据值,比如开关值(On/Off),温度值、百分比等。

二、群集群集Cluster是包含一个或多个属性(attribute)的群组。

简单的说,群集就是属性的集合。

每个群集都被分配一个唯一的群集ID 且每个群集最多有65536个属性。

三、设备描述设备描述Device Description是指一个大型目标应用的一部分,包括一个或多个群集,并且指定群集是输入还是输出。

四、端点端点EndPoint是协议栈应用层的入口,也可以理解应用对象(Application Object)存在的地方,它是为实现一个设备描述而定义的一组群集。

每个ZigBee 设备可以最多支持240这样的端点,这也意味着在每个设备上可以定义240个应用对象。

端点0被保留用于与ZDO接口而端点255被保留用于广播,端点241-254则被保留用于将来做扩展使用。

五、配置文件配置文件Profile可以理解为共同促成交互式应用的多个设备描述项的集合。

ZigBee联盟已经定义了部分标准的配置文件,比如远程控制开关配置文件和光传感器配置文件等。

任何遵循某一标准配置文件的节点都可以与实现相同配置文件的节点进行互操作。

用户也可以创建自己的配置文件然后递交ZigBee联盟测试、审核批准。

配置文件是对逻辑设备及其接口描述的集合,是面向某个应用类别的公约、准则。

ztack按键处理程序个人见解

ztack按键处理程序个人见解

ZStack-CC2530-2.3.0-1.4.0按键处理个人见解记得几个月前我看了飞比论坛上面的一些帖子,主要有小峰笔记以及其他在他基础上的一些看法和见解,看完以后对我的帮组还是蛮大的,但是还是有些东西没有弄太懂,今天又把他这个协议栈看了一下,有了进一步的理解,和大家分享一下,希望能够对大家有所帮助。

先看一下前人的成果:(蓝色字体)1,查询法函数调用流程如下:HalKeyConfig()配置一定时器为轮询按键作准备——>时间一到触发系统任务事件调用Hal_ProcessEvent()——>调用HalKeyPoll()得到按键值——>调用OnBoard_KeyCallback()进一步处理——调用OnBoard_SendKeys()构造消息包,准备触发应用按键事件【注意这个应用之前必须通过RegisterForKeys()注册接收按键事件的任务ID】——>调用osal_msg_send()向系统发送消息——>调用osal_set_event()设置事件发生标志——>调用SampleApp_ProcessEvent()处理事件——>最终调用SampleApp_HandleKeys()处理具体按键事件2,中断法函数调用流程如下:HalKeyConfig()进行按键中断配置——>按键引起中断进入中断函数HAL_ISR_FUNCTION()(该函数在hal_key.c中)——>调用halProcessKeyInterrupt()对按键中断进行下一步处理:清除中断标志,启动一定时器——>时间一到触发系统任务事件调用Hal_ProcessEvent()——> 调用HalKeyPoll()得到按键值——>调用OnBoard_KeyCallback()进一步处理——>调用OnBoard_SendKeys()构造消息包,准备触发应用按键事件【注意这个应用之前必须通过RegisterForKeys()注册接收按键事件的任务ID】——>调用osal_msg_send()向系统发送消息——>调用osal_set_event()设置事件发生标志——>调用SampleApp_ProcessEvent()处理事件——>最终调用SampleApp_HandleKeys()处理具体按键事件3,两种方法相似之处:都是经过了两次触发系统事件(第一次通过osal_start_timerEx()启动一个软定时器触发,第二次通过osal_msg_send()发送系统消息触发),分别调用相应任务事件处理函数,第一次是HAL层的Hal_ProcessEvent()来查询按键得到键值,一系列处理,第二次是APP层的SampleApp_ProcessEvent()把传送过来的按键事件进行最终处理osal_start_timerEx()------触发------> Hal_ProcessEvent()osal_msg_send()--------触发--------->SampleApp_ProcessEvent()4,两种方法不同之处:从上面对按键查询法和中断法的总结,可以看到中断法就比查询法大致多出两步:进入中断函数HAL_ISR_FUNCTION()与调用调用halProcessKeyInterrupt(),后面都是开始开启一软定时器触发相同事件HAL_KEY_EVENT,然后……………………。

ZStack协议按键处理流程分析

ZStack协议按键处理流程分析

在分析之前我先说一下ZStack协议栈有很多版本,版本不一样,代码多少有一些不一样,我的ZStack是ZStack-CC2530-2.3.1-1.4.0。

另外我的这篇文章中有很多内容是参考网友的文章,不知道有没有侵犯版权。

我自己总结一下按键处理流程,在ZStack协议栈中,按键的处理有两种方式,一种是中断方式,另一种是轮询方式,在这里,我以中断的方式来处理按键。

我的按键接在P0_1,如图所示:从图中可以看出,当按键没有按下的时候P0_1引脚为高电平,当按键按下时,引脚变成低电平,在这里,我的按键的中断触发方式为下降沿有效。

为了让按键按下后,程序能做点事情,我以LED灯为例,也就是说,当按键按下后,我让LED的状态翻转,也就是说按键按下一次,LED灯亮,在按下一次,LED灯灭,在按一下一次,LED灯亮……。

下图是LED的引脚图:纵观总的ZStack协议栈,我们发现P0_1和P1_0接的正好是按键和LED灯,因此在协议栈中,关于的按键和LED灯的代码我们不需要修改的太多。

我从main函数开始一步一步的分析,为了减小篇幅和代码量,我只分析与按键和中断有关的代码。

Int main(){// Turn off interrupts关闭中断osal_int_disable( INTS_ALL );//就是设置EA为0,EA为各种中断的总开关// Initialization for board related stuff such as LEDs//初始化系统时钟,LED等HAL_BOARD_INIT();//这个里面我没有动//电压检测,最好是能保证芯片能正常工作的电压// Make sure supply voltage is high enough to runzmain_vdd_check();// Initialize board I/O初始化板载IOInitBoard( OB_COLD );// Initialze HAL drivers初始化HAL驱动HalDriverInit();// Initialize NV System初始化NV系统osal_nv_init( NULL );// Initialize the MAC初始化MACZMacInit();// Determine the extended address确定IEEE地址zmain_ext_addr();#if defined ZCL_KEY_ESTABLISH// Initialize the Certicom certificate information. zmain_cert_init();#endif// Initialize basic NV items//初始化基本NV条目zgInit();#ifndef NONWK// Since the AF isn't a task, call it's initialization routine afInit();#endif// Initialize the operating system//初始化操作系统osal_init_system();// Allow interrupts使能所有中断,就是让EA为1 osal_int_enable( INTS_ALL );// Final board initialization最后的板载初始化InitBoard( OB_READY );// Display information about this devicezmain_dev_info();/* Display the device info on the LCD */#ifdef LCD_SUPPORTEDzmain_lcd_init();#endif#ifdef WDT_IN_PM1/* If WDT is used, this is a good place to enable it. */ WatchDogEnable( WDTIMX );#endifosal_start_system(); // No Return from herereturn 0; // Sh}在这里只分析红色部分的代码:// Initialize board I/O初始化板载IOInitBoard( OB_COLD );我们进入到到这个函数void InitBoard( uint8 level ){if ( level == OB_COLD ){// IAR does not zero-out this byte below the XSTACK.*(uint8 *)0x0 = 0;// Interrupts offosal_int_disable( INTS_ALL );// Check for Brown-Out resetChkReset();}else // !OB_COLD{/* Initialize Key stuff *///这个函数的作用是对按键使用的IO进行初始以及设置按键工作方式,按键IO初始化主要是将按键所对应的IO口定义为输入口//如果这个函数的第一个参数是HAL_KEY_INTERRUPT_ENABLE,那么按下该按键会触发IO终端,因此这个函数还要对IO终端//进行初始化的配置;如果这个函数的第一个参数是HAL_KEY_INTERRUPT_DISABLE,那么主程序后周期性的执行按键扫描程序//查看按键状态HalKeyConfig(HAL_KEY_INTERRUPT_ENABLE,OnBoard_KeyCallback);//在TI的源码中,第一个参数是HAL_KEY_INTERRUPT_DISABLE}}进入这个函数的时候,if条件成立,在这个if语句中没有做什么实际的事情,我们不管它,else语句不成立,我暂且先部分分析,在下面还会被调用,在下面我们在分析这个else语句。

Zstack中如何实现自己的任务

Zstack中如何实现自己的任务

Zstack中如何实现自己的任务在Zstack(TI的Zigbee协议栈)中,对于每个用户自己新建立的任务通常需要两个相关的处理函数,包括:(1).用于初始化的函数,如:SampleApp_Init(), 这个函数是在osalInitTasks()这个osal(Zstack中自带的小操作系统)中去调用的,其目的就是把一些用户自己写的任务中的一些变量,网络模式,网络终端类型等进行初始化;(2).用于引起该任务状态变化的事件发生后所需要执行的事件处理函数,如:SampleApp_ProcessEvent(),这个函数是首先在const pTaskEventHandlerFn tasksArr[ ] 中进行设置(绑定),然后在osalInitTasks()中如果发生事件进行调用绑定的事件处理函数.下面分3个部分分析.1.用户自己设计的任务代码在Zstack中的调用过程(1).main() 执行(在ZMain.c中)main() ---> osal_init_system()(2). osal_init_system()调用osalInitTasks(), (在OSAL.c中)osal_init_system() ---> osalInitTasks()(3). osalInitTasks()调用SampleApp_Init() , (在OSAL_SampleApp.c中)osalInitTasks() ---> SampleApp_Init()在osalInitTasks()中实现了多个任务初始化的设置,其中macTaskInit( taskID++ )到ZDApp_Init( taskID++ )的几行代码表示对于几个系统运行初始化任务的调用,而用户自己实现的SampleApp_Init()在最后,这里taskID随着任务的增加也随之递增.所以用户自己实现的任务的初始化操作应该在osalInitTasks()中增加.void osalInitTasks( void ){uint8 taskID = 0;//这里很重要, 调用osal_mem_alloc()为当前OSAL中的各任务分配存储空间(实际上是一个任务数组),并用tasksEvents指向该任务数组(任务队列).tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt)); //将taskSEvents所指向的空间清零macTaskInit( taskID++ );nwk_init( taskID++ );Hal_Init( taskID++ );#if defined( MT_TASK )MT_TaskInit( taskID++ );#endifAPS_Init( taskID++ );ZDApp_Init( taskID++ );SampleApp_Init( taskID ); //用户自己需要添加的任务}2.任务处理调用的重要数据结构这里要解释一下,在Zstack里,对于同一个任务可能有多种事件发生,那么需要执行不同的事件处理,为了方便,对于每个任务的事件处理函数都统一在一个事件处理函数中实现,然后根据任务的ID号(task_id)和该任务的具体事件(events)调用某个任务的事件处理函数,进入了该任务的事件处理函数之后,再根据events再来判别是该任务的哪一种事件发生,进而执行相应的事件处理.pTaskEventHandlerFn 是一个指向函数(事件处理函数)的指针,这里实现的每一个数组元素各对应于一个任务的事件处理函数,比如SampleApp_ProcessEvent对于用户自行实现的事件处理函数uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events ),所以这里如果我们实现了一个任务,还需要把实现的该任务的事件处理函数在这里添加.const pTaskEventHandlerFn tasksArr[] = {macEventLoop,nwk_event_loop,Hal_ProcessEvent,#if defined( MT_TASK ) //一个MT任务命令MT_ProcessEvent,#endifAPS_event_loop,ZDApp_event_loop,SampleApp_ProcessEvent};注意, tasksEvents和tasksArr[]里的顺序是一一对应的, tasksArr[]中的第i个事件处理函数对应于tasksEvents中的第i个任务的事件.//计算出任务的数量const uint8 tasksCnt = sizeof( tasksArr ) / sizeof( tasksArr[0] );uint16 *tasksEvents;3. 对于不同事件发生后的任务处理函数的调用osal_start_system() 很重要,决定了当某个任务的事件发生后调用对应的事件处理函数void osal_start_system(void){#if !defined ( ZBIT )for(;;) // Forever Loop#endif{uint8 idx = 0;Hal_ProcessPoll(); // This replaces MT_SerialPoll() and osal_check_timer().//这里是轮询任务队列,并检查是否有某个任务的事件发生do {if (tasksEvents[idx]) // Task is highest priority that is ready.//序号低的优先级高{break;}} while (++idx < tasksCnt);if (idx < tasksCnt){uint16 events;halIntState_t intState;HAL_ENTER_CRITICAL_SECTION(intState); //进入临界区,来提取出需要处理的任务中的事件events = tasksEvents[idx]; //处理该idx的任务事件, 是第idx个任务的事件发生了tasksEvents[idx] = 0; // Clear the Events for this task.HAL_EXIT_CRITICAL_SECTION(intState); //退出临界区,保存尚未处理的事件//对应调用第idx个任务的事件处理函数,用events说明是什么事件events = (tasksArr[idx])( idx, events );//当没有处理完,把返回的events继续放到tasksEvents[idx]当中HAL_ENTER_CRITICAL_SECTION(intState);tasksEvents[idx] |= events; // Add back unprocessed events to the current task.HAL_EXIT_CRITICAL_SECTION(intState);}#if defined( POWER_SA VING )else // Complete pass through all task events with no activity?{osal_pwrmgr_powerconserve(); // Put the processor/system into sleep}#endif}}//临界区资源管理先看一个临界区代码保护的例子:HAL_ENTER_CRITICAL_SECTION(intState);events = activeTask->events;activeTask->events = 0; //清楚任务的事件HAL_EXIT_CRITICAL_SECTION(intState);其中:中断宏定义如下#define HAL_ENABLE_INTERRUPTS() st( EA = 1; )#define HAL_DISABLE_INTERRUPTS() st( EA = 0; )#define HAL_INTERRUPTS_ARE_ENABLED() (EA)typedef unsigned char halIntState_t;#define HAL_ENTER_CRITICAL_SECTION(x) st( x =EA; HAL_DISABLE_INTERRUPTS(); )#define HAL_EXIT_CRITICAL_SECTION(x) st( EA = x; )#define HAL_CRITICAL_STATEMENT(x) st( halIntState_t s;HAL_ENTER_CRITICAL_SECTION(s); x; HAL_EXIT_CRITICAL_SECTION(s); )以及相关的st宏:#define st(x) do { x } while (__LINE__ == -1)(1)cc2430芯片中的中断使能的特殊功能寄存器(SFRs):IEN0,IEN1和IEN2,(见cc2430 datasheet: P49)。

OSAL系统框架

OSAL系统框架

taskID 这个 task,设置一个 event_id,让这个事件在后面的主循环中运行到。
下面我们通过一个图表来解释下这种机制:
8
这个表就是 osalTimerUpdate 函数的“任务表”,上面讲过这个函数给应用程序提供 了“软计时”,就是体现在这里:osal_start_timerEx 通过 osalAddTimer 向链表里添加了 “定时任务”,由 osalTimerUpdate 来以 ms 为单位对这些“软定时器”减计数,溢出时, 即调用 osal_set_event,实现主循环里对任务事件的调用。
二、通过消息机制调用事件
这是另外一种设置事件(Set Event)的重要方式,下面我们以 ZStack 协议栈的基础 例程-GenericApp 来看一下按键是如何产生的,及如何调用相应的接口程序。
前文讲过,按键的相关处理都安排在了 HAL 的 task 当中,在 HAL 的核心处理函数 Hal_ProcessEvent 中,有个 HalKeyPoll 的处理函数,在 HalKeyPoll 函数中,无论按键是 ADC 方式,或者是扫描 IO 口的方式,最后都会生成一个键值 key,然后通过下面的语句来 调用按键服务程序:
1.2 任务(task)的概念 在 OSAL 中,所有的“事件”会被安排到不同的“任务”里进行执行,比如按键、串口、 LCD 等外设均被安排在 Hal 任务中,而无线数据的底层收发则放在 mac 任务中等等。 以一个简单的 OSAL 项目为例:
macTaskInit( taskID++ ); nwk_init( taskID++ ); Hal_Init( taskID++ ); MT_TaskInit( taskID++ ); APS_Init( taskID++ ); APSF_Init( taskID++ ); ZDApp_Init( taskID++ ); ZDNwkMgr_Init( taskID++ ); SampleApp_Init( taskID );

ZigBee源码程序及解释

ZigBee源码程序及解释

协议栈无线透传编程原理:第一个功能:协调器的组网,终端设备和路由设备发现网络以及加入网络//第一步:Z-Stack 由 main()函数开始执行,main()函数共做了 2 件事:一是系统初始化,另外一件是开始执行轮转查询式操作系统int main( void ) { .......// Initialize the operating systemosal_init_system(); //第二步,操作系统初始化......osal_start_system(); //初始化完系统任务事件后,正式开始执行操作系统......}//第二步,进入 osal_init_system()函数,执行操作系统初始化uint8 osal_init_system( void ) //初始化操作系统,其中最重要的是,初始化操作系统的任务{// Initialize the Memory Allocation Systemosal_mem_init();// Initialize the message queueosal_qHead = NULL;// Initialize the timersosalTimerInit();// Initialize the Power Management Systemosal_pwrmgr_init();// Initialize the system tasks.osalInitTasks(); //第三步,执行操作系统任务初始化函数// Setup efficient search for the first free block of heap.osal_mem_kick();return ( SUCCESS );}//第三步,进入osalInitTasks()函数,执行操作系统任务初始化void osalInitTasks( void ) //第三步,初始化操作系统任务{uint8 taskID = 0;tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));//任务优先级由高向低依次排列,高优先级对应 taskID 的值反而小macTaskInit( taskID++ ); //不需要用户考虑nwk_init( taskID++ ); //不需要用户考虑Hal_Init( taskID++ ); //硬件抽象层初始化,需要我们考虑#if defined( MT_TASK )MT_TaskInit( taskID++ );#endifAPS_Init( taskID++ ); //不需要用户考虑#if defined ( ZIGBEE_FRAGMENTATION )APSF_Init( taskID++ );#endifZDApp_Init( taskID++ ); //第四步,ZDApp层,初始化,执行ZDApp_init函数后,如果是协调器将建立网络,如果是终端设备将加入网络。

Zstack基本工作原理

Zstack基本工作原理

Zstack基本工作原理Z-Stack协议栈是一个基于任务轮询方式的操作系统,其任务调度和资源分配由操作系统抽象层OSAL管理着。

Z-Stack协议栈 = OSAL操作系统 + CC2530硬件模块 + AF无线网络应用总体来看,Z-Stack协议栈只做了两件事情:首先进行系统的初始化,然后启动OSAL操作系统。

在任务轮询过程中,系统将会不断查询每个任务是否有事件发生,如果有事件发生,就执行相应的事件处理函数,如果没有事件发生,则查询下一个任务。

1.系统初始化:系统启动代码需要完成初始化硬件平台和软件架构所需要的各个模块,为操作系统的运行做好准备工作,主要分为:初始化系统时钟,检测芯片工作电压,初始化堆栈,初始化各个硬件模块,初始化 FLASH存储,形成芯片 MAC 地址,初始化非易失变量,初始化 MAC 层协议,初始化应用层协议,初始化操作系统等。

osalInitTasks();得到taskID:在这个函数中,先定义了一个任务ID号,tasksEvents所指向的地址长度是两个字节,然后使tasksEvents指向一个为任务总数*2个字节大小的空间的首地址,并将空间内容初始化为0,这里就可以知道tasksEvents其实就是指向每个任务事件的指针了。

而且不难发现,这个函数中的任务排序和tasksArr[]数组定义的排序是一样的。

事实上,当某个tasksEvents[idx]非空时,就表明有对应该任务的事件要处理,可能是一件,也可能是很多件。

然后通过idx在taskArr[idx]中找到相应的事件处理函数进行处理,处理完了之后有这样一句指令return(events^SYS_EVENT_MSG),当然后面的宏定义可能不一样,这是一个异或处理,1^1=0,1^0=1,也就是说SYS_EVENT_MSG这个事件处理完了清零了,剩下的events继续反馈上去,进行下一轮的循环然后处理。

2.启动OSAL操作系统:系统初始化为操作系统的运行做好准备工作以后,就开始执行操作系统入口程序,并由此彻底将控制权交给 OSAL操作系统。

TI ZSTACK OSAL内核机制图析

TI ZSTACK OSAL内核机制图析

TCB 链表最高优先级T C B最低优先级T C Bstruct osalTaskRec *next; pTaskInitFn pfnInit;pTaskEventHandlerFn pfnEventProcessor;byte taskID;byte taskPriority; uint16 events;} osalTaskRec_t;任务控制块TCB 的结构:typedef void (*pTaskInitFn)( unsigned char task_id );typedef unsigned short (*pTaskEventHandlerFn)( unsigned char task_id, unsigned short event );:任务的事件标志TCB 都带有自己的事件标志字,其中每一位代表一个事件,具体的事件定义由服务任务函数决定。

tsskID 由建立任务次序决定taskPriority :最多可设定256个优先级!消息头结构:消息块的结构:│││消息块1消息块2消息块3消息块N*next *prev 相互连接说明接收此消息的taskID )消息链表INVALID_LEN :参数len 为0!或参数len 与消息头中len 值不相等!INVALID_TASK :无效的任务号!INVALID_MSG_POINTER :消息头没有初始化!注:若插入消息块失败,函数osal_msg_send ()返回前会先释放新消息块所占的内存(osal_msg_deallocate( msg_ptr ))!任务调用系统函数osal_set_event( destination_task, SYS_EVENT_MSG )通知目标任务消息链中有它的消息等待接收处理!此函数作用:置位destination_task 任务TCB 中相应的事件标志位!destination_task :接收此消息的目标任务号SYS_EVENT_MSG :自定义的事件标志位,表示消息链中有当前任务的消息等待接收!服务任务函数可调用系统函数osal_msg_received_t *osal_msg_receive( byte task_id )提取消息链中排在最前面的一条属于task_id (通常是当前服务任务本身)任务的消息!并将原消息内容转移到此函数返回的osal_msg_received_t 结构变量(见下图)中去!此时被提取的消息块将从消息链中“脱离”,消息链会在断开处重新连接。

实验8—基于Z-Stack的无线自组网实验

实验8—基于Z-Stack的无线自组网实验

实验8—基于Z-Stack的⽆线⾃组⽹实验实验题⽬:实验8—基于Z-Stack的⽆线⾃组⽹实验实验时间:2015.12.24⼀、实验⽬的:学习TI ZStack2007协议栈内容,掌握CC2530模块⽆线组⽹原理及过程。

有关Z-Stack2007协议栈的具体内容,请参考附录中相关说明及TI官⽅⽂档。

使⽤IAR 开发环境设计程序,ZStack-2.3.0-1.4.0协议栈源码例程SampleApp⼯程基础上,实现⽆线组⽹及通讯。

即协调器⾃动组⽹,终端节点⾃动⼊⽹,并发送周期信息“~HELLO!~”⼴播,协调器接收到消息后将数据通过串⼝发送给PC 计算机。

⼆、实验原理及程序分析:a)ZigBee(CC2530)模块LED硬件接⼝图1 LED 硬件接⼝ZigBee(CC2530)模块硬件上设计有2个LED灯,⽤来编程调试使⽤。

分别连接CC2530的P1_0、P1_1两个IO 引脚。

从原理图上可以看出,2个LED灯共阳极,当P1_0、P1_1引脚为低电平时候,LED灯点亮。

b)SampleApp实验简介SampleApp实验是协议栈⾃带的ZigBee⽆线⽹络⾃启动(组⽹)样例,该实验实现的功能主要是协调器⾃启动(组⽹),节点设备⾃动⼊⽹。

之后两者建⽴⽆线通讯,数据的发送主要有2中⽅式,⼀种为周期定时发送信息(本次实验采⽤该⽅法测试),另⼀种需要通过按键事件触发发送FLASH信息。

由于实验配套ZigBee模块硬件上与TI公司的ZigBee样板有差异,因此本次实验没有采⽤按键触发⽅式。

Periodic消息是通过系统定时器开启并定时⼴播到group1出去的,因此在SampleApp_ProcessEvent事件处理函数中有如下定时器代码:case ZDO_STATE_CHANGE:SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status);if ( (SampleApp_NwkState == DEV_ZB_COORD)|| (SampleApp_NwkState == DEV_ROUTER)|| (SampleApp_NwkState == DEV_END_DEVICE) ){// Start sending the periodic message in a regularinterval.HalLedSet(HAL_LED_1, HAL_LED_MODE_ON);osal_start_timerEx( SampleApp_TaskID,SAMPLEAPP_SEND_PERIODIC_MSG_EVT,SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT );}else{// Device is no longer in the network}break;当设备加⼊到⽹络后,其状态就会变化,对所有任务触发ZDO_STATE_CHANGE 事件,开启⼀个定时器。

OSAL的工作原理

OSAL的工作原理

OSAL的工作原理ZigBee 协议栈依据IEEE 802.15.4 标准和ZigBee 协议规范。

ZigBee 网络中的各种操作需要,利用协议栈各层所提供的原语操作来共同完成。

原语操作的实现过程往往需要向下一层发起一个原语操作并且通过下层返回的操作结果来判断出下一条要执行的原语操作。

IEEE 802 .15 .4 标准和ZigBee 协议规范中定义的各层原语操作多达数十条,原语的操作过程也比较复杂,它已经不是一个简单的单任务软件。

对于这样一个复杂的嵌入式通信软件来说,其实现通常需要依靠嵌入式操作系统来完成。

挪威半导体公司Chipcon( 目前已经被TI 公司收购)作为业界领先的ZigBee 一站式方案供应商,在推出其CC2530 开发平台时,也向用户提供了自己的ZigBee 协议栈软件-Z-Stack 。

这是一款业界领先的商业级协议栈,使用CC2530 射频芯片,可以使用户很容易的开发出具体的应用程序来。

Z-Stack 使用瑞典公司IAR 开发的IAR Embedded Workbench for MCS .51 作为它的集成开发环境。

Chipcon 公司为自己设计的Z-Stack 协议栈中提供了一个名为操作系统抽象层OSAL 的协议栈调度程序。

对于用户来说,除了能够看到这个调度程序外,其它任何协议栈操作的具体实现细节都被封装在库代码中。

用户在进行具体的应用开发时只能够通过调用API 接口来进行,而无权知道Zig,Bee 协议栈实现的具体细节。

Z-Stack1.4.3及以后的版本中引入了一个OSAL(Operating System Abstraction Layer 操作系统抽象层),但在我们整个的ZigBee协议栈的结构图中,我并没有能够发现这个层在哪个位置。

但是整个的协议栈都要在OS的基础上才能运行。

OSAL和我们通常所说的RTOS,pc上的操作系统还是有很大的不同,ZigBee2006中只是利用了操作系统的概念和思想,利用OS把Z-Stack软件组件从特殊的处理过程相分离,并将软件成分保护了起来。

触发任务事件方式

触发任务事件方式
return ( ZSUCCESS ); }
/********************************************************************* 可以看到通过 tasksEvents[task_id] |= event_flag 就能让系统主循环函数轮询到所发生的任务事件,再调用相应任 务事件处理函数进行处理,具体参见“系统主循环流程”。
我使用的协议栈版本及例子信息: ZigBee2006\Texas Instruments\ZStack-1.4.3-1.2.1\Projects\zstack\Samples\SampleApp
……~~
个人觉得,整个协议栈中触发事件有三种方式
1、通过设置一个“软件定时器”,当其溢出时触发事件。osal_start_timerEx()—osalTimerUpdate()— osal_set_event() 2、通过调用系统消息传递机制触发事件。osal_msg_send()—osal_set_event() 3、直接调用 osal_set_event()触发事件。
return ( ZSUCCESS ); } /***********************
说明: 本文作者所记录,以上基本为个人见解,错误之处还请高手指点,本人随时更新,转载请注明出处,谢谢! 参考资料: 《OSAL 系统框架专题》
// When timeout, execute the task if ( srchTimer->timeout == 0 ) { osal_set_event( srchTimer->task_id, srchTimer->event_flag );
………Байду номын сангаас } /************************ 对于 2,对 msg_ptr 一系列处理后,调用 osal_set_event()触发事件,如下 /************************ byte osal_msg_send( byte destination_task, byte *msg_ptr ) { ………… osal_set_event( destination_task, SYS_EVENT_MSG );

基于CC2530的ZigBee通信网络的应用设计

基于CC2530的ZigBee通信网络的应用设计

基于CC2530的ZigBee通信网络的应用设计李俊斌;胡永忠【摘要】ZigBee无线传感网络在的家居、工业、医疗等领域应用的发展暗示着它已经成为一种新的技术趋势。

为了快速构建自己的无线通信网络,从应用方面着手对ZigBee技术的网络拓扑结构进行研究和介绍,在IAR开发环境下,采用TI公司的Z-STACK协议栈,以CC2530芯片为核心构建了一个无线传感网络,硬件设计中重点讨论了匹配电路和倒F天线的设计,并且对应用层软件设计流程进行说明。

最后构建了一个由6个节点组成的星型网络,各终端器利用CC2530自带的A/D转化器采集温度数据并通过网络汇聚到协调器。

实现了ZigBee网络的通信并验证了ZigBee网络自组网、网络自愈的特性。

%The application of ZigBee wireless sensor network in the fields of intelligent home,industry,medical health and others implies that Zigbee is becoming one trend of new technology.In order to build wireless communication network yourself quickly,the ZigBee network topology was researched and introduced in this paper.A kind of wireless network is built using the SOC chip CC2530 and TI's Z-STACK protocol under the development environment IAR.The hardware design is introduced focus on match circuit and invert F antena,the application layer of protocol is explained in the design of software designing.At last,a star network is built including six nodes,the signal of temperature is gathered by ADCs in CC2530 and transferred to a coordinator.The experimental result shows the self-organization and self-repair function of ZigBee network are realized.【期刊名称】《电子设计工程》【年(卷),期】2011(019)016【总页数】4页(P108-111)【关键词】CC2530;IFA;ZigBee;无线网络【作者】李俊斌;胡永忠【作者单位】电子科技大学电子工程学院,四川成都611731;电子科技大学电子工程学院,四川成都611731【正文语种】中文【中图分类】TN925为了满足人们日益对智能化生活的需求,在微电子技术、计算机技术发展推动下,无线传感网络取得长足发展,其在各方面的应用暗示着它已经成为一种新的技术趋势。

中南大学刘伟荣物联网-《无线传感器网络》实验报告

中南大学刘伟荣物联网-《无线传感器网络》实验报告

.中南大学信息科学与工程学院物联网无线传感器网络实验报告班级:物联网学号:姓名:指导老师:刘伟荣实验时间:2014年4月11日目录实验一基础实验(LED实验) .................................................................................................................... - 2 -1.1实验目的 ........................................................................................................................................ - 2 -1.2实验设备及工具........................................................................................................................... - 2 -1.3实验原理 ........................................................................................................................................ - 2 -1.4 实验步骤及结果 ......................................................................................................................... - 5 - 实验二射频实验......................................................................................................................................... - 6 -2.1 实验目的 ....................................................................................................................................... - 6 -2.2 实验内容 ....................................................................................................................................... - 6 -2.3 实验设备及工具 ......................................................................................................................... - 7 -2.4 实验原理 ....................................................................................................................................... - 7 -2.5 实验步骤 ....................................................................................................................................... - 9 -2.6 实验数据分析及结论.............................................................................................................. - 10 - 实验三Zstack组网实验......................................................................................................................... - 11 -3.1 实验目的 ..................................................................................................................................... - 11 -3.2 实验内容 ..................................................................................................................................... - 11 -3.3 预备知识 ..................................................................................................................................... - 12 -3.4 实验设备及工具 ....................................................................................................................... - 12 -3.5 实验原理 ..................................................................................................................................... - 12 -3.6 实验步骤 ..................................................................................................................................... - 17 -3.7 实验数据分析及结论.............................................................................................................. - 18 - 实验四综合实验(传感器网络) ............................................................................................................. - 18 -4.1 智能网关程序设计................................................................................................................... - 19 -4.2 Android 用户控制程序设计.................................................................................................. - 20 -4.3 Zigbee 节点控制程序设计.................................................................................................... - 30 -4.4 平台控制操作............................................................................................................................ - 34 -实验一基础实验(LED实验)1.1实验目的◆通过I/O控制小灯闪烁的过程。

ZStackOSAL中文说明

ZStackOSAL中文说明

1.概述OSAL (Operating System Abstraction Layer),翻译为“操作系统抽象层”。

在基于ZigBee协议的应用开发中,应用程序框架中包含了最多240个应用程序对象。

如果我们把一个应用程序对象看做为一个任务的话,那么应用程序框架将包含一个支持多任务的资源分配机制。

于是OSAL便有了存在的必要性,它正是Z-Stack为了实现这样一个机制而存在的。

OSAL就是以实现多任务为核心的系统资源管理机制。

所以OSAL与标准的操作系统还是有很大的区别的。

简单而言,OSAL实现了类似操作系统的某些功能,但并不能称之为真正意义上的操作系统。

2. OSAL 的API 接口2.1消息管理功能(1)u int8 * osal_msg_allocate( uint16 len ):申请一个指定长度的消息缓存区, 该函数调用void *osal_mem_alloc( uint16 size )函数实现,从堆中申请存储空间。

(2)uint8 osal_msg_deallocate( uint8 *msg_ptr ):接收到消息的任务处理完成后释放消息的缓存空间。

(3)uint8 osal_msg_send( uint8 destination_task, uint8 *msg_ptr )发送消息至U 指定任务,将消息放入队列,并把任务的相应事件标志置位。

(4)uint8 *osal_msg_receive( uint8 task_id ):接收发送到某个消息的任务,在任务处理完消息后,必修释放消息的存储空间。

该函数查找消息队列,如果消息队列中有多个发送给该任务的消息,保持事件标志位。

(5)osal_eve nt_hdr_t *osal_msg_fi nd(ui nt8 task_id, uint8 eve nt) 寻找发送给具有某个事件的任务的消息。

2.2任务同步功能(1)uint8 osal_set_event(uint8 task_id, uint16 event_flag ):设置某个任务的某个事件标志。

转:ZigBeeZ-StackCC2530实现低功耗运行的配置简介

转:ZigBeeZ-StackCC2530实现低功耗运行的配置简介

转:ZigBeeZ-StackCC2530实现低功耗运⾏的配置简介设备⽀持低功耗运⾏是ZigBee⽹络的⼀⼤特点,该特性借助CC2530芯⽚能够很好地体现出来。

CC2530芯⽚有五种运⾏模式,分别为主动模式、空闲模式、PM1、PM2和PM3。

主动模式是⼀般运⾏模式;空闲模式除了CPU内核停⽌运⾏外,其他和主动模式⼀样;PM1、PM2、PM3是低功耗运⾏模式,CC2530通过关闭不必要的部分和调整系统时钟来达到低功耗的效果。

PM1:稳压器的数字部分开启,32 MHzXOSC和 16 MHz RCOSC都不运⾏。

32 kHz RCOSC或32 kHz XOSC运⾏。

复位、外部中断或睡眠定时器溢出时系统将转到主动模式。

PM2:稳压器的数字内核关闭。

32 MHzXOSC和 16 MHz RCOSC都不运⾏。

32kHz RCOSC或32 kHz XOSC运⾏。

复位、外部中断或睡眠定时器过期时系统将转到主动模式。

PM3:稳压器的数字内核关闭。

所有的振荡器都不运⾏。

复位或外部中断时系统将转到主动模式。

⼏种运⾏模式的对⽐如下表所⽰:PM2模式⼜叫LITE SLEEP模式,其功耗在毫安级别,多⽤于需要定时唤醒的场合,⽐如周期性地唤醒传感器来进⾏数据的采集。

PM3模式⼜叫做DEEP SLEEP模式,在⼏种运⾏模式中功耗最低,在微安级别,多⽤于远程遥控场合,⽐如使⽤CC2530做⼀个远程遥控器,在没有按键按下时,可使其进⼊PM3模式以减少电能消耗。

Z-STACK提供了两种低功耗运⾏模式,PM2和PM3。

PM2模式可被睡眠定时器,外部中断和复位唤醒,PM3模式可被外部中断和复位唤醒。

在Z-Stack的使⽤⽂档中得知为了使设备能够进⼊睡眠模式,必须满⾜以下的条件:1、通过添加预编译项POWER_SAVING来使能睡眠模式2、ZDO节点描述符指定“在空闲时发送功能是关闭的”,通过在f8wConfig.cfg⽂件中将RFD_RCVC_ALWAYS_ON设置为FALSE来实现。

OSAL详解

OSAL详解

Zstack OSAL详解1. void osal_start_system( void )所有应用程序,无论是自己写的最简单的测试程序还是复杂的OSAL操作系统,都必须从main( )来入口。

所谓的OS操作系统,我们不妨这样想像:自己写一个最简单的main( ),里面就一句打印“Hello, World”.如果需要加入Key, LED这样的输入输出功能,那么就需要扩充main( ),加入Key, LED的驱动,如果要实现多线程调度,就要加入Timer驱动等等。

其实操作系统就是这么来的,简单吧。

一般在OS中都会有个死循环,在这个循环中去处理各种各样的事件。

在Zstack OSAL中,这个死循环就存在于osal_start_system()这个函数中。

下面来详细分析在这个死循环中到底在做哪些事情。

2. OSAL的“心跳”在OSAL的死循环中,各个事件只是在某些特定的情况下发生,如果OSAL一刻不停去轮询去处理这些应用程序,迟早会累死(热量,功耗,寿命…),这样做是完全没有必要的。

所以这里就引入了心跳的概念,也就是OS的时钟节奏。

在Zstack OSAL中这个节奏定义为1ms, 由8 bits HW_TIMER4来控制,当然这些都可以由程序员来修改,后面就以系统的默认值来讲述。

在void InitBoard( byte level )这个函数中有下面这段代码就是在定义系统的心跳Timer。

HalTimerConfig (OSAL_TIMER,HAL_TIMER_MODE_CTC, HAL_TIMER_CHANNEL_SINGLE,HAL_TIMER_CH_MODE_OUTPUT_COMPARE,OnboardTimerIntEnable,Onboard_TimerCallBack);在OSAL的Timer定义好了以后,就要启动Timer, 至于如何启动Timer, 请自行查阅2430 Spec, 我这里想说的是,在一步步跟踪源码到死循环开始,都没有发现启动OSAL Timer的代码,最后通过观察Timer 相关的控制寄存器,发现,在网络层初始化函数nwk_init( taskID++ )执行完毕后Timer启动了,也就是说在网络层初始化函数中有启动Timer的语句,因为网络层初始化是不开源的,无从去看源代码验证,总之,Timer启动了就好。

系统时钟定时器

系统时钟定时器

系统时钟定时器我使用的协议栈版本及例子信息:ZigBee2006\Texas Instruments\ZStack-1.4.3-1.2.1\Projects\zstack\Samples\SampleApp……OOXX……~~~~个人觉得,在协议栈里面涉及到两类定时器:一类是硬件定时器,对应cc2430上的几个Timer。

系统时钟定时器为硬件定时器另一类是软件定时器,通过osal_start_timer()添加到软定时器链表,再由系统时钟进行统一减计数。

在"OSAL调试机制"中记录过这段话:时间管理对事件进行时间管理,OSAL采用了链表的方式进行,有时发生一个要被处理的事件,就启动一个逻辑上的定时器,并将此定时器添加到链表当中。

利用硬件定时器作为时间操作的基本单元。

设置时间操作的最小精度为1ms,每1ms硬件定时器便产生一个时间中断,在时间中断处理程序中去更新定时器链表。

每次更新,就将链表中的每一项时间计数减1,如果发现定时器链表中有某一表项时间计数已减到0,则将这个定时器从链表中删除,并设置相应的事件标志。

这样任务调度程序便可以根据事件标志进行相应的事件处理。

时间管理函数:extern byte osal_start_timer(byte task_id, uint16 event_id, uint16 timeout_value);这个函数为事件event_id设置超时等待时间timeout_value。

一旦等待结束,便为task_id所对应的任务设置相应的事件发生标记,进行相应处理.这段话中的硬件定时器,即为系统时钟定时器,定时时间为“T ICK_TIME—系统时间片”。

1、何为系统时间片?引用outman的话:每个操作系统都有一个“节拍”-tick,就像每一个“活人”都有心跳一样。

2、系统时间片是多少?在OnBoard.h中定义:/* OSAL timer defines */#define TICK_TIME 1000 // Timer per tick - in micro-sec 1000us,即1ms,3、系统时钟什么时候初始化?在OnBoard.c中InitBoard():/***************************************void InitBoard( byte level )//在zmain.c中先OB_COLD启动,后OB_READY启动{if ( level == OB_COLD )//冷启动{…………/* Timer2 for Osal timer* This development board uses ATmega128 Timer/Counter3 to provide* system clock ticks for the OSAL scheduler. These functions perform* the hardware specific actions required by the OSAL_Timers module.*/OnboardTimerIntEnable = FALSE;HalTimerConfig (OSAL_TIMER, // 8bit timer2HAL_TIMER_MODE_CTC, // Clear Timer on CompareHAL_TIMER_CHANNEL_SINGLE, // Channel 1 - defaultHAL_TIMER_CH_MODE_OUTPUT_COMPARE, // Output Compare modeOnboardTimerIntEnable, // FALSEOnboard_TimerCallBack); // Channel Mode}…………}/***************************************4、系统时钟对应的cc2430哪个定时器?从上面的初始化中可以看到Timer2 for Osal timer,但事实上就像outman说的,要跟halTimerRemap()函数对应起来:/***************** @fn halTimerRemap** @brief Maps(映射) API HAL_TIMER_ID to HW Timer ID.* HAL_TIMER_0 --> HW Timer 3* HAL_TIMER_2 --> HW Timer 4* HAL_TIMER_3 --> HW Timer 1** @param timerId - ID of the timer/****************Timer2映射到硬件上去即为Timer45、系统时钟什么用?系统时钟定时器由osal_timer_activate()开启,溢出时调用其回调函数(中间这一系列流程后面具体记录),回调函数在InitBoard()被初始化为Onboard_TimerCallBack(),而Onboard_TimerCallBack()调用了osal_update_timers(),而osal_update_timers()调用osalTimerUpdate()对系统软定时器链表中的每一项定时器时间计数减1ms,如果有软定时器计数减到0,删除这个软定时器并调用osal_set_event()设置相应事件发生标志。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

写在前面:之所以会注意到定时器事件是因为在做断点调试的时候会进入
osal_start_timerEx这个函数,而且这个函数之后还会涉及到hal_uartpoll有关DMA之类的函数,于是发现了这篇文章,写得很详细。

我们先看一下osal_start_timerEx()函数,是怎么调用到最后的osal_set_event()函数,触发事件处理的。

下面是osal_start_timerEx()函数的源代码,从中间我们并没有看到有关osal_set_events()函数的相关信息。

当然这个函数中没有直接的调用该函数,那
osal_set_events()函数,是怎么和我们的osal_start_timerEx()函数联系起来的呢?我们应该先从系统中的主循环开始查找其中的奥妙。

byte osal_start_timerEx( byte taskID, UINT16 event_id, UINT16 timeout_value )
{
halIntState_t intState;
osalTimerRec_t *newTimer;
HAL_ENTER_CRITICAL_SECTION( intState ); // Hold off interrupts.
// Add timer
newTimer = osalAddTimer( taskID, event_id, timeout_value );
if ( newTimer )
{
#ifdef POWER_SAVING
// Update timer registers
osal_retune_timers();
(void)timerActive;
#endif
// Does the timer need to be started?
if ( timerActive == FALSE )
{
osal_timer_activate( TRUE );
}
}
先在osal_start_system( void )函数开始时调用Hal_ProcessPoll();因为Hal_ProcessPoll()函数是在一个死循环中,所以每过一定的时间就会执行到。

在Z-Stack OSAL中这个时种节奏定义是1ms,由8bits HW_TIMER4来控制,这些都可以有程序员进行修改,我们先看一下Hal_ProcessPoll()函数。

void Hal_ProcessPoll ()
{
HalTimerTick();
#if (defined HAL_UART) && (HAL_UART == TRUE)
HalUARTPoll();
#endif
}
在这是就会有一个疑问是在什么时候溢出呢?我们知道每个系统都会有一个节拍,也就是系统的时钟,在OSAL中也不例外,这个时钟就是由Timer4提供的计时的。

在void InitBoard(byte level)函数中调用下面这个函数,进行了配置
HalTimerConfig (OSAL_TIMER, // 8bit timer2
HAL_TIMER_MODE_CTC, // Clear Timer on Compare
HAL_TIMER_CHANNEL_SINGLE, // Channel 1 - default
HAL_TIMER_CH_MODE_OUTPUT_COMPARE, // Output Compare mode
OnboardTimerIntEnable, // Use interrupt
Onboard_TimerCallBack); // Channel Mode
OSAL的Timer定义好之后,就要启动Timer,在网络层初始化函数nwk_init(taskID++)执行完后,Timer启动了,也就是说在网络层的初始化函数中启动了Timer,网络层的代码是不开源的,所以也就无法看到其真正的启动代码。

每当1ms心跳来临时,Timer4的中断标志置位,这样在OSAL的死循环中,通过一开始的Hal_ProcessPoll()函数检测到这中断标志位,在Hal_ProcessPoll ()函数中调用
了HalTimerTick();函数,这个函数是专门用来检测是否有硬件定时器溢出的。

如果定时器有溢出的话,就要调用halProcessTimerX ();(X表示1 3 4).这里假设是HalProcessTimer4(),在HalProcessTimer4()中,通过下面的一句话,调用了函数halTimerSendCallBack (HAL_TIMER_2,
HAL_TIMER_CHANNEL_B,
HAL_TIMER_CH_MODE_OUTPUT_COMPARE);
在halTimerSendCallBack中调用了真正的回调函数,
if (halTimerRecord[hwtimerid].callBackFunc)
(halTimerRecord[hwtimerid].callBackFunc) (timerId, channel, channelMode);
这个回调函数通过
uint8 HalTimerConfig (uint8 timerId, uint8 opMode, uint8 channel, uint8 channelMode,bool intEnable, halTimerCBack_t cBack)
也就是前面的那个函数。

进行的配置。

在InitBoard()函数中调用了函数HalTimerConfig ()。

也就是调用了Onboard_TimerCallBack()函数,在这个函数中调用了
osal_update_timers();函数,这个函数又调用了osalTimerUpdate( tmr_decr_time );这个函数中又调用了osal_set_events()函数。

osalTimerUpdate( tmr_decr_time )函数会去轮询Timer事件链表,Timer事件链表是下面这样一个数据结构,next指向下一个Timer事件,timerout值表明本Timer事件还需要timerout个心跳才需要被处理,因为些处的心跳是1ms,所以也就是说还需要timerout个ms才处理。

也就是检测timeout是否小于1ms,如果小于1ms,则发出event_flag这个消息到消息队列,这个消息隶属于task_id这个任务,如果不大于1ms,说明该Timer事件还不到处理的时间,则Timeout= Timeout-1,然后继续等待下一次心跳,Timer事件链表的维护是通过osal_start_timerEx()这个函数来实现的。

这样就把前面的
osalTimerUpdate( tmr_decr_time )函数和我们应用程序中经常调用的osal_start_timerEx()函数联系在了一起,
typedef struct
{
void *next;
UINT16 timeout;
UINT16 event_flag;
byte task_id;
} osalTimerRec_t;
如果到达定时器的定时值,也就是说Timeout< 1ms后,就会发送一个event_flag这个消息给消息队列,这样在主循环中就可以检测到这个消息,并且检测到这个消息是属于那个任务的,然后,调用相应的消息处理函数。

相关文档
最新文档