ECU 应用层软件如何周期性运行3

文摘   2024-11-19 07:03   上海  

ECU 应用层软件模型系列文章不断更新中,从零开始教你做开发:


在之前文章 ECU 应用层软件模型如何自动生成代码2 提到了 ECU 应用层软件模型生成代码不需要main_function,这是因为ECU 应用层软件会被底层软件配置好的任务调度。本文来具体了解下到底是怎么回事。

1 ECU应用层软件如何周期性运行?

ECU应用层软件代码(函数)如何被周期性运行,其实现方式如下图示意的这样:

ECU底层软件配置好不同时间周期的任务函数,比如10ms周期的Task_10ms,20ms周期的Task_20ms等。

在此基础上,假设有不同运行周期的ECU应用层软件函数,其中函数Component1和Component2需要10ms运行一次,函数Component11和Component22需要20ms运行一次。此时怎么办?那就让底层软件给提供不同运行周期的任务函数就行,比如底层软件可以针对应用层软件定义10ms任务的接口函数Task_ASW_10ms和20ms任务的接口函数Task_ASW_20ms。
对于ECU应用层软件开发人员来说,通常了解到这一步也就够了,其实也够了,即只管我要的任务是否按照预期的时间周期运行,其他我都不关注了。如果你有兴趣了解更多,继续往下看,ECU软件如何实现周期型调度。
2 ECU软件如何实现周期型调度?
为了确保系统的实时性和可靠性,特别是在需要快速响应和精确控制的ECU中,汽车ECU应用层软件都采用周期型运行方式,其实ECU底层软件也是如此,那么如何确保各个任务按预定的时间间隔执行呢?下面我们来看实现周期型调度的方法和步骤:

周期型任务是指在固定的时间间隔内定期执行的任务。例如,1ms任务、10ms任务、100ms任务等,即每个任务的执行周期决定了任务的频率。

首先需要硬件支持。定时器,用于生成周期性的中断,可以设置为在特定的时间间隔内产生中断,当定时器产生中断时,CPU会跳转到预先定义的中断服务例程(ISR),执行相应的任务。具体代码的实现示意如下:

1) 配置定时器。配置定时器的周期,使其在指定的时间间隔内产生中断。

void configureTimer(uint32_t period) {        // 设置定时器周期        Timer_setPeriod(period);        // 启动定时器         Timer_start();}

2)定义中断服务例程。即在定时器中断发生时,执行相应的任务。

void timerISR(void) {// 清除定时器中断标志    Timer_clearInterruptFlag();// 执行周期型任务    execute1msTask();    execute10msTask();    execute100msTask();}
然后需要实时操作系统 (RTOS),比如FreeRTOS、VxWorks、AUTOSAR OS等。RTOS提供任务管理和调度机制,以此简化周期型任务的实现。在RTOS中,可以创建多个任务,每个任务有自己的优先级和执行周期,RTOS会根据任务的优先级和周期进行调度。具体代码的实现示意如下:

3)创建周期型任务。定义任务函数:定义每个周期型任务的执行函数。

void execute1msTask(void) {    // 执行1ms周期的任务}void execute10msTask(void) {    // 执行10ms周期的任务}void execute100msTask(void) {    // 执行100ms周期的任务}

4)使用RTOS进行任务管理。在RTOS中创建多个任务,每个任务有自己的优先级和执行周期。

void createTasks(void) {    // 创建1ms任务    os_createTask(1, execute1msTask, 1000);  // 优先级1,周期1000us    // 创建10ms任务    os_createTask(2, execute10msTask, 10000);  // 优先级2,周期10000us    // 创建100ms任务    os_createTask(3, execute100msTask, 100000);  // 优先级3,周期100000us}

这里任务调度策略有几种形式:

  • 优先级调度:RTOS根据任务的优先级进行调度,高优先级的任务会优先执行。
  • 时间片轮转:对于同优先级的任务,可以使用时间片轮转的方式进行调度,确保每个任务都能得到执行机会。
  • 抢占式调度:高优先级的任务可以抢占低优先级任务的执行,确保实时性。

除了上述这些工作,还有几个点需要注意,一是任务执行时间,需要确保每个任务的执行时间远小于其周期,避免任务堆积导致系统崩溃;二是资源竞争,需要处理好任务之间的资源竞争,避免死锁和竞态条件;三是调试和测试,进行充分的调试和测试,确保任务按预期执行,系统稳定可靠。以此来确保系统的实时性和可靠性。

5)代码程序。上面几个部分的代码是单独的,为了更好理解周期型调度如何实现的,下面将这些代码联合起来看如何使用定时器和中断服务例程实现周期型调度,如下:

#include <stdint.h>#include "timer.h"#include "os.h"
// 定义周期型任务void execute1msTask(void) { // 执行1ms周期的任务}
void execute10msTask(void) { // 执行10ms周期的任务}
void execute100msTask(void) { // 执行100ms周期的任务}
// 中断服务例程void timerISR(void) { // 清除定时器中断标志 Timer_clearInterruptFlag();
// 执行周期型任务 static uint32_t counter = 0; counter++;
if (counter % 1 == 0) { execute1msTask(); } if (counter % 10 == 0) { execute10msTask(); } if (counter % 100 == 0) { execute100msTask(); }}
// 配置定时器void configureTimer(uint32_t period) { // 设置定时器周期 Timer_setPeriod(period); // 启动定时器 Timer_start();}
// 创建任务void createTasks(void) { // 创建1ms任务 os_createTask(1, execute1msTask, 1000); // 优先级1,周期1000us // 创建10ms任务 os_createTask(2, execute10msTask, 10000); // 优先级2,周期10000us // 创建100ms任务 os_createTask(3, execute100msTask, 100000); // 优先级3,周期100000us}
int main(void) { // 初始化定时器 configureTimer(1000); // 1ms周期
// 初始化RTOS os_init();
// 创建任务 createTasks();
// 启动RTOS调度 os_start();
return 0;}
3 小结
以上就是关于ECU应用层软件函数如何周期性运行的表象和背后原理的基本介绍,通常对于ECU应用层软件工程师来说,掌握这部分内容很足够了,若还有兴趣,后续增加一篇AUTOSAR OS内容的基本介绍,下篇文章继续回归到ECU 应用层软件模型自动代码生成的相关问题和具体操作。


创作不易,欢迎关注点赞再看收藏

汽车研发交流群,有兴趣的朋友请添加群主:prOmiseyes,备注:公司+职务入群。仅限汽车从业人员。

谦益行
分享汽车研发日常,助力你我共同成长。
 最新文章