STM32F1移植任务调度

STM32F1移植任务调度

什么是任务调度呢?

我在匿名代码任务管理中有提到任务调度,那么我们今天来把任务调度真正的移植出来

任务调度就是把你要做的事件分成一个一个的任务,然后确定任务执行的频率
SYSTICK滴答定时器
作为内核部分的SYSTICK定时器,是每个学单片机的人都必须会的。
因为他不会占用软件执行的时间,它的计时完全是由硬件完成的,
所以我们不需要关心它的执行时间会影响我们的程序。作为内核部分,不管是TI的tiva还是STM32都可以适用。
首先我们呢要初始化SYSTICK滴答定时器,因为默认的情况下,滴答定时器都是关闭的,因此我们需要将他开启。
SYSTICK由几个寄存器控制,分别是 
1.控制集状态寄存器 2.重装载值寄存器 3.当前数值寄存器 4.校准数值寄存器(可以参考M3权威指南)

我们需要用到只有两个,一个是控制寄存器,一个重装载值寄存器设置重装载值,具体代码如下

在STM32中可以直接操作寄存器
void systick_Init(void)
{	
	SysTick->CTRL&=~(1<<2);												
	SysTick->CTRL|=1<<1;		
	SysTick->CTRL|=(1<<0);			
	SysTick->LOAD = (u32)4500;	
}
在Tiva中如果找不到寄存器也可以直接操作内存地址
void systick_Init(void)
{
	*((volatile u32 *)0xE000E010) &= ~(1<<2); 
	*((volatile u32 *)0xE000E010) |= 1<<1;
	*((volatile u32 *)0xE000E010) |= 1<<0;
	*((volatile u32 *)0xE000E014) = (u32)1000;
}
这段代码的含义是:
1.采用外部的时钟源 2.倒计时到0时产生异常,也就是中断 3.使能计数器 4.设置重装载值(可以随意设置)
滴答定时器是从重装载值开始倒计时,倒计时到0时,产生中断,那么我们还要写一个中断函数,
因为STM32默认的中断函数虽然是弱定义,但是默认都是死循环,如果我们不写中断服务函数,那么倒计时到0时,
会进入死循环
volatile u32 sysTickUptime = 0;
static u32 systime_ms = 0 ;
/* 没必要也可以删去 */
void sys_time(void)
{
	systime_ms++;
}
/* 滴答定时器中断服务函数 */
void SysTick_Handler(void)
{
 	sysTickUptime++;
	sys_time();
}
u32 SysTick_GetTick(void)
{
	return systime_ms;
}
这里我们写了中断服务函数,我们定义一个变量sysTickUptime前面加上是指volatile是指“易变的”,
意思是提醒编译器我们的值是易变的,告诉编译器不要优化但我们计数到0的时候,中断服务函数的变量就会++,
变量相当于一个计数器,当滴答定时器开启时从0开始计数,当滴答定时器计数到0,变量+1,
这样我们就可以获得当前距离开始的时间。当我们外部调用SysTick_GetTick就可以获取到这个变量值了,
就是获取到了当前距离开始的时间。

接下来我们来看主函数

/*任务结构体*/
typedef struct
{
void(*task_run_function)(void);
u16 rate_hz;	
u16 period;
u32 last_run_time;
}Task_Run_Struct;

/***************/
/*各个任务的结构体*/
/*
1:函数的指针,指向各个函数的执行
2:频率
3:周期
4:上次运行的时间
*/
static Task_Run_Struct task_run[] = 
{
	{Loop_1000Hz,1000,  1, 0},
	{Loop_500Hz , 500,  2, 0},
	{Loop_200Hz , 200,  5, 0},
	{Loop_100Hz , 100, 10,0},
	{Loop_50Hz , 50,  20, 0},
	{Loop_1Hz , 1,  1000, 0},
};
/***************/
/*计算任务的个数*/
#define TASK_NUM (sizeof(task_run)/sizeof(Task_Run_Struct))
void Task_Run(void)
{
	/*循环任务进行*/
	u8 index = 0;
	/*建议总任务的执行时间不要小于各个任务最短周期*/
	/*如果超过时间,建议把高优先级放在低索引处*/
	for(index = 0;index < TASK_NUM;index++)
	{
		/*获取当前的时间*/
		static u32 time_now = 0; 
		time_now = SysTick_GetTick();
		/*距离上次执行的时间已经大于或执行的周期了*/
		if((time_now - task_run[index].last_run_time)>=task_run[index].period)
		{
			/*把这次的时间赋值给上次任务执行的时间,然后执行任务*/
			task_run[index].last_run_time = time_now;
			task_run[index].task_run_function();
			break;
		}
	}
}

/*1ms执行一次*/
static void Loop_1000Hz(void)
{
}
/*2ms执行一次*/
static void Loop_500Hz(void)
{
}
/*5ms执行一次*/
static void Loop_200Hz(void)
{
}
/*10ms执行一次*/
static void Loop_100Hz(void)
{
}
/*20ms执行一次*/
static void Loop_50Hz(void)
{
}
/*1s执行一次*/
static void Loop_1Hz(void)
{
}
我自己写的一段代码注释很明了,应该能看懂
主函数
int main()
{
	state = All_Init();
	while(1)
	{
		Task_Run();
	}
}
我们只需要把Task_Run放在while中一直执行就行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值