1.操作系统与裸机的关系
1.1一心一用
一心一用的就是裸机。一般情况下,裸机代码的执行都是通过在main函数中的大while循环中执行子函数的方式来实现的。如下代码所示:
int main()
{
init(); //初始化一些外设或者变量等
while(1)
{
a(); //函数a
b(); //函数b
c(); //函数c
}
}
在main函数中的这些代码,我们可以称为后台系统,裸机除了main函数中的这些代码,还有中断服务函数,我们称为前台系统,如下代码就是一个串口中断服务函数。
void USART1_2_HANDLER()
{
//当串口接收到数据之后,就会到串口中断服务函数中执行相关代码。
}
如上图所示,该图是前后台系统(裸机)任务执行流程图。
该图来源于其他CSDN博客。该CSDN博客链接
如果现在你需要通过代码实现以下任务:
task1:在电脑上回复客户信息
task2:做晚饭
task3:给孩儿子喂隔夜饭
task4:回复女朋友信息
我们这边假设回复客户信息是一件非常重要的事情,所以我们要放在中断中。
int main()
{
init();//完成一些初始化
while(1)
{
做晚饭();
给孩子喂隔夜饭();
回复女朋友信息();
}
}
void 做晚饭()
{
if(判断饭菜是不是熟了)
{
熟了饭菜捞出来();
}
else
{
//没熟跳过
}
}
void 给孩子喂隔夜饭()
{
if(孩子饿了)
{
用勺子铲一勺饭();
放进孩子嘴里();
}
}
void 回复女朋友信息()
{
if(判断女朋友有没有发来信息)
{
回复女朋友的信息();
}
else
{
发送信息问女朋友在干吗();
}
}
//以上code是后台系统,以下代码是前台系统。
void 客户发来信息就会进入这个中断服务函数_HANDLER()
{
回复客户信息();
}
我们可以可以看到以上的4个任务,组成了一个前后台系统。回复客户信息作为重要任务,于是就放到中断中,其他三个不是很重要的任务采用轮询的方式执行。
我在执行做菜任务的时候,我是不知道孩子有没有饿,需不需要喂饭;不知道女朋友有没有发消息过来,需要回复。只有我做好了做菜这个任务之后,去执行给孩子喂饭这个任务的时候,才可以去判断孩子有没有饿了。但不管执行什么任务的时候,只要客户发来了消息,触发该任务的中断服务函数,那么会优先执行该中断服务函数的内容。这就是前后台系统(裸机)的任务执行流程。
1.2一心多用
一心多用指的是操作系统(OS),这里以FreeRTOS为例。可以理解为我既可以做饭,也可以给孩子喂饭,也可以回复女朋友信息。学习操作系统是一件很枯燥、烦琐的事情,我会尽量通俗的解释操作系统的原理。在理解操作系统任务调度之前,先去了解一个时间片的概念。我们执行一个任务是需要一个时间的,比如做晚饭函数。
void 做晚饭()
{
if(判断饭菜是不是熟了)
{
熟了饭菜捞出来();
}
else
{
//没熟跳过
}
}
做饭晚执行完这个函数需要a0~a10的时间。
给孩子喂饭执行完这个函数需要b0~b20的时间。
回复女朋友信息执行完这个函数需要c0~c15的时间。
1.3FreeRTOS任务调度的方式
今天介绍两种FreeRTOS任务调度的方式。
如上图所示,就是FreeRTOS任务执行流程图。
第一种不同优先级任务的任务调度。
在FreeRTOS中任务优先级越高的优先执行,当优先级高的任务执行完成之后,一般会把该任务挂起一段时间,把CPU资源让给其他任务。大概代码如下:
//我们这边假设做晚饭的任务的优先级是最高的。
void 做饭晚()
{
if(判断饭菜是不是熟了)
{
熟了饭菜捞出来();
}
else
{
//没熟跳过
}
//当做晚饭任务执行完成之后,一般会调用VTaskDelay(1000)函数将该任务挂起一段时间。
VTaskDelay(1000);
}
现在,尊敬的读者可能不知道将任务挂起是什么意思,你现在可以理解为:你在windows中打开了一个QQ,那么就是执行QQ这个函数。
当你挂起了,就是用任务调度器把这个QQ给结束进程了;
当任务恢复的时候,你可以理解为,又把QQ打开了。
高优先级的做晚饭任务做好并且将该任务 挂起之后,FreeRTOS会自己查找在任务列表中优先级最高的任务,并去执行他。
第二种任务优先级相同的情况下。
如果现在做晚饭、给孩子喂饭、回复女朋友信息这个三个任务优先级相同,那么FreeRTOS会怎么执行呢?我们之前已经知道了这三个函数执行完需要那些时间了。在FreeRTOS中有一个“心脏”,他就是滴答定时器,滴答定时器每滴答到一个时间单位,就会触发一次滴答定时器中断,在这个滴答定时器中断中,主要就是执行任务的切换。
做饭晚执行完这个函数需要a0~a10的时间。
给孩子喂饭执行完这个函数需要b0~b20的时间。
回复女朋友信息执行完这个函数需要c0~c15的时间。
流程如下:
做晚饭();执行了a0~a1;
滴答定时器触发中断,任务切换。
给孩子喂饭();执行了b0~b1;
滴答定时器触发中断,任务切换。
回复女朋友信息();执行了c0~c1;
滴答定时器触发中断,任务切换。
做饭晚();执行了a2~a4;
滴答定时器触发中断,任务切换。
给孩子喂饭();执行了b2~b4。
滴答定时器触发中断,任务切换。
…
3.结尾
那么此时肯定会有读者想了,在任务切换中,芯片是怎么知道这个函数执行到了哪里呢?
这个就涉及到了函数暂停/回复的概念了,我会在下一篇文章中写出。蟹蟹大家~