嵌入式:一种裸机编程多任务切换方法

嵌入式:一种裸机编程多任务切换方法


有时候为了实现一些简单的、对实时性要求不高的任务,采用操作系统不仅增加了程序的复杂性,对低性能单片机的资源占用也是值得考虑的问题。这时候操作系统可能不是必要的,可以通过一种简单的方法,在裸机编程中实现类似“多任务切换”的方法。

比如,在某个应用中,我们需要10ms做一次A/D转换,1s串口发送一次数据,500ms读一次外部IO,并且这些任务都不是对时间要求严格的任务,这时候就可以使用下面的方法实现“多任务”,不仅使程序结构更加清晰,也使我们的编程思路更加清晰


以51单片机为例,通过简单的封装,main.c可以更简短清晰:

#include "common.h"
#include "stdio.h"

void main()
{
    
    
	Gpio_Init();
	Out_Close(); 
	Timer0_Init();
	Uart1_Init();

    while(1) {
    
    

		THREAD(threadTime[0], 10, rain_capture_thread); //10ms 捕获雨量计数据

		THREAD(threadTime[1], 1000, msg_thread);  //1s 发送雨量值
		
		THREAD(threadTime[2],500,in_capture_thread) //500ms
	}
}

实现方法

定义计数器变量

首先实现一个定时器,用于递增计数器变量。定义一个uint32_t类型的timeFlag。这里定时器中断定时为1ms,如果几个任务的执行周期比较长,定义为10ms也是可以的。如果是stm32可以直接打开stm32的SysTick中断用于递增计数器

/**
 * @brief  定时器0 
 * @note   timeFlag为计数器,每毫秒递增一次
 * @retval None
 */
void Timer0() interrupt 1
{
    
    
	TF0 = 0;
	timeFlag++;
}

任务的时间变量

然后分别定义两个任务的时间变量threadTime1threadTime2,用于与计数器比较,实现方法如下:
基本思路为:用计数器变量减去任务的时间变量,如果时间大于等于执行周期,则执行func(),即我们的任务,否则不执行。然后将最新的计数器值赋值给任务的时间变量用于下一次比较。

uint32_t delay1 = 500; //这里的值与上述中断时间有关 ,执行周期 = delay * 中断时间
uint32_t delay2 = 100;
void main()
{
    
    
	Gpio_Init();
	Out_Close(); 
	Timer0_Init();
	Uart1_Init();

    while(1) //loop
    {
    
    
		if (timeFlag - threadTime1 >= delay1) //时间变量与计数器变量作比较 500ms
		{
    
                                 
			threadTime1 = timeFlag;      //更新时间变量    
			func1();                   //执行我们的任务
		}
		
		if (timeFlag - threadTime2 >= delay2) //时间变量与计数器变量作比较  100ms
		{
    
                                 
			threadTime2 = timeFlag;      //更新时间变量    
			func2();                   //执行我们的任务
		}
	}
}

简陋的封装一下

将时间变量比较的功能部分提升为宏的形式,这里没有判断参数是否合法。

uint32_t threadTime[4] = {
    
    0};//定义四个任务的时间变量
#define THREAD(time, delay, func)     \
	do                                \
	{
      
      							      \ 
		if (timeFlag - time >= delay) \
		{
    
                                 \
			time = timeFlag;          \
			func();                   \
		}                             \
	}                                 \
	while(0);

然后就可以在大循环中这样写,是不是显得很简洁。
这样rain_capture_thread任务将会每10ms执行一次,msg_thread1s执行一次,in_capture_thread500ms执行一次。

 while(1) 
 {
    
    
		THREAD(threadTime[0], 10, rain_capture_thread); 
		THREAD(threadTime[1], 1000, msg_thread);  
		THREAD(threadTime[2],500,in_capture_thread);
}

这样就可以使用一个定时器实现多个对时间要求不高的任务啦。

猜你喜欢

转载自blog.csdn.net/qq_27350133/article/details/115093972