很多单片机的初学者容易掉入阻塞式编程的陷阱.因为阻塞式编程符合我们对现实世界的理解,一个人在一段时间内,只能做一件事情.例如要是实现1Hz的闪灯程序,那么先让单片机端口拉高500ms,然后再拉低500ms,然后循环.因为等待时间太长了,没有打开看门狗.
下面是阻塞式编程的例子:
#include "extern.h"
BIT LED : PA.3;
BIT LED1 : PA.4;
void FPPA0 (void)
{
.ADJUST_IC SYSCLK=IHRC/2
$ LED out ,low;
$ LED1 out ,low;
while (1)
{
LED=1;
.delay 8000*500;
LED=0;
.delay 8000*500;
}
}
OK 完美运行.
但是,当要你再加上一个指示灯,要2Hz闪烁,也就是250ms关,250ms开,然后循环,那要怎么办了.
OK继续,刚刚辛辛苦苦写好的程序得重新写了.
void FPPA0 (void)
{
.ADJUST_IC SYSCLK=IHRC/2
$ LED out ,low;
$ LED1 out ,low;
while (1)
{
LED=1;
LED1=1;
.delay 8000*250;
LED=1;
LED1=0;
.delay 8000*250;
LED=0;
LED1=1;
.delay 8000*250;
LED=0;
LED1=0;
.delay 8000*250;
}
}
OK,完美运行,要加上按键呢?怎么办,感觉越来越麻烦了.
其实,单片机干起事情来比我们想象得要快得多.例如8M的主频,1T的单片机,在1S钟之内就可以执行8,000,000条指令.在很多时候,我们几乎可以忽略单片机在执行两条指令的时间差,也就是说虽然单片机程序是顺序执行的,在人看来效果和并行执行没有任何差别.不能让单片机在等待.LED开/关其实就是一条指令的事.做好定时就OK了,那定时怎么做呢?用定时中断,配置定时器每100us产生一次中断,那么计数10次就是1ms.在while循环里查询这个1ms标记并进行计数就可以进行定时了.
下面来个非阻塞式程序的案例.
#include "extern.h"
#define HIGH 1
#define LOW 0
#define DISABLE 0
#define ENABLE 1
#define EMPTY 0
#define FULL 1
#define ON 1
#define OFF 0
BIT LED : PA.3;
BIT LED1 : PA.4;
word usLedTmrCnt;
word usLedTmrCnt1;
bit FLAG_NMS;
byte count;
word T16COUNTER;
void TIME16_Init(void)
{
T16COUNTER =488;
FLAG_NMS =0;
$ INTEN T16;
INTRQ = 0;
T16M.5 =0;
STT16 T16COUNTER;
$ T16M IHRC,/1,BIT11;
}
void FPPA0 (void)
{
.ADJUST_IC SYSCLK=IHRC/2, IHRC=16MHz, VDD=3.5V,init_ram;
$ CLKMD IHRC/2,En_IHRC,En_ILRC,En_WatchDog;
$ LED OUT,LOW;
$ LED1 OUT,LOW;
TIME16_Init();
engint;
while (1)
{
wdreset;
if ( FLAG_NMS )
{
usLedTmrCnt++;
if(usLedTmrCnt>499)
{
usLedTmrCnt=0;
if(LED)
{
LED=0;
}
else
{
LED=1;
}
}
#if 1
usLedTmrCnt1++;
if(usLedTmrCnt1>249)
{
usLedTmrCnt1=0;
if(LED1)
{
LED1=0;
}
else
{
LED1=1;
}
}
#endif
FLAG_NMS=0;
}
}
}
void Interrupt ( void )
{
pushaf;
if ( Intrq.T16 )
{
Intrq.T16 = 0;
STT16 T16COUNTER;
if ( count>0 )
{
count--;
}
else
{
count = 9;
FLAG_NMS= 1;
}
}
popaf;
}
给LED 和LED1各分配一个计数器,可以设置1-65535ms的翻转时间.LED亮/灭只需要一条指令.其他的时候就查询一下1ms标记,有就计数,当计数值溢出的时候就把LED进行翻转.就这么简单.各自独立,没有长时间的等待,看门狗也打开了.在端口和内存允许的情况下还可以添加N个.在这个框架下,还可以扩展按键,显示.....
这里并不是说阻塞式的程序不好,而是有一定的局限性.在写简单的应用中也很好用.很直观.