UCOSII的3d touch 多任务切换是怎么切换的呢

ucos&ii的任务在何时切换
刚才在做实验的时候,发现:当有一个任务没有进入延时的时候,这个任务就会一直执行不会挂起。就算有高优先级的任务已经准备好了,得等低优先级的任务执行完,或处于就绪态的时候,才能响应高优先级的的任务。所以任务里必须要有ucos
ii系统里的延时函数,否则,没有延时函数的某优先级的任务会一直执行。
有人会想到,不用ucos ii系统里的延时函数可不可以?例如用:
while(x--);
这种延时的方法。
这个,虽然有延时的效果,但系统默认为语句的执行而已,并不能使该任务在进入延时的时间里释放CPU的控制权。
大家都知道,进入延时的时候,该任务并没有对任何的外设进行控制,所以延时对于CPU来说是浪费资源,但在延时的时候能让CPU去执行其它的任务或做其它的操作,那就能达到高效利用CPU的资源。当该任务的延时时间到的时候,该任务就会处于就绪态,这样就由任务的高低决定是否马上返回到该任务来。
所以,想执行多个任务的时候,就必须利用系统里的延时函数,否则多个任务就变得无意义了。
但有一种情况比较特殊,当在一个任务里创建另一个任务时(不管被创建的任务的优先级怎样),系统会将当前任务挂起,执行被创建的任务,当被创建的任务因为被阻塞或延时被挂起时,才会跳回当前的任务继续执行。所以当一个任务处于就绪态时,执行它的情况,目前本人碰到两种情况:
1、它并不在正在执行的低优先级的任务里创建,所以只有当它是处于就绪态的最高优先级的任务时,低优先级的任务被挂起后,才被执行。
2、任务A被任务B创建时,系统会马上挂起任务B,转而去执行任务A,只有当任务A被阻塞或延时被挂起时,系统将会执行处于就绪列表里的最高优先级的任务。
如果当前任务利用OSMutexPend(mutex,0,&err)函数申请互斥信号量时,如果该互斥信号量被占用;那么系统将会把当前任务挂起,然后执行最高优先级的任务。
注意:当高优先级的任务挂起的时间不够时,处于就绪态的低优先级的任务将得不到CPU的使用权,可能被创建后,就一直在就绪列表时,但不能被执行。
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。uCOS-II中的任务切换机制 - apollius - 博客园
【@.1 函数周期与死循环】
一般函数的生命周期很简单,从开始调用函数起,直到函数返回,即结束。这样一来就完成了这个函数的使命,它也就不再需要了。对于一般的函数就是这样,但是回过头想想,对于一个系统、OS、或者工业控制中的一个控制器重的系统个,函数返回是很轻易很随便的就能返回吗?返回就意味着函数结束,死亡,若是想系统这样一个很大的函数,它的返回就意味着系统结束。因此,对于系统的函数返回有些时候我们不希望它返回,返回时是需要好好设计的,像嵌入式中的控制程序我们也并不需要它返回,直接关机就好了。因此,一个系统往往就是一个很大的循环,不停的扫描,而我们编程的时候对于这个死循环是需要好好设计的。考虑以下一个控制要求,
@.按键控制电机启、停、正转反转,并每秒发送CAN报文报告当前情况。
我们可以有多种方法实现这一要求:
方法一:每次在循环体重扫描当前按键的电平,从而进入对应的控制电机函数,如果所有电平都没有信号则直接进入下一个循环。发送CAN报文就直接用一个定时中断。这样的好处就是编程简单直白,每次循环进入不同的电机控制函数,坏处很明显,一定要等待到下一个循环才能进入其他的电机控制函数,每次循环的时间不好控制,不管你用函数指针还是if/else来判断,每次循环一定要等待电机动作结束才能进入下一个循环。
方法二:改用外部中断来处理按键。仅当按键按下时触发外部中断,从而控制响应的电机进行操作。这样的好处就是循环体简单,可以仅仅就是一个计数器加一,所有控制都等中断来实现。但这样带来的问题也很明显,就是中断嵌套问题。比如当电机正转时按下停止按钮,这时由于是在中断中,停止按钮是否真的能够得到响应?这就涉及到中断嵌套问题,并不见得所有CPU都能支持中断嵌套,我的对中断嵌套问题进行了一个讨论。
方法三:采用RTOS的思想,加入任务调度系统。每次任务调度系统就是一个小小的循环,对于各个任务进行轮询,当这次轮询发现某任务是已经就绪的优先级最高的任务,则交给CPU处理,所有中断与任务,任务与任务之间有通讯机制可以交换信息。当然实际上并不仅仅只在任务调度器轮询时才进行任务的切换,实际上的操作比这个复杂一些,我的这篇文章就想以uCOS-II为例讨论RTOS的任务调度系统是怎样执行的。
【@.2 uCOS-II中的任务调度】
回到前面的方法一,二,我们将这种任务称作前后台任务。
后台就是指程序的大循环,程序一定要等到前台任务(可以说中断或某个功能函数)返回才能继续运行下去。而在RTOS中每个任务都有自己的控制块指向改任务,由任务调度器来决定这个时候该运行哪个任务。
所有这些任务控制快(TCB)构成一个双向链表,每个TCB中都有一些控制字,比如一个指向堆栈的指针(*sp),一个表明当前任务状态的位(State),指明任务被挂起等待的超时时间(dly),任务的优先级(Prio),指向事件控制块的指针(*Event,事件机制后面会讨论)。一个全局的任务就续表记录了当前任务是否就绪,任务调度器就靠查询任务就绪表寻找到就绪任务中优先级最高的一个任务。
每一个任务都是一个死循环,并且必须在循环内调用系统函数来释放CPU控制权,比如调用系统的延时函数OSTimeDly()延时一段时间,这个时候系统就会知道这个任务被延时了,延时时间记录在TCB中的超时时间dly中,任务调度器将其他任务予以运行。
实际的任务调度有两种机制
1.中断级任务调度:任何中断返回时必须调用一个系统函数OSIntExit(void),进行一次任务调度。比如一般任务调度器通常是一个定时中断,比如1000次每秒,成为OS时钟。每次OS时钟要返回时都会调用OSInitExit()进行任务切换,运行当前就绪的优先级最高任务。一般这个OS时钟的优先级很低,为整个系统优先级倒数第二低(倒数第一低的是Idle Task,空闲任务),因此实际上这个OS时钟最终并不会返回。
2.任务级任务调度:在任务运行中执行一次OS的特定函数,比如前面提到的OSTimeDly(),此函数在返回之前会执行一次任务调度。
因此总的任务调度次数会远远高于OS时钟的轮询频率的。
我们下面举例来说明这两种调度机制:
【@.3 中断级任务调度】
当OS时钟的定时中断来临时(比如1000次每秒),会进入OS时钟的服务函数,它会做大致一下工作,递增一个全局的计数器OSTIme,遍历所有OSTCB链表,将其中的dly超时时间递减,若等于0,则在就绪列表中置位。最后这个中断要返回时会调用OSInitExit(),它会找到在任务就绪表中处于就绪状态的最高优先级的任务,并且调用OSInitCtxSw(),即上下文切换,将之前找到的任务放在任务堆栈中的寄存器推入到CPU的R0~R15,CPSR中,最后结束。这里的这个OSInitCtxSw(),上下文切换函数是实际上跟CPU打交道的函数,也是移植uCOS-II需要编写的函数。
任何中断返回时都必须调用这个OSInitExit(),不管是外部中断,定时器中断,串口中断。当然,我们可以在实际编写中将这一中断过程编写一个统一模板,调用中断服务实际函数。这是后话了。
【@.4 任务级任务调度】
这种调度方式实际上丰富了任务之间的通讯机制以及任务的控制,也是最需要理解的一种方式。主要的流程跟中断级方式类似,不过是需要在任务中调用一些特定的系统函数。实际的任务切换函数是OSSched(),会调用实际的上下文切换函数OS_TASK_SW()。这个函数往往跟中断级的上下文切换函数是一样的,我们移植时只需要编写一个函数即可。下面以几个具体的函数为例进行讲解:
1.OSTaskResume/ OSTaskSuspend
首先是一个比较好理解的OSTaskSuspend()和OSTaskResume(),直接控制任务的挂起和恢复。对于图中的TaskA,在任务运行到某处调用OSTaskSuspend()之后,会挂起就绪表中优先级为prio的任务x(优先级也就是这个函数的传入参数)。之后调用OSSched,进行任务切换。若挂起的是自己,即调用OSTaskSuspend时传入的优先级是自己的,则自身被挂起,函数不返回;若挂起的是别的任务,那么别的任务就直接被挂起,当前函数返回。
另一个任务TaskB中调用OSTaskResume(),将首先在置位表中置位优先级为prio的任务,之后交给OSSched()进行任务切换,之后就是一个优先级的判断问题,若恢复的任务比自己任务高,那么自己被挂起,高优先级任务运行;若被恢复的任务优先级低于自己,则函数自己函数返回,继续运行,直到TaskB运行到其他函数释放CPU控制权。所以像TaskB这样的任务中还需要包含一个其他的函数,比如OSTimeDly来释放CPU。
最后,若恢复的任务是自己,很明显是没有意义的。
2.OSSemPost/OSSemPend
在通讯机制上uCOS-II利用事件管理块(ECB)统一进行处理,其中信号量是最基本的一种方式,可以起到共享资源单独访问和任务间同步的功能。
我们建立一个信号量,类型为OS_EVENT的指针,其内部包含了一个事件等待表,记录着等待该事件(也就是Sem自身)的所有任务,当某一任务等待此信号量时,在它的事件等待表上相应优先级置一。若任务TaskA调用了OSSemPend()等待一个信号量,此函数会调用OS_EventTaskWait,一个内部的事件等待函数。图中表明了此函数的流程,首先会建立任务A的TCB与此信号量Sem之间的链接,即TCB中的Event指针指向Sem。之后清楚任务就绪表中的相应位,再将Sem中的事件等待表置一,OS_EventTaskWait之后会调用OSSched进行实际的上下问切换,此时由于之前的一些列操作将导致这个时候任务会被挂起,只能等待其他任务(或等待超时)将其重新恢复成就绪状态。
调用OSSemPost时的流程如下
OSSemPost会调用OS_EventTaskRdy,图中可以看出这个函数的流程,首先从Sem的等待事件列表中寻找到等待该事件的优先级最高的任务。可能同时有多个任务在等待此信号量,假如其中优先级最高的寻找结果就是前面的TaskA,则接下来将切断此任务的TCB与ECB的联系,并且在任务就续表中置位此任务。OS_EventTaskRdy返回之后将进入OSSched,将根据前面的一些列操作进行任务调度,当然,若发送信号量后接收方(TaskA)的优先级大于发送方(TaskB),则TaskB自身被挂起,运行TaskA;反之,TaskB继续运行。
这种信号量的发送/接收机制适用于任务同步,共享资源的独占,比如:
上图中所示,当TaskA调用Pend接收到信号量Sem时执行foo函数,此时TaskB在Pend处,不管怎么调度也不会执行foo函数,直到TaskA运行到Post处时才有可能执行下去。这样就防止了同一时间有两个任务同时处理共享资源(这里是函数foo())。
另一种情况如上图示,Post一方由一个任务或一个中断服务函数调用,接受的一方由另一个任务调用Pend。只有当发送方Post这个信号量之后,接收方Pend处才有可能继续往下运行。
注意:这点跟OSTaskResume恢复一个任务很像,但是还是有区别,一旦Resume一个任务这个任务就一直运行下去了,但是Post一个信号量之后含有Pend的任务执行一次,之后到进入任务的下个循环继续Pend,只有等新的一次Post了之后才能继续运行。
3.OSFlagPost/OSFlagPend
信号量集的发送和接受,也是一种多信号的集体通讯方式,这里不详细讨论,只举例简单说明其作用
图中所示TaskA和TaskB共同控制TaskTarget,只有当TaskA,B都发送了信号之后,TaskTarget才得以运行。实际上这种信号集的机制还可以有其他的逻辑关系可以配置,比如发送方中任意一个发送任务之后就可以让接收方运行。
【@.5 任务调度总结】
先简单的利用前面的内容,回过头来看文章一开头的任务,搭建一个完整的电机控制系统。这里我们利用uCOS-II中的通讯机制进行设计。
例:带按键去抖的电机控制任务:
四个外部中断控制电机的启停,正转反转。外部中断服务函数中Post一个信号量给一个专门的电机调度任务,电机调度任务之后Post一个信号量给按键去抖任务,此任务会利用OSTimeDly函数延时一段时间,比如说20ms,再次判断刚才按键的电平值,若任然有按键值则说明不是抖动,可以控制电机,之后利用Resume,恢复一个电机转动的实际任务。
Post信号量启用一个任务跟Resume恢复一个任务是区别很大的,最大的区别是,Post信号量之后只能让接收方运行一次,必须不停的Post才能不停的运行,而Resume一个任务之后,被恢复的任务将一直运行,只能用Suspend将其再次挂起。
下图表明了任务状态之前切换的关系,调用哪种函数可以进行任务切换。uCOS-II就是通过这些直接或间接调用的系统函数进行任务切换的。
@.[FIN]      @.date-&Mar 28, ;     @.author-&apollius房地产估价师考试备战已经开始,为了方便考生进行全面备考,小编特别对房估考生如何进行报考、备考提出了建议,并对重点预习知识、考试大纲与笔记画重点。房地产估价师职业前景可是大好,做好考试准备,事半功倍。
在此可输入您对该资料的评论~
(window.slotbydup = window.slotbydup || []).push({
id: '4540180',
container: s,
size: '250,200',
display: 'inlay-fix'
热门资料排行
添加成功至
资料评价:
所需积分:2查看: 8884|回复: 0
uC/OS-II学习笔记—任务的调度和多任务的启动
&&uC/OS-II操作系统是实时操作系统,而且是基于优先级调度的实时操作系统,因此在启动多任务以后,每个时钟中断都要执行任务的调度。至于如何实现时钟中断,对于不同硬件环境是不同的。如果时间片是20ms,那么每20ms执行一次任务调度。这个任务调度的函数就是OSTimeTick。OSTimeTick是与硬件无关的,代码如下所示:
001642hpw9c0pd9bpizbpp.png (17.46 KB, 下载次数: 32)
01:57 上传
vnj9.png (46.16 KB, 下载次数: 22)
01:57 上传
w5w1dppf1kfp8.png (15.89 KB, 下载次数: 22)
01:57 上传
从操作系统的初始化函数OSInit来看,我们创建的第一个任务是空闲任务。然后每次创建的新任务都是将该任务的TCB插入到就绪链表的表头,而空闲任务不允许被删除。因此,在就绪链表中,最后一个TCB永远是空闲任务的。所以,while循环从就绪链表的表头开始,一直到空闲任务为止,遍历了除空闲任务之外的所有任务。
OSTCBStat中的各个位的意义如下所示:
001645efbkq7kfdkef6dfr.png (11.49 KB, 下载次数: 22)
01:57 上传
在这里,看到了我们熟悉的挂起,在从低到高的第4位,如果从0位开始算,是位3。
相关的宏定义如下所示:
001645bbdehboobicd4w3l.png (20.93 KB, 下载次数: 23)
01:57 上传
001646gczvrnv5rtcubqqs.png (2.37 KB, 下载次数: 18)
01:57 上传
很明显,只要任务在等待任何一个事件发生,那么OS_STAT_PEND_ANY的值都不会是OS_STAT_RDY。因此,这个条件判断语句的含义就是,如果任务在等待任何一个事件的发生(信号量、邮箱、队列、互斥信号量、标志),就执行下面的操作,判断是否延迟结束等。 任务可能因为等待事件而处于阻塞态,但是阻塞态的任务的控制块仍然在就绪链表中,而并非由一个阻塞链表。任务等待事件发生的时候,可以设定或不设定超时时间。如果设定了超时时间,那么时间到了就算事件仍没有发生,也不再等待了,这样可以避免死等。
因此,结合带啊,调度器遍历每个任务,如果任务被设置了时间延时,那么就将延时时间减1.不论是等待事件发生的任务,还是单纯等待一段时间的任务,只要不是被挂起的任务,延时时间到了就要使任务进入就绪态。使任务进入就绪态的方法也就是就绪组和就绪表的操作。
OSTimeTick在每个时间片开始的时候有规律地被操作系统调用,将对延时的任务修改延时时间,然后设置哪些任务就绪,但是还没有真正进入任务的切换。
就绪的任务获得CPU才能运行。任务切换函数就是执行这样的操作系统服务功能:如果正在运行的任务不是优先级最高的或即将被阻塞,需要选择一个优先级最高的就绪的任务运行。该过程中非常重要的一点是,要保留正在运行的上下文,也就是运行环境,如cPU寄存器的值,以便在任务重新开始运行之前能恢复CPU寄存器的值。当然还要将要运行任务的上下文恢复到CPU寄存器。
因此,任务切换函数式设计硬件操作,是和CPU类型密切相关的,因此对不同的系统,实现的代码必然不同。任务切换函数是OS_Sched,在OS_Sched中还要调用与CPU无关的函数OS_SchedNew和与CPU密切相关的代码OS_TASK_SW。OS_Sched与OS_SchedNew写在os_core.c中,与CPU密切相关的代码OS_TASK_SW则写在os_cpu.c中。
首先来看一下OS_SchedNew,这个函数被其他uC/OS-II系统服务调用,用来确定最高优先级的就绪任务。该函数运行的结果就是给全局变量OSPrioHighRdy赋值。显然,OSPrioHighRdy是最高的优先级任务。
代码如下所示:
001647gvivvzjgksekk2k1.png (29.88 KB, 下载次数: 18)
01:57 上传
代码很简单,找到优先级最高的就绪任务,将该任务的优先级赋值给OSPrioHighRdy。
在OS_Sched代码中将调用OS_SchedNew来找到最高优先级的任务。
代码如下所示:
uzgupf0c4my49a.png (24.85 KB, 下载次数: 32)
01:57 上传
可见,OS_Sched首先判断是否可以进行任务切换,如果中断服务程序没有完成,或者是调度器被上锁,或当前运行的任务正是优先级最高的,那么都不会进行任务切换。当需要进行任务切换时,OS_Sched首先增加将要被换入CPU的任务的被调用次数OSTCBCtxSwCtr,然后是整个操作系统的任务切换的次数OSCtxSwCtr。最后调用OS_TASK_SW完成任务切换。从中可以看出,OS_TASK_SW应该是真正进行任务切换的地方。
一切都准备好了,将进行任务的最终切换,OS_TASK_SW首先将CPU寄存器中的内容压入被换出的任务的堆栈中,然后将被换入的任务的堆栈中的内容弹出到CPU寄存器。需要知道的是,这些寄存器是任务运行的环境,在任务被换出,再换回继续执行的时候,寄存器的值不能发生变化,否则程序的运行会产生错误的结果,有些结果甚至是灾难性的。
OS_TASK_SW的代码实现如下所示:
001649ykq3i0tq0k96hhet.png (2.15 KB, 下载次数: 16)
01:57 上传
可以看到OS_TASK_SW()等同于OSCtxSw()。OSCtxSw的定义如下所示:
i2pnioorpzpt.png (10.92 KB, 下载次数: 25)
01:57 上传
可以看出这是一段汇编代码,执行的主要操作是触发PendSV中断,那接下来看一下PendSV中断的服务程序:
jjj3i729uffcz.png (111.09 KB, 下载次数: 16)
01:57 上传
PendSV中首先关闭中断,然后判断PSP的值是不是0,如不是0就将没有自动保存的寄存器r4~r11压入到堆栈中,然后将PSP的值更新到OSTCBCur-&OSTCBStkPtr中。如果是0就说明之前没有任务运行,所以不要保存。然后调用OSTaskSwHook()。然后执行OSPrioCur = OSPrioHighR然后执行OSTCBCur&&= OSTCBHighR 然后取得最高优先级任务的TCB,进而得到它的堆栈地址。然后把R4~R11的值从堆栈中恢复。然后,更新PSP的值。然后将LR的bit3置位,然后使能中断,最后中断返回。
uC/OS-II作为实时多任务操作系统,在每个时钟滴答进入时钟中断服务程序,如果有比目前运行的任务更高优先级的任务就绪,在需要的时候进行一次任务调度。这个任务调度函数并不是前面的OS_Sched,而是OSIntExit。
在时钟中断的时候,紧接着OSTimeTick,操作系统调用OSIntExit实现任务的切换,程序如下所示:
001832hauuy9lt55507y0y.png (30.43 KB, 下载次数: 23)
01:57 上传
可见,OSIntCtxSw()才是真正在中断程序中进行实际的任务切换的地方,OSIntExit与OSSched类似,进行了全局变量的配置,决定是否进行任务切换。那么OSIntCtxSw很明显也将在os_cpu.c中实现,原因是也要进行与CPU密切相关的操作,相关程序如下所示:
001833eftiwnavpf7akt8s.png (12.57 KB, 下载次数: 30)
01:57 上传
可见,在中断处理过程中的任务切换和普通的任务切换时相同的。
多任务启动的代码是内核中的OSStart函数,在运行OSStart之前,必须已经执行了操作系统初始化函数OSInit,并且至少创建了1个以上的任务。OSStart的代码如下所示:
001834jbhh8bb.png (26.8 KB, 下载次数: 20)
01:57 上传
可见,OSStart先找到优先级最高的就绪任务,然后对OSPrioCur赋值为该任务的优先级,将OSTCBHighRdy及OSTCBCur赋值为该任务的TCB地址,之后就调用OSStartHighRdy来启动多任务。因此,核心的代码还在OSStartHighRdy。OSStartHighRdy启动多任务又是和硬件有关的,因此该代码在os_cpu.c中,对于不同的硬件平台,该代码必然不同。
l7yyl0fd0l5vk5.png (95.77 KB, 下载次数: 26)
01:57 上传
汇编的代码和恢复任务的时候如初一辄,从堆栈中取出任务的地址运行任务!而任务的地址在创建任务时的堆栈初始化的时候已经准备好了。启动任务就是先将设置PendSV,然后将PSP清零,然后将OSRunning设置为真表示进入多任务,然后触发PendSV,然后由PendSV中断服务程序来执行相关的任务切换。
Powered byucos是如何在中断中切换任务的? - uCOS-II论坛 -
中国电子技术论坛 -
最好最受欢迎电子论坛!
后使用快捷导航没有帐号?
ucos是如何在中断中切换任务的?
15:10:44  
最近在学习UCOS,看到书上说在完成中断子程序并在退出中断之前要运行 OSIntExit() 函数,如果有已经就绪的高优先级任务,那么该函数将进行任务切换。并在退出后执行高优先级的任务。
我的问题是:
中断本身是硬件产生,中断产生时现场的保护,中断结束后现场的恢复,都是硬件来处理的。UCOS是通过什么方法使CPU在退出中断后,去执行高优先级任务,而不是恢复到中断前的任务? 原则上说是这硬件进行的恢复,恢复也应该是中断前正在运行的任务。这些是如何通过代码改变的呢?难道是修改中断时硬件压栈的数据?
07:14:20  
自己看看源代码不就知道了
10:44:38  
PCB在线计价下单
板子大小:
板子数量:
PCB 在线计价
中断服务程序的中断退出函数里不是调用了OS_TASK_SW()函数进行任务切换吗,这里进行环境保护和上下文切换(即你说的通过栈操作改变寄存器值)。
等待验证会员
11:47:35  
中断服务程序的中断退出函数里不是调用了OS_TASK_SW()函数进行任务切换吗,这里进行环境保护和上下文切换(即你说的通过栈操作改变寄存器值)。
Powered by
供应链服务
商务及广告合作
Jeffery Guo
关注我们的微信
供应链服务 PCB/IC/PCBA
版权所有 (C) 深圳华强聚丰电子科技有限公司

我要回帖

更多关于 3d touch 多任务切换 的文章

 

随机推荐