嵌入式:一种裸机编程多任务切换方法
有时候为了实现一些简单的、对实时性要求不高的任务,采用操作系统不仅增加了程序的复杂性,对低性能单片机的资源占用也是值得考虑的问题。这时候操作系统可能不是必要的,可以通过一种简单的方法,在裸机编程中实现类似“多任务切换”的方法。
比如,在某个应用中,我们需要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);
THREAD(threadTime[1], 1000, msg_thread);
THREAD(threadTime[2],500,in_capture_thread)
}
}
实现方法
定义计数器变量
首先实现一个定时器,用于递增计数器变量。定义一个uint32_t
类型的timeFlag
。这里定时器中断定时为1ms,如果几个任务的执行周期比较长,定义为10ms也是可以的。如果是stm32可以直接打开stm32的SysTick中断用于递增计数器。
void Timer0() interrupt 1
{
TF0 = 0;
timeFlag++;
}
任务的时间变量
然后分别定义两个任务的时间变量threadTime1
,threadTime2
,用于与计数器比较,实现方法如下:
基本思路为:用计数器变量减去任务的时间变量,如果时间大于等于执行周期,则执行func()
,即我们的任务,否则不执行。然后将最新的计数器值赋值给任务的时间变量用于下一次比较。
uint32_t delay1 = 500;
uint32_t delay2 = 100;
void main()
{
Gpio_Init();
Out_Close();
Timer0_Init();
Uart1_Init();
while(1)
{
if (timeFlag - threadTime1 >= delay1)
{
threadTime1 = timeFlag;
func1();
}
if (timeFlag - threadTime2 >= delay2)
{
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_thread
1s执行一次,in_capture_thread
500ms执行一次。
while(1)
{
THREAD(threadTime[0], 10, rain_capture_thread);
THREAD(threadTime[1], 1000, msg_thread);
THREAD(threadTime[2],500,in_capture_thread);
}
这样就可以使用一个定时器实现多个对时间要求不高的任务啦。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)