利用Protothread实现实时多任务系统.doc_第1页
利用Protothread实现实时多任务系统.doc_第2页
利用Protothread实现实时多任务系统.doc_第3页
利用Protothread实现实时多任务系统.doc_第4页
利用Protothread实现实时多任务系统.doc_第5页
已阅读5页,还剩2页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

在许多系统资源非常紧张的单片机应用中,使用实时操作系统进行任务调度来实现实时多任务系统时,由操作系统带来的系统开销往往是不可接受的。通过升级硬件来改善系统资源紧张,意味着成本的增加,降低产品的竞争力。本文介绍采用Protothread在非常小的系统开销下实现实时多任务系统的方法。关键词 Protothread 实时 多任务 线程模型嵌入式程序框架一般类似于程序1所示结构:系统中有3个任务TaskA、TaskB、TaskC,均放置于主循环内,在每一个循环周期内都被执行一次。在这种结构中,能满足系统实时性要求的条件是:(当且仅当)TaskA 、TaskB、TaskC三个任务的运行时间之和要小于系统实时响应的时间要求。在系统较为简单、任务运行时间能满足实时要求的情况下,可以采用这种最简单、最直接的顺序执行方式。但是更多的情形是,系统不仅要对一些事件做出实时响应,并且还要承担很多其他的非实时任务,并且这些非实时任务的运行时间要远远超出了实时响应时间的要求。传统的这种程序结构显然不能满足系统的实时性要求。通常的解决方案是,引入实时操作系统,由操作系统进行任务的调度,优先执行实时任务,达到满足系统实时性的要求。程序1嵌入式程序框架void main(void) Init();while(1) TaskA();TaskB();TaskC();void Interrupt_1(void) interrupt 1 void Interrupt_2(void) interrupt 2 一般来说,在嵌入式系统开发中引入实时操作系统有诸多优点: 更好地支持多任务,实时性要求能够得以保障; 程序开发更加容易,也更便于维护; 有利于提高系统的稳定性和可靠性。但是,操作系统的引入也将带来较多的系统开销: 实时操作系统往往使用定时器中断来切换任务,需要消耗不少的CPU处理时间; 实时操作系统在切换任务时需要保护当前任务的执行现场,这就需要为每个任务准备足够多的RAM空间来实现任务切换; 实时操作系统的本身也需要占用相当数量的Flash空间和RAM空间。如果这些系统开销都在可承受的范围内,那么采用实时操作系统将是最佳的选择。但是在很多应用的场合,特别是系统的资源非常紧张的单片机应用,实时操作系统带来的系统开销往往是不可接受的。而更换速度更快、RAM更大、Flash更多的CPU意味着成本的增加,且会降低产品的竞争力。当系统中的任务不须进行非常复杂的优先级调度,而且其任务也相对简单时,引入实时操作系统似有杀鸡用牛刀之嫌。1 Protothread的特点Protothread是专为资源有限的系统设计的一种耗费资源特别少并且不使用堆栈的线程模型,其特点是: 以纯C语言实现,无硬件依赖性; 极少的资源需求,每个Protothread仅需要2个额外的字节; 可以用于有操作系统或无操作系统的场合; 支持阻塞操作且没有栈的切换。使用Protothread实现多任务的最主要的好处在于它的轻量级。每个Protothread不需要拥有自已的堆栈,所有的Protothread共享同一个堆栈空间,这一点对于RAM资源有限的系统尤为有利。相对于操作系统下的多任务而言,每个任务都有自已的堆栈空间,这将消耗大量的RAM资源,而每个Protothread仅使用一个整型值保存当前状态。2 Protothread的阻塞运行机制以下是一个典型的Protothread程序示例:程序2Protothread程序示例PT_THREAD(radio_wake_thread(struct pt *pt) PT_BEGIN(pt);while(1) radio_on();timer_set(&timer, T_AWAKE);PT_WAIT_UNTIL(pt, timer_expired(&timer);timer_set(&timer, T_SLEEP);if(!communication_complete() PT_WAIT_UNTIL(pt, communication_complete()timer_expired(&timer);if(!timer_expired(&timer) radio_off();PT_WAIT_UNTIL(pt, timer_expired(&timer);PT_END(pt);这是一个非常简单的无线通信的状态切换程序,展开Protothread的宏定义,便可以得到程序3所示的展开代码:程序3Protothread宏展开代码void radio_wake_thread(struct pt *pt) switch(ptlc) case 0:while(1) radio_on();timer_set(&timer, T_AWAKE);ptlc = 8;case 8:if(!timer_expired(&timer) return;timer_set(&timer, T_SLEEP);if(!communication_complete() ptlc = 13;case 13:if(!(communication_complete() |timer_expired(&timer) return;if(!timer_expired(&timer) radio_off();ptlc = 18;case 18:if(!timer_expired(&timer) return;当Protothread程序运行到PT_WAIT_UNTIL时,判断其运行条件是否满足,若不满足,则阻塞。通过比对程序2和程序3的程序代码可以得知,Protothread的阻塞其实质就是函数返回,只不过在返回前保存了当前的阻塞位置,待下一次Protothread被调用时,直接跳到阻塞位置执行,再次判断运行条件是否满足,并执行后续程序或继续阻塞。3 利用Protothread构造实时多任务系统与操作系统下的多任务不同,操作系统下的每个任务可在任意时刻被打断并阻塞,Protothread仅能在程序员指定位置阻塞。用Protothread实现实时多任务,正是利用了Protothread在指定位置阻塞的特点,让出执行权限给更高优先级的任务先运行。下面举例说明如何利用Protothread构造实时多任务系统。系统要求:TaskA实时任务,30 ms内响应,运行时间20 ms;TaskB实时任务,200 ms内响应,运行时间30 ms。设计思路:将TaskB和TaskC分成若干步,每步运行时间不超过10 ms(这个时间可视系统需求而定,例如TaskA若为40 ms内响应,则每步可扩至20 ms)。任务以3个Protothread的方式运行。首先执行TaskA,在TaskA执行完成1次后,释放执行权限,让TaskB和TaskC执行。TaskB或TaskC在每执行1步之前检查运行时间,一旦发现30 ms内不够执行1步时,阻塞运行,让出执行权限给TaskA。同样,TaskB和TaskC的调度关系也类似,先运行TaskB,完成时释放执行权限,让TaskC执行;TaskC在每执行1步之前检查运行时间,若发现200 ms内不够执行1步时,阻塞运行,让出执行权限重新交给TaskB。源程序(Task0TimeCounter、Task1TimeCounter为计数器,每毫秒加1):#include ptsem.h#define TASKA_MAX_RUN_TIME20#define TASKA_CYCLE_TIME30#define TASKB_CYCLE_TIME200#define TASK_STEP_TIME10#define TASK0_VALID_TIME TASKA_CYCLE_TIMETASK_STEP_TIME#define TASK1_VALID_TIME TASKB_CYCLE_TIMETASK_STEP_TIMETASKA_MAX_RUN_TIME *2/*按照PT_WAIT_UNTIL 的宏定义扩展一个新宏:当程序进入阻塞时发送一信号,告知高优先级任务获得执行权限*/#define LC_STEP_SET(s,n) s = _LINE_ + n; case _LINE_ + n:#define PT_SEM_WAIT_UNTIL(pt, s, condition, n)do LC_STEP_SET(pt)lc,n);if(!(condition) if(s)count=0)PT_SEM_SIGNAL(pt,s);return PT_WAITING; while(0)struct pt TaskAPt;struct pt TaskBPt;struct pt TaskCPt;struct pt_sem SemRunTaskA;struct pt_sem SemRunTaskB;/*若30 ms内已经不够时间执行1步,则让出TaskA的执行权限*/#define TASKB_STEP(pt) PR_SEM_WAIT_UNTIL(pt, & SemRunTaskA,TaskOTimeCounter=TASKO_VALID_TIME,0)/*若200 ms内已经不够时间执行1步,则让出TaskB的执行权限*/*若30 ms内已经不够时间执行1步,则让出TaskA的执行权限*/#define TASKC_STEP(pt) PT_SEM_WAIT_UNTIL(pt, &SemRunTaskB,Task1TimeCounter=TASK1_VALID_TIME,0);PT_SEM_WAIT_UNTIL(pt, &SemRunTaskA,Task0TimeCounter=TASK0_VALID_TIME,1)int ProtothreadTaskA(struct pt *pt) PT_BEGIN(pt);PT_SEM_WAIT(pt, &SemRunTaskA);/*等待其他任务让出执行权限*/ResetTask0TimeCounter;/*对时间计数器置0*/TaskA();/*TaskA任务*/PT_END(pt);int ProtothreadTaskB(struct pt *pt) PT_BEGIN(pt);PT_SEM_WAIT(pt, &SemRunTaskB);/*等待TaskC让出执行权限*/ResetTask1TimeCounter;/*对时间计数器置0*/TASKB_STEP(pt);/*如果不够1步执行,则阻塞,让出执行权限*/TaskB_1();/*TaskB任务的第1步*/TASKB_STEP(pt);TaskB_2();/*TaskB任务的第2步*/TASKB_STEP(pt);TaskB_3();/*/PT_END(pt);int ProtothreadTaskC(struct pt *pt) PT_BEGIN(pt);TASKC_STEP(pt);/*如果不够1步执行,则阻塞,让出执行权限*/TaskC_1();/*TaskB任务的第1步*/TASKC_STEP(pt);TaskC_2();/*TaskB任务的第2步*/TASKC_STEP(pt);TaskC_3();/*/TASKC_STEP(pt);TaskC_4();PT_END(pt);void main(void) /*系统初始化*/PT_INIT(&TaskAPt);PT_INIT(&TaskBPt);PT_INIT(&TaskCPt);PT_SEM_INIT(&SemRunTaskA,1);PT_SEM_INIT(&SemRunTaskB,1);/*运行任务*/while(1) ProtothreadTaskA(&TaskA

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论