一、概述
OSAL(Operating System Abstraction Layer),翻译为“操作系统抽象层”,OSAL就是以实现多任务为核心的系统资源管理机制。所以OSAL与标准的操作系统还是有很大的区别的。简单而言,OSAL实现了类似操作系统的某些功能,但并不能称之为真正意义上的操作系统。
二、OSAL系统的初始化
首先在main()中调用OSAL初始化函数Init_Osal(),在Init_Osal()中通过调用osal_init_system()来进行初始化OSAL,在调用osal_init_system()过程中关闭所有中断。
在osal_init_system()中包括了内存、定时器、任务初始化、添加任务和初始化添加的任务等。(分别为函数osal_mem_init();osalTimerInit();osalTaskInit(); osalAddTasks();osalInitTasks();osal_mem_kick();)注:在新版本中已经没有osalAddTasks()函数
现在我们先进行OSAL系统任务是如何运行的进行分析。关于任务初始化中主要用到 osalTaskInit(); osalAddTasks();osalInitTasks();这三个函数。
osalTaskInit()函数的功能是将任务头指针tasksHead置零,有效任务指针activeTask置零,并且初始化任务ID变量taskIDs 为零。
osalAddTasks()函数的功能是添加所有的任务,所谓的添加任务就是在系统内存空间(此部分关于内存的操作将放到最后进行说明)中申请一段空间用于存储任务的结构变量osalTaskRec,按照链表的形式存储所有的任务结构变量,此结构变量中将存储所有任务所需要的信息。通过调用osalTaskAdd()依次添加每个任务。添加任务有三个作用的参数,他们分别是:pfnInit、pfnEventProcessor和taskPriority(任务初始化函数地址、任务处理函数地址和任务的优先级)而taskID参数则是系统通过osalAddTasks()函数随机给分配的。因此编写初始化任务之前必须先编写任务的相关函数(初始化和处理函数)备注:任务处理函数是负责处理传递给此任务的事件,比较重要,具体将在本文的后面进行分析。
osalInitTasks()函数的功能是依次调用所有任务的初始化函数,进行初始化。一般都在任务初始化函数中将系统分配的taskID赋值给任务ID全局变量这样在设置任务时方便使用这个任务ID全局变量来传递参数和识别。
三、OSAL系统的运行
还是先从mian()函数中来寻找OSAL系统运行的蛛丝马迹,轻易的就能找到osal_start_system();这个函数。分析此函数就能大概明白OSAL系统是如何运行的了,首先是定义一个定时器中断,每隔一定的时间产生一次中断,这里使用的是看门狗定时器中断。(这个定时器中断是很重要的,它相当于OSAL系统的时钟,每隔一定的时间进行一次系统的刷新,而后判断任务和时间是否激活,激活的话转入相应的函数进行处理。)紧接着会看到一个for(;;){},这是一个死循环,可以得出程序将一直在这个循环中运行,这段代码的主要功能是:调用osalNextActiveTask()函数判断是否有事件产生,如果有的话返回系统内存空间中相应任务地址,而后读取事件标识并清该事件标识,最后调用相应任务的处理函数,并传递事件标识号,处理相应的事件。那么系统是如何设置事件标识的呢?
一、熟悉单片机的都应该知道中断,既然程序将始终在for(;;){}中循环,唯一的方式就是通过中断,在中断程序中调用函数进行事件标识的设置。上文中已经提到过定时器中断(看门狗定时器)在此中断中调用osal_set_event()传递参数:TaskID和EVENT标识,这样将设置相应任务并且设置任务中的事件标识,在for(;;){}中就能读取到有事件产生。
二、上面这种方式比较直接,另一种也是通过中断,但是不是直接调用osal_set_event()来设置任务事件,而是通过定时器这样经过一定的延时后才设置任务事件的。这里涉及到OSAL系统中的定时器,这是软件级的定时器,并非单片机上硬件定时器的概念。但是这个软件定时器也是通过上文提到的定时器中断(看门狗定时器)提供的基本时间来进行定时的。白话点就是:当定时器中断(看门狗定时器)产生时,调用一次软件定时器。即调用osal_update_timers();->osalTimerUpdate( tmr_decr_time )。
osalTimerUpdate()函数的主要功能是:通过传递的参数更新OSAL系统时间即osal_systemClock += updateTime;而后判断定时器链表中是否有定时器,有的话按链表的顺序依次判断是否达到定时时间(timeout),达到的话则设置该定时器对应的taskID和event_flag,在for(;;){}中就能读取到有事件产生。达到定时时间的定时器将被从链表中清除,未达到的继续等待。此处还有一个问题没有解释,那就是这些对应于不同的taskID的定时器是在哪里初始化和设定的。
现在再分析一下定时器的初始化,在OSAL系统初始化的时候就调用过osalTimerInit();函数对定时器进行初始化了,主要的功能是对几个定时器相关变量进行赋值 tmr_count = TICK_TIME; //TICK_TIME=250000
tmr_decr_time = TIMER_DECR_TIME;//TIMER_DECR_TIME=250ms
osal_timer_activate( false );
timerActive = false;
而后就可以在需要的地方进行定时器的添加了,一般都在中断中调用
osal_start_timerEx( );进行添加操作的。例如本人使用的程序中在按键中断中调用
osal_start_timerEx( Hal_TaskID, HAL_KEY_XIAODOU_EVENT, 10);函数进行添加定时器的,对于定时器的添加操作过程中关闭所有中断,其中调用了osalAddTimer( );函数进行定时器的添加(添加定时器的代码和添加任务的代码很相似)。也是在系统内存空间中申请一段空间用于存储定时器的结构变量osalTimerRec_t并且按照链表的形式存储所有的定时器结构变量。
阅读(1968) | 评论(0) | 转发(0) |