第3章第2节 任意任务间的切换

第9章 中断 第9章 中断 cpsr 中断" TITLE="第9章 中断" /> 中断" TITLE="第9章 中断" /> 9.1.1 s3c2440中断控制器 中断方式:当某件事情发生时,硬件会设置某个寄存器;cpu在每执行完一个指令时,通过硬件查看这个寄存器,如果发生所关注的事件发生了,则中断当前程序流程,跳转到一个固定的地址处理这件事情。 中断" TITLE="第9章 中断" /> 阅读详情

源代码请在https://github.com/ifreecoding/MbedRtos.git下载

第2节 任意任务间的切换

上一节我们使用2个固定的任务验证了操作系统任务切换的功能,但这些代码并不具有通用性,如果要扩充其它任务,就必须修改操作系统函数,这显然是不可接受的。操作系统作为独立于用户代码的部分,它的内部细节应该是不被用户所见的,是一个黑盒,需要做到用户只需要修改操作系统提供的接口文件里面的参数,调用接口函数就可以完全满足程序开发的要求。因此,在本节我们将对上节的代码做些改动,使其可以支持任意多个任务之间的互相切换,而又不需要修改Wanlix目录下的操作系统代码,仅仅是编写srccode目录下的用户代码,调用操作系统的接口函数即可,这样才真正实现了操作系统的独立性。

首先我们来看看任务切换函数——WLX_TaskSwitch。上节中,这个函数固定在两个任务之间切换,因此要实现可以切换到任何一个函数的功能就必须修改此函数,需要为这个函数增加一个入口参数,用这个入口参数来指明需要切换到的任务。WLX_TaskSwitch函数的主要功能是做好任务切换前的准备,将当前运行任务的栈指针和将要运行任务的栈指针存入到对应的全局变量中,上节中,为每个任务分别指定了guiTask21CurSp和guiTask2CurSp全局变量保存它们的当前栈指针,每个全局变量绑定到了任务,因此,这个入口参数还必须能够关联到任务的栈指针。

为此,我们引入TCB的概念,在操作系统里这是一个非常重要的概念。TCB是Task Control Block的缩写,意为任务控制块,与任务控制相关的重要信息都放被到TCB里。TCB是一个结构体,每个任务都拥有一个TCB ,可以把每个任务的与任务控制相关的结构都放入到它的TCB中,因此我们可以将任务当前的栈指针保存到它的TCB中,到目前为止,TCB格式如下:

typedef struct w_tcb

{

    U32 uiTaskCurSp;

}W_TCB;

TCB结构不只是这么简单,只是到目前为止就是这么简单,随着操作系统功能的不断完善,TCB也会不断的增加它的结构。

我们可以考虑将TCB放到任务的栈中。当任务创建时在栈的开始处保留一块内存作为TCB的存放空间,TCB之后的栈空间才作为真正的栈使用,这样,任务的TCB也就与任务绑定到了一起,每个TCB就可以代表一个任务。由于ARM芯片是线性地址空间,也就是说每个内存地址都是唯一的,因此每个任务堆栈的开始地址也就是唯一的,因此每个TCB的地址也就是唯一的了,这样我们就可以使用TCB的地址来代表各个不同的任务。

图 17  TCB在栈中的位置

有了TCB,下面我们来修改WLX_TaskSwitch函数。修改很简单,只是将TCB指针作为入口参数,在函数里替换掉原来与任务相关的全局变量,修改后的函数如下:

00107  void WLX_TaskSwitch(W_TCB* pstrTcb)

00108  {

00109      

00111      gpuiCurTaskSpAddr = &gpstrCurTcb->uiTaskCurSp;

00112  

00113      

00114      guiNextTaskSp = pstrTcb->uiTaskCurSp;

00115  

00116      

00117      gpstrCurTcb = pstrTcb;

00118  

00119      WLX_ContextSwitch();

00120  }

00107行,入口参数pstrTcb是将要运行任务的TCB指针,准备切换到该任务运行。

00111行,将当前运行任务的TCB中保存当前栈指针变量的地址存入全局变量gpuiCurTaskSpAddr中。

00114行,将将要运行任务的TCB中保存当前栈指针的变量,也就是当前的栈指针,存入全局变量guiNextTaskSp中。

00117行,将全局变量gpstrCurTcb 更新为将要运行任务的TCB,为下次任务切换做准备。

00119行,调用汇编函数WLX_ContextSwitch执行具体的寄存器备份、恢复操作。

同理,WLX_TaskStart函数也需要做类似的变量替换,不再介绍,读者自行分析。

00127  void WLX_TaskStart(W_TCB* pstrTcb)

00128  {

00129      

00130      guiNextTaskSp = pstrTcb->uiTaskCurSp;

00131  

00132      

00133      gpstrCurTcb = pstrTcb;

00134  

00135      WLX_SwitchToTask();

00136  }

由于增加了TCB,因此必须修改任务初始化函数。从本节开始,所有的任务将采用WLX_TaskCreate函数创建,在WLX_TaskCreate函数内分别对TCB和栈进行初始化。

00018  W_TCB* WLX_TaskCreate(VFUNC vfFuncPointer, U8* pucTaskStack, U32 uiStackSize)

00019  {

00020      W_TCB* pstrTcb;

00021  

00022      

00023      if(NULL == vfFuncPointer)

00024      {

00025          

00026          return (W_TCB*)NULL;

00027      }

00028  

00029      

00030      if((NULL == pucTaskStack) || (0 == uiStackSize))

00031      {

00032          

00033          return (W_TCB*)NULL;

00034      }

00035  

00036      

00037      pstrTcb = WLX_TaskTcbInit(pucTaskStack, uiStackSize);

00038  

00039      

00040      WLX_TaskStackInit(pstrTcb, vfFuncPointer);

00041  

00042      return pstrTcb;

00043  }

00018行,函数返回值是被创建任务的TCB指针;入口参数vfFuncPointer是创建任务所使用的函数;入口参数pucTaskStack是创建任务所使用的栈地址,是栈的低地址;入口参数uiStackSize是栈的大小。

00023行,对入口参数判断,如果函数指针为空,则返回NULL空指针代表创建任务失败。在C语言里,指针为NULL(也就是0)代表无效指针,因为0地址的内存一般都是中断向量表的复位向量,正常使用指针时是不会指向这里的。

00030行,对入口参数判断,如果栈指针为NULL或者栈大小为0,则返回失败。

00037行,调用WLX_TaskTcbInit函数初始化任务的TCB,并得到当前任务的TCB指针。

00040行,调用WLX_TaskStackInit函数初始化当前的任务栈。

00042行,任务创建成功,返回当前任务的TCB。以后就可以使用这个返回值来代表这个任务了。

目前的TCB比较简单,只有一个保存栈地址的变量,在WLX_TaskTcbInit函数里就是来初始化这个变量的,并返回TCB指针。

00051  W_TCB* WLX_TaskTcbInit(U8* pucTaskStack, U32 uiStackSize)

00052  {

00053      W_TCB* pstrTcb;

00054      U8* pucStackBy4;

00055  

00056      

00057      pucStackBy4 = (U8*)(((U32)pucTaskStack + uiStackSize) & 0xFFFFFFFC);

00058  

00059      

00060      pstrTcb = (W_TCB*)(((U32)pucStackBy4 - sizeof(W_TCB)) & 0xFFFFFFFC);

00061  

00062      

00063      pstrTcb->uiTaskCurSp = (U32)pstrTcb;

00064  

00065      return pstrTcb;

00066  }

00051行,函数返回值是被创建任务的TCB指针,创建任务后这个TCB就代表该任务;pucTaskStack是任务的栈地址,是栈的低地址;uiStackSize是栈的大小。

00057行,确定栈顶地址。“(U32)pucTaskStack + uiStackSize”是栈顶地址,由于栈必须是4字节对齐,因此再通过“& 0xFFFFFFFC”操作,从栈顶向下寻找4字节对齐的地址作为栈顶地址。

00060行,确定TCB地址。“(U32)ucStackBy4 - sizeof(W_TCB)”操作,从栈中减去存放TCB的空间,再通过“& 0xFFFFFFFC”操作,向下寻找4字节对齐的地址作为存放TCB的起始地址,这个也是任务调度时使用的栈顶地址。

00063行,初始化TCB中的变量,保存任务的栈指针。

00065行,返回任务的TCB指针。

TCB的引入也需要对WLX_TaskStackInit函数做简单的修改,由于该函数只是简单使用TCB替换了原来专用的全局变量,没有大的改动,就不做过多介绍了,读者可以对比上节的函数自己分析。

00074  void WLX_TaskStackInit(W_TCB* pstrTcb, VFUNC vfFuncPointer)

00075  {

00076      U32* puiSp;

00077  

00078      

00079      puiSp = (U32*)pstrTcb->uiTaskCurSp; 

00080  

00081      *(--puiSp) = (U32)vfFuncPointer;    

00082      *(--puiSp) = pstrTcb->uiTaskCurSp;  

00083      *(--puiSp) = 0;                     

00084      *(--puiSp) = 0;                     

00085      *(--puiSp) = 0;                     

00086      *(--puiSp) = 0;                     

00087      *(--puiSp) = 0;                     

00088      *(--puiSp) = 0;                     

00089      *(--puiSp) = 0;                     

00090      *(--puiSp) = 0;                     

00091      *(--puiSp) = 0;                     

00092      *(--puiSp) = 0;                     

00093      *(--puiSp) = 0;                     

00094      *(--puiSp) = 0;                     

00095      *(--puiSp) = 0;                     

00096      *(--puiSp) = MODE_USR;              

00097  

00098      

00099      pstrTcb->uiTaskCurSp = (U32)puiSp;

00100  }

经过上述修改操作系统就具有通用性了,无论建立多少个任务都无需修改操作系统的代码,只要为任务分配一个栈空间,使用WLX_TaskCreate函数就可以创建任务,并可以使用这个任务的TCB指针作为入口参数,调用WLX_TaskSwitch函数就可以切换到这个任务。

另外说一点,创建任务时,需要用户先用全局变量为所创建的任务申请一个任务栈空间,将它的起始地址和大小作为参数传递给WLX_TaskCreate函数来创建任务。如果能将申请任务栈的操作封装到WLX_TaskCreate函数里面就会更方便一些,但我在GNU环境下没有找到配置堆(heap)的方法(谁知道请在论坛上反馈一下,谢谢!),因此无法在WLX_TaskCreate函数里使用C函数库里的malloc函数从堆中申请任务栈。如果使用自己编写的堆函数则不如C库函数的方便,兼容性也不好,因此这里需要用户自己申请任务的栈空间。后面在Cortex内核芯片上,我们将换一个编译器,到那时候再完善这个功能。

在看最终效果前,我们再对任务切换过程中寄存器备份、恢复操作做最后一点优化。上节我们使用WLX_ContextSwitch函数完成任务寄存器入栈、出栈及最后跳转的操作,这样做存在2个问题:

1. 每次执行任务切换时都需要多执行2条汇编指令,来判断是否是从非操作系统状态切换到操作系统状态,请参考上节WLX_ContextSwitch函数的00024行和00025行。

2. 在程序从非操作系统状态切换为操作系统状态时,没有必要将芯片寄存器保存到系统栈中。

为此,我们将原有的WLX_ContextSwitch函数拆分成2个函数,WLX_ContextSwitch函数和WLX_SwitchToTask函数。WLX_ContextSwitch函数仍被WLX_TaskSwitch函数调用,用于每次任务切换,WLX_SwitchToTask函数被WLX_TaskStart函数调用,用于第一次任务切换。

这两个汇编函数没有实质性的改动,不再详细介绍,请读者自行分析。

00012      .func WLX_ContextSwitch

00013  WLX_ContextSwitch:

00014  

00015      @保存当前任务的堆栈信息

00016      STMDB  R13, {R0-R14}

00017      SUB    R13, R13, #0x3C

00018      MRS    R0, CPSR

00019      STMDB  R13!, {R0}

00020  

00021      @保存当前任务的指针值

00022      LDR    R0, =gpuiCurTaskSpAddr

00023      LDR    R1, [R0]

00024      STR    R13, [R1]

00025  

00026      @获取将要运行任务的指针

00027      LDR    R0, =guiNextTaskSp

00028      LDR    R13, [R0]

00029  

00030      @获取将要运行任务的堆栈信息并运行新任务

00031      LDMIA  R13!, {R0}

00032      MSR    CPSR, R0

00033      LDMIA  R13, {R0-R14}

00034      BX     R14

00035  

00036      .endfunc

00043      .func WLX_SwitchToTask

00044  WLX_SwitchToTask:

00045  

00046      @获取将要运行任务的指针

00047      LDR    R0, =guiNextTaskSp

00048      LDR    R13, [R0]

00049  

00050      @获取将要运行任务的堆栈信息并运行新任务

00051      LDMIA  R13!, {R0}

00052      MSR    CPSR, R0

00053      LDMIA  R13, {R0-R14}

00054      BX     R14

00055  

00056      .endfunc

至此就完成了本节代码的修改。在测试代码里我们建立3个任务,TEST_TestTask1、TEST_TestTask2和TEST_TestTask3,并将它们的TCB保存到全局变量gpstrTask1Tcb、gpstrTask1Tcb 和gpstrTask1Tcb 中,供任务切换时使用。

00020  S32 main(void)

00021  {

00022      

00023      DEV_HardwareInit();

00024  

00025      

00026      gpstrTask1Tcb = WLX_TaskCreate((VFUNC)TEST_TestTask1, gaucTask1Stack,

00027                                     TASKSTACK);

00028      gpstrTask2Tcb = WLX_TaskCreate((VFUNC)TEST_TestTask2, gaucTask2Stack,

00029                                     TASKSTACK);

00030      gpstrTask3Tcb = WLX_TaskCreate((VFUNC)TEST_TestTask3, gaucTask3Stack,

00031                                     TASKSTACK);

00032  

00033      

00034      WLX_TaskStart(gpstrTask1Tcb);

00035  

00036      return 0;

00037  }

00044  void TEST_TestTask1(void)

00045  {

00046      while(1)

00047      {

00048          DEV_PutString((U8*)"\r\nTask1 is running!");

00049  

00050          DEV_DelayMs(1000);              

00051  

00052          WLX_TaskSwitch(gpstrTask3Tcb);  

00053      }

00054  }

00061  void TEST_TestTask2(void)

00062  {

00063      while(1)

00064      {

00065          DEV_PutString((U8*)"\r\nTask2 is running!");

00066  

00067          DEV_DelayMs(2000);              

00068  

00069          WLX_TaskSwitch(gpstrTask1Tcb);  

00070      }

00071  }

00078  void TEST_TestTask3(void)

00079  {

00080      while(1)

00081      {

00082          DEV_PutString((U8*)"\r\nTask3 is running!");

00083  

00084          DEV_DelayMs(3000);              

00085  

00086          WLX_TaskSwitch(gpstrTask2Tcb);  

00087      }

00088  }

这3个任务在循环运行,向串口打印数据,每间隔一段时间切换到另外一个任务继续运行。TEST_TestTask1任务运行时向串口打印“Task1 is running!”代表TEST_TestTask1任务开始运行,1秒后主动切换到TEST_TestTask3任务,TEST_TestTask3任务运行时向串口打印“Task3 is running!”代表TEST_TestTask3任务开始运行,3秒后主动切换到TEST_TestTask2任务,TEST_TestTask2任务运行时向串口打印“Task2 is running!”代表TEST_TestTask2任务开始运行,2秒后主动切换到TEST_TestTask1任务,如此反复循环。

编译本节代码,串口打印如下图:

图 18  可创建任意多个任务的运行结果

    读者也可通过本节的视频观察这3个任务的动态执行过程,读者也可以自行增加任务在单板上运行一下,体验本节的收获!

C语言试题四之计算并输出3到n之间所有素数的平方根之和 1、题目 请编写函数function,它的功能是:计算并输出3到n之间所有素数的平方根之和 例子:若我们main函数从键盘给n输入5之后,我们需要输出结果为3.968119 输入值n的要求:正整数n, 要求小于100。 2、部分函数说明 C 库函数 double sqrt(double x) 返回 x 的平方根 3、源代码实现 #include <stdio.h> #... 阅读详情

相关推荐

pandas,构造MultiIndex的四种方法:from_tuples、from_arrays、from_product、from_frame

1、from_tuples:通过 “元组对” 构造MultiIndex """ 一对元组,为一个索引 """ tuples = [(1, 'red'), (1, 'blue'), (2, 'red'), (2, 'blue')] pd.MultiIndex.from_tuples(tuples, names=('number', 'color')) 2、from_arrays:通过 “列表元素的组合” 构造MultiIndex """ 列中表的元素,按位置 对应组合,形成索引 """ arrays

jieru_liu的博客 5387

Linux switch_to()深入分析

深入分析任务切换与堆栈 by Liu Wanli    下面可以直接链接文章出处:http://www.linuxforum.net/forum/showflat.php?Cat=&Board=linuxK&Number=301272&fpart=all关键字:时间中断、任务切换、堆栈、LINUX0.01 引言: 任务切换与堆栈的关系怎样?很多朋友可能不知道她们之间有什么关系,还有一些朋友可能认为

少帅的天空 7070

用Matlab系统辨识工具箱搞定温控系统建模:从阶跃响应到传递函数(附完整代码)

本文详细介绍了如何使用Matlab系统辨识工具箱进行温控系统建模,从阶跃响应数据采集到传递函数参数辨识的全过程。通过实际案例和完整代码,帮助工程师快速掌握PID控制参数整定技巧,提升温控系统设计效率。特别适合单片机开发者和自动化控制工程师参考。

weixin_30736301的博客 310

任务切换的堆栈细节,你懂?

我们知道 Cortex-M3 系列单片机内部有双堆栈机制。即 Cortex‐M3 拥有两个堆栈指针:主堆栈(MSP)和进程堆栈(PSP)。任一时刻只能使用其中的一个。通过控制寄存器 CONTROL 中的选择位进行控制。两个堆栈指针如下:主堆栈指针( MSP):复位后缺省使用的堆栈指针,用于操作系统内核以及异常处理例程(包括中断服务例程)进程堆栈指针( PSP):由用户的应用程序代码使用。将RTO...

嵌入式Linux 1507

win10和Mac上安装Freesurfer

Mac安装Freesurfer 软件下载地址 可以根据官方给出的demo视频一步一步下载

Daily_365的博客 6077

基于C#的跨平台上位机开发:一次编写,多平台运行

摘要: 本文探讨了如何利用C#进行跨平台上位机开发,以适配Windows、Linux、macOS等多平台需求。通过分析传统单平台开发的局限性(如API差异、硬件接口兼容性),提出基于.NET 5/6/7的解决方案,重点推荐Avalonia(类WPF的跨平台UI框架)和GtkSharp(基于GTK+)实现图形界面。同时,针对硬件通信需求,介绍了System.IO.Ports串口通信和LibUsbDotNet的跨平台支持,并强调多平台调试(VS Code、Docker)的重要性,最终实现一次编码、多端部署的高效

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1409

第3章第3节&nbsp;用户代码入口——根任务…

源码请在https://github.com/ifreecoding/MbedRtos.git下载 第3节用户代码入口——根任务 经过上节的修改,Wanlix操作系统可以建立任意多个任务,但是在操作系统运行之前必须得先建立一个任务,然后再调用WLX_TaskStart函数从非操作系统状态切换到

ifreecoding的博客 542

树莓派4B网线直连Windows全流程:从IP查询到SSH登录避坑指南

本文提供了一份详细的树莓派4B通过网线直连Windows电脑的实战指南。核心步骤包括配置Windows网络共享、查询树莓派IP地址以及通过SSH进行安全登录与初始配置。文章深入解析了直连的网络原理,并重点分享了使用CMD命令和工具定位IP、避免常见错误的避坑技巧,帮助用户在没有显示器或路由器的环境下快速完成树莓派初始化。

grape的博客 1081

FreeRTOS高级篇4---FreeRTOS任务切换分析

FreeRTOS任务相关的代码大约占总代码的一半左右,这些代码都在为一件事情而努力,即找到优先级最高的就绪任务,并使之获得CPU运行权。任务切换是这一过程的直接实施者,为了更快的找到优先级最高的就绪任务,任务切换的代码通常都是精心设计的,甚至会用到汇编指令或者与硬件相关的特性,比如Cortex-M3的CLZ指令。因此任务切换的大部分代码是由硬件移植层提供的,不同的平台,实现发方法......

朱工的专栏 7万+

数字IC设计——功耗分析

功耗是数字IC芯片的一个重要指标

知识,既贵,又便宜。 9362

ADS 2024实战:手把手教你搞定2.3-3.5GHz宽带Doherty功放仿真与版图(附源文件)

本文详细解析了在ADS 2024环境中实现2.3-3.5GHz宽带Doherty功放的全流程设计,包括仿真与版图实现。从软件环境搭建、器件模型导入到核心电路设计、匹配网络优化,再到系统集成与版图生成,提供了实战技巧和关键参数设置。特别针对5G通信和卫星应用中的高效率需求,展示了如何通过ADS 2024的新功能提升设计效率。

weixin_42639246的博客 461

uC/OS-ii在M3中的任务切换与任务堆栈

uc/os在M3任务切换时的堆栈情况

sunheshan的专栏 2569

WPS访问权限不足怎么解决??具体怎么操作?

🏆本文收录于 《全栈 Bug 调优(实战版)》 专栏。专栏聚焦真实项目中的各类疑难 Bug,从成因剖析 → 排查路径 → 解决方案 → 预防优化全链路拆解,形成一套可复用、可沉淀的实战知识体系。无论你是初入职场的开发者,还是负责复杂项目的资深工程师,都可以在这里构建一套属于自己的「问题诊断与性能调优」方法论,助你稳步进阶、放大技术价值。

**My Coding Family** 4171

第3章第1节&nbsp;两个固定任务之间的切…

源码请在https://github.com/ifreecoding/MbedRtos.git下载 第1节两个固定任务之间的切换 程序的执行只与指令和数据相关,指令是不可修改的,编译后就确定了,能改变的只有数据,但指令需要对数据进行判断,走不同的指令分支,因此,如果我们需要控制程序的执行过程,

ifreecoding的博客 722

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

第3章第5节&nbsp;发布Wanlix操作系统

​源代码请在https://github.com/ifreecoding/MbedRtos.git下载 第5节发布Wanlix操作系统 经过前面3.1~3.3节循序渐进的开发,我们已经使Wanlix操作系统具备了最基本的任务切换功能,并在3.4节使用Wanlix开发了一个交通红绿灯控制系统,到此为

ifreecoding的博客 813

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

第4章第2节&nbsp;定时器触发的实时抢占…

源码请在https://github.com/ifreecoding/MbedRtos.git下载 本节中新增的重要内容已经介绍的差不多了,下面我们来看看使用tick中断的任务上下文切换过程。 在本节中,tick中断被配置为使用Timer1产生IRQ中断。产生tick中断时,硬件会自动将PC指针指向I

ifreecoding的博客 518

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

第3章第4节&nbsp;使用Wanlix编写交通红…

源码请在https://github.com/ifreecoding/MbedRtos.git下载 第4节使用Wanlix编写交通红绿灯控制系统 至此我们已经实现了一个非常简单、小巧的操作系统——Wanlix,简单到它只具备任务切换这一项任务管理功能,而且需要用户自己主动切换,实时性较差。但无

ifreecoding的博客 554

第4章第6节&nbsp;任务自结束

目前更新到5.3节,请在http://dl.dbank.com/c02ackpwp6下载5.3节的全部文档 本节源代码请在http://dl.dbank.com/c0ss54iddw下载     第6节 任务自结束 上节增加了删除任务的函数MDS_TaskDelete,任务可以调用该函数结束其它任务或自身任务的运行。在前面章节我们说过,目前任务还不具备自结束功能,需要使用类似while的结

ifreecoding的博客 466

第4章第5节&nbsp;任务创建和任务删除钩…

目前更新到5.3节,请在http://dl.dbank.com/c02ackpwp6下载5.3节的全部文档 本节源代码请在http://dl.dbank.com/c0t7gmgx2q下载   第5节 任务创建和任务删除钩子函数 上节增加了任务切换钩子功能,打印出任务切换的信息,本节将增加任务创建钩子函数和任务删除钩子函数,分别打印出任务创建和删除的信息。   任务创建和删除钩子函数的原理与

ifreecoding的博客 579

第4章第3节&nbsp;实时事件触发的实时抢…

源码请在https://github.com/ifreecoding/MbedRtos.git下载 本节用户代码在打印输出方面做了较大的修改,从本节开始,串口打印功能不再由任务实时向串口打印,而是由任务先将字符串打印到内存,然后使用一个低优先级的任务从内存中取出字符串打印到串口。串口是一个低速率的外设,960

ifreecoding的博客 349

第1章第1节&nbsp;为什么要使用操作系统

源码请在https://github.com/ifreecoding/MbedRtos.git下载 第1节为什么要使用操作系统 在没有操作系统的情况下,C语言是以函数为单位实现功能的,一个函数一个函数串行的执行,一个完整的功能会由多个函数共同完成。然而当软件系统的功能变得多而庞大的时候,这种方法几乎无法使用,因为此时各个功能之间必然会有千丝万缕的联系,不可能依次串行的完成每个

ifreecoding的博客 831

第4章第7节&nbsp;二进制信号量(一)

目前更新到5.3节,请在http://dl.dbank.com/c02ackpwp6下载5.3节的全部文档 本节源代码请在http://dl.dbank.com/c0fp2g5z9s下载   第7节 二进制信号量 某些资源在同一时刻只可以被一个任务操作,实时操作系统的任务抢占特性会导致这些资源可能被多个任务同时操作,从而产生错误。本节将讲述二进制信号量的原理,可以利用二进制信号量保护这些资源

ifreecoding的博客 2039

第4章第1节&nbsp;Mindows的文件组织结构

源码请在https://github.com/ifreecoding/MbedRtos.git下载 第1节Mindows的文件组织结构 在第3章,我们依据任务切换的原理编写了Wanlix操作系统,Wanlix很简单,只实现了任务切换功能,从本章开始,我们将编写Mindows操作系统,Mindows将会实现更多的功能,相对Wanlix来说要复杂一些,文件也更多一些,因此,Min

ifreecoding的博客 620

第3章&nbsp;Wanlix操作系统

源码请在https://github.com/ifreecoding/MbedRtos.git下载 第3 章Wanlix操作系统 有了前面章节的铺垫,本章开始正式编写操作系统!本章将实现Wanlix操作系统,从零起步,先实现2个固定任务的互相切换来验证操作系统的切换功能,然后再不断的加入新功能,由浅入深,一步步将操作系统充实起来。每一个功能的加入都是一个独立的阶段性,读者可以通

ifreecoding的博客 606

linux操作系统&nbsp;任务管理器与调度概…

1. 任务调度概述:     任务调度(schedulers)是内核的主要职责,实际上它就是一个法官,决定当前由哪个任务占用CPU,多数实时内核都是基于优先级调度算法的,每个任务根据其重要程度的不同被赋予一定的优先级。基于此算法,CPU总是让处于就绪而且优先级最高的任务优先运行,然而何时高优先级任务能够得到CPU使用权,由内核的类型而定。基于优先级的内核有两种: 不可抢占型和抢占型。 1) 不可

李东军博客 544

Sublime&nbsp;Text&nbsp;2&nbsp;入门及技巧

以下文章根据 http://lucifr.com/139225/sublime-text-2-tricks-and-tips/ 进行部分修改,以适用Windows平台。感谢原文译者的努力。   看了 Nettuts+ 对 Sublime Text 2 的介绍, 立刻就兴奋了,诚如作者 Jeffrey Way 所说:“《永远的毁灭公爵》都发布了,TextMate 2 还没发”,你还能指望它么?Tex

zhexiao 1073
上一篇: 第3章第1节&nbsp;两个固定任务之间的切…
下一篇: 第3章第3节&nbsp;用户代码入口——根任务…
ifreecoding
博客等级 码龄15年 148粉丝 33原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值