开启辅助访问 切换到窄版

打印 上一主题 下一主题

嵌入式简易操作系统剖析(二)

[复制链接]
楼主
跳转到指定楼层
| 只看该作者 回帖奖励 |倒序浏览 |阅读模式
冬天没回你消息,不是因为高冷,而是因为手冷。




CYoung做一个有温度的公众号
这是我的第三十一篇原创文章


哎,这周过的真特么的憋屈,在弄USB打印机,又要搞USB协议栈,主要是USB打印机真鸡儿操蛋,不懂就是建立不了数据连接,如果有懂的小伙伴给我支支招呗。
上周写了一些关于嵌入式系统的文章,这篇我们就稍微的深入了解下任务调度呗,在ucos中核心就是任务调度,好多大神都说ucos的金典就是任务的调度。所以这篇文章写的不好的地方,还请多多宽待。
在我们嵌入式领域中,一般只有颗CPU,但是我们要实现多任务,这就要求我们有自己的堆栈,程序代码,数据存储区等,这一系列就是决定一个任务独立的最基本的条件。这个多说句,咱们人也是一样的,人要独立也得有自己的私有财产,让我们自己自由分配,不然怎么算的上最基本的独立呢?
01
可重入与不可重入函数在多任务中还有一个问题,就是可重入函数与不可重入函数的概念。那什么是可重入函数,什么又是不可重入函数呢?举个例子,一个低优先级的任务正在运行,他在操作一个全局变量,可能已经改变它的数值,正想使用这个变量的时候,另一个高优先级的任务正好打断他们,也使用这个函数,改变了这个全局变量。
所以一般情况下可重入函数使用的数据为局部变量,不带静态局部变量的那种。还有一种如果有malloc和free的也不是可重入函数。这里有点比较重要的是,全局变量是系统各个任务共享的,所以在似乎用多任务操作系统中尽量不要使用全局变量。
如果两个任务共用一套数据,破坏原先的数据结构,这时候我们就引入两种方法解决:可重入函数的设计和互斥调用。互斥调用就是之前说的临界区。
02
临界区临界区函数要求是互斥的,意思是说一次仅允许一个任务使用公共资源,中断也不可以影响,这个是为了保障数据的可靠性和完整性,我们之前使用的临界区是关中断的方式,其实还有一些,例如:使用互斥信号量,关任务调度等等。

这里要注意的地方是,在临界区的代码必须成对的出现,否则会出现不可预测的问题。我们使用临界区的时候,临界区的代码尽量短,因为一直在临界区中,别的任务是无法有使用CPU的机会的,这样会影响多任务系统的使用性能。
03
任务堆栈大伙也知道,我们在创建任务的时候,除了会传入任务优先级,还会传入一个任务栈,这个任务栈其实就是一个全局变量的静态数组。为啥用数组呢?主要他是地址是线性的,我们在使用的时候,如果这个栈是递增栈,只需要将栈顶指针SP指向数组首元素;如果是递减栈,SP指针指向最后一个元素,这样就实现了一个任务的私有栈了。

要注意的是,我们传入的栈大小视情况设定,避免导致任务的栈溢出,出现不可预测的问题,甚至可能出现系统奔溃的问题。
到目前为止,我们只解决了一个任务栈的问题,但是还没有说明如何进行任务的切换调度的问题。我们要实现任务的切换,还有一个条件就是要知道各个任务的栈顶指针的变量。说白了就是要保存它,这里就引入一个任务控制块的概念。
04
任务控制块什么是任务控制块呢?简单的说就是系统记录任务执行的环境,在ucos中任务控制块内容贼鸡儿长,长到什么地步呢?结构体有60多行,反正就是一张图片放不下呗。内容包括当前任务栈位置,任务栈大小,任务状态等等。




是不是特别的长,这里列出两个简单的务控制块,只包含了任务的堆栈指针和任务延时节拍数。

这个任务块结构体有点要注意的是,任务栈的栈顶凡在第一个位置,为什么这样做呢?原因是结构体首元素的首地址和结构体的地址是相同的,我们访问结构体的第一个元素,只需要得到结构体的地址即可。这个方式的好处我在之前的文章有介绍。感兴趣回头瞅瞅。
任务控制块是任务切换中的关键,也是任务的唯一标识,他里面保存任务的所有信息,他将任务的代码与数据链接起来,我们只要找到任务控制块就能找到任务的所有资源信息。
任务的三要素分别为:任务程序代码,任务私有堆栈和任务控制块。看下图可能就能了解任务控制块的重要性了。


目前为止,我们了解了任务的调度过程,但是还是少了一些细节,就是任务是如何进行切换的。这里就涉及到一些arm汇编的问题了,关于汇编我也不是很懂,反正不会就百度呗。
还有一点比较重要,就是在C语言中,我们是不可以直接访问SP指针,只能用汇编的形式,我们先定义一个结构体指针指向当前任务块,然后用汇编把当前任务的栈赋值给SP指针即可。代码示例如下:

汇编代码如下:
任务切换时,把当前任务的现场数据保存在自己的任务栈里面,再把待运行的任务的数据从自己的任务栈装载到 CPU 中,改变 CPU 的 PC,SP,寄存器等。可以说,任务的切换是任务运行环境的切换。而任务的运行环境保存在任务栈中,也就是说,任务切换的关键是把任务的私有堆栈指针赋予处理器的堆栈指针 SP。部分代码示例如下:

任务调度的汇编函数示例如下:

上面的代码看不同没关系,我们只需要知道的他是怎么实现任务切换的的就可以了,毕竟我们并不是写操作系统的,任务切换流程图如下:

好吧,这篇文章先写到这里,我想可能没有多少人能耐心的看到这里,能看到这里的人,个人觉得是真正想了解系统的人。再者我写的也比较简单,因为微信文章与文档还有差别的,只是给大伙介绍为主,并不是以实现为目的。
那就这样吧,周末愉快,大伙。还有还有,有了解USB协议栈的可以带我学习学习,感激不尽!


-END-



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表