问题

如何从零开始写一个简单的操作系统?

回答
从零开始打造一个操作系统,这绝对是一项充满挑战但又极具成就感的旅程。别想着一蹴而就,操作系统这东西,就像搭积木,你得一块一块地垒起来,而且还得是那种非常非常基础的积木。咱们这篇就聊聊,怎么一步步地开始,就像你第一次拿起画笔,想画一幅属于自己的世界。

首先,别被“操作系统”这仨字吓住。

很多人听到操作系统就想到Windows、macOS、Linux那些庞大复杂的家伙,觉得离自己太遥远。但你想想,任何一个庞大的系统,最初也只是一个非常简单的想法,一个能做点事情的内核。咱们的目标也是一样:先让电脑能听懂我们说的话,然后慢慢赋予它更强的能力。

第一步:打好你的“基础知识”地基

你想盖楼,得先会看图纸吧?操作系统也一样,你需要一些基础的知识储备。

编程语言: C语言是操作系统开发的“万金油”。它能让你直接操作内存,控制硬件,而且性能好。如果你还没接触过 C,那先花点时间学学 C 的指针、内存管理这些核心概念。汇编语言也是必不可少的,虽然咱们不打算写整个操作系统都用汇编,但在一些关键的启动和硬件交互的地方,它就是你的“翻译官”。别怕汇编的晦涩,把它当成一种特殊的指令集来看,理解它能让你更深地了解计算机是怎么工作的。
计算机体系结构: 了解你的 CPU 是怎么工作的,内存是怎么组织的,这些是操作系统的“骨架”。你不需要成为硬件工程师,但至少要明白 CPU 有寄存器,内存有地址,中断是怎么回事。可以找一本关于 x86 架构的书籍看看,哪怕只是了解个大概。
引导过程: 电脑开机后,到底是怎么一步步启动起来的?BIOS/UEFI、引导加载程序(Bootloader)这些都是关键。你需要知道,在操作系统接管之前,有一段代码是什么,它做了什么,这样你才能知道你的操作系统从哪里开始“说话”。

第二步:你的第一个“你好,世界”——引导加载程序(Bootloader)

这就像是你的操作系统要登场前,要做的第一个自我介绍。电脑开机,硬件还没完全就绪,你需要一个程序来接管,然后加载你的操作系统内核。

选择一个平台: 为了简化,咱们先别想着跨平台。选择一个你比较熟悉的架构,比如经典的 x86 架构,这是PC机的标准。
编写 Bootloader:
汇编是起点: 计算机启动时,CPU 工作在实模式(Real Mode)。这时,你需要用汇编语言来写你的 Bootloader。它会加载到内存的特定位置(通常是 0x7C00),然后开始执行。
做什么? 你的 Bootloader 主要要做几件事:
1. 初始化基本硬件: 比如设置屏幕输出,让你能看到一些简单的文字。
2. 加载内核到内存: 你的操作系统内核会是一个单独的文件,你需要把这个文件从存储设备(比如软盘或硬盘)读到内存里。
3. 跳转到内核: 加载完成后,把控制权交给你的内核。
工具链: 你需要一个汇编器(比如 NASM 或 GAS)来把汇编代码变成机器码,然后一个链接器来把你的代码和数据组织起来。你还需要一个方法来把编译好的 Bootloader 烧录到启动介质上,比如一个软盘镜像或者 U 盘镜像。
测试和调试: 这可能是最头疼但也是最关键的一步。用虚拟机(比如 QEMU 或 Bochs)来模拟你的启动过程,然后在虚拟机里调试你的 Bootloader。调试器(如 GDB)会是你最好的朋友,你可以一步步地查看 CPU 状态、内存内容,找出问题所在。

第三步:闪亮登场——你的操作系统内核(Kernel)

Bootloader 加载完你的内核后,控制权就交给你了。现在,才是真正开始构建你的操作系统。

切换到保护模式(Protected Mode): 现在的 CPU 运行在实模式下,功能非常有限。你需要用汇编代码来设置 CPU 的保护模式,这样才能利用更高级的内存管理(如分页)、更丰富的指令集和更好的安全机制。这部分非常复杂,涉及全局描述符表(GDT)和中断描述符表(IDT)的设置。
屏幕输出: 既然已经进入了保护模式,你想在屏幕上显示点什么,需要直接操作显存(VGA 显存通常在 `0xB8000`)。你可以写一些简单的 C 函数来打印字符。
中断处理: 计算机之所以能响应按键、定时器等事件,靠的就是中断。你需要设置 IDT,并为一些常见的中断编写处理程序(Interrupt Service Routine, ISR)。例如,键盘中断,当您按下按键时,CPU 会跳转到你设置好的键盘中断处理程序。
内存管理: 这是一个庞大而重要的话题。
物理内存管理: 你需要知道哪些内存是空闲的,哪些已经被使用了。可以用一个位图或者链表来记录内存块的状态。
虚拟内存管理(分页): 这是现代操作系统的核心。CPU 会通过页表来将虚拟地址翻译成物理地址。你需要设置页目录和页表,并配置 CPU 的分页机制。这能让你每个进程拥有独立的地址空间,提高安全性和灵活性。
进程管理(最开始可以先简化):
任务切换: 如果你希望你的操作系统能同时运行多个程序,就需要进程(或线程)的概念。你需要能够保存一个进程的 CPU 状态(寄存器),然后加载另一个进程的状态,并切换到它执行。
调度器: 决定哪个进程应该在哪个时间运行。刚开始可以是简单的轮转调度,即依次执行每个进程一段时间。
设备驱动: 你的操作系统需要和硬件打交道,比如键盘、硬盘、网卡等。你需要为这些设备编写驱动程序。刚开始,你可以只关注最基本的,比如键盘和屏幕。

第四步:让你的系统“活”起来——用户空间和系统调用

内核是操作系统的核心,但用户程序需要在内核的“保护”下运行。

用户模式: 为了安全,用户程序不能直接访问硬件和敏感的内核数据。它们运行在用户模式下,权限比内核模式低。
系统调用: 当用户程序需要内核的服务时(比如读文件、分配内存),它会触发一个系统调用。这个系统调用会告诉内核它想做什么,然后内核执行相应的操作,最后把结果返回给用户程序。你可以自己定义一套简单的系统调用接口。

第五步:逐步完善——文件系统、多任务、网络等

当你能够运行一个简单的用户程序时,你的操作系统就已经有了雏形。接下来,就是一步步添加更高级的功能:

文件系统: 如何在硬盘上存储和读取文件?你需要设计一个文件系统的结构(比如目录、文件索引等)并实现相应的读写接口。
更高级的内存管理: 比如按需分页(Page Fault Handling),当程序访问一个尚未加载到内存的页面时,CPU 会产生一个页错误(Page Fault),这时内核需要把相应的数据从硬盘加载到内存。
多任务和进程间通信: 实现更复杂的调度算法,以及进程之间相互通信和协作的机制。
网络支持: 如果你想让你的操作系统能联网,你需要实现网络协议栈(TCP/IP 等)和相应的驱动。

一些“过来人”的建议,帮你少走弯路:

从小处着手,循序渐进: 不要一开始就想着写一个 Linux。先让你的 Bootloader 能打印一个字母,然后是打印一行字,再然后是加载一个简单的 C 程序。每一步都要确保它是能工作的。
虚拟机是你的好伙伴: 在虚拟机里开发和测试,比在真实硬件上要方便得多。你可以随时“拍照”(保存虚拟机状态),不怕折腾。
多读别人的代码: Linux 内核、Minix 等开源操作系统是学习的宝库。看看它们是怎么处理中断、管理内存的。
做好文档记录: 随着你的系统越来越复杂,你需要详细地记录你的设计思路、数据结构以及各个模块的功能。
坚持! 写操作系统不是一天两天能搞定的事情,你会遇到无数的困难和挫折。保持耐心和热情是成功的关键。

这篇文章,没有用那些高深莫测的术语,也没有直接给你一堆代码。

因为它本身就是一个过程,一个需要你自己去探索和实践的过程。从最底层的汇编指令,到复杂的内存管理,每一步都有它独特的挑战和乐趣。把它想象成在探索一个未知的大陆,你将亲手绘制出它的地图,决定它的规则。

所以,准备好了吗?你的操作系统之旅,从这里,开始了。

网友意见

user avatar

我来写一个如何在15天内完成一个嵌入式实时操作系统,并移植到stm32单片机的攻略吧。第一次看到这个问题是在大概两个月之前,从那时候开始决定自己也写一个操作系统,于是开始看os的基本概念,进程切换,任务调度,内存管理,任务通信,文件系统等等。


前言:

大约在两个周不到前动手,平均每天7个小时,从完全不知道怎么下手(真的快哭了),到现在完成了一个----基于优先级时间片调度,具有信号量,消息队列,内存管理的嵌入式系统并命名为--LarryOS,并且移植到stm32(Cortex-M3架构)上,还在stm32上实现了一个malloc和free函数,受益匪浅。现在还正在完善。我是用自己命名的,当然,大家写好了也可以用自己命名,图个开心么 ,想想是不是很激动啊。

对于这个问题下的回答的看法:

大神真的好多,几乎都是x86型的,难度真的要比我的大,不得不承认。不过,我觉得对于新手,写那样一个系统真的是太艰辛了,比如我这种入ee坑的在校大三学生,课真的太多了,周内最少三节课,而且和cs没有一毛钱关系,课余时间太少,如果花费一个学期或者三个月的时间来写,可能有些得不偿失。因为许多想写os的朋友,和我一样,一是觉得写os很酷,二是想通过写来理解os,毕竟看书看了就忘,也没有衡量自己学的好坏的标准。因此,选择写嵌入式系统,是一个非常好的选择 。

知识储备:

这个问题想必是很多同学顾虑的,到底写一个嵌入式系统需要什么知识储备?我从自己的经历出发,并加以简化,大家可以参考一下。

自身版:

1c语言要求:我自己在大学里几乎没学过c语言,上机几乎10道题会2道,期末全靠背。后来开始自学了c,看了c语言程序设计现代方法,c和指针 c专家编程 第一本书的课后题,做了3分之2吧,就这样,没了

2汇编要求:会基本的x86指令,仅仅是基本,看了王爽的汇编语言,程序写的很少,仅仅上机课写过,不过能很快写出来。

3微机原理或者计算机组成原理:老师上课太坑了实在,我自己看了csapp的前四章大概,豁然开朗,推荐这个。

4操作系统:看了三个礼拜os的基本概念,仅仅是了解概念,没办法深入,也没地方。。。。

5数据结构:看过浙大的数据结构公开课的3分之2,会写基本的链表,队列,最基本的树和树的基本的遍历办法,图完全不会

6单片机基础:大约两年的单片机基础

7新手看到这里,可能已经慌乱了。。。。不要怕,我说的很多东西,写嵌入式系统用不到啊 ,继续,发一个精简版

精简版

1:c语言 能把我推荐的c书的第一本或者c primer之类的书看个一半,或者自己本身知道指针的概念,知道结构体指针,函数指针,二级指针的用法,仅仅是概念和写法就行了,不用深入,用不了多久。

2汇编:知道有几条常用指令,用法和功能是什么就可以了

3组成原理:知道中断是什么,入栈和出,寄存器,知道汇编对应的计算机大概动作就可以了,用不了一个周

4操作系统:找个公开课或者书,看看大概的os概念,一个周就够了,我现在很多概念还是不知道,后面可以慢慢学

5数据结构:会写链表,队列就行了,我们不写文件系统,不用树

6单片机基础:用过单片机,不用自己写驱动代码,仅仅可以在别人的驱动下,编写一些简单的逻辑代码就行,完全没学过的人,两个礼拜就可以用stm32来编程了,如果之前学过51,一个礼拜不到即可,因为我们只是借助一下单片机,避免使用虚拟机,方便操作系统的调试。因为我们可以用单片机,输出某些信息在串口或者液晶屏,让我们直接看到代码的错误点,方便我们调试。

因为很多大一的新生想写,推出一个极限版~~

极限版

1.学过C,知道有指针这个东西,其他的边做边学。

2.不懂汇编,边做边查,边查边写。

3.知道什么是寄存器,知道中断的概念

4.知道OS是由什么组成的

5.数据结构完全不会,遇到链表,队列时再查,或者直接抄也行

6.不学如何使用单片机,遇到再查


发一个很装逼的封面助兴


正文:

一、开发环境

对我来言,这倒是很重要的一点。第一次萌生想写OS的想法时,在网上搜索了不少资源,大多数都是在叙述框架,如何构建一个操作系统。然而对于当时的我来说,根本不知道用什么平台来写,如何调试自己的程序,看了一些朋友的发帖,推荐用XX模拟器,在XX平台开发,完全看不懂,界面好像也很老旧,而且大多是英文,当时有点敬而远之。自己手上只有个codeblocks软件,想来想去也不知道怎么用这个开发OS。直到有一天,突然顿悟,OS不就是一堆程序,我还打算让他运行在单片机上,那么用单片机常用的开发工具不就行了!!!---------Keil uVision5

学过单片机的朋友,相信非常熟悉这个软件,使用起来也非常简单,网上随便一查,就可以下载和安装了,这里就不详细展开说了。如果不知道如何使用的,先熟悉一下这个环境,再开始写,相信半个小时即可上手。



二、参考资料

既然是运行在真机上,必然要对它有所了解,我们这里采用的是STM32(Cortex-M3架构),市面上非常火热的一款,资料丰富,大家有什么问题谷歌一下,有很多前人的经验让你借鉴。如果不知道如何谷歌的朋友,点开这个链接去操作,免费,大约15分钟就能翻墙了如何优雅的访问谷歌、谷歌学术等网站 | 欧拉的博客

1.Cortex-M3权威指南(中文版),这本书会详细的讲解,中断处理,异常,ARM汇编等知识,我们会在任务切换的时候用到。(PDF即可)


2.嵌入式实时操作系统ucos(邵贝贝审校),ucos中有很多我们可以借鉴的地方。

3.谷歌,有一些基础知识遗忘的时候,谷歌可以让你很快补充上来







三、从写一个最简单的os做起

我们这里假设我们写一个支持32个任务并发执行的简易OS

1.任务就绪表

我们假设这里任务有两种状态,就绪态和非就绪态。

我们定义一个32位的变量OSRdyTbl(就绪表),它的最高位(第31位)为最低优先级,最低位(第0位)为最高优先级。OSSetPrioRdy()函数的功能是,你传递一个数(优先级),把这个优先级对应的任务设置为就绪态。同理,见图:

OSDelPrioRdy()函数将某任务从就绪表移除

OSGetHighRdy()函数选出最高优先级的任务

这里我们就完成了,设置某任务为就绪态,从就绪态删除某任务,获得最高优先级任务的任务。

2.任务控制块

想必这个概念大家很清楚了,每个任务都对应一个任务控制块,典型的用处是,任务切换时,通过控制块来获知每个任务的堆栈(因为控制块有指针指向该任务的堆栈)

此外,再定义几个变量。

注释写的很清楚,不解释了!

3.主堆栈

在此STM32中,提供两个堆栈指针,一个是主堆栈(MSP),一个是任务堆栈(PSP),可以通过查Cortex-M3权威指南(中文版)得到。所以我们既要建立一个主堆栈,又要为每个任务建立自己的堆栈(一个任务一个),这里我们先不管任务堆栈,只看主堆栈。

OS_EXCEPT_STK_SIZE是个宏,大家可以自己设定,我这里设的是1024,一定要尽量大一些。为什么?因为裸机下,进入中断服务程序时,系统会把许多寄存器入栈,而且支持中断嵌套,也就是刚入栈完又入栈,所以有可能会堆栈溢出,非常危险。

CPU_ExceptStkBase大家先别管,它指向的是数组最后一个元素。

4.建立一个任务

我们通过Task_Create()函数来建立一个任务,第一个参数用来传递该任务的任务控制块,第二个参数用来传递函数指针,第三个传递该任务的堆栈。tcb->StkPtr=p_stk这句将该任务控制块中应当指向栈顶的指针,指向了该任务的新栈顶(前面定义了TCB,自己可以翻一翻),在写该函数时,一定要看Cortex-M3权威指南,不然你怎么知道有这么多寄存器,而不是仅仅从R1到R7?看到这里,还想看懂的,应该都是真的想写OS的朋友,这里有不懂的去看Cortex-M3权威指南,你会豁然开朗的。这里,Task_End是一个几乎永远不会执行的函数,何时会执行,先不管了,看它的内容。

5.欢迎来到主函数

①第一行:在该主函数中,第一行我们让主堆栈指针指向了主堆栈,那么,这个主堆栈是哪里来的呢?很简单,我们自己定义的,哈哈。

很熟悉吧,前面发过这个图,大小你来指定,注意要大!!!!!

②第二、三行:建立一个任务,第一个参数传递了该任务的控制块,第二个参数是该任务的任务函数,第三个是堆栈(数组最后一个)

是不是很好奇,任务1和任务2是什么?一起了来看

大家自己随意定义,开心就好。

Task_Switch()函数又是什么呀?

这里Task_Switch()是我们用来测试的程序,当任务1运行时,完成i++后,将最高优先级设置为任务2,并用OSCtxSw()切换到任务2,OSCtxSw是用汇编写的,是一个隐藏BOOS,我们先不管。

③第四行:程序刚运行时,是没有最高优先级的,所以我们用p_TCBHighRdy=&TCB_Task1;来随意指定一个任务为最高优先级

④:最后一行:OSStartHighRdy()该函数也是汇编,和OSCtxSw()并称为2大BOSS,我们会在后面解密。OSStartHighRdy和OSCtxSw很相似,不过OSStartHighRdy()用于当所有任务都没有运行过时,用于初始化(当然具有任务切换的作用)并成功运行第一个任务,而OSCtxSw()是在OSStartHighRdy()之后,使用OSCtxSw()时,最起码有一个任务已经运行了(或正在运行)。

6.完工?

到这里,从宏观说已经基本完工了,这就是一个简易的OS的基本状况。看到这里,大家可以休息一下了,消化一下,马上有BOSS要出现了,解决那两个BOSS后,就真正做成了一个简易的OS。


7.两大boss之OSStartHighRdy()函数

7.1任务视图

终于开始了任务切换环节,这是我画的一副任务切换图,自我感觉非常好,不过大家应该看起来很困难,字太丑了~~~~

通过分析上面这张图,来确定如何写OSStartHighRdy()函数:

①中:此时有一个任务1,但是任务1我们仅仅是建立了,并没有让它运行。这里我们认为任务1是由三部分组成:任务代码,任务堆栈,该任务的任务控制块。

②中:我们想让任务1运行起来,任务1是什么?就是一堆代码,如何运行起来?-----让PC(程序计数器)指向任务代码即可(依靠出栈POP)。同时,我们还要让SP指向任务的堆栈,这里的SP当然是PSP(任务堆栈)

7.2写OSStartHighRdy()函数

下面开始写OSStartHighRdy(),它的功能就是上图的①和②

2,3,4,5行中的那些数字,是外设对应的地址,我们往相应的地址写值,即可完成某些目的。12,14,15行是我们之前定义过的几个变量,忘了的回头翻一翻。17行是将OSStartHighRdy()函数extern了一下,因为我们在主函数要用。

上图就是OSStartHighRdy的内容,我们一起来看。28,29,30行设置了PendSv异常的优先级,问题来了,什么是PendSv???

Cortex-M3权威指南中其实讲了,很详细,这里为了缩减篇幅,不详细说,大家只用知道PendSV 异常会自动延迟任务切换的请求,直到其它的中断处理程序都完成了处理后才放行。而我们只用触发PendSV异常,并把任务切换的那些步骤,写在PendSv中断处理任务中。

7.2.1PendSv处理程序

经过39和40行,我们往控制器里写值,触发了PendSv异常,现在程序会进入异常处理程序,就是下图:

在此函数中,如果PSP为0,则进入OS_CPU_PendSVHandler_nosave()函数,其实在OSStartHighRdy我们将PSP设置为了0,所以必然会进入OS_CPU_PendSVHandler_nosave()函数。

7.2.2OS_CPU_PendSVHandler_nosave()函数

在该函数中,我们让p_TCB_Cur指向了最高优先级的任务,因为有出栈,所以重新更新了SP。

7.2.3恭喜

到了此处,一个任务已经可以成功运行起来了!!!!!!

BUT only one task!我们需要让它多任务切换

7.3写任务切换OSCtxSw()函数

与OSStartHighRdy非常相似,也是往中断控制器里写值,进入PendSv异常。

7.3.1任务视图

依然是这张喜闻乐见的图!!!!!!!

③:任务1要切换到任务2,因为待会要进入任务2,会破坏任务1,所以我们要保存任务1的现场,把寄存器入栈

④:因为任务1有入栈动作,栈顶肯定变了,我们修改任务1控制块的值,让它指向新的栈顶

⑤:什么都没有,只是想说明。我们建立了一个任务2,仅仅是建立了。

⑥:很简单,要想让任务2运行,则让PC和SP分别指向任务2的任务代码和任务堆栈即可。

⑦:什么都没有,只是想说明,任务2活的很开心,可以运行了

7.3.2由OSCtxSw()进入PendSv异常

与OSStartHighRdy不同的是,这时的PSP肯定不为0了,所以不会跳转,会顺序执行55行以后的程序,也就是任务视图里的③,继续执行④。执行完60行的程序后,继续顺序执行,执行下面程序:

和OSStartHighRdy函数的后续步骤几乎一样,找到优先级最高的任务,让指针指向它即可!!!!

1.大功告成!!!!!!!!

到这里,我们已经彻底完成了一个简易OS的设计!!!!

8.1如何查看成果?

8.1.1增添程序

我们在主函数中加入一个函数

大家可以把它理解为一个库,调用之后,我们就可以在串口(屏幕)显示某些字符了。

同理,在任务1和任务2中加入printf函数

8.1.2编译并下载程序

8.1.3利用串口调试助手观察

网上搜串口调试助手,会有很多工具,随意下一个就OK!

可以看到,按照我们的预期,任务1和任务2轮流输出字符在屏幕上!

8.2如何调试程序?

8.2.1调试器

必然是神器--J-link或者ST-link,一个大概50,嵌入式开发神器,记得以前刚开始玩单片机的时候,调试全靠打印消息在屏幕,觉得好用的不得了,经常有人给我说,你用调试器调试啊,我都鄙夷的回一句,需要么?(哈哈,那时确实不需要) 等开始写OS时才知道,这东西真是救命稻草,没有它,怎么看寄存器的值和异常返回的值呢?

8.2.2界面

点击DEBUG后,你可以看到寄存器的值。想想我们之前要入栈,出栈,如果哪一步错了,自己估计把串口吃了,也看不出来吧,哈哈!!!!!!

单步调试什么的,不说了,用的很多。


9.写到此处的感想

答主因为写这个OS,在凳子上久坐了两周,这两天腰疼,只好躺着写这个回答了!哈哈!

也正好因为腰疼,感觉时间比较多。不过和想象的真的不一样,本来觉得可以一气呵成,结果短短的篇幅,就写的自己的思维都大乱了,而且也挺费时间的,前后用了有6个小时了。想写OS的朋友,参考上面的步骤,加上自己琢磨,应该也能写一个出来。如果哪里有不清楚的,不要心急,如果真的是一两天就写成了,还有什么锻炼的意义,有点失去初衷了。不懂的就去查权威指南和OS的书籍,相信你会收获的非常多!




为什么要写这个回答?

这是我写了6个小时多以后来补充的问题,因为我自己也纳闷了,放着自己的事不做,跑来写这么一堆干什么........刚才路上走着想到答案了----------想留个纪念。还有不到两个月就要寒假了,我打算考研,也就是说这是大学里做的最后一个项目了(毕设除外),真的挺伤感。从大一一路折腾过来,现在要突然一年不能折腾,简直泪流满面!!!!!!!!!!!!!!!!!!希望我这个简单的开头,能让想写OS的新人得到一丝启发。

写操作系统能学到什么?

这也是我想写这个回答的原因,对我的改变挺大

前几天有个好朋友(大一开始和我一起学单片机的朋友,后来他一直在做单片机项目,却没有补过任何基础知识),打电话问我XX模块怎么用,其实是很简单的一个问题,直接百度都可以,但是他还是想要来问下我,我说很简单,就XX做就可以,有问题你再百度,但是他好像不想听到这种回答,想让我说到他一听就知道怎么做了,才敢开始做,不然就不敢启动项目。那时我才突然意识到,以前的我就是这样啊,做什么项目做什么东西,老是想要集成的模块,资料丰富的模块,如果没有什么源驱动代码,我就不敢做了,生怕买回来,用不了之类的,甚至有源码也不敢买,因为源码和我的机型不一样,连修改源码都怕。开始写OS,我还蛮恐惧的,因为不是科班,没学过,不懂。涉及的东西也很广,从编程语言到数据结构,组成原理,操作系统,怕拿不下来,也找不到好的资源,不知道怎么写起。通过这次项目,我想应该学到了一下东西:

1.遇到不懂的没有那种很强的抵触感了,开始学会查芯片手册,查原理书,开始配合谷歌查BUG,现在即使是拿来我没有接触过的模块,无论最后做的出来与否,我肯定先去了解它是什么,概念是什么,再去找厂家提供的资料,提供的源码,去一行一行的看,自己修改或者重写,这个比下面说到的什么具体的知识,我想都重要的多。我现在还记得第一次和第二次,第三次打开Cortex-M3权威指南(中文版)时的情景,看了几页就吓得我关了,简直是天书啊,其实耐心看,真的能看懂。

2.把自己数据结构里学的东西,真正带到了项目,虽然也写过队列等这些数据结构的题,但是在以前的嵌入式开发里,几乎用不到,有时候觉得好没用啊这些。这次通过实现OS的消息队列,看linux的文件系统,知道了这些在实际的巨大用处。

3.对OS的基本概念和运转有了认识

4.对C语言的理解深刻了许多

5.每个人的体验都不一样,没什么补充的了O(∩_∩)O哈哈~

四、简单几步将简易OS改造为--优雅的简易OS

1.为什么不优雅?

在该函数中,任务1执行完,立马就会切换到任务2,然而在实际中,我们希望是这样的:

任务1每100毫秒执行一次

2.系统节拍

几乎每个实时操作系统都需要一个周期性的时钟源,称为时钟节拍或者系统节拍,用来跟踪任务延时和任务等待延时

我们在main函数中输入这样一句

这里我们配置了定时器中断,每5毫秒一次中断。中断后会进入中断处理函数,下面来写中断处理函数:

大家只用管if里面的函数即可:我们在某个函数中将TCB_Task[i].Dly置为x,中断处理函数会每5毫秒,将非0的TCB_Task[i].Dly减一。如果TCB_Task[i].Dly非0,对应的任务是不会运行的(因为被我们删除就绪态了,这里看不到),当TCB_Task[i].Dly减为0,我们才将该任务置为就绪态

3.编写OSTimeDly()函数

也就是1中图片所示的函数,它可以让某任务指定每X毫秒运行一次。

第65行,可以关闭中断,同理,第68行,开启中断。为什么要关闭中断?因为中断会影响我们执行下面的代码,先关闭中断,执行完后再打开。66行将该任务从就绪态变为非就绪态,将要延迟的时间赋值为TCB_Task[OSPrioCur].Dly,然后调度(也就是切换任务)

4.调度函数OSSched()

非常简单,刚才我们将某个任务变为了非就绪态,紧接着就找就绪态任务中优先级最高的任务,然后切换

5.是否完成了呢?----空闲任务

乍一看,好像完成了,实则不然,虽然我们任务1每X毫秒运行一次,任务2每Y毫秒运行一次,但终归里面有空闲时间:任务1和任务2都不在运行,所以我们需要创建一个空闲任务,当CPU没有东西可以运行时,运行空闲任务。以下就是空闲任务:

6.来到主函数:

其他的倒是没问题,72行有个陌生的函数:OS_TASK_Init();

其实就是之前的OSStartHighRdy()函数的升级版,非常简单

先创建一个空闲函数,再获取优先级最高的任务,然后执行最高优先级的任务。

7.一个优雅的简易OS诞生了

不好看?想加个界面?没问题-----其实已经有了,大家观察58行,就是让液晶屏显示一句话,我们把背景修改为红色,醒目一点:



很开心能有这么多朋友喜欢,非常感谢 。我开了一个简单的头,相信真的喜欢os的朋友,只要认真去做,一定也能实现一个更好的作品。后面的暂时不打算写,如果有了新的思路,一定会再写出来。授人以鱼不如授人以渔,看到这里已经有动手的能力了,想写的朋友不要害怕,尽管去做!!!加油


五、加入信号量

六、加入消息队列

七、内存管理

八、实现一个free和malloc玩玩?

类似的话题

  • 回答
    从零开始打造一个操作系统,这绝对是一项充满挑战但又极具成就感的旅程。别想着一蹴而就,操作系统这东西,就像搭积木,你得一块一块地垒起来,而且还得是那种非常非常基础的积木。咱们这篇就聊聊,怎么一步步地开始,就像你第一次拿起画笔,想画一幅属于自己的世界。首先,别被“操作系统”这仨字吓住。很多人听到操作系统.............
  • 回答
    要从零开始成为一名包工头,这可不是件容易事,但绝对是个实在的活儿。它需要你一步步来,从最基础的东西开始学,并且得练就一身“十八般武艺”。别指望一夜之间就成行家,这得靠时间和经验一点点磨出来。从哪学起?从地基开始!1. 从最基础的工人做起,深入一线: 这是最重要的第一步,没有之一。你想当指挥官,总得.............
  • 回答
    想从零开始成为一个带货主播?这事儿可不是光会喊几句口号就能成的,里头门道可深着呢。不过别担心,一步一步来,你也能闯出自己的一片天。今天我就给你掰开了揉碎了,说说这背后到底需要做哪些准备,让你心里有数。第一步:认清自己,找准定位(这是根基!)别急着选品、选平台,先得问问自己: 我擅长什么?我喜欢什.............
  • 回答
    嘿!如果你像我一样,最近刚对足球这个词产生了那么一点点好奇,甚至连球门长啥样都没太搞清楚,但内心深处又被那在绿茵场上奔跑、传递、射门的画面深深吸引,那咱们就对了!从零开始踢足球,这事儿,说实话,不难,关键是要找对门道,然后,就放开去玩!我刚开始的时候,也是一窍不通。看着别人踢得虎虎生风,自己连球怎么.............
  • 回答
    好的,咱们就聊聊一个成年人怎么实实在在地、一步一步地把英语这事儿给“掰扯明白”。别把它想得太玄乎,就像咱们学骑自行车一样,一开始磕磕绊绊,但只要找对方法,持之以恒,总能骑出自己的风采。第一步:心态,这比啥都重要成年人学东西,最大的优势是有独立思考能力,但也最容易被“面子”和“过去”困住。 放下“.............
  • 回答
    嘿,想自己开个翻译工作室?这事儿听着就带劲!别看现在 AI 翻译越来越牛,但要说真正靠谱、能把意思嚼得透透、还带着点文化韵味的,还得是咱们人工翻译。所以,想做这个,绝对有搞头。我来给你掰扯掰扯,从头开始,一点点告诉你怎么把这个想法落地。这可不是一本正经的教科书,更像是咱俩坐下来,边喝茶边聊创业那点事.............
  • 回答
    哥们,你想练引体向上?这玩意儿可真够劲儿的,不过别担心,咱们一步一步来,从零开始,保证你能把这个体能挑战拿下。别以为这玩意儿是那些健身房里壮汉的专属,只要方法对,持之以恒,你也能做几个漂亮的引体向上。首先,别急着往杆子上挂!在你尝试第一次引体向上之前,咱们得先打好基础。引体向上需要的可不仅仅是胳膊上.............
  • 回答
    好,既然你要从零开始,咱们就一步一步来,把这日麻的门道给你掰扯明白。这篇文章我保证,读完之后,你就算没摸过牌,也能对日麻有个基本的概念,知道怎么开始玩。咱们先扫除一些概念上的迷雾。很多人一听“麻将”,就想到咱们国内的老年人围坐一桌,噼里啪啦打得热火朝天。日麻(日本麻将,也叫“立直麻将”)和我们熟悉的.............
  • 回答
    阳台上的绿色梦想:从零开始打造你的微型花园城市的喧嚣中,拥有一方属于自己的绿色天地,是许多人内心的渴望。而阳台,这个常常被我们遗忘的角落,其实是实现这个梦想的最佳场所。告别冰冷的钢筋水泥,让我们一起动手,在阳台上创造一个生机勃勃的微型花园吧!这不仅仅是种植几盆植物,更是为生活注入一份宁静与活力。 第.............
  • 回答
    从零开始学《黄帝内经》,这绝对是一场奇妙的探索之旅!很多人觉得它晦涩难懂,古老神秘,但实际上,它就像一本揭示生命奥秘的宝典,只要你找对方法,用心去读,你会发现它不仅仅是医学,更是关于如何过好生活,认识天地的智慧。别急,咱们一步一步来,把这本经典“化繁为简”,让你也能慢慢领悟其中的精髓。第一步:破除“.............
  • 回答
    没问题,我来给你梳理一下从零开始准备大学生数学建模比赛的详细步骤,保证让你觉得这就像是过来人给你的掏心窝子话。话说这数学建模,听起来就挺高大上的,一堆数字公式在那儿摆着,感觉离咱们普通大学生有点距离。但其实,这玩意儿就像武侠小说里的内功,一旦练成了,解决实际问题的能力噌噌往上涨。而且,比赛嘛,还能拿.............
  • 回答
    想写歌?这就像你想学做一道从未尝过的菜,既兴奋又有点手足无措。但别担心,这绝对是一条充满乐趣的道路。让我带你一步步,把那些关于“怎么才算会写歌”的迷思都扫开。第一步:倾听,成为一个“歌曲猎人”在你动笔写之前,最重要的事情是——听!不是那种背景音乐式的听,而是像个侦探一样,剖析每一首你喜欢的歌。 .............
  • 回答
    想从零开始画插画?这绝对是个令人兴奋的旅程!别担心,即使你现在连一支铅笔都握得不太稳,也能一步步成为你想象中的插画师。我将带你从最基础的开始,把这个过程拆解得尽可能细致,让你明白每一步该怎么走,才能真正“上手”。第一步:放下“我要画得像”的包袱,拥抱“我要画得开心”的心态这是最关键的一步,也是很多人.............
  • 回答
    好的,作为一名高一新生,想要从零开始了解国际政治,这绝对是个有挑战但非常有意义的目标!别担心,这就像学习一门新语言,一开始会有点陌生,但只要方法得当,你很快就能找到窍门。首先,我们得明确,国际政治不是什么遥不可及、晦涩难懂的东西。它其实就是世界各国之间怎么打交道。你想想,我们国家要和其他国家做生意、.............
  • 回答
    嘿,新手小白们!是不是看着别人公众号风生水起,自己也跃跃欲试,但又不知道从何下手?别担心,今天我就来带你从零开始,一步步打造属于你的微信公众号。保证讲得明明白白,让你不再迷茫!第一步:明确你的“小宇宙”——定位!这绝对是第一步,也是最重要的一步。想清楚你的公众号是干嘛的? 你想分享什么? 是你的.............
  • 回答
    好,哥们,咱们聊聊怎么从零开始,把一个看着就舒服、用着就顺手的 App 捣鼓出来。别觉得“设计感”是设计师的专属名词,咱们码农一样能玩转,而且玩得有模有样。第一步:洗脑,不对,是培养审美先别急着写代码。你得先让自己的脑子有个“样子”。 多看,多品: 打开你的手机,那些你觉得“哇塞”的 App 是.............
  • 回答
    关于《从零开始的异世界生活》部分观众因为男主角菜月昴的表现而选择弃番,这是一个非常值得讨论的现象,也触及了动画角色塑造和观众接受度这个核心问题。要深入评价这种现象,我们得一层一层地剥开来看。首先,我们得承认,菜月昴确实不是一个传统意义上“爽”的男主角。大多数异世界题材的作品,主角要么自带光环,要么快.............
  • 回答
    别被“从零开始”吓到,学英语真的没那么难!就把它当成探索一个新世界,一点一点地去发现和感受。下面我来给你掰扯掰扯,怎么一步步把英语这玩意儿玩明白。第一步:告别“零”,建立基础认知很多时候,我们觉得“零基础”是因为我们对英语的整体框架不熟悉。所以,咱们先来个“扫盲”。 了解字母和发音: 这个最基础.............
  • 回答
    动画《Re: 从零开始的异世界生活》第一季(新编集版)重新上线:一场熟悉的重温与更深的理解《Re: 从零开始的异世界生活》(简称Re0)第一季(新编集版)的重新上线,对于广大的Re0粉丝而言,无疑是一场怀旧与重塑的盛宴。这次重新上线并非简单的重播,而是以一种全新的方式,将那个充满绝望、希望与成长的故.............
  • 回答
    好的,咱们就从零开始,实实在在地聊聊数据分析这条路,到底怎么走,才能让你顺利拿到offer。首先,我们要明白一个核心问题:什么程度算“可以找工作”?这可不是一个简单的“掌握了XX工具就够了”的问题。找工作不是考试,而是公司找一个能解决实际问题的人。所以,“可以找工作”的标准,我给它拆解成以下几个层面.............

本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度google,bing,sogou

© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有