搜索
bottom↓
回复: 4

再问关于uCOS II的疑问-任务到底是如何执行的???求指导...

[复制链接]

出0入0汤圆

发表于 2012-11-6 10:23:24 | 显示全部楼层 |阅读模式
    这篇帖子在阿莫论坛的其他板块已经发过,可能是发帖的地方不对,所以根本没有人替我解答,思来想去,认为还是应该在这个板块里发帖!好了,下面开始说我的疑问!
    最近把uCOS II的源代码看完了,其中有两处不明白,现在只说其中的一处希望野火哥和论坛中的各位大侠能帮我解答一下!就我从代码的阅读来看,任务的切换实质上是把处于就绪状态的
最高优先级任务控制块的指针赋给当前任务控制块的指针,而且相关的代码也支持我的这个看法:
OSStart();启动多任务运行
OSStart();函数调用了汇编文件os_cpu_a.asm 中的函数OSStartHighRdy();
再看函数OSStartHighRdy()的编写:
OSStartHighRdy
        ;设置可悬挂系统服务中断的优先级
    LDR     R0, =NVIC_SYSPRI14                                  ; Set the PendSV exception priority
    LDR     R1, =NVIC_PENDSV_PRI
    STRB    R1, [R0]
        ;将进程堆栈指针置0以此来初始化上下文切换调用
    MOVS    R0, #0                                              ; Set the PSP to 0 for initial context switch call
    MSR     PSP, R0
        ;将OSRunning置1以此指示系统开始运行
        ;由下面语句可得,汇编语言若是想要操作C语言中定义的函数或者变量,其本质是获得函数或者变量的地址,
        ;再由地址进行相关操作
    LDR     R0, =OSRunning                                      ; OSRunning = TRUE
    MOVS    R1, #1
    STRB    R1, [R0]
        ;触发可悬挂系统服务中断
    LDR     R0, =NVIC_INT_CTRL                                  ; Trigger the PendSV exception (causes context switch)
    LDR     R1, =NVIC_PENDSVSET
    STR     R1, [R0]
        ;开中断
    CPSIE   I                                                   ; Enable interrupts at processor level
        ;该函数永远不会返回
OSStartHang
    B       OSStartHang                                         ; Should never get here

由代码可知,函数OSStartHighRdy()主要是设置了可悬挂系统服务中断的优先级并且触发了中断(其他操作暂且忽略),下面再砍可悬挂系统服务中断的代码:

OS_CPU_PendSVHandler
        ;禁止中断(关中断)
    CPSID   I                                                   ; Prevent interruption during context switch
        ;将进程堆栈指针的值送入工作寄存器R0,由OSStartHighRdy函数知PSP的初始值为0
    MRS     R0, PSP                                             ; PSP is process stack pointer
        ;第一次可悬挂系统服务中断调过寄存器的保护,因为第一次存放的是无意义的值
    CBZ     R0, OS_CPU_PendSVHandler_nosave                     ; Skip register save the first time
        ;CBZ:跳转指令!C:比较;B:跳转;Z:0;指令解释:比较R0的结果是否为0,如果为0则跳转到OS_CPU_PendSVHandler_nosave

    SUBS    R0, R0, #0x20                                       ; Save remaining regs r4-11 on process stack
        ;STM:存储若干寄存器中的字到一片连续的地址空间中
    STM     R0, {R4-R11}

    LDR     R1, =OSTCBCur                                       ; OSTCBCur->OSTCBStkPtr = SP;
    LDR     R1, [R1]
    STR     R0, [R1]                                            ; R0 is SP of process being switched out

                                                                ; At this point, entire context of process has been saved
OS_CPU_PendSVHandler_nosave
        ;-------------------------执行用户定义的任务钩子函数--------------------------------
    PUSH    {R14}                                               ; Save LR exc_return value
    LDR     R0, =OSTaskSwHook                                   ; OSTaskSwHook();
    BLX     R0
    POP     {R14}
        ;-----------------将已就绪的最高优先级变量的值赋给当前优先级变量------------------
    LDR     R0, =OSPrioCur                                      ; OSPrioCur = OSPrioHighRdy;
    LDR     R1, =OSPrioHighRdy
    LDRB    R2, [R1]
    STRB    R2, [R0]
        ;----------将已就绪的最高优先级任务控制块指针赋给当前任务控制块的指针-----------
    LDR     R0, =OSTCBCur                                       ; OSTCBCur  = OSTCBHighRdy;
    LDR     R1, =OSTCBHighRdy
    LDR     R2, [R1]
    STR     R2, [R0]
      
        ;获得进程栈的栈顶
    LDR     R0, [R2]                                            ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
        ;将进程栈中的指定内容存储到r4-r11 8个寄存器
        ;LDM:从一片连续的地址空间中加载多个字到若干寄存器
    LDM     R0, {R4-R11}                                        ; Restore r4-11 from new process stack
        ;将进程栈的指针减去32!因为8个寄存器总共32个字节,而一个地址指向8位的字节存储区,而STM32的堆栈为满栈向下增长型
        ;故将地址减去32      
    ADDS    R0, R0, #0x20
        ;将新的堆栈指针装入进程栈指针
    MSR     PSP, R0                                             ; Load PSP with new process SP
        ;确保异常返回使用进程栈。这条指令不是很懂
    ORR     LR, LR, #0x04                                       ; Ensure exception return uses process stack
      
    CPSIE   I
    BX      LR                                                  ; Exception return will restore remaining context

    END
由代码可知:可悬挂系统服务中断所做的事情就是将就绪状态的最高优先级任务控制块的指针赋给当前任务控制块的指针,然而至于任务到底是怎么执行的我就不知道了!!!
任务调度函数OS_Sched()实现任务的调度主要是调度了两个函数:
1、OS_SchedNew()函数仍然是找出就绪状态的最高优先级,随后由OS_Sched()中的代码得到处于就绪状态的最高优先级任务的指针
2、OS_TASK_SW()函数的作用是触发可悬挂系统服务中断,到这里所做的工作就跟上面说的一样了,做可悬挂系统服务函数OS_CPU_PendSVHandler()所做的事
总结:还是不知任务是怎样运行的!!!求野火哥和论坛中的各位大侠指导!!!

阿莫论坛20周年了!感谢大家的支持与爱护!!

曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……

出0入0汤圆

发表于 2012-11-6 11:49:42 | 显示全部楼层
mark 留着看看 最近也在研究这个

出0入0汤圆

发表于 2012-11-6 17:15:43 | 显示全部楼层
在进入子程序或中断程序的时候程序会将现在的PC指针保存在堆栈中, 在子程序返回的时候会从堆栈中取PC指向的位置。如果你在子程序中改变了堆栈的内容使PC指向其他地方,这时候子程序返回的就不是进入这个子程序的地方了。任务切换程序就是将现在的SP堆栈指针改成你就绪态的最高优先级任务的堆栈,这样任务切换程序结束返回的时候就回跳到你的就绪态的最高优先级任务。这样完成了任务的调度。

出0入0汤圆

发表于 2012-11-6 17:23:24 | 显示全部楼层
http://www.amobbs.com/thread-1398508-1-1.html
这个帖子说的很详细。
将代码移到GCCAVR上仿真看,超详细

出0入0汤圆

发表于 2012-11-6 20:03:32 | 显示全部楼层
如果OS_CPU_PendSVHandler是由OSStartHighRdy()首次触发的话,当可悬挂系统服务执行到最后一条语句BX      LR,硬件自动把任务入口地址(建立任务的时候已经放进堆栈)从堆栈弹出去程序计数器的了.这样就开始运行任务了,只有第一次运行的任务才是从建立任务的时候放进堆栈的函数入口地址,以后再次运行就是从被中断的地方继续运行的了.
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-8-25 22:18

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表