欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

用 400 行代码编写实时操作系统(IV):观察奔跑的麻雀

最编程 2024-10-14 14:23:33
...

为了验证上一节笔者所说的学习方法,笔者决定让Sparrow先跑起来,并且使用gdb调试Sparrow。不过在此之前,笔者先简单说一下Sparrow RTOS是如何工作的,因为程序只是算法的体现,了解必要的算法,再去看实现,会轻松不少。

RTOS的工作原理

RTOS,也就是实时操作系统,它与裸机的一个重大区别就是拥有了多线程。多线程,简单理解就是多个任务同时运行。

如何做到同时?

我们知道mcu在同一时间只能做一件事情,执行一个上下文的代码,在裸机中我们使用while(1)的形式来进行轮询,while(1)中是任务,通常是执行完一个任务代表的函数再去执行下一个,一个任务代表执行的最小单元,那么我们可不可以把任务进行分割呢?

试想,如果mcu不断切换任务,那不就能做到看起来是在同时做两件事情吗?这当然是可以的。

rtos的本质就是不断切换任务达到模拟同时的效果,它把任务分割为更小的单元,从更微观的层面分配任务执行的时间。

我们把切换任务的过程称为上下文切换。

如何切换?

读者想一想,在arm架构中,有什么东西能够持续执行,完成上下文切换的任务?

答案是:中断

中断是一种异常,在发生中断时,单片机会保存现场,在中断完成后,会及时恢复现场。那么,假设只有两个任务,一个是正常执行的任务,一个是中断中的任务,假设中断不断发生,从微观层面上看,单片机的任务执行过程是这样的:

中断
返回
中断
返回
任务A
任务B
任务A
任务B
任务A

但是从宏观层面上,可不可以理解成这样呢?

中断
中断
中断
中断
中断
任务A
任务B
任务A
任务B
任务A
任务B
任务A
任务B
任务A
任务B

读者发现没有,如果我们能利用中断不断分割任务执行的尺度,那么它不就看起来是并行的吗?

观察运行中的Sparrow

承接上文,笔者将会实践上一篇博客中所说的学习方法。

在第一篇博客中我们已经完成了Sparrow的移植,现在让我们开始上手操作。

让程序先跑起来

先在Sparrow启动程序这里打上断点(笔者使用的调试软件是gdb,读者也可以使用keil,都是一样的):

img

现在我们进入了启动程序内部:

img

通过注释,我们可以判断,这是在配置中断,联系上文笔者所说,上下文切换与中断息息相关,所以我们现在要去查找程序中相关的中断。

继续执行程序,我们发现我们进入了一个由汇编程序组成的函数中,这是SVC中断,通过注释,我们知道,就是它开启了第一个任务:

img

继续执行,果然,它进入了第一个任务内部:

img

为了观察上下文切换,程序中的中断是首要观察目标,我们在xPortPendSVHandler和SysTick_Handler里面打上断点,继续执行,在执行完TaskDelay后,程序进入了xPortPendSVHandler中断函数内部:

img

现在让笔者告诉大家,它就是执行上下文切换的中断,在一定时间内它都会触发,完成上下文切换。

继续执行,程序来到了vTaskSwitchContext,看函数名称读者便知道,上下文切换要完成了:

img

对于单片机来说,一个周期内能做无数次事情,我们继续一行行执行,不知道要执行多久,所以我们直接快速运行程序(gdb使用c命令运行到下一个断点处),我们发现我们来到了systick中断这里:

img

对systick有了解的朋友知道,它是一个时钟,也就是说,它会在一定时间周期触发,继续快速运行,我们发现我们又来到了pendsv中断内部:

img

难道说,systick中断会在一定周期触发PendSV中断,从而不断进行上下文切换吗?

是的,这是正确的!

总结

通过对RTOS原理的一些简单介绍以及上手调试,我们大概知道了RTOS的运行原理:通过中断来进行上下文切换,同时systick中断会不断触发中断,从而使各个任务不断进行切换,从而模拟并行线程。