前后台程序的嵌入式时间转轮算法

用过stm32的一些芯片,写过一些代码,在学习的过程中对自己的程序框架做一个理解。

在Keil里面,我们利用主函数和中断来运行代码。

main函数理解

我们知道main函数里面是顺序执行代码,while(1)是一个死循环。

而main函数就像一个大中断(例如:70ms运行一次main函数)

看门狗

个人理解看门狗的作用:

定义:看门狗(watchdog timer)为定时器中断。

作用:防止程序跑飞、程序死循环。

应用:初始化中断和定时器T0,开始计时。

主控程序需要70ms运行完成,看门狗定时器设置90ms。

定时器T0每90ms 开始T0=0ms;

如果90ms后定时器还没有重置,则证明程序跑飞或者进入死循环。

这时开启中断服务发送命令,重置程序。

中断

中断的作用是什么,发出响应任务,让CPU处理响应任务。

正常main函数里面的程序为实时任务,当接受到中断的响应任务时,CPU优先处理响应任务,待响应任务结束后,CPU正常运行实时任务。

(一般中断为2.5ms)

前后台系统

前台系统:理解为大中断(主函数的逻辑输入)

后台系统:理解为底层硬件的信号输出。

操作系统时间转轮任务调度:

若有任务A 任务B 任务C

时间片:10ms ,

则运行任务A 15ms,在运行任务B 10ms,在运行任务C 5ms。

优先从队首运行任务,

若仍没在时间片内未运行完:则把改任务放到队尾,继续执行下一个任务。

若在时间片内提前完成任务:则进行下一个任务。

A(10ms)→B(10ms)→C(5ms)→A(5ms)

前后台程序的顺序执行:

这是一种大家新手编程最常用的一种方法,不用思考程序的具体架构,直接按照程序的执行顺序编写代码。

优点:比较容易上手,程序设计简单,思路清晰。

缺点:当程序复杂时,很难看懂程序的运行状态,没有流程图思路混乱,不利于升级以及维护。

前后台的时间转轮算法:

这有什么用?

我们的main函数大中断70ms重置一次,小中断2.5ms重置一次。

那如果有任务在2.5ms——70ms之间呢? 例如20ms 重置一次

利用2.5ms小中端,一直刷新逻辑获取处理,会不会太浪费了?

利用70ms 大中断,会不会使程序在一定时间内得不到响应?

本质其实时定时器的多处复用

首先定义一个结构体

typedef struct TASK_COMPONENTS
{
 uint8 Run;              // 程序运行标记: 0-不运行, 1 运行
 uint8 Timer;            // 计时器
 uint8 ItvTime;          // 任务运行间隔时间
 void (*TaskHook)(void); // 要运行的任务函数
}TASK_COMPONENTS;

TASK_COMPONENTS TaskComps[TASK_NUM]  //定义结构体数组
#define TASK_NUM 3                   //代表3个task任务

函数理解:逐个任务处理,当任务计时时间为0时,设置标志位Run=1,可以进行处理任务,当任务计时时间不为0时,--处理直到为0,重置计时,进行处理。

void TaskRemarks(void) 
{ 
 uint8 i; 
 for (i=0; i<TASK_NUM; i++) // 逐个任务时间处理
 { 
  if (TaskComps[i].Timer) // 时间不为 0 
  { 
   TaskComps[i].Timer--; // 减去一个节拍
   if (TaskComps[i].Timer == 0) // 时间减完了
   { 
    TaskComps[i].Timer = TaskComps[i].ItvTime; // 恢复计时器值,从新开始
    TaskComps[i].Run = 1; // 任务可以运行
   } 
  } 
 } 
}

函数理解:逐个任务处理,当运行状态为1时,进行处理任务,清除标志位。

void TaskProcess(void) 
{ 
 uint8 i; 
 for (i=0; i<TASKS_NUM; i++) // 逐个任务时间处理
 { 
  if (TaskComps[i].Run)      // 时间不为 0 
  { 
   TaskComps[i].T askHook(); // 运行任务
   TaskComps[i].Run = 0;     // 标志清 0 
  } 
 } 
}

猜你喜欢

转载自blog.csdn.net/qq_51679917/article/details/129691568