mcudesign 发表于 2011-2-12 14:55:11

Small RTOS51是怎么管理堆栈的?

Small RTOS51把所有的内部自由RAM空间分配给当前任务。为了顺利进行堆栈变换,Small RTOS51定义了一个数组OSTaskStackBotton保存所有任务堆栈的顶端和底端位置。它的定义如下:
uint8 idata *OSTaskStackBotton;//任务堆栈底部位置。

http://cache.amobbs.com/bbs_upload782111/files_36/ourdev_615609RPW01B.jpg
(原文件名:1111.jpg)

http://cache.amobbs.com/bbs_upload782111/files_36/ourdev_615610NJZS6Z.jpg
(原文件名:22222.jpg)

http://cache.amobbs.com/bbs_upload782111/files_36/ourdev_615611RV0DJ0.jpg
(原文件名:333333.jpg)

这三个图系统假设有三个任务。因为OSTaskStackBotton为字节宽度,所以,当IDATA_RAM_SIZE为0x100时,OSTaskStackBotton=0。
为什么要这样做呢?只是因为51系列单片机内部RAM小,通过中断切换任务要保存的内容我(最少17个;R0~R7,A,B,PSW,DPTR和PC),全局变量和局部变量还要使用一些,寄存器组还要占用一些。若不把所有空闲RAM分配给当前任务作堆栈,则堆栈几乎肯定溢出,故只好以时间换空间。。

这里uint8 idata *OSTaskStackBotton保存的是指向各个任务堆栈的堆底的指针吗?为什么该指针数组中的元素个数为OS_MAX_TASKS+2个?
这里的把全部空闲RAM分配给当前任务堆栈是什么意思?
Small RTOS51是怎么管理堆栈的?

我看了很久还是没看明白?
哪位大虾学过Small RTOS51能给我讲一下吗?非常感谢了。。

rigol_fan 发表于 2011-2-12 15:24:16

这里uint8 idata *OSTaskStackBotton保存的是指向各个任务堆栈的堆底的指针吗?
是的

为什么该指针数组中的元素个数为OS_MAX_TASKS+2个?
空闲任务也在里面,为什么+2忘记了

这里的把全部空闲RAM分配给当前任务堆栈是什么意思?
这个看图,就是当前没有使用的RAM都给当前任务作堆栈用

Small RTOS51是怎么管理堆栈的?
把全部空闲RAM分配给当前任务堆栈。当发生任务切换时做护好现场,做做堆栈迁移,并恢复下个任务的现场

书多看几遍就明白了
===============================

ba_wang_mao 发表于 2011-2-12 17:25:46

例如:ucos等操作系统,要求每个任务都必须分配一个堆栈,用于任务切换,操作系统用一个链表将所有的堆栈串接起来,便于管理。

   而small 51 由于要求的单片机是C51(RAM可能只有128 byte),因此不能给每个任务都分配一块专用的区域,作为任务堆栈。

   作者采用了变通的方式:

      1、定义了一个数组OSTaskStackbottom[] 保存所有任务堆栈的“栈顶指针”和“栈底指针”。

      2、把所有“剩余的自由空间-RAM”分配给当前运行任务。
         目的是为了进行堆栈的搬移工作。

mcudesign 发表于 2011-2-12 18:24:32

ba_wang_mao前辈你好、
我看书上说,如果是任务主动放弃CPU、即调用函数OSSched(),它就只压当前任务的PC指针入栈。而在无中断嵌套时退出中断就必须压PC、ACC、R0~R7等内容入栈,是这样的吗?

还有就是,OSTaskStackbottom[]怎么存放栈顶和栈底指针的呢?uint8 idata *OSTaskStackBotton,它只定
义了OS_MAX_TASKS+2个单元,一个任务的栈顶和栈底指针不是需要两个BYTE的单元吗、OS_MAX_TASKS个任务,不就需要2倍的OS_MAX_TASKS的单元吗?

mcudesign 发表于 2011-2-12 20:14:20

哦=基本上看明白了、下一个任务的栈底指针就可以做为相连的上一个任务的栈顶指针。
OSTaskID保存着当前任务的ID、OSNestTaskID保存着将要运行任务的ID、
但是在 C_OSCtxSw()函数中有三个判断,然后根据判断结果,移动堆栈内容。
这三个判断是:
OSTaskID>OSNestTaskID?
OSTaskID<OSNestTaskID?
OSTaskID=OSNestTaskID?

OSNestTaskID是将要运行任务的ID,也就是就绪表中的最高优先级的任务。
那么OSNestTaskID一定是小于或者等于OSTaskID。不可能大于OSTaskID、因为它大于的话,那么它就不是就绪表中优先级别最高的任务了。为什么这里还有这么一个判断语句呢?

mcudesign 发表于 2011-2-12 21:26:40

哦,光研究中断退出时的函数去了、任务调用OSWait()函数将自身挂起时那个任务调度函数也要调用这个堆栈变换函数。在那里可能有OSTaskID<OSNestTaskID这种情况。

ba_wang_mao 发表于 2011-2-13 08:53:58

1、OSTaskID保存着当前任务的ID、OSNestTaskID保存着将要运行任务的ID
   OSTaskID保存着当前任务的ID、OSNestTaskID保存着将要运行任务的ID(即目前找到的最高优先级任务)
2、这三个判断是:
   OSTaskID>OSNestTaskID?当前正运行任务的任务号 > 目前找到的最高优先级任务的任务号
   OSTaskID<OSNestTaskID?
   OSTaskID=OSNestTaskID?当前正运行任务的任务号 = 目前找到的最高优先级任务的任务号
   主要应该是为了搬移数组OSTaskStackbottom[] 做判断。

3、OSNestTaskID是将要运行任务的ID,也就是就绪表中的最高优先级的任务。
   那么OSNestTaskID一定是小于或者等于OSTaskID。不可能大于OSTaskID、因为它大于的话,那么它就不是就绪表中优先级别最高的任务了。为什么这里还有这么一个判断语句呢?

   答案:不一定。
      如果共有8个任务,其中任务0-任务6由于某些原因,正在等待信号量而被操作系统挂起。显示当前能够找到的最高优先级任务是 “7”。

ba_wang_mao 发表于 2011-2-13 09:17:13

ba_wang_mao前辈你好、
我看书上说,如果是任务主动放弃CPU、即调用函数OSSched(),它就只压当前任务的PC指针入栈。而在无中断嵌套时退出中断就必须压PC、ACC、R0~R7等内容入栈,是这样的吗?

还有就是,OSTaskStackbottom[]怎么存放栈顶和栈底指针的呢?uint8 idata *OSTaskStackBotton,它只定
义了OS_MAX_TASKS+2个单元,一个任务的栈顶和栈底指针不是需要两个BYTE的单元吗、OS_MAX_TASKS个任务,不就需要2倍的OS_MAX_TASKS的单元吗?
-----------------------------------------------------------------------------------------------------------------------

   1、OSSched()调度导致任务切换的实质:
      人为通过软件方法模拟一次硬件中断。

   2、中断打断当前正运行任务时,中断服务程序已经帮忙将所有寄存器压入了堆栈。
      因此中断调度导致任务切换的切换函数必须和任务主动放弃CPU的调度程序不同。

   3、任务主动放弃CPU,即调用函数OSSched()
         3.1首先打到最高优先级任务的任务号
         3.2调用宏OS_TASK_SW()---> 这个宏是由汇编语言编写的,跟具体的单片机有关

         

   4、还有就是,OSTaskStackbottom[]怎么存放栈顶和栈底指针的呢
http://cache.amobbs.com/bbs_upload782111/files_36/ourdev_615717LGCPVO.JPG
(原文件名:未命名.JPG)

mcudesign 发表于 2011-2-13 16:57:30

非常感谢ba_wang_mao前辈、、

longfeixue 发表于 2011-2-16 10:45:13

ba_wang_mao 大侠你好!
我最近一直想学RTOS,本身打算直接看uCOS2呢,但是感觉不太好懂,特别是汇编函数移植那一块实在搞不清。偶然想起以前看过一个帖子,你在上面说入门还是选择Small RTOS51比较合适。于是下了一篇电子书来看,已经看了一个多星期,除了后边第6章,第7章讲信号量、信号队列的没看,前边的五章都看了。我是分程序模块一部分一部分看的,大部分内容都理解了,但是中间关于堆栈变换函数的一部分一直不明白,今天早上来回又看了这一部分,感觉弄明白了一些。除此之外就是对整个程序的执行流程,在头脑里还没有联系起来想清楚。关于堆栈变换这一部分,感觉书上有些部分写的有些混乱或是不对。
首先书上第55页最下面一行说,“因为OSTaskStackBotton为字节宽度,所以,当IDATA_RAM_SIZE为0x100时,OSTaskStackBotton=0。”觉得数组里边的下标弄错了,应该是OSTaskStackBotton=0,因为数组定义大小是OS_MAX_TASKS+2,所以最后一个可以引用的元素下标应该是OS_MAX_TASKS+1,对应的元素数组里存放的应是优先级最低的任务,即系统定义的最大任务数OS_MAX_TASKS,它代表的就是系统预定义的空闲任务,的堆栈栈顶地址。它是内部RAM空间的最大值,当为0x100时,8位截断,所以应该是0。
另一个大的问题就是书上66页中下部到69页中上部的,这部分内容,专讲C语言版的堆栈变换函数的C_OSCtxSw( )。这一部分我原来一直没看明白,是因为没有弄清它的堆栈变换和自由RAM搬移到底指的的什么。今天早上再看时,我联系起来前边55页下边的地方和后面所附的三个示意图,弄清了他说的数据移动的源起始地址、目的起始地址和结束条件指的的是什么,因此基本弄清了它说的自由RAM移动所代表的堆栈变换的意思。

关于这几个关键的变量我是这样理解的:
程序第(1)行的SP的值是经过上一步程序调整后的当前任务的堆栈指针的值,它指向当前任务堆栈中,最上边一个有用数据的值,就是51单片机中所说的堆栈栈顶的值。

程序第(2)行CP1的值是当前任务的堆栈指针SP的值加1,也就是自由RAM的低端地址。即是搬移的源起始地址。

程序第(3)行是指把当前堆栈指针设为备用数组的起始地址减1的值,因为51单片机入栈时,是先将SP+1后,再将数据压入SP+1所指地址的单元中的。

程序第(4)行temp指向的是新任务的下一个任务的栈底的地址,也就是,新任务的栈顶的地址。即循环搬移的结束条件判断值。

程序第(5)行CP2指向的是当前任务的下一个任务的栈底,也就是,当前任务的栈顶,也就是当前任务的自由RAM的高端地址。即是搬移的目的起始地址。

其中CP1和CP2代表的含义在OSTaskID小于或大于OSNextTaskID两种情况下是互换的。

但是对这一部分看过之后,还有如下疑惑或混乱的感觉:
1. 其中程序第(18)行是不是写错了,while循环判断条件应该是while(cp1 !=(uint8 idata * )temp)吧?
2. 图5.7画的流程图,里边写的大小条件是一样的,不对。
3. 对于69页上班页说的第二和第三两种情况的叙述,我怎么感觉是说反了。比如关于自由RAM在两种情况下是向高端或低端移动方向的叙述。
我自己理解那一阵感觉是对的,清楚的,但是看了他的叙述一对照又好像混了。想请你给一个明确的解释,澄清一下这一部分的混乱。
现在的问题就是这些,繁繁的写了这么多,期待你的释疑,先在此谢过!以后活或许还有问题要请教你。

ba_wang_mao 发表于 2011-2-16 13:26:04

我当年粗粗的学完small 51后,就放弃了该操作系统的学习,转去学习 uc/OS-II , 因为small 只是用来学习,没有多少实用价值 。

   1、如果你原先使用过汇编语言的话,会对学习 small 有帮助的。

   2、small 51 的学习难点就在于 任务级任务切换 和队列(其中队列难学习是因为作者为了节省一个字节的队尾指针,而把数据结构中的标准算法,修改的非常难懂)

   3、关于small 堆栈变换我再提示一下

      (1)、在uc/OS-II等稍微大型的操作系统中,由于内存空间足够大,因此每个任务都在ram 中建立一个缓冲区,用于保存当前任务的现场信息,称之为任务控制块,用于任务切换。

                这种情况,我们称之为:私栈。

      (2)、在small 51 中,由于内存空间太小,因此“不可能”给每一个任务都建立一个任务控制块用来保存现场信息。
               陈明计先生采用的方法是:把所有剩余的自由空间做为“公共的堆栈区域”(记住:是所有剩余的自由空间)。

               当任务1占用CPU时,公共的堆栈区域中,保存的就是任务1的现场信息
               当任务2占用CPU时,公共的堆栈区域中,保存的就是任务2的现场信息

                这种情况,我们称之为:公栈。(必须来回的倒腾数据)


http://cache.amobbs.com/bbs_upload782111/files_36/ourdev_616415RAJ7TA.JPG
(原文件名:1.JPG)


   
点击此处下载 ourdev_616416Z6M971.pdf(文件大小:27K) (原文件名:演变.pdf)

longfeixue 发表于 2011-2-16 14:57:58

谢谢ba_wang_mao 大侠。51的汇编我以前还挺熟的。虽然具体的问题你没有回答,但是从宏观上说明了RTOS公栈与私栈的区别,这样就很容易明白了对自由RAM搬来搬去的必要性了。我也知道了这两个名词,还谢谢你发的说明资料。我想等把Small RTOS51的东西基本搞清楚了之后,再弄uCOS2的。
中午我对那段程序又推演了一遍,现在对这一部分的思路比较清晰了。但是我感觉书上有些地方叙述的还是有些不对,比如69页上面说的第二种情况OSTaskID<OSNextTaskID,上边说接着要调整数组OSTaskStackBottom【】,... ,也就是将其部分元素的值增加空闲空间的字节数的值。这里说的就是加上自由空间RAM的个数。但是我认为这里应该是减去自由空间RAM的个数,这也对应于程序第(12)行。
同理,下边一段说的第三种情况OSTaskID>OSNextTaskID,书上说的是接着要调整数组OSTaskStackBottom【】,... ,也就是将其部分元素的值减少空闲空间的字节数的值。我认为应该是加上自由空间RAM的个数。这对应着程序第(23)行。
同时流程图中写的也相反。
还有就是我上边说的程序第(18)行是不是写错了,while循环判断条件应该是while(cp1 !=(uint8 idata * )temp),而不是while(cp2 !=(uint8 idata * )temp)? 这两个问题就让正在读这本书的,或者现在熟悉Small RTOS51同志们来回答一下吧

qin2010 发表于 2011-9-17 13:08:58

small 的堆栈管理我看了很久,就是不懂,做个记号先

xiaoming123 发表于 2011-9-23 12:49:39

学习了

yujietangying 发表于 2013-9-30 15:58:02


yujietangying 发表于 2013-9-30 15:59:03

attach://142564.png

yujietangying 发表于 2013-9-30 16:00:06

假设正在运行的是任务0,要转都任务1运行
页: [1]
查看完整版本: Small RTOS51是怎么管理堆栈的?