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

嵌入式框架Zorb Framework搭建过程

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

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

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

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

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

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

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

一、前言

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

二、任务功能设计

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

  初步要提供的功能如下:

  1、可以开始和停止任务

  2、任务有优先级区分

  3、可以进行系统延时

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

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

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

 /* 任务状态 */
typedef enum _TaskState
{
TASK_STATE_STOP = , /* 停止 */
TASK_STATE_RUNNING /* 运行 */
} TaskState; /* 任务结构 */
typedef struct _Task
{
uint32_t *pStkPtr; /* 堆栈指针 */
uint32_t *pStkBase; /* 堆栈基地址 */
uint32_t StkSize; /* 堆栈大小 */
uint32_t DelayTime; /* 任务延时时间(系统周期) */
uint8_t Priority; /* 任务优先级 */
uint8_t State; /* 任务状态 */
uint32_t RunTime; /* 任务总运行时间(系统周期) */ /* 开始任务 */
bool (*Start)(struct _Task * const pTask); /* 停止任务 */
bool (*Stop)(struct _Task * const pTask); /* 销毁任务 */
void (*Dispose)(struct _Task * const pTask); /* 延时任务 */
bool (*Delay)(struct _Task * const pTask, uint32_t tick);
} Task;

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

 /******************************************************************************
* 描述 :PendSV异常处理
* 参数 :无
* 返回 :无
******************************************************************************/
__asm void PendSV_Handler(void)
{
IMPORT pCurrentTask
IMPORT pTopPriorityTask /* 任务的保存,即把CPU寄存器的值存储到任务的堆栈中 */
/* 关中断,NMI和HardFault除外 */
CPSID I /* 判断是否第一次运行 */
MRS R0, PSP
CBZ R0, PendSVHandler_NotSave /**
在进入PendSV异常的时候,当前CPU的xPSR,PC(任务入口地址),
R14,R12,R3,R2,R1,R0会自动存储到当前任务堆栈,同时递减PSP的值
**/
/* 手动存储CPU寄存器R4-R11的值到当前任务的堆栈 */
STMDB R0!, {R4-R11} /* R0指向pCurrentTask的堆栈指针(指向空闲位置的顶部) */
LDR R1, = pCurrentTask
LDR R1, [R1]
STR R0, [R1]
NOP /* 任务的切换,即把下一个要运行的任务的堆栈内容加载到CPU寄存器中 */
PendSVHandler_NotSave /* 等效操作pCurrentTask = pTopPriorityTask; */
LDR R0, = pCurrentTask
LDR R1, = pTopPriorityTask
LDR R2, [R1]
STR R2, [R0] /* pTopPriorityTask的信息出栈 */
LDR R0, [R2]
LDMIA R0!, {R4-R11} /* 设置PSP指向下一个要执行的任务的堆栈的栈底(已弹出了寄存器信息) */
MSR PSP, R0
/* 确保异常返回使用的堆栈指针是PSP */
ORR LR, LR, #0x04 /* 设置LR寄存器的位2为1 */
CPSIE I /* 开中断 */ /**
函数返回,这个时候任务堆栈中的剩下内容将会自动加载到
xPSR,PC(任务入口地址),R14,R12,R3,R2,R1,R0(任务的形参)
同时PSP的值也将更新,即指向任务堆栈的栈顶。
在STM32中,堆栈是由高地址向低地址生长的
**/
BX LR
NOP
}

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

三、任务结果测试

  简单的测试代码如下:

 /**
*****************************************************************************
* @file app_task.c
* @author Zorb
* @version V1.0.0
* @date 2018-06-28
* @brief 任务测试的实现
*****************************************************************************
* @history
*
* 1. Date:2018-06-28
* Author:Zorb
* Modification:建立文件
*
*****************************************************************************
*/ #include "app_task.h"
#include "zf_includes.h" static Task *pTask1; /* 任务1 */
static Task *pTask2; /* 任务2 */
static Task *pTask3; /* 任务3 */ static void Process1(void *pArg); /* 任务1程序定义 */
static void Process2(void *pArg); /* 任务2程序定义 */
static void Process3(void *pArg); /* 任务3程序定义 */ /******************************************************************************
* 描述 :任务1程序
* 参数 :(in)-pArg 参数指针
* 返回 :无
******************************************************************************/
static void Process1(void *pArg)
{
ZF_DEBUG(LOG_D, "\r\n");
ZF_DEBUG(LOG_D, "system time is %dms\r\n", ZF_SYSTIME_MS());
ZF_DEBUG(LOG_D, "I am %s\r\n", (char *)pArg);
ZF_DEBUG(LOG_D, "task count is %d\r\n", TASK_GET_TASK_COUNT()); ZF_DEBUG(LOG_D, "I will create task3\r\n"); /* 创建任务3 */
Task_create(&pTask3, Process3, "task3", , ); ZF_DEBUG(LOG_D, "task count is %d\r\n", TASK_GET_TASK_COUNT()); ZF_DEBUG(LOG_D, "I will dispose myself\r\n"); pTask1->Dispose(pTask1);
} /******************************************************************************
* 描述 :任务2程序
* 参数 :(in)-pArg 参数指针
* 返回 :无
******************************************************************************/
static void Process2(void *pArg)
{
while()
{
ZF_DEBUG(LOG_D, "\r\n");
ZF_DEBUG(LOG_D, "system time is %dms\r\n", ZF_SYSTIME_MS());
ZF_DEBUG(LOG_D, "I am %s\r\n", (char *)pArg);
ZF_DEBUG(LOG_D, "task count is %d\r\n", TASK_GET_TASK_COUNT());
ZF_DEBUG(LOG_D, "I will sleep 1000ms\r\n");
ZF_DEBUG(LOG_D, "wake up time is %dms\r\n", ZF_SYSTIME_MS() + );
ZF_DELAY_MS();
}
} /******************************************************************************
* 描述 :任务3程序
* 参数 :(in)-pArg 参数指针
* 返回 :无
******************************************************************************/
static void Process3(void *pArg)
{
while()
{
ZF_DEBUG(LOG_D, "\r\n");
ZF_DEBUG(LOG_D, "system time is %dms\r\n", ZF_SYSTIME_MS());
ZF_DEBUG(LOG_D, "I am %s\r\n", (char *)pArg);
ZF_DEBUG(LOG_D, "task count is %d\r\n", TASK_GET_TASK_COUNT());
ZF_DEBUG(LOG_D, "I will sleep 1000ms\r\n");
ZF_DEBUG(LOG_D, "wake up time is %dms\r\n", ZF_SYSTIME_MS() + );
ZF_DELAY_MS();
}
} /******************************************************************************
* 描述 :任务初始化
* 参数 :无
* 返回 :无
******************************************************************************/
void App_Task_init(void)
{
/* 创建任务1 */
Task_create(&pTask1, Process1, "task1", , );
/* 创建任务1 */
Task_create(&pTask2, Process2, "task2", , );
/* 运行任务系统 */
Task_run(); /* 程序不会到这 */
} /******************************** END OF FILE ********************************/

  结果:

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

四、最后

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

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

  版权所有,转载请打赏哟

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

嵌入式框架Zorb Framework搭建七:任务的实现的更多相关文章

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

    我是卓波,我是一名嵌入式工程师,我万万没想到我会在这里跟大家吹牛皮. 嵌入式框架Zorb Framework搭建过程 嵌入式框架Zorb Framework搭建一:嵌入式环境搭建.调试输出和建立时间系 ...

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

    我是卓波,我是一名嵌入式工程师,我万万没想到我会在这里跟大家吹牛皮. 嵌入式框架Zorb Framework搭建过程 嵌入式框架Zorb Framework搭建一:嵌入式环境搭建.调试输出和建立时间系 ...

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

    我是卓波,我是一名嵌入式工程师,我万万没想到我会在这里跟大家吹牛皮. 嵌入式框架Zorb Framework搭建过程 嵌入式框架Zorb Framework搭建一:嵌入式环境搭建.调试输出和建立时间系 ...

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

    我是卓波,我是一名嵌入式工程师,我万万没想到我会在这里跟大家吹牛皮. 嵌入式框架Zorb Framework搭建过程 嵌入式框架Zorb Framework搭建一:嵌入式环境搭建.调试输出和建立时间系 ...

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

    我是卓波,我是一名嵌入式工程师,我万万没想到我会在这里跟大家吹牛皮. 嵌入式框架Zorb Framework搭建过程 嵌入式框架Zorb Framework搭建一:嵌入式环境搭建.调试输出和建立时间系 ...

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

    我是卓波,我是一名嵌入式工程师,我万万没想到我会在这里跟大家吹牛皮. 嵌入式框架Zorb Framework搭建过程 嵌入式框架Zorb Framework搭建一:嵌入式环境搭建.调试输出和建立时间系 ...

  7. 浅谈一下SSI+Oracle框架的整合搭建

    浅谈一下SSI+Oracle框架的整合搭建 最近换了一家公司,公司几乎所有的项目都采用的是Struts2+Spring+Ibatis+Oracle的架构,上一个东家一般用的就是JSF+Spring,所 ...

  8. C#代码生成工具:文本模板初体验 使用T4批量修改实体框架(Entity Framework)的类名

    转自:http://www.cnblogs.com/huangcong/archive/2011/07/20/1931107.html 在之前的文本模板(T4)初体验中我们已经知道了T4的用处,下面就 ...

  9. Ubuntu12.04嵌入式交叉编译环境arm-linu-gcc搭建过程,图解

    转载:王文松的博客Ubuntu12.04嵌入式交叉编译环境arm-linu-gcc搭建过程,图解 安装环境       Linux版本:Ubuntu 12.04    内核版本:Linux 3.5.0 ...

随机推荐

  1. mysql 统计连续天数

    以下为例子数据 图1 图1 首先根据要求取出BeforeMeal要在7.0以下 并且 bingAfterMeal要在11.1以下 select AccountId,CreateTime from Di ...

  2. Linux中如何安装配置Mysql和SVN服务端

    目标Linux系统为centOS 一.安装登陆mysql   1.直接以root用户运行:yum install mysql 和yum install mysql-server等带安装完成. 2.安装 ...

  3. 【分享】Adobe Flash Player各版本安装包官方直接下载地址

    用常规方法下载比较繁琐,先会下个下载器,再下载安装包安装, 这里直接列出了安装包的下载地址,点击进入各版本的下载总页面, 拉到最下方就有各版本的下载地址,这里我直接列出来了: Chrome用的PPAP ...

  4. apache poi根据模板导出excel

    需要预先新建编辑好一个excel文件,设置好样式. 编辑好输出的数据,根据excel坐标一一对应. 支持列表数据输出,列表中列合并. 代码如下: package com.icourt.util; im ...

  5. table自适应

    当table大于屏幕时,table可以左右滑动 //给table的父元素设置样式 .edit_table{ width:100%; overflow: auto; }

  6. hadoop核心逻辑shuffle代码分析-map端 (转)

    一直对书和各种介绍不太满意, 终于看到一篇比较好的了,迅速转载. 首先要推荐一下:http://www.alidata.org/archives/1470 阿里的大牛在上面的文章中比较详细的介绍了sh ...

  7. 【OJ-UVa227】

    耗时一周.哭. 本题重在输入输出.所以对英文题目的理解非常重要.看清楚题目,省时省力. 题目要点: 1.开始有5×5的数据,每行仅有5个字符.注意:样例输入中的尾部空格是无法复制的(UVa官网上),其 ...

  8. 01_常用 Linux 命令的基本使用

    01. 学习 Linux 终端命令的原因 Linux 刚面世时并没有图形界面,所有的操作全靠命令完成,如 磁盘操作.文件存取.目录操作.进程管理.文件权限 设定等 在职场中,大量的 服务器维护工作 都 ...

  9. 关闭Debut.Log

    unity5.3支持了运行时关闭产生的debug.log Debug.logger.logEnabled = false; 谢谢你们,让我能在晚上凝视夜空的时候,脑海中浮现出更广阔的世界.

  10. linux 怎么查看系统的环境变量 与设置jdk 系统环境变量

    1.win 7 ,win10 怎么查看,添加系统环境的变量,大家都非常清楚的.但是linux 的 却不一定哦. 打开终端输入 :  “echo $PATH “ or  “export ”      如 ...