说明:近期通过学习韦东山老师的裸机与RTOS再次强化了软件设计思想,因此特通过此博客进行记录。
韦东山老师学习资料链接
1、上一节提到使用定时器的事件驱动方式调度任务依然有缺陷,主要的缺陷有一旦某个函数执行的时间超长,就会有如下后果:
- 影响其他函数;
- 延误整个时间基准;
上一节的链接地址
改进方法是在定时器中断中只负责每个任务当前时间的减减,而任务调度放在主循环中,这种方式情况下,时间基准不会被耽误,但是A 、B 、 C的调用再次退化为轮询方式,A、B、C相互之间有影响,每个任务运行的时间不能过长,不能被其他时间卡住,不然会影响后面的任务运行。
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()
{
int i;
while (1)
{
/* 如果timers数组里某个成员的expire等于0:
* 1. 调用它的函数
* 2. 恢复expire为period
*/
for (i = 0; i < 3; i++)
{
if (timers[i].remain == 0)
{
timer[i].function();
timers[i].remain = timers[i].period;
}
}
}
}
void timer_isr()
{
int i;
/* timers数组里每个成员的expire都减一 */
for (i = 0; i < 3; i++)
if (timers[i].remain)
timers[i].remain--;
}
2、逻辑程序的缺陷
- 假设要调用两个函数AB,AB执行的时间都很长,裸机就很难处理这种场景。
- 如果非要基于裸机解决这个问题的话,可以使用状态机。
示例代码如下:
void feed_kid(void)
{
static int state = 0;
switch (state)
{
case 0: /* 开始 */
{
/* 盛饭 */
state++;
return;
}
case 1: /* 盛菜 */
{
/* 盛菜 */
state++;
return;
}
case 2:
{
/* 拿勺子 */
state++;
return;
}
}
}
void send_msg(void)
{
static int state = 0;
switch (state)
{
case 0: /* 开始 */
{
/* 打开电脑 */
state++;
return;
}
case 1:
{
/* 观看信息 */
state++;
return;
}
case 2:
{
/* 打字 */
state++;
return;
}
}
}
void main()
{
while (1)
{
feed_kid();
send_msg();
}
}
引入的问题:
需要我们使用状态机拆分程序:
- 比较麻烦
- 有些复杂的程序无法拆分为状态机