架构的运行机制
while (1)
{
task_handle();
}
voidtask_handle(void)
{
uint8_t i;
for (i = 0; i < ARRAY_SIZE(tasks); ++i)
{
if ((is_task_set(tasks[i].id))
||(is_task_always_alive(tasks[i].flags)))
{
reset_task(tasks[i].id);
tasks[i].handle(tasks[i].args);
}
}
}
从代码上来看这是一个轮询机制。
调度函数的条件有两个如下:
1) is_task_set(tasks[i].id)
2) is_task_always_alive(tasks[i].flags)
第一种调度的原理:
我们先看第一种条件的调度:
Ø notify(tasks[i].id);
Ø is_task_set(tasks[i].id)
Ø reset_task(tasks[i].id)
structtask
{
uint8_t id;
uint8_t flags;
void *args;
void (*handle)(void *args);
};
对应于下列:
const struct tasktasks[] =
{ uint8_t id; uint8_t flags; void*args; void (*handle)(void *args)
{EV_TICK_LITTLE, ALWAYS_ALIVE, NULL, sys_tick_little},
{EV_READ, ALWAYS_ALIVE, NULL, read_rf_status_cmd},
{EV_CONTROL_IR, 0, NULL, period_control_ir},
{EV_100MS, 0, NULL, task_100ms},//
{EV_SEC, 0, NULL, task_sec},
{EV_TICK, ALWAYS_ALIVE, NULL, sys_tick},
{EV_REPORT_DATA, 0, NULL, report_data_rf},
{EV_USB_TASK, 0, NULL, handle_usb_task},
{EV_3MS, 0, NULL, task_3ms},
{EV_6MS, 0, NULL, task_6ms},
{EV_12MS, 0, NULL, task_12ms},
{EV_CALIBRATE_GRY_ACC, 0, NULL, calibrate_gry_acc},
};
第一种条件下的调度原理,先看这个函数的展开:
Ø notify(tasks[i].id);
#define notify(task_bit) set_bit(task_monitor,task_bit)
#define set_bit(x, bit) do{ __disable_irq();(x) |= 1 <<(bit);__enable_irq();}while(0)
注:执行置位的时候开启了总中断。
Ø is_task_set(tasks[i].id)
#define is_task_set(task_bit) is_bit_set(task_monitor, task_bit)
#define is_bit_set(x, bit) ((x) & (1 << (bit)))
Ø reset_task(tasks[i].id)
#define reset_task(task_bit) reset_bit(task_monitor, task_bit)
#define reset_bit(x, bit) do{ __disable_irq();(x) &= ~(1<< (bit));__enable_irq();}while(0)
上面这三个函数里,有一个共同的全局变量task_monitor,在代码里的定义为:
uint16_t task_monitor;
三个函数项目间的联系是通过这个全局变量task_monitor,从定义上看,这是一个16位的全局变量,也就意味着我们的框架最多可以调度16个任务,每一个任务占用一位。
16个任务对于一般的项目是够用了,如果不够用这个框架还可以扩展到32个任务,可以修改如下:
uint32_t task_monitor;
下面是定义的ID号:
enum
{
EV_TICK_LITTLE,
EV_READ,
EV_CONTROL_IR,
EV_100MS,
EV_SEC,
EV_TICK,
EV_MIN,
EV_CALLBACK,
EV_USB_TASK,
EV_3MS,
EV_6MS,
EV_12MS,
EV_CALIBRATE_GRY_ACC,
EV_REPORT_DATA,
EV_CALIBRATE_TRIGGER_AD
};
目前用到的是14个任务,从左往右,从上往下,是对应16位task_monitor;的从低位到高位,如下图对应:
EV_TICK_LITTLE | EV_READ | EV_CONTROL_IR | EV_100MS | EV_SEC | EV_TICK | EV_MIN | EV_CALLBACK |
EV_USB_TASK | EV_3MS | EV_6MS | EV_12MS | EV_CALIBRATE_GRY_ACC | EV_REPORT_DATA |
|
|
第一种情况下函数调度的调度原理如下:
task_monitor |
is_task_set |
USB等中断 |
reset_task |
notify |
调度对应的函数 |
定时器 |
第二种调度的原理以及定时任务的建立:
is_task_always_alive(tasks[i].flags
如果任务对应的flag 是ALWAYS_ALIVE,那么轮询到这个flag就会调用对应的函数。
const struct tasktasks[] =
{ uint8_t id; uint8_t flags; void*args; void (*handle)(void *args)
{EV_TICK_LITTLE, ALWAYS_ALIVE, NULL, sys_tick_little},
{EV_READ, ALWAYS_ALIVE, NULL, read_rf_status_cmd},
{EV_CONTROL_IR, 0, NULL, period_control_ir},
{EV_100MS, 0, NULL, task_100ms},//
{EV_SEC, 0, NULL, task_sec},
{EV_TICK, ALWAYS_ALIVE, NULL, sys_tick},
{EV_REPORT_DATA, 0, NULL, report_data_rf},
{EV_USB_TASK, 0, NULL, handle_usb_task},
{EV_3MS, 0, NULL, task_3ms},
{EV_6MS, 0, NULL, task_6ms},
{EV_12MS, 0, NULL, task_12ms},
{EV_CALIBRATE_GRY_ACC, 0, NULL, calibrate_gry_acc},
};
从上面的任务看使用ALWAYS_ALIVE的任务有三个分别是sys_tick_little,read_rf_status_cmd,sys_tick 。
sys_tick_little和sys_tick是用来驱动定时任务的。
sys_tick函数驱动的任务:
sys_tick_little |
notify(EV_12MS)
|
notify(EV_3MS) |
notify(EV_6MS)
|
sys_tick |
notify(EV_MIN)
|
notify(EV_100MS) |
notify(EV_SEC)
|
定时调度任务是用time2来进行计时的。
TIME2
|
_sys_tick |
last_tick |
sys_tick |
notify(EV_MIN)
|
notify(EV_SEC)
|