分享

小白 30 分钟学会移植操作系统 - UCOS 系列一

 求知_时光 2019-06-20

在开始前,给大家一个问题:

为什么我们需要操作系统?就像最开始学C编程时,老师告诉我们,指针很重要,那时你肯定有一个大的疑问,指针到底有什么好?心里一直犯嘀咕着:不用指针不一样把程序编出来了?  现在想想看c语言没了指针,是不是寸步难行呢。回到正题,我们到底为什么需要操作系统?


这一篇,主要讲解理论层面的知识,忍住,看下去。后续将会进行傻瓜式移植操作系统的教程。准你能学会。

前言:

首先比较主流的操作系统有UCOSII、FREERTOS、LINUX等,UCOSII的资料相对比其余的两个操作系统的资料是多很多的。在这里选择 UCOSII/UCOSIII 来讲解。

1、操作系统的作用

操作系统是计算机硬件系统与应用程序之间的接口,应用程序设计人员只是以操作系统层为基础使用计算机系统,所以程序设计人员

看到和使用的只是一些由计算机操作系统所提供的函数API,至于操作系统的这些底层函数是怎么实现的,作为一个应用开发人员是不需要管的。

2、嵌入式系统的特点

(1)专用性强:嵌入式系统通常是面向某个特定的应用的,所以嵌入式系统的硬件是特定用户群来设计的

(2)可以裁剪:Linux系统有很多网络协议栈之类的,有些做个数码相框的,没有必要的话,那么直接把那段源码去掉也是可以的

(3)实时性与可靠性:所谓的实时性不是指,你代码写的东西必须要马上执行,而是你写的代码可以在合适的时间中执行,因为操作系统有很多机制,比如资源的抢占,优先级低的任务是不可能实现。

【重点理解实时性】

3、嵌入式实时操作系统的基本功能:

(1)内存管理:

内存管理主要是动态内存的管理,当应用程序需要使用内存的时候,可以利用操作系统所提供内存分配函数来获得足够的内存空间。

动态内存就是指malloc、free函数的分配,就是从堆里面拿内存,因为我们本来嵌入式系统的内存分配就比较少,所以这里很关键。

(2)多任务管理:

裸机就是一个单任务的前后台的程序,就是一个任务加上中断的机器的实现方法。程序设计人员就可以按照多线程来设计自己的程序,程序的耦合性和单元测试方面就会比较的容易。关键就是程序的可复用性会更加的好。

(3)外围资源管理:

除了本身自己必须需要的东西,内存和CPU,还有很多输入型设备和输出型设备需要管理。

由于资源是有限的,因此操作系统必须对这些资源进行合理的调度和管理,才能保证每个要使用资源的任务在运行时可以获得足够的资源。

4、裸机和操作系统最大的区别

裸机是在一个main函数中不断的执行,除了有中断才会跳转到别的相应的代码中执行的。不然运行的指针就会按照地址的不断的加地址来执行。顺序的执行结构,就是你可以通过代码的找到相应的执行流程。

一般的简单的嵌入式设备的编程思路是下面这样的:

main

{

    {处理事务1};

    {处理事务2};

    {处理事务3};

        .......

    {处理事务N};

}

isr_server

{

    {处理中断};

}

这是最一般的思路,对于简单的系统当然是够用了,但这样的系统实时性是很差的,比如“事务1”如果是一个用户输入的检测,当用户输入时,如果程序正在处理事务1下面的那些事务,那么这次用户输入将失效,用户的体验是“这个按键不灵敏,这个机器很慢”,而我们如果把事务放到中断里去处理,虽然改善了实时性但会导致另外一个问题,有可能会引发中断丢失,这个后果有时候比“慢一点”更加严重和恶劣!又比如事务2是一个只需要1s钟处理一次的任务,那么显然事务2会白白浪费CPU的时间。


操作系统之后,main函数,当通过函数堆栈切换的跳转到第一个任务之后,通过优先级的判断优先级高的任务可以得到优先的执行,就好像有多个main函数在一起执行的假象(并行)

main

{

      {任务1的时间片到了则处理任务1};

      {任务2的时间片到了则处理任务2};

               .......

      {任务N的时间片到了则处理任务N};

}

time_isr_server

{

       {判断每个任务的时间片是否到来,并进行标记};

}

isr_server

{

      {处理中断};

}

我们可以看到,这种改进后的思路,使得事务的执行时间得到控制,任务只在自己的时间片到来后,才会去执行,但我们发现,这种方式仍然不能彻底解决“实时性”的问题,因为某个任务的时间片到来后,也不能立即就执行,她必须等到当前任务的时间片用完,并且后面的任务时间片没到来,她才有机会获得“执行时间”。

这时候我们需要继续改进思路,为了使得某个任务的时间片到来后能立即执行,我们需要在时钟中断里判断完时间片后,改变程序的返回位置,让程序不返回到刚刚被打断的位置,而从最新获得了时间片的任务处开始执行,这样就彻底解决了任务的实时问题。

我们在这个思路上,进行改进,我们需要在每次进入时钟中断前,保存CPU的当前状态和当前任务用到的一些数据,然后我们进入时钟中断进行时间片处理,若发现有新的更紧急的任务的时间片到来了,则我们改变中断的返回的地址,并在CPU中恢复这个更紧急的事务的现场,然后返回中断开始执行这个更紧急的任务。


简述:需要执行任务 -> 判断对应的任务的时间片是否到了 -> 到了,执行任务 -> 时间片时间用完了 -> 挂起此任务,切换成新的任务,新一轮时间片开始计时。

上面的这段话有些不好读,事实上,这是因为要实现这个过程是有些复杂和麻烦的,这时候我们就需要找一个操作系统(OS)帮我们做这些事了,如果你能自己用代码实现这个过程,事实上你就在自己写操作系统了,其实从这里也可也看出,操作系统的原理其实并不那么神秘,只是一些细节你很难做好。uCos就是这样一个操作系统,她能帮你完成这些事情,而且是很优雅的帮你完成!

到这里,我们终于知道了为什么我们需要uCos了。事实上,uCos的用处远不止帮你完成这个“事务时间片的处理”,它还能帮你处理各种超时,进行内存管理,完成任务间的通信等,有了它,程序的层次也更加清晰,给系统添加功能也更方便,这一切在大型项目中越发的明显!

奋斗的小青年,终生学习者

有趣的灵魂终会遇见。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多