本帖最后由 Eric2013 于 2014-12-16 19:50 编辑
3.4 实验说明 本期教程配套的实验是:基于时间触发的合作式调度器,工程中需要添加如下驱动:
3.4.1 实验一:基于时间触发的混合式调度器实验目的: 1. 学习基于时间触发的混合式调度器。 实验内容: 1. 通过函数hSCH_Add_Task添加三个任务 hSCH_Add_Task(bsp_KeyScan,0, 10, 1); /* 按键扫描合作式任务, 周期10ms */ hSCH_Add_Task(AppTask_KeyScan, 0, 4,1); /* 执行按键打印合作式任务 周期4ms */ hSCH_Add_Task(AppTask_LedToggle,0, 500, 0); /* 四个LED闪烁抢占式任务 周期500ms */ 2. 主程序不断执行hSCH_Dispatch_Tasks();刷新函数。 实验现象: 四个LED灯实现每500ms闪烁一次,按下3个按键中的某一个,或者五向摇杆会打印如下信息:
程序设计: 本程序主要分为四个部分: Ø 混合式调度器的设计 Ø 混合式调度器的初始化 Ø 任务API Ø 主程序 下面将这四个部分讲述一下: 1. 混合式调度器的设计 这个已经在前面的1.2小节详细进行了说明,这里就不再赘述了。 2. 混合式调度器的初始化 这里主要是时标间隔的初始化(这个放在了主函数里面实现,也就是嘀嗒定时器的初始化)和任务函数的添加,源代码如下: /* ********************************************************************************************************* * 函 数 名: bsp_Init * 功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次 * 形 参:无 * 返 回 值: 无 ********************************************************************************************************* */ void bsp_Init(void) { /* 由于ST固件库的启动文件已经执行了CPU系统时钟的初始化,所以不必再次重复配置系统时钟。 启动文件配置了CPU主时钟频率、内部Flash访问速度和可选的外部SRAM FSMC初始化。 系统时钟缺省配置为168MHz,如果需要更改,可以修改 system_stm32f4xx.c 文件 */
bsp_InitLed(); /* 初始LED指示灯端口 */ bsp_InitUart(); /* 初始化串口 */ bsp_InitKey(); /* 初始化按键 */
/* 添加三个任务 */ hSCH_Add_Task(bsp_KeyScan, 0,10, 1); /* 合作式 周期10ms */ hSCH_Add_Task(AppTask_KeyScan,0, 4, 1); /* 合作式 周期4ms */ hSCH_Add_Task(AppTask_LedToggle,0, 500, 0); /* 抢占式 周期500ms */
} 3. 任务API 主要是按键任务和LED闪烁任务,按键扫描任务就不说了,这个在前面按键FIFO里面有详细的讲解。 /* ********************************************************************************************************* * 函 数 名: AppTask_KeyScan * 功能说明: 打印按键扫描结果 * 形 参:无 * 返 回 值: 无 ********************************************************************************************************* */ void AppTask_KeyScan(void) { uint8_t ucKeyCode;
ucKeyCode = bsp_GetKey(); /* 读取键值, 无键按下时返回KEY_NONE = 0 */ if (ucKeyCode != KEY_NONE) {
switch (ucKeyCode) { case KEY_DOWN_K1: /* K1键按下 */ printf("K1键按下, LED1点亮\r\n"); break;
case KEY_UP_K1: /* K1键弹起 */
printf("K1键弹起, LED1熄灭\r\n"); break;
case KEY_DOWN_K2: /* K2键按下 */
printf("K2键按下, LED2点亮\r\n"); break;
case KEY_UP_K2: /* K2键弹起 */ printf("K2键弹起, LED2熄灭\r\n"); break;
case KEY_DOWN_K3: /* K3键按下 */ printf("K3键按下, LED3点亮\r\n"); break;
case KEY_UP_K3: /* K3键弹起 */ printf("K3键弹起, LED3熄灭\r\n"); break;
case JOY_DOWN_U: /* 摇杆UP键按下 */ printf("摇杆上键按下\r\n"); break;
case JOY_DOWN_D: /* 摇杆DOWN键按下 */ printf("摇杆下键按下\r\n"); break;
case JOY_DOWN_L: /* 摇杆LEFT键按下 */ printf("摇杆左键按下\r\n"); break;
case JOY_DOWN_R: /* 摇杆RIGHT键按下 */ printf("摇杆右键按下\r\n"); break;
case JOY_DOWN_OK: /* 摇杆OK键按下 */ printf("摇杆OK键按下\r\n"); break;
case JOY_UP_OK: /* 摇杆OK键弹起 */ printf("摇杆OK键弹起\r\n"); break;
default: /* 其他的键值不处理 */ break; } } }
/* ********************************************************************************************************* * 函 数 名: AppTask_LedToggle * 功能说明: 四个LED闪烁的程序 * 形 参:无 * 返 回 值: 无 ********************************************************************************************************* */ void AppTask_LedToggle(void) { bsp_LedToggle(1); bsp_LedToggle(2); bsp_LedToggle(3); bsp_LedToggle(4); } 4. 主函数 主函数比较简单,主要是在大循环里面调用调度函数。 /* ********************************************************************************************************* * 函 数 名: main * 功能说明: c程序入口 * 形 参:无 * 返 回 值: 错误代码(无需处理) ********************************************************************************************************* */ int main(void) { bsp_Init(); /* 硬件初始化 */ Printf**(); /* 打印例程信息到串口1 */ bsp_InitTimer(); /* 初始化系统滴答定时器 */
/* 进入主程序循环体 */ while (1) { /* 任务执行函数 */ hSCH_Dispatch_Tasks(); } } 3.5 总结 为了更好的使用混合式式调度器,这里简单的总结写使用注意事项: l 建立数量满足要求的混合式任务,很可能因为一个或者多个任务的运行时间大于时标间隔,所以需要使用混合式调度器。混合式调度器的使用是安全的,然而必须的保存任务不重叠。 l 实现一个抢占式任务,这种任务一般在每个时标间隔调用,这种任务常用来检测错误或者紧急事件。 l 抢占式任务可以中断合作式任务。 l 抢占式任务必须的简短,运行时间最多不能超多时间间隔%50,否则将极大的削弱系统的性能。 l 在所有的状态下仔细测试该系统,检测错误。 关于时间触发方式的调度器设计,就跟大家讲这么多,有兴趣的可以查阅相关资料做深入的了解。
参考资料: 1. Patterns fortime-triggered embedded systems英文版和中文版
|