一.裸机开发模式
1.轮询模式
void main()
{
while(1)
{
A(); //实现A函数
B(); //实现B函数
}
}
在main中不断循环,轮询A,B。这样做的缺点是当其中一个函数执行时间过长时会导致另一函数等待过长。
2.事件驱动模式
也就是利用中断来实现有条件触发,比如按下按键触发中断实现对应功能。
void main()
{
while(1)
{
;
}
}
void A_IRQ() //A的中断函数
{
A();
}
void B_IRQ() //B的中断函数
{
B();
}
当触发条件满足时才跳转到对应的回调函数。但同样也有缺陷。
(1):当有一个函数的执行时间过长时就会影响另一函数。
(2):当AB同时触发,只会触发一个中断,另一个中断被延迟甚至是丢失。
3.改进的事件驱动
void main()
{
while(1)
{
if(key==1) A();
else B();
}
}
void A_IRQ() //A的中断函数
{
key=1;
}
void B_IRQ() //B的中断函数
{
key=0;
}
可以解决2中第(2)点,让中断处理更快,不再丢失。但是对于功能的实现实际上与轮询方式没有太大差别。
4.定时器驱动
设置一个定时器,每1ms产生一次中断。同时设置A,B,C函数并设置执行周期。其中函数的设置用结构体来写。A为1ms执行一次,B是2ms,C是3ms。
typedef struct soft_timer{
int remain;
int period;
void *(function)(void);
}soft_timer,*p_soft_timer;
static soft_timer timers[]={
{1,1,A}
{2,2,B}
{3,3,C}
}
void main()
{
while(1)
{
;
}
}
void timer_IRQ()
{
int i;
for(i=0;i<3;i++)
{
timers[i].remain--;
}
for(i=0;i<3;i++)
{
if(timers[i].remain == 0)
timers[i].function();
timers[i].remain=timers[i].period;
}
}
每ms产生一次中断,通过对period的递减来实现函数。这里的运行周期通过多次测试ABC函数的运行时间来进行修改,可以达到一个较好的效果。但是同样会有函数执行过长导致互相影响的问题。
总结:要同时调用AB函数,且其执行时间较长时,裸机下较难解决。或者可以用状态机
5.状态机
将原来轮询方式里面的AB函数拆分成n小块,每次固定时间内只执行A和B的某个小块,从而在宏观层面上达到一个同时运行的效果,并且也不会有某个函数执行时间过长而导致另一个函数一直在等待执行。
void A(void)
{
static int state = 0;
switch (state)
{
case A0: /* 开始 */
{
state++;
return;
}
case A1:
{
state++;
return;
}
case A2:
{
state++;
return;
}
}
}
void B(void)
{
static int state = 0;
switch (state)
{
case B0: /* 开始 */
{
state++;
return;
}
case B1:
{
state++;
return;
}
case B2:
{
state++;
return;
}
}
}
void main()
{
while (1)
{
A();
B();
}
}
但在实际应用中,状态机拆分较为麻烦,而且复杂程序难以拆分。
因此,基于裸机的程序框架无法完美地解决这类问题:复杂的、很耗时的多个函数。