OSAL

一、概述 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();)现在我们先进行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并且按照链表的形式存储所有的定时器结构变量。
OSAL(Operating System Abstraction Layer,操作系统抽象层)中,按键功能的实现通常依赖于定时器事件和任务调度机制。以下是对OSAL按键功能实现的分析以及常见问题的解决方案。 ### OSAL 按键功能实现 1. **按键检测机制** 在OSAL中,按键检测通常通过定时器事件触发。系统使用 `osal_start_timerEx()` 函数将按键检测事件周期性地放入事件链表中,确保每隔一定时间(如100ms)执行一次按键扫描。这种机制避免了直接使用中断处理按键可能带来的抖动问题,同时保持系统资源的合理利用 [^1]。 2. **按键事件的定义与处理** 按键事件通常被定义为一个任务事件,并与特定的任务相关联。通过在头文件中定义结构体(例如 `typedef struct { osal_event_hdr_t hdr; uint8* name; } getName_t;`),可以封装按键事件的数据内容,便于后续处理 [^2]。 按键事件的处理函数通常在任务初始化时注册,任务 ID 通过 `osalInitTasks()` 函数分配,每个任务 ID 对应一个事件处理函数和事件变量 [^3]。 3. **任务调度与事件处理** OSAL 使用任务调度机制来响应按键事件。当按键被检测到按下时,系统会通过 `osal_set_event()` 函数触发对应任务的事件标志,随后由任务的事件处理函数进行具体操作。 ### 常见问题及解决方案 1. **按键检测不灵敏或误触发** - **原因**:可能是定时器间隔过长(如500ms),导致按键检测滞后;或者未进行软件去抖处理。 - **解决方案**:调整 `osal_start_timerEx()` 的时间间隔至100ms左右,并在按键检测函数中加入简单的去抖逻辑,如连续两次检测到按下才认为有效。 2. **按键事件未被正确处理** - **原因**:事件未正确绑定到任务,或任务 ID 分配错误。 - **解决方案**:检查任务初始化函数 `osalInitTasks()` 中的任务 ID 分配是否正确,并确认事件处理函数已注册 [^3]。确保事件发送使用 `osal_set_event()` 并指定正确的任务 ID。 3. **按键事件结构体定义错误** - **原因**:结构体未正确继承 `osal_event_hdr_t` 头部信息,导致事件传递失败。 - **解决方案**:确保结构体定义如 `getName_t` 包含 `osal_event_hdr_t hdr` 作为第一个成员,并在事件发送时使用 `osal_msg_send()` 函数 [^2]。 4. **多按键同时按下处理问题** - **原因**:未设计优先级或冲突处理机制。 - **解决方案**:在按键扫描函数中,增加按键优先级判断逻辑,或在事件处理中加入互斥机制,如只处理第一个被按下的键。 ### 示例代码 以下是一个简单的按键检测任务事件处理示例: ```c // 定义按键事件结构体 typedef struct { osal_event_hdr_t hdr; uint8 key; } keyEvent_t; // 按键检测任务事件处理函数 uint16 keyTaskProcessEvent(uint8 task_id, uint16 events) { if (events & KEY_DETECT_EVENT) { uint8 keyPressed = scanKey(); // 自定义按键扫描函数 if (keyPressed != KEY_NONE) { keyEvent_t *pMsg = (keyEvent_t *)osal_msg_allocate(sizeof(keyEvent_t)); if (pMsg) { pMsg->hdr.event = KEY_PRESSED_EVENT; pMsg->key = keyPressed; osal_msg_send(keyTaskId, (uint8 *)pMsg); } } // 重新启动定时器 osal_start_timerEx(keyTaskId, KEY_DETECT_EVENT, 100); return events ^ KEY_DETECT_EVENT; } if (events & KEY_PRESSED_EVENT) { keyEvent_t *pMsg; while ((pMsg = (keyEvent_t *)osal_msg_receive(keyTaskId))) { processKeyPressed(pMsg->key); // 处理按键按下事件 osal_msg_deallocate((uint8 *)pMsg); } return events ^ KEY_PRESSED_EVENT; } return 0; } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值