RTX任务管理

Posted 邓小俊

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RTX任务管理相关的知识,希望对你有一定的参考价值。

    默认情况下用户创建的任务栈大小是由参数Task stack size决定的。
    如果觉得每个任务都分配同样大小的栈空间不方便的话,可以采用自定义任务栈的方式创建任务。采用自定义方式更灵活些

    由于Cortex-M3和M4内核具有双堆栈指针,MSP主堆栈指针和PSP进程堆栈指针,或者叫PSP任务堆栈指针也是可以的。
    在RTX操作系统中,主堆栈指针MSP是给系统栈空间使用的,进程堆栈指针PSP是给任务栈使用的。
    也就是说,在RTX任务中,所有栈空间的使用都是通过PSP指针进行指向的。一旦进入了中断函数已经可能发生的中断嵌套都是用的MSP指针

    实际应用中系统栈空间分配多大,主要是看可能发生的中断嵌套层数,下面我们就按照最坏执行情况进行考虑,所有的寄存器都需要入栈,此时分为两种情况:
    64字节 对于Cortex-M3内核和未使用FPU(浮点运算单元)功能的Cortex-M4内核在发生中断时需要将16个通用寄存器全部入栈,每个寄存器占用4个字节,也就是16*4 = 64字节的空间。 可能发生几次中断嵌套就是要64乘以几即可。当然,这种是最坏执行情况,也就是所有的寄存器都入栈。 (注:任务执行的过程中发生中断的话,有8个寄存器是自动入栈的,这个栈是任务栈,进入中断以后其余寄存器入栈以及发生中断嵌套都是用的系统栈)。
    200字节 对于具有FPU(浮点运算单元)功能的Cortex-M4内核,如果在任务中进行了浮点运算,那么在发生中断的时候除了16个通用寄存器需要入栈,还有34个浮点寄存器也是要入栈的,也就是(16+34)*4 = 200字节的空间。当然,这种是最坏执行情况,也就是所有的寄存器都入栈。(注:任务执行的过程中发送中断的话,有8个通用寄存器和18个浮点寄存器是自动入栈的,这个栈是任务栈,进入中断以后其余通用寄存器和浮点寄存器入栈以及发生中断嵌套都是用的系统栈。)。

os_sys_init()    

  1. void os_sys_init (
  2. void (*task)(void) ); /* 操作系统启动后执行的任务 */

函数描述:

    该方法初始化并启动操作系统内核.
    参数为系统初始化完成之后启动的任务的指针. 内核给予该任务默认的优先级1.

注意要点:

    该函数在 rtl.h中定义.
    该方法必须在主函数中调用main.
    该任务使用默认的堆栈大小,该大小在 rtx_config.c中为任务定义.

返回值:

    该函数不返回,函数会直接开始执行参数中指向的方法.

演示:

  1. #include <rtl.h>
  2. void main (void) {
  3. os_sys_init (task1); /* start the kernel */
  4. while(1); /* will never come here */
  5. }

os_sys_init_prio

  1. void os_sys_init_prio (
  2. void (*task)(void), /* Task to start */
  3. U8 priority); /* Task priority (1-254) */

函数描述:

    该函数初始化并启动RTX内核.
    task指针指向启动后系统执行的第一个任务.
    优先级参数设置系统启动之后的第一个执行的任务的优先级. 默认优先级为1. 优先级0为空闲任务保留. 如果设置参数值为0,他会自动被参数1取代. 优先级255同样被保留.
    该函数定义在rtl.h.

注意要点:

    该函数必须在main函数中被调用. 
    该任务使用默认的堆栈大小,该大小在 rtx_config.c中为任务定义
    优先级255表示最重要任务,优先级越高,任务越重要.

返回值:

    函数不返回,直接开始执行参数中指定的方法任务

演示:

  1. #include <rtl.h>
  2. void main (void) {
  3. os_sys_init_prio (task1, 10);
  4. while(1);
  5. }

os_sys_init_user

  1. void os_sys_init_user (
  2. void (*task)(void), /* Task to start */
  3. U8 priority, /* Task priority (1-254) */
  4. void* stack, /* Task stack */
  5. U16 size); /* Stack size */

函数描述:

    初始化并启动操作系统内核. 当启动任务需要比较大的堆栈的时候使用该函数,可以自定义堆栈.
    task参数指向系统启动后执行的第一个任务的指针.
    优先级参数设置系统启动之后的第一个执行的任务的优先级. 默认优先级为1. 优先级0为空闲任务保留. 如果设置参数值为0,他会自动被参数1取代. 优先级255同样被保留.
    stack参数指向启动任务将使用的堆栈的开头.
    size表明任务堆栈的大小.
    该函数定义在rtl.h.

该函数定义在rtl.h.注意要点:

    T该函数必须在main函数中被调用
    任务栈空间必须8字节对齐,可以将任务栈数组定义成uint64_t类型即可(unsigned long long). 
    默认的堆栈大小,该大小在 rtx_config.c中为任务定义.
    优先级255表示最重要任务,优先级越高,任务越重要.

返回值:

    函数不返回,直接开始执行参数中指定的方法任务.

演示:

  1. static U64 stk1[400/8]; /* 400-byte stack */
  2. void main (void) {
  3. os_sys_init_user (task1, 10, &stk1, sizeof(stk1));
  4. while(1);
  5. }

os_tsk_create

  1. OS_TID os_tsk_create (
  2. void (*task)(void), /* Task to create */
  3. U8 priority ); /* Task priority (1-254) */

函数描述:

    该任务创建一个任务,任务指向task指针指向的方法,函数将动态的创建一个任务表示符TID,并将该任务放到系统就绪任务队列中. 
    优先级参数设置系统启动之后的第一个执行的任务的优先级. 默认优先级为1. 优先级0为空闲任务保留. 如果设置参数值为0,他会自动被参数1取代. 优先级255同样被保留. 
    如果新创建的了任务优先级高于当前正在执行的任务,将引发一次调度,系统执行更高优先级的任务.
    该函数定义在rtl.h.

注意要点:

    该API创建的任务使用rtx_config.c定义的堆栈大小创建任务.
    优先级255表示最重要任务,优先级越高,任务越重要.

返回值:

   该函数返回创建的任务的标识符TID. 如果函数调用失败,将会返回0.

演示:

  1. OS_TID tsk1, tsk2;
  2. __task void task1 (void) {
  3. ..
  4. tsk2 = os_tsk_create (task2, 1);
  5. ..
  6. }
  7. __task void task2 (void) {
  8. ..
  9. }

os_tsk_create_ex

  1. OS_TID os_tsk_create_ex (
  2. void (*task)(void *), /* Task to create */
  3. U8 priority, /* Task priority (1-254) */
  4. void* argv ); /* Argument to the task */

函数描述:

    该任务创建一个任务,任务指向task指针指向的方法,函数将动态的创建一个任务表示符TID,并将该任务放到系统就绪任务队列中. 该函数是os_tsk_create的扩展方法,可以支持先task指针指定的任务发送一个参数argv.
    优先级参数设置系统启动之后的第一个执行的任务的优先级. 默认优先级为1. 优先级0为空闲任务保留. 如果设置参数值为0,他会自动被参数1取代. 优先级255同样被保留. .
    argv参数在创建的任务被启动的时候,被系统传递给该任务. 该函数对于同一方法的多个任务的模式下比较实用.
    该函数定义在rtl.h.

注意要点:

    函数定义任务的时候使用rtx_config.c中指定的任务堆栈大小

返回值:

    该函数返回创建的任务的标识符TID. 如果函数调用失败,将会返回0.

演示:

  1. #include <rtl.h>
  2. OS_TID tsk1, tsk2_0, tsk2_1;
  3. int param[2] = {0, 1};
  4. __task void task1 (void) {
  5. ..
  6. tsk2_0 = os_tsk_create_ex (task2, 1, &param[0]);
  7. tsk2_1 = os_tsk_create_ex (task2, 1, &param[1]);
  8. ..
  9. }
  10. __task void task2 (void *argv) {
  11. ..
  12. switch (*(int *)argv) {
  13. case 0:
  14. printf("This is a first instance of task2.\\n");
  15. break;
  16. case 1:
  17. printf("This is a second instance of task2.\\n");
  18. break;
  19. }
  20. ..
  21. }

os_tsk_create_user

  1. OS_TID os_tsk_create_user(
  2. void (*task)(void), /* Task to create */
  3. U8 priority, /* Task priority (1-254) */
  4. void* stk, /* Pointer to the task\'s stack */
  5. U16 size ); /* Number of bytes in the stack */

函数描述:

    该任务创建一个任务,任务指向task指针指向的方法,函数将动态的创建一个任务表示符TID,并将该任务放到系统就绪任务队列中. 该函数支持为任务定义私有堆栈区. 在任务需要一个大的堆栈的时候该函数比较实用.
    优先级参数设置系统启动之后的第一个执行的任务的优先级. 默认优先级为1. 优先级0为空闲任务保留. 如果设置参数值为0,他会自动被参数1取代. 优先级255同样被保留.如果新创建的了任务优先级高于当前正在执行的任务,将引发一次调度,系统执行更高优先级的任务.
    第3个参数是任务栈地址.   第4个参数是任务栈大小,单位是字节.
    该函数定义在rtl.h.

注意要点:

    任务栈空间必须8字节对齐,可以将任务栈数组定义成uint64_t类型即可 (unsigned long long). 

返回值:

    该函数返回创建的任务的标识符TID. 如果函数调用失败,将会返回0.

演示:

  1. OS_TID tsk1,tsk2;
  2. static U64 stk2[400/8];
  3. __task void task1 (void) {
  4. ..
  5. /* Create task 2 with a bigger stack */
  6. tsk2 = os_tsk_create_user (task2, 1, &stk2, sizeof(stk2));
  7. ..
  8. }
  9. __task void task2 (void) {
  10. /* We need a bigger stack here. */
  11. U8 buf[200];
  12. ..
  13. }

os_tsk_create_user_ex

  1. OS_TID os_tsk_create_user_ex (
  2. void (*task)(void *), /* Task to create */
  3. U8 priority, /* Task priority (1-254) */
  4. void* stk, /* Pointer to the task\'s stack */
  5. U16 size, /* Size of stack in bytes */
  6. void* argv ); /* Argument to the task */

函数描述:

    该任务创建一个任务,任务指向task指针指向的方法,函数将动态的创建一个任务表示符TID,并将该任务放到系统就绪任务队列中. 该函数支持为任务定义私有堆栈区. 在任务需要一个大的堆栈的时候该函数比较实用.同时还可以向任务传递一个argv参数.
    优先级参数设置系统启动之后的第一个执行的任务的优先级. 默认优先级为1. 优先级0为空闲任务保留. 如果设置参数值为0,他会自动被参数1取代. 优先级255同样被保留.如果新创建的了任务优先级高于当前正在执行的任务,将引发一次调度,系统执行更高优先级的任务.
    第3个参数是任务栈地址.   第4个参数是任务栈大小,单位是字节.
    argv参数在创建的任务被启动的时候,被系统传递给该任务. 该函数对于同一方法的多个任务的模式下比较实用.

注意要点:

    任务栈空间必须8字节对齐,可以将任务栈数组定义成uint64_t类型即可 (unsigned long long). 

返回值:

    该函数返回创建的任务的标识符TID. 如果函数调用失败,将会返回0.

演示:

  1. #include <rtl.h>
  2. OS_TID tsk1,tsk2_0,tsk2_1;
  3. static U64 stk2[2][400/8];
  4. __task void task1 (void) {
  5. ..
  6. /* Create task 2 with a bigger stack */
  7. tsk2_0 = os_tsk_create_user_ex (task2, 1,
  8. &stk2[0], sizeof(stk2[0]),
  9. (void *)0);
  10. tsk2_1 = os_tsk_create_user_ex (task2, 1,
  11. &stk2[1], sizeof(stk2[1]),
  12. (void *)1);
  13. ..
  14. }
  15. __task void task2 (void *argv) {
  16. /* We need a bigger stack here. */
  17. U8 buf[200];
  18. ..
  19. switch ((int)argv) {
  20. case 0:
  21. printf("This is a first instance of task2.\\n");
  22. break;
  23. case 1:
  24. printf("This is a second instance of task2.\\n");
  25. break;
  26. }
  27. ..
  28. }

os_tsk_delete

  1. OS_RESULT os_tsk_delete (
  2. OS_TID task_id ); /* Id of the task to delete */

函数描述:

    当任务完成所有工作并不再想要的时候,可以调用该函数停止并删除任务,依靠task_id来停止并删除任务

注意要点:

    如果task_id为0,则当前正在执行的任务被停止和删除. 程序将执行就绪队列中的下一个就绪任务.

返回值:

    如果任务删除成功,函数返回OS_R_OK,其余所有情况返回OS_R_NOK,比如所写的任务ID不存在.

演示:

  1. #include <rtl.h>
  2. OS_TID tsk3;
  3. __task void task2 (void) {
  4. tsk3 = os_tsk_create (task3, 0);
  5. ..
  6. if (os_tsk_delete (tsk3) == OS_R_OK) {
  7. printf("\\n\'task 3\' deleted.");
  8. }
  9. else {
  10. printf ("\\nFailed to delete \'task 3\'.");
  11. }
  12. }
  13. __task void task3 (void) {
  14. ..
  15. }

os_tsk_delete_self

  1. #include <rtl.h>
  2. void os_tsk_delete_self (void);

函数描述:

    该函数停止并删除当前正在执行的任务,程序将执行就绪队列中的下一个就绪任务.

注意要点:

    该函数没有返回.,程序将执行就绪队列中的下一个就绪任务

返回值:

    该函数没有返回.,程序将执行就绪队列中的下一个就绪任务.

演示:

  1. #include <rtl.h>
  2. __task void task2 (void) {
  3. ..
  4. os_tsk_delete_self();
  5. }

os_tsk_pass

  1. #include <rtl.h>
  2. void os_tsk_pass (void);

函数描述:

    该函数将切换到和当前任务优先级相同的就绪队列中的其他任务. 如果就绪队列中没有相同优先级的任务, 当前任务将继续执行且没有任务切换发生。

注意要点:

    可以用该方法在相同优先级的几个任务之间切换.

返回值:

    None

演示:

  
  1. #include <rtl.h>
  2. OS_TID tsk1;
  3. __task void task1 (void) {
  4. ..
  5. os_tsk_pass();
  6. ..
  7. }

os_tsk_prio

  1. OS_RESULT os_tsk_prio (
  2. OS_TID task_id, /* ID of the task */
  3. U8 new_prio ); /* New priority of the task (1-254) */

函数描述:

    该函数将修改task_id指定的任务的优先级.
    如果新设置的优先级比当前执行的任务的优先级高,那么任务切换将会切换到task_id指定的任务并执行,同时优先级被修改. 如果低,那么依然执行当前任务.
    如果task_id为0,修改的优先级是当前运行任务的优先级.

注意要点:

    新优先级的取值为1-254.
    新的优先级将一直保持直到你再次修改它. 
    优先级0是idle任务的优先级,如果设置某个任务优先级为0,程序将自动修改为1,255是保留优先级,也是一样的. 
    优先级数值越大,优先级越高.

返回值:

    返回值如下所示:

演示:

  1. #include <RTL.h>
  2. OS_TID tsk1,tsk2;
  3. __task void task1 (void) {
  4. ..
  5. os_tsk_prio_self (5);
  6. /* Changing the priority of task2 will cause a task switch. */
  7. os_tsk_prio(tsk2, 10);
  8. ..
  9. }
  10. __task void task2 (void) {
  11. ..
  12. /* Change priority of this task will cause task switch. */
  13. os_tsk_prio_self (1);
  14. ..
  15. }

os_tsk_prio_self

  1. #include <rtl.h>
  2. OS_RESULT os_tsk_prio_self (
  3. U8 new_prio ); /* New priority of task (1-254) */

函数描述:

    修改当前运行任务的优先级为新的优先级.

注意要点:  

    新优先级的取值为1-254.
    新的优先级将一直保持直到你再次修改它. 
    优先级0是idle任务的优先级,如果设置某个任务优先级为0,程序将自动修改为1,255是保留优先级,也是一样的. 
    优先级数值越大,优先级越高.

返回值:

    该函数始终返回 OS_R_OK.

演示:

  1. #include <rtl.h>
  2. OS_TID tsk1;
  3. __task void task1 (void) {
  4. ..
  5. os_tsk_prio_self(10); /* Increase its priority, for the critical section */
  6. .. /* This is a critical section */
  7. ..
  8. os_tsk_prio_self(2); /* Decrease its priority at end of critical section */
  9. ..
  10. }

os_tsk_self

  1. #include <rtl.h>
  2. OS_TID os_tsk_self (void);

函数描述:

    该函数将返回当前运行任务的标识符,也就是TID.

注意要点:

    无

返回值:

    返回当前执行任务的TID标识符.

演示:

  1. #include <rtl.h>
  2. OS_TID tsk1;
  3. __task void task1 (void) {
  4. tsk1 = os_tsk_self();
  5. ..
  6. }

isr_tsk_get

  1. #include <rtl.h>
  2. OS_TID isr_tsk_get (void);

函数描述:

    该函数返回当前正在运行的中断任务的标识符TID.

注意要点:

    该函数只能在ISR任务中调用.

返回值:

    该函数返回当前正在运行的中断任务的标识符TID.

演示:

  1. #include <rtl.h>
  2. void os_error (U32 err_code) {
  3. /* This function is called when a runtime error is detected. */
  4. OS_TID err_task;
  5. switch (err_code) {
  6. case OS_ERR_STK_OVF:
  7. /* Identify the task with stack overflow. */
  8. err_task =

    以上是关于RTX任务管理的主要内容,如果未能解决你的问题,请参考以下文章

    RTX临界段,中断锁与任务锁

    使用RTX的一些流水账

    腾讯通RTX卡死

    RTX——第8章 任务优先级修改

    RTX51 Tiny

    RTX5任务优先级分配和修改