开始学习单片机那是大二时候的事了,当时最为困惑的是为什么主函数中要是一个while(1),在windows下写c语言程序不就是主函数里面直接写,到最后return 0不就完了么。到后来随着学习的深入,渐渐明白,单片机下的程序可以认为是一个单线程的程序,只能在这个超级循环中往复的运行,最多加一些中断,处理一些异步事件,组成前后台系统,就这样一直幸福的在while(1)中做了一些事情,如下面的实现一个LED小灯以间隔500ms闪烁,多么令人愉快的事情啊。
while(1)
{
LED0 = 1;
delay_ms(500);
LED0 = 0;
delay_ms(500);
}
直到某一天,当我再次的加入一个LED小灯,想实现两个灯分别以500ms和300ms的间隔依次闪烁的时候,我困惑了,这可怎么办?噢,有定时器么,在定时器中断中实现小灯的闪烁不就完了,如下:
while(1)
{
;
}
/* 定时器中断处理函数,500ms执行一次 */
void Led0_handler(void)
{
static char i = 0;
if(i == 0)
{
LED0 = 0;
i = 1;
}
else
{
LED0 = 1;
i = 0;
}
}
/* 定时器中断处理函数,300ms执行一次 */
void Led1_handler(void)
{
static char i = 0;
if(i == 0)
{
LED1 = 0;
i = 1;
}
else
{
LED1 = 1;
i = 0;
}
}
但似乎又有一些问题,你让我的while(1)干什么,呆呆的在那看着,我的定时器就那么几个,你让小灯都用了,其他设备用什么啊,可不可以就在while(1)里面干活,不要让它们 占用我宝贵的定时器资源了。想想办法,那这样吧,状态机或许是一种不错的解决方案。
int count0 = 500;
int count1 = 300;
int STA = 4;
int last_sta0 = 0;
int last_sta1 = 0;
while(1)
{
switch(STA)
{
case 0: LED0 = 1;STA = 4;break;
case 1: LED0 = 0;STA = 4;break;
case 2: LED1 = 1;STA = 4;break;
case 3: LED1 = 0;STA = 4;break;
case 4: count0--;count1--;
if(count0 == 0)
{
count0 = 500;
STA = last_sta0;
last_sta0 = ~last_sta0;
}
if(count1 == 0)
{
count1 = 300;
STA = last_sta1 + 2;
last_sta1 = ~last_sta0;
}
break;
default:break;
}
}
很显然,没有用定时器并且全部在while(1)中实现,但是只有两个灯,如果5个8个岂不是逻辑特别混乱,还怎么让人看代码呀。并且这种方式存在一个弊端,定时时间并不完全准确,需要准确的测量case 4的间隔时间,如果又有一些中断事件的话那就造成了时间的不确定性。
基于以上种种问题,终于发现在裸机下有些问题解决起来真是费劲,但不用怕,问题都是先发现后解决,不过早已有人替我们解决了这些问题,试试操作系统怎么样?或许会让你一下子豁然开朗,体验到飞一般的感觉。