单片机时间片轮询架构

Author:家有仙妻谢掌柜
Date:2021/2/3

学一个东西一定要学会总结,学单片机也不例外,总结一下用单片机做项目时代码的架构,写在这里记录自己的成长历程,也分享出去供大家参考!

首先声明在本程序中和移植相关的针对不同MCU等差异所需要的做出的修改如下:
1.中断服务函数
Timer1Callback();
2.主函数中
timer_1_enable(32768/10,Timer1Callback);//我这里用的是100ms中断一次来做实验
参数32768表示1S,我这里32768/10表示100ms,这个速度已经很慢了,但是为了兼容打印,因为事件中没有实际的任务,太快打印跟不上。在实际操作中,中断的时间可以缩短一些,但是不能太短,频繁的中断效率也会低的。
3.这里测试了10个任务同时进行,效果满足预期,只要每一个任务执行的时间小于该任务设定的时间即可。


//时间片架构测试
void Task1(void);
void Task2(void);
void Task3(void);
void Task4(void);
void Task5(void);
void Task6(void);
void Task7(void);
void Task8(void);
void Task9(void); 
void Task0(void);

/**************************************************************************************
* Name   		:TaskStruct
* Description   :任务结构体
* Details 		:它包含了一个任务所需要的所有信息;
*              1:运行状态标志位:0-不运行;1-运行。  
*              2:计数器TimerCountdown--												
*              3:计数器数值填充器,预设的初值:TimerInitialValue(任务运行间隔时间)  
*              4:任务对应的函数指针  
**************************************************************************************/
typedef struct _TaskStruct
{
     
	uint8_t		RunningStatus;
	uint8_t 	TimerCountdown;
	uint8_t 	TimerInitialValue;
	void 		(*TaskHook)(void);
}TaskStruct;

/**************************************************************************************
* Name   		:TaskManage
* Description   :任务数组
* Details 		:它包含了所有任务所需要的参数;
**************************************************************************************/
//定时器中断实验目前是100ms中断一次
#define InitStatus 0
#define TimerTask1 10 
#define TimerTask2 20
#define TimerTask3 30
#define TimerTask4 40
#define TimerTask5 50
#define TimerTask6 60
#define TimerTask7 70
#define TimerTask8 80
#define TimerTask9 90
#define TimerTask0 100

static TaskStruct TaskManage[] = 
{
     
    {
     InitStatus,TimerTask1,TimerTask1,Task1},
    {
     InitStatus,TimerTask2,TimerTask2,Task2},
    {
     InitStatus,TimerTask3,TimerTask3,Task3},
	{
     InitStatus,TimerTask4,TimerTask4,Task4},
    {
     InitStatus,TimerTask5,TimerTask5,Task5},		
    {
     InitStatus,TimerTask6,TimerTask6,Task6},		
    {
     InitStatus,TimerTask7,TimerTask7,Task7},		
    {
     InitStatus,TimerTask8,TimerTask8,Task8},		
    {
     InitStatus,TimerTask9,TimerTask9,Task9},		
    {
     InitStatus,TimerTask0,TimerTask0,Task0},

    /* 这里添加需要的任务。。。。 */
};
/**************************************************************************************
* Name   		:TaskList
* Description   :任务列表
* Details 		:包含所有任务;
*              1:ListTask1
*              2:ListTask2												
*              		...
*			   N:ListTasksMax:总的可供分配的定时任务数目
**************************************************************************************/
typedef enum _TaskList
{
     
    ListTask1,
    ListTask2,
    ListTask3,
    ListTask4,
    ListTask5,
    ListTask6,
    ListTask7,
    ListTask8,	
    ListTask9,
    ListTask0,
    /* 这里添加需要的任务。。。。 */
    ListTasksMax
}TaskList;
/**************************************************************************************
* FunctionName   : TaskMarks()
* Description    : 标志位处理函数
* EntryParameter : None
* ReturnValue    : None
这个函数是用来更新每个任务的计数器以及它们的运行标志位的,
它是写在单片机的定时器中断服务函数中的
**************************************************************************************/
void TaskMarks(void)
{
     
	uint8_t i;

	for (i=0;i<ListTasksMax;i++)//逐个任务时间处理
	{
     
		if(TaskManage[i].TimerCountdown)//计数器不为0
		{
     
			TaskManage[i].TimerCountdown--;      //计数器减去一个节拍
			if(TaskManage[i].TimerCountdown == 0)//计数器数值减完了
			{
     
				TaskManage[i].TimerCountdown = TaskManage[i].TimerInitialValue;//恢复计时器值,重新下一次
				TaskManage[i].RunningStatus  = 1;//任务可以运行
			}
		}
	}
}
/**************************************************************************************
* FunctionName   : TaskMarks()
* Description    : 任务处理函数
* EntryParameter : None
* ReturnValue    : None
这个函数用来判断任务是否到了执行时间,它会逐个检查任务列表中的任务
如果到了就执行,同时清空执行标志位,没到就不执行
**************************************************************************************/
void TaskProcess(void)
{
     
	uint8_t i;

	for (i=0;i<ListTasksMax;i++)           	  // 逐个任务时间处理
	{
     
		if (TaskManage[i].RunningStatus)      // 时间不为0
		{
     
			TaskManage[i].TaskHook();         // 运行任务
			TaskManage[i].RunningStatus = 0;  // 标志清0
		}
	}
}
/**************************************************************************************
* FunctionName   : Task1()/Task2()/Task3()/Task4()...
* Description    : 任务函数
* EntryParameter : None
* ReturnValue    : None
**************************************************************************************/
void Task1(void)
{
     
	dbg_printf("Task1\r\n");
}
void Task2(void)
{
     
	dbg_printf("Task2\r\n");
}
void Task3(void)
{
     	
	dbg_printf("Task3\r\n");
} 
void Task4(void)
{
     
	dbg_printf("Task4\r\n");
} 
void Task5(void)
{
     
	dbg_printf("Task5\r\n");
}
void Task6(void)
{
     
	dbg_printf("Task6\r\n");
}
void Task7(void)
{
     
	dbg_printf("Task7\r\n");
}
void Task8(void)
{
     
	dbg_printf("Task8\r\n");
}
void Task9(void)
{
     
	dbg_printf("Task9\r\n");
}
void Task0(void)
{
     
	dbg_printf("Task0\r\n");
}
/**************************************************************************************
* FunctionName   : Timer1Callback()
* Description    : 定时中断服务函数,回调函数
* EntryParameter : None
* ReturnValue    : None
**************************************************************************************/
static void Timer1Callback(void)
{
     
	TaskMarks();
}
/**************************************************************************************
* FunctionName   : main()
* Description    : 主函数
* EntryParameter : None
* ReturnValue    : None
**************************************************************************************/
int main(void)
{
     
	All_Initialize();
	timer_1_enable(32768/10,Timer1Callback);//我这里用的是100ms中断一次来做实验
	while(1)
	{
     
		TaskProcess();// 任务处理
	}
}
总结:
整个程序的执行流程就是:中断函数不断刷新着每一个任务的状态,
任务处理函数根据这些状态来判断哪些函数要被执行,如果要执行,就立马执行。
添加任务就是在任务数组中添加一个结构体信息,编写一个任务函数,在任务列表中添加一个函数。

基本思想:
举个例子,有一个函数A,我们给它设置
一个计数器B(程序多久执行一次)
和一个状态标志位C(用来判断这个程序是否需要执行)
还有一个计数填充值D,
其中的B会被单片机自带的定时器中断服务函数不断地刷新(递减刷新),
当B到0的时候C会被置位,同时B会被重新填满D值,
当主程序运行到A的时候不会直接去运行它,而是先检查C,
如果C没有被置位,说明还没有到A的执行时间,不执行A,
如果C被置位了,就执行A,执行完后将C复位,让C再等上一段时间才再次被执行。

这个是记录自己学习的过程!
感谢您的支持!

你可能感兴趣的:(单片机架构,c语言,嵌入式,单片机)