beirvin 发表于 2012-11-6 10:23:24

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

    这篇帖子在阿莫论坛的其他板块已经发过,可能是发帖的地方不对,所以根本没有人替我解答,思来想去,认为还是应该在这个板块里发帖!好了,下面开始说我的疑问!
    最近把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,
      ;将进程堆栈指针置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,
      ;触发可悬挂系统服务中断
    LDR   R0, =NVIC_INT_CTRL                                  ; Trigger the PendSV exception (causes context switch)
    LDR   R1, =NVIC_PENDSVSET
    STR   R1,
      ;开中断
    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,
    STR   R0,                                           ; 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,
    STRB    R2,
      ;----------将已就绪的最高优先级任务控制块指针赋给当前任务控制块的指针-----------
    LDR   R0, =OSTCBCur                                       ; OSTCBCur= OSTCBHighRdy;
    LDR   R1, =OSTCBHighRdy
    LDR   R2,
    STR   R2,
      
      ;获得进程栈的栈顶
    LDR   R0,                                           ; 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()所做的事
总结:还是不知任务是怎样运行的!!!求野火哥和论坛中的各位大侠指导!!!

zhaov5 发表于 2012-11-6 11:49:42

mark 留着看看 最近也在研究这个

Tliang 发表于 2012-11-6 17:15:43

在进入子程序或中断程序的时候程序会将现在的PC指针保存在堆栈中, 在子程序返回的时候会从堆栈中取PC指向的位置。如果你在子程序中改变了堆栈的内容使PC指向其他地方,这时候子程序返回的就不是进入这个子程序的地方了。任务切换程序就是将现在的SP堆栈指针改成你就绪态的最高优先级任务的堆栈,这样任务切换程序结束返回的时候就回跳到你的就绪态的最高优先级任务。这样完成了任务的调度。

Tliang 发表于 2012-11-6 17:23:24

http://www.amobbs.com/thread-1398508-1-1.html
这个帖子说的很详细。
将代码移到GCCAVR上仿真看,超详细

fshunj 发表于 2012-11-6 20:03:32

如果OS_CPU_PendSVHandler是由OSStartHighRdy()首次触发的话,当可悬挂系统服务执行到最后一条语句BX      LR,硬件自动把任务入口地址(建立任务的时候已经放进堆栈)从堆栈弹出去程序计数器的了.这样就开始运行任务了,只有第一次运行的任务才是从建立任务的时候放进堆栈的函数入口地址,以后再次运行就是从被中断的地方继续运行的了.
页: [1]
查看完整版本: 再问关于uCOS II的疑问-任务到底是如何执行的???求指导...