目录
1.初识多任务。
2.深入多任务的第一跃,揭开多任务的核心秘方。
(其它章节随缘更新。)
说在前面:
在说FreeRTOS之前,我们得思考一个问题。
为什么单片机要引入RTOS?
如果不理解好这个问题,我相信很多人,包括之前的我对于学习这一个技术而言是毫无动力的。
在回答这个问题之前我们可以看一个简单的程序。
void Task1(void) {
while(1) {
LED_ON();
sleep(1000);
LED_OFF();
sleep(1000);
}
}
这只是一个简单的闪灯任务,看起来好像没有什么问题,如果这时我想加入一点功能,比如播放音乐之类的,你会怎么办?
你可能会想很简单啊,我在这个while循环里添加播放音乐的逻辑不就行了。
看我谁手一挥,就写出来了。
void LED_Task(void) {
LED_ON();
sleep(1000);
LED_OFF();
sleep(1000);
}
void playMusic_Task(void) {
...
}
void Task1(void) {
while(1) {
LED_Task();
playMusic_Task();
}
}
嗯,怎么说呢?
如果有这种思路的同学,难道没有发现不对劲的地方吗?
假设我们播放音乐是用无源蜂鸣器模拟出来的,那也就是播放音乐是不能断下来的,而看看LED_Task()任务中,我们用到了sleep它将整个程序阻塞在了那个地方,那我的音乐谁来播放???
而且sleep()此时还在资源十分紧张的单片机上大张旗鼓的浪费CPU资源,你不该气愤吗?
有点经验的同学可能会想,那我们可以用状态机,就像下面那样。
void playMusic_Task(void) {
...
}
void Task1(void) {
char led_statu = 0;
uint32_t old_tick = getTickCount();
uint32_t new_tick;
while(1) {
new_tick= getTickCount();
switch(led_statu) {
case 0:
if (new_tick - old_tick > 1000) {
LED_ON();
old_tick = new_tick;
led_statu = 1;
}
break;
case 1:
if (new_tick - old_tick > 1000) {
LED_OFF();
old_tick = new_tick;
led_statu = 0;
}
break;
}
playMusic_Task();
}
}
问题好像是解决了,单从这段程序看来阻塞程度可能比RTOS还小,虽然大部分还没接触RTOS,但也一定能猜到任劳任怨的RTOS内部肯定还做了许多事情,那些都是时间上的开销。
好像看到这,我们似乎并不需要用RTOS。是的,对于这种复杂程度不高的程序,我反而不建议用RTOS,教程只是为了演示简单方便,才选取了这样的例子。
我们假设上述程序很复杂,对于一个复杂逻辑的拆分是不太可能像单纯拆分两个1000ms逻辑这样简单的,内部可能还需要计算好各个逻辑执行的时间,这可能需要工程师有一定经验,并且需要花一定的时间。
现在我们不得不思考几个问题。
对于一个产品的开发,我们需要将精力放在这里吗?
对于一个完整的逻辑我们将其大卸八块,不觉得别扭吗?
即使我们觉得自己很强,可以避免sleep()的使用,难道我们能避免本该休息的一段程序也屁颠屁颠的跑来抢CPU资源吗?
想明白了这几点,我想我们大概能回答为什么要有RTOS了。
因为RTOS可以减少开发人员在无关紧要的事情上投入精力。
因为RTOS可以尽量避免让一段完整的功能不会被大卸八块。
因为RTOS可以尽可能的利用CPU资源。
那么接下来,我们将开启RTOS的旅途,让我们看看凭什么RTOS可以这么神奇的解决这些问题。我想在接下来的文章中除了教大家怎么使用RTOS,还想带领大家看看RTOS内部精巧的运行机制。
(ps: 本文不会讲解配置相关的问题,网上已经很详细了,而且我也不喜欢讲这些东西,感觉没啥技术含量。)