完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
本帖最后由 硬汉Eric2013 于 2015-1-4 17:05 编辑 第3章 基于时间触发的混合式调度器 本期教程带领大家学习混合式调度器的设计和使用方法,有了第2期合作式调度器的基础,本期教程的混合式调度器也相对比较容易。 3.1 抢占式调度器介绍 3.2混合式调度器介绍 3.3混合式调度器设计 3.4实验说明 3.5实验总结 3.1 抢占式调度器介绍 在上期教程,我们简单的介绍了抢占式调度器,本期教程再做进一步的讨论,主要集中于抢占式调度器的优缺点的讨论,让大家对抢占式调度器有一个更加深入的了解。 先来说一下抢占式调度器的特性(来自时间触发嵌入式模式这本书,这里说的特性和现在常用的小型RTOS有些区别),进而引出我们要讨论的问题: 抢占式调度器 l 抢占式调度器提供了一种多任务的系统结构 操作: l 任务在特定的时刻被调度运行(以周期性或者单次方式) l 当任务需要运行的时候,被添加到等待队列。 l 等待的任务(如果有的话)运行一段固定的时间,如果没有完成,将被放回到等待队列。然后 下一个等待任务将会运行一段固定的时间,以此类推。 实现: l 这种调度器相对复杂,访问共享资源时,要防止冲突。 l 该调度器必须为强占任务的所有中间状态分配存储器。 l 该调度器通常将(至少部分)由汇编语言编写。 l 该调度器通常作为一个独立的系统被创建。 性能: l 对外部事件的响应速度快 可靠性和安全性: l与合作式任务相比,通常认为更不可预测,并且可靠性低。 使用抢占式调度器最大的好处是对外部事件的快速响应,提高系统的实时性。带来好处的同时也是要付出代价的,下面就举一个例子,这个例子比较典型。 假设系统中的一个任务要从ADC端口读取模拟信号,这时发生了上下文切换,另一个任务也要访问这个端口,在这种情况下如果不采取措施阻止这种情况,数据将可能丢失或者破坏。这种问题往往出现在多任务平台中所谓的“临界段”,这些代码段一旦开始就必须不中断地运行,直到跑完这段代码。临界段还有很多,比如: l 读取或者修改变量(特别是任务间通信的全局变量)的代码,一般来说这时最常见的关键代码。 l 如果读过μCOS-II或μCOS-III源代码的话,会发现里面很多地方都做了开关中断的处理,就是为了防止多任务造成错误。 l 调用公共函数的代码,特别是不可重入的函数,如果多个任务都访问这个函数,结果是可想而知的。 解决这种情况最常用的的办法就是在临界段做开关中断处理,这种情况是最影响实时性的,如果关中断期间发生了外部中断事件,那么这个中断事件只有临界段执行完之后才能得到相应。还有一种解决办法就是使用调度锁,这样在一定程度上能够提供任务的实时性,在发生外部中断的时候会得到相应,但是不会发生任务切换,必须等到调度锁被解开。 关于抢占式调度器和合作式调度器到底谁好,在嵌入式领域没有一个定论,要根据自己的时间应用选择,很多嵌入式领域的专家都发表过这方面的文章,有兴趣的可以找找深入研究下,下面是Michael J. Pont的观点,原话如下: Finally, it should be noted that the reasons why pre-emptive schedulershave been more widely discussed and used may not be for technical reasons atall: in fact, the use of pre-emptive environments can be seen to have clearcommercial advantages for some companies. For example, a co-operative schedulermay be easily constructed, entirely in a high-level programming language, inaround 300 lines of ‘C’ code, as we demonstrate in Chapter 9. The code ishighly portable, easy to understand and to use and is, in effect, freelyavailable. By contrast, the increased complexity of a preemptive operatingenvironment results in a much larger code framework (some ten times the size,even in a simple implementation: Labrosse, 1998). The size and complexity of thiscode makes it unsuitable for ‘in-house’ construction in most situations andtherefore provides the basis for a commercial ‘RTOS’ products to be sold,generally at high prices and often with expensive run-time royalties to bepaid. The continued promotion and sale of such environments has, in turn,prompted further academic interest in this area. 上面这段话的意思是说,抢占式调度器被广泛的讨论和使用的原因可能并不完全是技术上的问题,实际上对于一些公司来说,使用抢占式平台有明显的商业上的好处,这个该怎么理解呢?比如我们做了一款产品,产品的系统是用的μCOS-II。我们肯定会在说明书中宣称我们使用的是μCOS-II系统,因为这个系统已经得到了业界的认可,而不会使用我们自己的设计的系统,用户在购买产品的时候肯定会首选用μCOS-II设计的系统。如果使用合作式调度器,只需要300行左右的C代码就可以实现一个合作式调度器,这些代码的可移植性非常好,易于理解和使用,并且实际上是免费使用的。相比而言,抢占式运行环境增加了复杂性,从而导致更复杂的代码结构。在大多数情况下,这些代码的复杂性和长度使其不适合于普通开发人员自己构建,因此提供了商业实时操作系统的产品的销售基础。抢占式调度器通常价格比较贵,而且还需占用很大的实时开销。这些平台持续不断的宣称和销售反过来又促进了这个领域的更进一步的学术研究。 关于抢占式调度器就跟大家讲这么多,更深入的东西我们会在讲解μCOS-III源码的时候再跟大家分析。 3.2 混合式调度器介绍 合作式调度器为各种嵌入式系统提供了一个可预测的平台。在一些场合可能需要在合作式调度器结构中加入抢占式调度器的一些特性,并小心的加以控制,混合式调度器应运而生。 混合式调度器综合了合作式调度器和抢占式调度器的特性,而且这种方式始终是受控的,不依赖复杂的上下文切换程序,以及任务间复杂的通信机制。下面是混合式调度器的特性: 混合式调度器 l 混合式调度器提供了有限的多任务处理能力。 操作: l 支持多个合作式调度的任务。 l 支持一个抢占式任务(可以中断合作式任务)。 实现: l 这种调度器很简单,用少量代码即可实现。 l 该调度器必须同时为两个任务分配存储器。 l 该调度器通常完全由高级语言(比如”C”实现)。 l 该调度器不是一种独立的系统,它成为开发人员的代码的一部分。 性能: l 对外部事件的响应速度快 可靠性和安全性: l只要小心设计可以和纯碎的合作式调度器一样可靠。 这里所描述的混合式调度器和合作式调度器是有区别的,区别如下: l 不再要求所有任务都在时标间隔之间完成任务。一个(或者更多)的合作式任务的运行时间可以大于时标间隔。 l 与前面讨论的合作式调度器一样,可以调度任意个合作式任务。然而,还可以同时调度一个抢占式任务。 l 抢占式任务可以抢先(中断)合作式任务。 l 一旦抢占式任务开始运行,将一直运行到完成。 同时注意: l 与完全的抢占式解决方案相比,只有一个抢占式任务,而且该任务连续运行直到完成,这将及大地简化系统的结构。尤其是不需要实现上下文切换的机制。这意味着:1. 该结构仍然十分简单。2. 运行环境可以全部由C实现。 l 和完全的抢占式调度器相比,简化了任务间的通信。 l 应该只有一个短任务(最长的运行时间大于为时标间隔的%50,尽可能的短)可以强占运行,否则将削弱系统的整体性能。 下面详细讲一下混合式调度器的设计,这样大家会有一个更好的认识。 3.3 混合式调度器设计 上期教程我们讲解了合作式调度器设计,只要稍作修改就可以改为混合式调度器。可以看到,很多设计人员使用混合式设计仅仅是因为它很容易实现,这通常是错误的。因为在混合式调度器中已经没有了合作式的调度特性,这可能对设计过程和以及最终系统的可靠性带来深远的影响,在使用混合式调度器的时候,大家要特别注意这点。 混合式调度器主要由以下几部分组成: l 调度器数据结构 l 初始化函数 l 嘀嗒定时器中断,用来以一定的时间间隔刷新调度器 l 向调度器增加任务函数 l 使任务在应当运行的时候被执行的调度函数 l 从调度器删除任务的函数(此功能未做) 下面就把这几方面的设计详细讲述下。 3.3.1 调度器数据结构 调度器的数据结构如下:
任务队列的大小通过下面进行定义:
建立任务的时候要注意不能超过这个最大任务数。 3.3.2 初始化函数 这里的初始化函数主要是指滴答定时器的初始化,以此来产生调度器所需要的时标。一般情况下把时标间隔都设置为1ms。关于嘀嗒定时器方面的知识已经在前面第10章: SysTick实验有详细的讲解,这里就不再赘述了,只把初始化函数贴出来:
刷新函数的主要功能是:每个时标中断执行一次,在嘀嗒定时器中断里面执行。当刷新函数确定某个合作式任务要执行的时候,将这个任务结构体的成员RunMe加1,要注意的是刷新任务不执行任何合作式任务,这里只是设置 一下RunMe标志,由调度函数根据此标志执行相应任务。抢占式任务需要执行的话,立即就会得到执行。 下面是具体的函数代码: 3.3.4 添加任务函数
添加任务函数的主要功能是将任务添加到任务队列上,下面主要是说一下这个函数中参数的功能: tByte hSCH_Add_Task(void (*pFuntion)(void), tWord DELAY, tWord PERIOD, tByte Co_op); 1. void (*pFuntion)(void) :表示函数的地址,也就是将函数名填进去就行了。 2. DELAY :表示函数第一次运行需要等待的时间。 3. PERIOD:表示函数周期性执行的时间间隔 4. Co_op:混合式调度和合作式调度的区分 合作式用1表示抢占式用0表示 举四个例子说明一下: l hSCH_Add_Task(DOTASK,1000, 0, 0) 抢占式任务,DOTASK是函数的运行地址,1000是1000个时标以后开始运行,只运行一次。 l hSCH_Add_Task(DOTASK,0, 1000,0) 抢占式任务,DOTASK是函数的运行地址,每个1000个时标周期性的运行一次。 l hSCH_Add_Task(DOTASK,300, 1000, 1) 合作式任务,DOTASK是函数的运行地址,300是300个时标以后开始运行,以后就是每1000个时标周期运行一次,也就是说运行时刻是300,1300,2300,3300,4300等等。 l Task_ID= hSCH_Add_Task(DOTASK,1000,0); Task_ID是任务标示符,将任务标示符保存以便以后删除任务。 下面是函数的源代码: 3.3.5 调度函数
在前面已经说过,刷新函数不执行任何合作式任务,需要运行的任务由调度函数激活。下面是调度函数的源码:
有上面的五步,一个简单的合作式调度器就算设计完成了。 3.4 实验说明 本期教程配套的实验是:基于时间触发的合作式调度器,工程中需要添加如下驱动: 3.4.1 实验一:基于时间触发的混合式调度器 实验目的: 1. 学习基于时间触发的混合式调度器。 实验内容: 1. 通过函数hSCH_Add_Task添加三个任务 hSCH_Add_Task(bsp_KeyScan,0, 10, 1); /* 按键扫描合作式任务, 周期10ms */ hSCH_Add_Task(AppTask_KeyScan, 0, 4,1); /* 执行按键打印合作式任务 周期4ms */ hSCH_Add_Task(AppTask_LedToggle,0, 500, 0); /* 四个LED闪烁抢占式任务 周期500ms */ 2. 主程序不断执行hSCH_Dispatch_Tasks();刷新函数。 实验现象: 四个LED灯实现每500ms闪烁一次,按下3个按键中的某一个,或者五向摇杆会打印如下信息: 程序设计: 本程序主要分为四个部分: Ø 混合式调度器的设计 Ø 混合式调度器的初始化 Ø 任务API Ø 主程序 下面将这四个部分讲述一下: 1. 混合式调度器的设计 这个已经在前面的1.2小节详细进行了说明,这里就不再赘述了。 2. 混合式调度器的初始化 这里主要是时标间隔的初始化(这个放在了主函数里面实现,也就是嘀嗒定时器的初始化)和任务函数的添加,源代码如下:
3. 任务API 主要是按键任务和LED闪烁任务,按键扫描任务就不说了,这个在前面按键FIFO里面有详细的讲解。
4. 主函数 主函数比较简单,主要是在大循环里面调用调度函数。
3.5 实验总结 为了更好的使用混合式式调度器,这里简单的总结写使用注意事项: l 建立数量满足要求的混合式任务,很可能因为一个或者多个任务的运行时间大于时标间隔,所以需要使用混合式调度器。混合式调度器的使用是安全的,然而必须的保存任务不重叠。 l 实现一个抢占式任务,这种任务一般在每个时标间隔调用,这种任务常用来检测错误或者紧急事件。 l 抢占式任务可以中断合作式任务。 l 抢占式任务必须的简短,运行时间最多不能超多时间间隔%50,否则将极大的削弱系统的性能。 l 在所有的状态下仔细测试该系统,检测错误。 关于时间触发方式的调度器设计,就跟大家讲这么多,有兴趣的可以查阅相关资料做深入的了解。 参考资料: 1. Patterns fortime-triggered embedded systems英文版和中文版 |
|
相关推荐
|
|
|
|
|
|
|
|
590 浏览 0 评论
AI模型部署边缘设备的奇妙之旅:如何在边缘端部署OpenCV
2241 浏览 0 评论
tms320280021 adc采样波形,为什么adc采样频率上来波形就不好了?
1233 浏览 0 评论
1788 浏览 0 评论
1464 浏览 0 评论
74851 浏览 21 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 12:53 , Processed in 0.455999 second(s), Total 38, Slave 30 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号