专注电子技术学习与研究
当前位置:单片机教程网 >> MCU设计实例 >> 浏览文章

详解基于51单片机的small rtos(2)

作者:佚名   来源:本站原创   点击数:  更新时间:2012年01月15日   【字体:

    我们继续上篇。上篇我漏了个开总中断忘说了。
  开中断。  对了调试的时候吧任务A的睡眠给隐掉。因为一步一步来学习嘛!  当开了中断,于是开始执行定时器0中断,定时器中的代码一个是OSTimeTick();  执行任务时间片的分配。这里注意了,我自个写的时候调试出现问题才发现的。他是先判断是否有时间片,有则--,然后再判断是否为0为0则 OSIntSendSignal(TaskId)。  OSIntSendSignal就是把任务置为就绪的没什么,有必要提的就是关中断和开中断。这个为了避免产生中断导致不可预知的错误。 然后回到定时器0的中断服务程序中,执行OSIntExit()。然后转到==》OSIntCtxSw ==》  C_OSCtxSw  ==》LoadCtx    然后就切换到任务B 。现在我开始慢慢的分析这几个函数,因为这里是需要慢慢讲解的。首先从原理上讲下。定时器中断时依次把
PC+ACC+B+DPTR+PWD+r0-r7  共15个字节 ,然后OSIntCtxSw 这个函数会判断当前任务是空闲任务的还是任务ABC中一个,如果是任务函数则栈顶指针  sp=sp-4; 如果是空闲的就sp=sp-17 置相应的中断方式标志位     OSCtxSw  内存块的重新布局。 LoadCtx    加载任务环境 。 
 现在开始从代码调试中看下。 
定时器0中断前                                                                               

        
 

 中断后    然后查看  内存 按推断应该是sp-15 个字节  =i:0x16     如图   你可以看出 中断服务程序保存环境是按什么次序入栈的。帅吧~~~

然后执行OSIntExit()压入    0x0256  

     

 

   15+2 =17个字节然后  再跳转到 OSIntCtxSw  

  17+2 个字节 =2+13+4

 

 这里开始用51

汇编写的,这里是经常执行的代码必须有效率。 在OSIntCtxSw    判断当前任务是什么性质的,现在这个是任务A随意是sp=sp-4 并置中断类型标志位,清任务运行标志位,LMJP  OSCtxSw  首先压入一个中断计数,然后开始吧 【前任务+1的存放地址 ----下个任务+1的地址】 这里有个第优先级上还存放了个任务就是为符合这个处理方式。吧括号中的数据整个搬到上图sp后面,然后吧修改后的函数首地址重新分配 OSTsakStackBotton存放   然后把下个任务切换成当前任务,他的内存空间就是现在SP ---任务+1之间的空间。  这里的堆栈是从低到高分配的和PC里不一样。然后还做了个清中断标志的操作  压入  LoadCtx    的函数地址的栈然后RETI 这个主要是清掉中断标志,然后跳转到环境加载函数 。然后LoadCtx    就把堆栈中下个任务的地址直接RET返回给$P于是就切换到下个任务了。 优先级低的也差不对这样处理的。

 

为了模拟跳转到任务B   在中断前加  extern uint8 OSTaskRuning;  在 OSIntExit(); 前+OSTaskRuning &=~OSMapTbl[0];  这样就模拟跳转到任务B

  嘿嘿,不好意思 +了那么入栈的数据就有变化了。但是数目应该没变,我就不重新截图了。

sp 0x28  ,

OSIntCtxSw 执行后SP-4


 

放B的地址可以通过

 


 

看到i:0xF7是存储的B的首地址,


 

 

数据块应该是 【A+1】-    【B+1】之间的数据整个搬到当前sp+1后面 搬移后的内存分布 


 

 

后面  中断计数 00  +搬过来的B-C间的2个字节 C7  03这个正好是B任务的首地重新修改存放函数首地址的数组

 

 
 

这里可以跳转到LoadCtx     吧任务切到任务B中。 

至此通过中断任务切换已经完毕,此时可以向下如果任务中有数据在其中,那么这样做会不会丢失数据,其实仔细想想就可以了解,不会的。
本例源代码下载:http://www.51hei.com/f/small_rtos1.12.1.zip


接下篇:

    这篇就讲解信号来模拟软中断,切换任务。
     吧上篇的操作权清掉,然后程序到任务A后会通过睡眠信号,进入OSWait()处理。这里程序主动放弃任务的使用CPU的权利 OSClearSignal (),OSSched()来进入到OSCtxSw  这个函数中,然后他来设置中断的性质标志位。==》C_OSCtxSw  ==》LoadCtx  加载环境来达到切换任务的目的。
     这个没上面的那个复杂,就是在LoadCtx  的时候会根据中断的标志位来跳过寄存器的恢复。因为软中段是不会吧寄存器的数据保存到堆栈中这是为什么呢?嘿嘿,这个让我纠结了半小时,其实很简单。他这个事主动放弃的,如果再次执行就是重新运行这个任务,那么这个任务中用到得数据部就全初始化了吗。嘿嘿,所以没必要保存寄存器中的数据。
     呵呵这个我就不截图也不具体说了,有了上篇这个应该很快就能看明白。信号量可能更新慢了点,因为本人自己写的代码才写到这里而已,就在出差前才调试好的。当然我写的有点乱很多变量都是自起的名字,而且还加了自己想到得一些奇怪的想法的代码,这代码我不提供,所以我按RTOS代码解析每步的。

 

关闭窗口

相关文章