第一步:定义任务个数(非必要),如下所示:
#define TASKS_MAX 3 //任务个数
第二步:定义一个结构体类型,该结构体定义了一个任务结构,定义如下所示:
typedef struct _TASK_COMPONENTS {
uint8_t Run; // 程序运行标记:0-不运行,1运行
uint16_t Timer; // 计时器
uint16_t ItvTime; // 任务运行间隔时间
void (*TaskHook)(void); // 要运行的任务函数
}TASK_COMPONENTS; // 任务定义
第三步:定义任务变量,并初始化。代码如下所示:
static TASK_COMPONENTS TaskComps[3] =
{
{0, 600, 600, UART3_Tra_Process}, // 串口3发送处理函数
{0, 400, 600, UART4_Tra_Process}, // 串口4发送处理函数
{0, 200, 600, UART5_Tra_Process}, // 串口5发送处理函数
};
三个任务在初始状态都是处于不运行状态,在200毫秒后串口5发送处理函数被调用,再过200毫秒(即上电初始化后的第400毫秒后),串口4发送处理函数被调用。同理600毫秒后串口3发送处理函数被调用。三个任务函数每两次被调用的时间间隔都是600毫秒。这样就实现了串口轮流发送报文的操作,轮流间隔时间为200毫秒。
第四步:在系统时钟中断(比如1毫秒中断)中调用计时任务标志处理函数。函数代码如下所示:
void TaskRemarks(void)
{
uint8_t i;
for (i=0; i<TASKS_MAX; i++) // 逐个任务时间处理
{
if (TaskComps[i].Timer != 0)
{
TaskComps[i].Timer--;
if (0 == TaskComps[i].Timer)
{
TaskComps[i].Timer = TaskComps[i].ItvTime;
TaskComps[i].Run = 1; // 任务可以运行
}
}
}
}
该函数在毫秒中断中被调用,轮流扫描各项任务,当每项任务的计时器不为0时,则对该计时器减1。直到减至0时,重新给计时器赋值,且置运行标志位为1。
第五步:在主循环中调用任务处理函数。函数代码如下所示:
void TaskProcess(void)
{
uint8_t i;
for(i=0; i<TASKS_MAX; i++)
{
if (1 == TaskComps[i].Run)
{
TaskComps[i].Run = 0;
TaskComps[i].TaskHook();
}
}
}
该函数在主循环中被调用,轮流扫描各项任务。当任务运行标志为1时,执行对应任务函数,且清零任务运行标志。
最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。