zoukankan      html  css  js  c++  java
  • 嵌入式框架Zorb Framework搭建七:任务的实现

    我是卓波,我是一名嵌入式工程师,我万万没想到我会在这里跟大家吹牛皮。

    嵌入式框架Zorb Framework搭建过程

    嵌入式框架Zorb Framework搭建一:嵌入式环境搭建、调试输出和建立时间系统

    嵌入式框架Zorb Framework搭建二:环形缓冲区的实现

    嵌入式框架Zorb Framework搭建三:列表的实现

    嵌入式框架Zorb Framework搭建四:状态机的实现

    嵌入式框架Zorb Framework搭建五:事件的实现

    嵌入式框架Zorb Framework搭建六:定时器的实现

    嵌入式框架Zorb Framework搭建七:任务的实现

    一、前言

      在开发程序时,有时候会发现单线程程序开发起来比较吃力,要是可以多线程那该多好。本篇要为Zorb Framework提供多线程功能,也就是多任务功能。

    二、任务功能设计

      我们先来看看要实现的任务提供什么功能:

      初步要提供的功能如下:

      1、可以开始和停止任务

      2、任务有优先级区分

      3、可以进行系统延时

      4、可以知道任务的运行时间

      5、可以动态创建和销毁任务

      因此,初步设计的数据结构如下:

     1 /* 任务状态 */
     2 typedef enum _TaskState
     3 {
     4     TASK_STATE_STOP = 0,          /* 停止 */
     5     TASK_STATE_RUNNING            /* 运行 */
     6 } TaskState;
     7 
     8 /* 任务结构 */
     9 typedef struct _Task
    10 {
    11     uint32_t *pStkPtr;            /* 堆栈指针 */
    12     uint32_t *pStkBase;           /* 堆栈基地址 */
    13     uint32_t StkSize;             /* 堆栈大小 */
    14     uint32_t DelayTime;           /* 任务延时时间(系统周期) */
    15     uint8_t Priority;             /* 任务优先级 */
    16     uint8_t State;                /* 任务状态 */
    17     uint32_t RunTime;             /* 任务总运行时间(系统周期) */
    18     
    19     /* 开始任务 */
    20     bool (*Start)(struct _Task * const pTask);
    21     
    22     /* 停止任务 */
    23     bool (*Stop)(struct _Task * const pTask);
    24     
    25     /* 销毁任务 */
    26     void (*Dispose)(struct _Task * const pTask);
    27     
    28     /* 延时任务 */
    29     bool (*Delay)(struct _Task * const pTask, uint32_t tick);
    30 } Task;

      为Zorb Framework提供的任务功能比较简单,状态也只有运行和关闭两种状态。任务功能实现的关键在于任务调度,而任务调度的核心又在于任务堆栈的保存和恢复。这部分需要根据使用的芯片进行修改,在STM32中,通过触发PendSV异常进行任务切换:

     1 /******************************************************************************
     2  * 描述  :PendSV异常处理
     3  * 参数  :无
     4  * 返回  :无
     5 ******************************************************************************/
     6 __asm void PendSV_Handler(void)
     7 {
     8     IMPORT  pCurrentTask
     9     IMPORT  pTopPriorityTask
    10     
    11     /* 任务的保存,即把CPU寄存器的值存储到任务的堆栈中 */
    12     /* 关中断,NMI和HardFault除外 */
    13     CPSID   I
    14     
    15     /* 判断是否第一次运行 */
    16     MRS     R0, PSP
    17     CBZ     R0, PendSVHandler_NotSave
    18     
    19     /**
    20         在进入PendSV异常的时候,当前CPU的xPSR,PC(任务入口地址),
    21         R14,R12,R3,R2,R1,R0会自动存储到当前任务堆栈,同时递减PSP的值
    22     **/
    23     /* 手动存储CPU寄存器R4-R11的值到当前任务的堆栈 */
    24     STMDB   R0!, {R4-R11}
    25     
    26     /* R0指向pCurrentTask的堆栈指针(指向空闲位置的顶部) */
    27     LDR     R1, = pCurrentTask
    28     LDR     R1, [R1]
    29     STR     R0, [R1]
    30     NOP
    31     
    32 /* 任务的切换,即把下一个要运行的任务的堆栈内容加载到CPU寄存器中 */
    33 PendSVHandler_NotSave
    34 
    35     /* 等效操作pCurrentTask = pTopPriorityTask; */
    36     LDR     R0, = pCurrentTask
    37     LDR     R1, = pTopPriorityTask
    38     LDR     R2, [R1]
    39     STR     R2, [R0]
    40     
    41     /* pTopPriorityTask的信息出栈 */
    42     LDR     R0, [R2]
    43     LDMIA   R0!, {R4-R11}
    44     
    45     /* 设置PSP指向下一个要执行的任务的堆栈的栈底(已弹出了寄存器信息) */
    46     MSR     PSP, R0
    47     /* 确保异常返回使用的堆栈指针是PSP */
    48     ORR     LR, LR, #0x04 /* 设置LR寄存器的位2为1 */
    49     CPSIE   I /* 开中断 */
    50     
    51     /**
    52         函数返回,这个时候任务堆栈中的剩下内容将会自动加载到
    53         xPSR,PC(任务入口地址),R14,R12,R3,R2,R1,R0(任务的形参)
    54         同时PSP的值也将更新,即指向任务堆栈的栈顶。
    55         在STM32中,堆栈是由高地址向低地址生长的
    56     **/
    57     BX      LR
    58     NOP
    59 }

      具体实现请看附件代码或在文末的github地址拉框架源码。

    三、任务结果测试

      简单的测试代码如下:

      1 /**
      2   *****************************************************************************
      3   * @file    app_task.c
      4   * @author  Zorb
      5   * @version V1.0.0
      6   * @date    2018-06-28
      7   * @brief   任务测试的实现
      8   *****************************************************************************
      9   * @history
     10   *
     11   * 1. Date:2018-06-28
     12   *    Author:Zorb
     13   *    Modification:建立文件
     14   *
     15   *****************************************************************************
     16   */
     17 
     18 #include "app_task.h"
     19 #include "zf_includes.h"
     20 
     21 static Task *pTask1; /* 任务1 */
     22 static Task *pTask2; /* 任务2 */
     23 static Task *pTask3; /* 任务3 */
     24 
     25 static void Process1(void *pArg); /* 任务1程序定义 */
     26 static void Process2(void *pArg); /* 任务2程序定义 */
     27 static void Process3(void *pArg); /* 任务3程序定义 */
     28 
     29 /******************************************************************************
     30  * 描述  :任务1程序
     31  * 参数  :(in)-pArg  参数指针
     32  * 返回  :无
     33 ******************************************************************************/
     34 static void Process1(void *pArg)
     35 {
     36     ZF_DEBUG(LOG_D, "
    ");
     37     ZF_DEBUG(LOG_D, "system time is %dms
    ", ZF_SYSTIME_MS());
     38     ZF_DEBUG(LOG_D, "I am %s
    ", (char *)pArg);
     39     ZF_DEBUG(LOG_D, "task count is %d
    ", TASK_GET_TASK_COUNT());
     40     
     41     ZF_DEBUG(LOG_D, "I will create task3
    ");
     42     
     43     /* 创建任务3 */
     44     Task_create(&pTask3, Process3, "task3", 3, 256);
     45     
     46     ZF_DEBUG(LOG_D, "task count is %d
    ", TASK_GET_TASK_COUNT());
     47     
     48     ZF_DEBUG(LOG_D, "I will dispose myself
    ");
     49     
     50     pTask1->Dispose(pTask1);
     51 }
     52 
     53 /******************************************************************************
     54  * 描述  :任务2程序
     55  * 参数  :(in)-pArg  参数指针
     56  * 返回  :无
     57 ******************************************************************************/
     58 static void Process2(void *pArg)
     59 {
     60     while(1)
     61     {
     62         ZF_DEBUG(LOG_D, "
    ");
     63         ZF_DEBUG(LOG_D, "system time is %dms
    ", ZF_SYSTIME_MS());
     64         ZF_DEBUG(LOG_D, "I am %s
    ", (char *)pArg);
     65         ZF_DEBUG(LOG_D, "task count is %d
    ", TASK_GET_TASK_COUNT());
     66         ZF_DEBUG(LOG_D, "I will sleep 1000ms
    ");
     67         ZF_DEBUG(LOG_D, "wake up time is %dms
    ", ZF_SYSTIME_MS() + 1000);
     68         ZF_DELAY_MS(1000);
     69     }
     70 }
     71 
     72 /******************************************************************************
     73  * 描述  :任务3程序
     74  * 参数  :(in)-pArg  参数指针
     75  * 返回  :无
     76 ******************************************************************************/
     77 static void Process3(void *pArg)
     78 {
     79     while(1)
     80     {
     81         ZF_DEBUG(LOG_D, "
    ");
     82         ZF_DEBUG(LOG_D, "system time is %dms
    ", ZF_SYSTIME_MS());
     83         ZF_DEBUG(LOG_D, "I am %s
    ", (char *)pArg);
     84         ZF_DEBUG(LOG_D, "task count is %d
    ", TASK_GET_TASK_COUNT());
     85         ZF_DEBUG(LOG_D, "I will sleep 1000ms
    ");
     86         ZF_DEBUG(LOG_D, "wake up time is %dms
    ", ZF_SYSTIME_MS() + 1000);
     87         ZF_DELAY_MS(1000);
     88     }
     89 }
     90 
     91 /******************************************************************************
     92  * 描述  :任务初始化
     93  * 参数  :无
     94  * 返回  :无
     95 ******************************************************************************/
     96 void App_Task_init(void)
     97 {
     98     /* 创建任务1 */
     99     Task_create(&pTask1, Process1, "task1", 1, 512);
    100     /* 创建任务1 */
    101     Task_create(&pTask2, Process2, "task2", 2, 512);
    102     /* 运行任务系统 */
    103     Task_run();
    104     
    105     /* 程序不会到这 */
    106 }
    107 
    108 /******************************** END OF FILE ********************************/

      结果:

    system time is 3ms
    I am task1
    task count is 3
    I will create task3
    task count is 4
    I will dispose myself
    
    system time is 13ms
    I am task2
    task count is 3
    I will sleep 1000ms
    wake up time is 1019ms
    
    system time is 21ms
    I am task3
    task count is 3
    I will sleep 1000ms
    wake up time is 1028ms
    
    system time is 1021ms
    I am task2
    task count is 3
    I will sleep 1000ms
    wake up time is 2027ms
    
    system time is 1030ms
    I am task3
    task count is 3
    I will sleep 1000ms
    wake up time is 2036ms
    
    system time is 2029ms
    I am task2
    task count is 3
    I will sleep 1000ms
    wake up time is 3035ms
    
    system time is 2038ms
    I am task3
    task count is 3
    I will sleep 1000ms
    wake up time is 3044ms
    
    省略...

    四、最后

      本篇为Zorb Framework提供了任务功能。使用多任务功能进行开发是方便了许多,但同时任务间的协作和资源调用加大了调试和排错的难度。在享受多任务带来的快乐的同时,要做好排错时痛苦的准备。

     

      Zorb Framework github:https://github.com/54zorb/Zorb-Framework

      版权所有,转载请打赏哟

    如果你喜欢我的文章,可以通过微信扫一扫给我打赏哟

  • 相关阅读:
    django操作mysql
    Pycharm 社区版本Database Navigator 安装教程
    自定义报告,用Java写一个html文件
    java中javamail收发邮件实现方法
    Java中的File操作总结
    JavaWeb学习总结(五十二)——使用JavaMail创建邮件和发送邮件
    画面分割和偏移计算
    MapView源代码
    MapUnit单元格源代码
    RecyclerView
  • 原文地址:https://www.cnblogs.com/54zorb/p/9337754.html
Copyright © 2011-2022 走看看