上一次我们说到了uCOS中的信号量,信号量具有同步的作用,今天做一个小实验来说明这个。
实验任务:使用操作系统,创建三个任务,实现跑马灯的效果(即三个灯依次实现亮200ms,灭200ms)。
先看一下效果吧。
乍一看,可能觉得这个实验特别简单,确实,在裸机编程当中,即使是初学者也可以写出这个程序。但是带上了操作系统,就不能再使用原来的思维了。
我们先回忆一下如果是裸机当中,我们会怎么编。最简单的,只需要像下面这样写(省略main函数):
while(1)
{
led1亮;
延时200ms;
led1灭;
延时200ms;
led2亮;
延时200ms;
led2灭;
延时200ms;
led3亮;
延时200ms;
led3灭;
延时200ms;
}
这样完全就可以实现要求,当然为了让主函数简洁,我们最好用三个函数封装一下:
void led1(void)
{
led1亮;
延时200ms;
led1灭;
延时200ms;
}
while(1)
{
led1();
led2();
led3();
}
当然有人可能会说,只要使用一个函数就行了,直接发送端码就行了,比如发送0x7f,延时,再发送0xbf ……。这样确实没毛病,但这不是我们今天讨论的内容。
好了,那我们能不能在操作系统中也这样,创建三个优先级不等的任务,实现跑马灯呢?答案是不行的。因为在裸机中,任务是按顺序执行的,执行完led1亮灭之后,再执行led2亮灭,最后执行led3亮灭,循环下来就是跑马灯效果,但是操作系统中是不会让CPU空闲的,点亮led1的时候,并不会在那里等,而是马上切换任务,这时led2就会点亮,再切换。所以虽然三个任务是有不同优先级,但是看到的效果是三个灯同时亮,同时灭,根本不会有跑马灯的效果,或者说,你感觉上是三个任务同时执行。
那为了避免这种情况,使用信号量是一种不错的方法。编程思路如下:
信号量1初值为1,三个任务同时去获取信号量1,但是只有优先级高的才能获取,然后执行,执行完之后释放信号量1,接着获取信号量2,由于信号量2初值为0,因此任务1被阻塞,任务2获取到了信号量1往下执行,执行完后释放信号量1,获取信号量2同样被阻塞,任务3执行完毕之后释放信号量1和信号量2,然后任务1被得到执行,并且再次阻塞在获取信号量2上(因为刚刚信号量2被任务2获取了),同理,其他任务也是重复上面的动作。这样就实现了一个闭环。
总结:信号量具有同步的作用,通过信号量可以实现任务之间的“交流”,即哪个任务该被阻塞,哪个任务可以得到执行。
另外,点灯是一门学问,不管是初学单片机,还是像现在使用操作系统,我们都是在点灯,因为点灯操作起来简单,现象也易于观察,只不过虽然都是点灯,但是使用的方法和涉及到的知识点是完全不一样的。当能够将各种理论综合起来花样点灯的时候,就说明有一定基础了。