时间片轮询法
时间片轮询法
时间片轮询法是一种比较简单易用的系统架构之一,它对于系统中的任务调度算法是分时处理。核心思路是把 cpu 的时间分时给各个任务使用。我们常用的定时方法是定时器,把调度器放在定时中,可以简单的实现时间片轮询法。
需要注意的是,这种方法的前提是执行的 每个任务都是短小精悍的,要不然一个任务执行的时间过长,大于其它任务设置的时间片值,那其它任务就无法保证按它预设的时间片来执行。
尤其需要注意任务中延时的使用,可能会产生不可预料的结果。如果任务内部需要延时的时候,或者说单个任务过长,需要保存任务执行到一半的状态,建议使用状态机切割长任务。
时间片轮询法架构
一个时间片轮询应用程序的架构是非常简单的,包括一个任务结构体,一个中断处理函数,一个轮询执行任务函数。
设计一个结构体:
// 任务结构 typedef struct { uint8_t task_id; // 任务 id uint16_t task_interval; // 任务运行间隔时间 void (*task_entry)(void); // 要运行的任务 volatile uint16_t task_tick_ms; // 计时器 }task_info_t;
定时器复用和中断处理
定时器可以是任意的定时器,这里采用系统滴答定时器 (systick) 来定时。systick 的配置就不细讲,假设定时器的定时中断为 10ms(可以自行设定,中断过于频繁效率就低,中断太长,实时性差)。
timing_task_tick
函数就相当于中断服务函数,需要在定时器的中断服务函数中调用此函数。
// 为每个任务计时,每次中断加 10ms void timing_task_tick(void) { uint8_t task_index = 0; while (task_index < array_size(timing_task_array)) { timing_task_array[task_index].task_tick_ms += config_system_tick_period_ms; // 每次加一个 systick 周期,即 10ms task_index++; } }
时间片轮询实例
下面我就就说说怎样应用吧,假设我们有三个任务:时钟显示,按键扫描,和工作状态显示。
定义一个上面定义的那种结构体数组
// 计算任务个数 #define array_size(x) (sizeof(x) / sizeof((x)[0])) // 定义了 3 个任务 static task_info_t timing_task_array[] = { {0, 100, task_disp_clock_running, 0}, // 显示时钟 {1, 20, task_scan_key_running, 0}, // 按键扫描 {2, 30, task_disp_ws_running, 0}, // 工作状态显示 };
在定义变量时,我们已经初始化了值,这些值的初始化,非常重要,跟具体的执行时间优先级等都有关系,这个需要自己掌握。
大概意思是,我们有三个任务,每 1s 执行一下时钟显示,因为我们的时钟最小单位是 1s,所以在秒变化后才显示一次就够了。
由于按键在按下时会参数抖动,而我们知道一般按键的抖动大概是 20ms,那么我们在顺序执行的函数中一般是延伸 20ms,而这里我们每 20ms 扫描一次,是非常不错的出来,即达到了消抖的目的,也不会漏掉按键输入。
为了能够显示按键后的其他提示和工作界面,我们这里设计每 30ms 显示一次,如果你觉得反应慢了,你可以让这些值小一点。后面的名称是对应的函数名,你必须在应用程序中编写这函数名称和这三个一样的任务。
编写任务函数
//description : 显示任务 void task_disp_clock_running(void) { } //description : 扫描任务 void task_scan_key_running(void) { } //description : 工作状态显示 void task_disp_ws_running(void) { }
任务处理
// 任务计划表,轮询执行任务 void timing_task_scheduler(void) { uint8_t task_index = 0; while (1) { for (task_index = 0 ; task_index < array_size(timing_task_array); task_index++) { if (timing_task_array[task_index].task_tick_ms >= timing_task_array[task_index].task_interval) { timing_task_array[task_index].task_tick_ms = 0; timing_task_array[task_index].task_entry(); } } } }
程序陷入死循环,依次判断每个任务是否符合执行要求。如果是,则执行相应的任务函数;否则等待计时。
上一篇: python 3 输入和输出
下一篇: python--线程同步原语