前面的文章讲述了裸机代码的4种写法 (1)轮询系统 (2)前后台系统 (3)基于时间片 (4)基于单向链表 这一篇文章我再扩展一点,大家可以看出,第二种写法比较通俗易懂,但是如果添加很多任务,修改的地方较多,第三种和第四种就非常不错,改动的地方比较少。 基于时间片裸机系统和基于链表的裸机系统,虽然一个是用数组来实现的,一个是用链表来实现的,可以看出基于链表的裸机代码更加全面,主要体现在如下几点 1.task_ticks的心跳自加变量,直接放在定时器中断里,作为时基,和判断是否要执行的任务其他代码都有剥离开来,更加容易维护。 2.可以自由的启动任务和停止任务。 3.可以单次触发,也就是只是执行一次。 如果上述三点,您能够总结出来,恭喜您,说明您已经掌握了裸机代码框架的精髓! 虽然单向链表使用起来很灵活,毕竟有用到了数据结构的链表技术点,对于链表,指针,我相信初学者看到这里,大部分都会懵逼了。。。 那再思考下,如果我们在基于链表的裸机代码框架上,用数组来实现,不用链表,并且也保留上述3个功能,能够实现吗?这种写法,我相信初学者也很喜欢,毕竟没有链表和指针嘛 答案是:可以的。我尝试了一下,修改代码如下: 【1】先定义宏定义,方便代码的理解 /*宏定义*/#define ON 1#define OFF 0#define TASK_COUNT 3#define LED1_Task taskArray[0]#define LED2_Task taskArray[1]#define LED3_Task taskArray[2] 【2】定义一个表示的任务的结构体类型 注意:和单链表的裸机代码相比,这里多加了一个enable变量,当为ON,表示执行,当为OFF,表示停止执行,链表是通过插入和删除来实现的,我们这里就用标志位判断就好。
【3】定义心跳全局变量和任务数组,包含3个任务 /*定义变量*/unsigned int g_task_ticks = 0;//心跳计数器Task_t taskArray[TASK_COUNT]; 【4】心跳函数将心跳全局变量自加
【5】任务初始化 void Task_Init(Task_t* htask, void(*pTask)(), unsigned int timeout, unsigned int repeat, unsigned char enable){ htask->timeout = g_task_ticks + timeout;htask->repeat = repeat;htask->pTask = pTask;htask->enable = enable;} 【6】任务启动和停止函数
【7】任务处理函数,判断时间是否到了,到了就执行 void Task_Process(){unsigned char i = 0;for (i = 0; i < TASK_COUNT; i++)//遍历任务数组 {if ((&taskArray[i])->enable == ON){if(g_task_ticks >= (&taskArray[i])->timeout){if((&taskArray[i])->repeat == 0){(&taskArray[i])->enable = OFF;}else{(&taskArray[i])->timeout = g_task_ticks + (&taskArray[i])->repeat;}(&taskArray[i])->pTask();}}}} 【8】定义task结构体中指针函数所指向的函数体,每个任务要执行的内容
通过以上8步,就完成了此框架的所有代码,应用上需要注意的地方 (1)应用方法操作步骤如下, ①Task_Init函数初始化并启动各个任务 ③心跳自加函数Task_Ticks()放到定时器中断中,每隔一段时间(本范例5ms)自加一次 ④在while(1)死循环中执行Task_Process() //系统初始化void System_Init(){Timer0_Init();Task_Init(&LED1_Task,DoTask1,100,100,ON);Task_Init(&LED2_Task,DoTask2,200,200,ON);Task_Init(&LED3_Task,DoTask3,300,300,ON);EA = 1;}// 主程序void main(){System_Init();while(1){Task_Process();}}//定时器0初始化void Timer0_Init(){TMOD &= 0xF0;TMOD |= 0x01;//T0工作于模式1,16位定时器TL0 = 0x00;//定时器赋初值TH0 = 0xEE;ET0 = 1;//允许T0中断TR0 = 1;}//定时器中断函数void Timer0_ISR() interrupt 1{TL0 = 0x00;//定时器赋初值TH0 = 0xEE;Task_Ticks();} 仿真结果如下,完全符合预期,并且我写试过,单次触发,停止或者启动,都是OK的,这里就不在演示了,您可以自行调试一下。 喜欢这篇文章,帮忙点个“关注 + 收藏”哦 附上源码: taks.h task.c main.c |
|
来自: 龙之吻6iinxl8c > 《单片机及控制系统》