STM32 简单多任务调度

        STM32的开发目前大多数还开处于“裸奔”的阶段,处于开发成本的考虑,可能还未嵌入任何的RTOS系统,由于没有操作系统的支持,因而不能方便的对多任务进行调度和管理,在main函数中你可能会写成如下方式:

int main(void)
{
	while (1)
	{
		Task1(); // 调用任务1
		Task2(); // 调用任务2
	}
}

       但简单这样写的话会存在一个问题,假如任务1是一个很紧急的任务,如AD采样任务,需要不断的去执行,而任务2是一个不太紧急的任务,只要保证一段时间执行一次就行(如控制LED灯闪烁,只需要每1s钟闪烁一次),这样的话一是频繁的调用任务2占用了任务1执行的时间,二是任务2根本不需要这样频繁的执行,白白耗费了CPU的处理。因此可以考虑实现一个调度策略来解决这个问题。对于每个任务,我们可以定义这样一个结构:

typedef struct{
	  void (*fTask)(void);
	  int64u uNextTick;
	  int32u uLenTick;
}sTask;

        其中fTask为任务指针,指向具体的任务,uNextTick为该任务下一次执行的时间,uLenTick为任务的调度周期或叫调度频率,即每隔多长时间执行一次。

        按照这个结构,可以预先定义一个结构体数组,然后将要调用的任务和任务的调度时间按照如下方式罗列出来:

// 任务列表
static sTask mTaskTab[] = 
{
	 {Task_SysTick,    0, 0}
	,{Task1,           0, 10}    // 10ms执行一次
	,{Task2,           0, 200}   // 200ms执行一次	
};

        其中第一个任务Task_SysTick为计算系统时间的任务,用以获取上电后运行的时间(Task_SysTick任务相关代码附在文章后面)。这里默认任务下一次执行的时间为0,在main函数中,不断的轮询这个数组,然后将当前任务的下一次调用时间和当前时间比较,如果发现轮到该任务执行,就执行该任务,执行完成后,将该任务的下一次执行时间设为当前时间加任务的调度时间,然后按照此方法去执行下一个需要执行的任务,代码如下:

	while (1)
	{
		// 任务循环
		for (i = 0; i < ARRAYSIZE(mTaskTab); i++)
		{
			if (mTaskTab[i].uNextTick <= GetTimingTick())
			{
				mTaskTab[i].uNextTick += mTaskTab[i].uLenTick;
				mTaskTab[i].fTask();	
			}
		}
	} 

        这样,就可以对多个任务做一个简单的调度,以后添加任务时只需要在mTaskTab表中添加即可,需要强调的是,由于执行每个任务也需要耗费时间,就会导致一个任务的实际调度周期可能会比设定的调度周期要长,这样会存在时间不准的情况,当然这仅仅是适合于对轮询周期不是很严格的任务,如果想要任务在严格的时间周期内执行或者需要更精确的时间处理,则必须采用定时器的方式了。

附:

        完整的main文件代码:

#ifndef ARRAYSIZE
#define ARRAYSIZE(a) (sizeof(a) / sizeof((a)[0]))
#endif

// 任务结构
typedef struct{
	  void (*fTask)(void);
	  u64 uNextTick;
	  u32 uLenTick;
}sTask;


// 任务列表
static sTask mTaskTab[] = 
{
	 {Task_SysTick,    0, 0}
	,{Task1,           0, 10}   // 10ms执行一次	
	,{Task2,           0, 200}  // 200ms执行一次	
	
	// 在这之前添加任务
};

/*******************************************************************************
* Function Name  : main
* Description    : Main program.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
int main(void)
{
	int i = 0;
	// 硬件初始化
	HW_init();
	// 初始化系统Tick任务
	dev_SysTick_init(void);
	// ...  
	while (1)
	{
		// 任务循环
		for (i = 0; i < ARRAYSIZE(mTaskTab); i++)
		{
			if (mTaskTab[i].uNextTick <= GetTimingTick())
			{
				mTaskTab[i].uNextTick += mTaskTab[i].uLenTick;
				mTaskTab[i].fTask();	
			}
		}
	} 
}


Task_SysTick任务相关代码:

volatile int64u g_TimingTick = 0;
volatile int64u g_TimingTickOld = 0;

//=================================================================================================
//【函 数 名 称】 void dev_SysTick_init(void)
//【参       数】 
//【功       能】 初始化
//【返   回  值】 None
//【创   建  者】 2010-07-27 firehood
//=================================================================================================
void dev_SysTick_init(void)
{
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

	/* Time base configuration */
	TIM_TimeBaseStructure.TIM_Period = 65535;               
	TIM_TimeBaseStructure.TIM_Prescaler = 36000-1; 
	TIM_TimeBaseStructure.TIM_ClockDivision = 0;    
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 
	
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
	
	TIM_SetCounter(TIM2, 0);

	/* TIM enable counter */
	TIM_Cmd(TIM2, ENABLE);
}

//=================================================================================================
//【函 数 名 称】 void GetTimingTick(void)
//【参       数】 
//【功       能】 获取MCU启动后的运行时间
//【返   回  值】 MCU启动后的运行时间,单位ms
//【创   建  者】 2010-07-27 firehood
//=================================================================================================
int64u GetTimingTick(void)
{
	return g_TimingTick;
}

//=================================================================================================
//【函 数 名 称】 void Task_SysTick(void)
//【参       数】 
//【功       能】 Tick任务,从TIM2获取系统时间
//【返   回  值】 None
//【创   建  者】 2010-07-27 firehood
//=================================================================================================
void Task_SysTick(void)
{
	int16u temp = TIM_GetCounter(TIM2);

	if (temp > 1000)
	{
		TIM_SetCounter(TIM2, 0);
		g_TimingTickOld = g_TimingTickOld + temp;
		temp = 0;
	}
	g_TimingTick = g_TimingTickOld + temp;
}

 

  • 10
    点赞
  • 90
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值