ANO匿名飞控时间片调度移植至普通STM32工程

工程结构ANO匿名飞控时间片调度移植至普通STM32工程

时间片调度相关的代码位于SCHEDULER目录下的Scheduler和Task文件中,匿名飞控原本的时钟由传感器输出的1ms脉冲实现的外部中断提供,为使时间片调度算法可以用于一般的工程,此处改为使用定时器TIM7的1ms定时器中断,位于HAEDWARE目录下的timer文件(原因:f407的TIM7无法用于PWM输出,使用定时器TIM7可减少移植的冲突,如有需要,可改为其他定时器)

具体代码

1.Task.c用于存放用户任务函数,线程中的用户任务的执行不应占用太长时间

#include "Task.h"
#include "usart.h"
#include "delay.h"
void task1()
{
	
	printf("任务1执行\r\n");

	
	
}

void task2()
{

	printf("任务2执行\r\n");
	
	
}

void task3()
{
	printf("任务3执行\r\n");
	
}


2.Scheduler.c,存放有调度器初始化函数,调度器运行函数,用户任务在此文件中进行注册(如task2()和task1()函数)

#include "Scheduler.h"
#include "Task.h"
//
//用户程序调度器
//

static void Loop_1000Hz(void) //1ms执行一次
{
	//

	//
}

static void Loop_500Hz(void) //2ms执行一次
{
	//

	//
}

static void Loop_200Hz(void) //5ms执行一次
{
	//

	//
}

static void Loop_100Hz(void) //10ms执行一次
{
	//

	//
}

static void Loop_50Hz(void) //20ms执行一次
{
	//
	
	//
}

static void Loop_20Hz(void) //50ms执行一次
{
	//
	task2();
	//
}

static void Loop_2Hz(void) //500ms执行一次
{
	//
	task1();
	
	//
}
//
//调度器初始化
//
//系统任务配置,创建不同执行频率的“线程”
static sched_task_t sched_tasks[] =
	{
		{Loop_1000Hz, 1000, 0, 0},
		{Loop_500Hz, 500, 0, 0},
		{Loop_200Hz, 200, 0, 0},
		{Loop_100Hz, 100, 0, 0},
		{Loop_50Hz, 50, 0, 0},
		{Loop_20Hz, 20, 0, 0},
		{Loop_2Hz, 2, 0, 0},
};
//根据数组长度,判断线程数量
#define TASK_NUM (sizeof(sched_tasks) / sizeof(sched_task_t))

void Scheduler_Setup(void)
{
	uint8_t index = 0;
	//初始化任务表
	for (index = 0; index < TASK_NUM; index++)
	{
		//计算每个任务的延时周期数
		sched_tasks[index].interval_ticks = 1000 / sched_tasks[index].rate_hz;
		//最短周期为1,也就是1ms
		if (sched_tasks[index].interval_ticks < 1)
		{
			sched_tasks[index].interval_ticks = 1;
		}
	}
}
//这个函数放到main函数的while(1)中,不停判断是否有线程应该执行
void Scheduler_Run(void)
{
	uint8_t index = 0;
	//循环判断所有线程,是否应该执行

	for (index = 0; index < TASK_NUM; index++)
	{
		//获取系统当前时间,单位MS
		uint32_t tnow = GetTimeMs();
		//进行判断,如果当前时间减去上一次执行的时间,大于等于该线程的执行周期,则执行线程
		if (tnow - sched_tasks[index].last_run >= sched_tasks[index].interval_ticks)
		{

			//更新线程的执行时间,用于下一次判断
			sched_tasks[index].last_run = tnow;
			//执行线程函数,使用的是函数指针
			sched_tasks[index].task_func();
		}
	}
}

/************************END OF FILE************/

相关说明匿名的注释已经说的很清楚了,这里做简单补充和移植说明。Scheduler_Setup函数是调度器初始化函数,需在主函数的while(1)前调用一次。Scheduler_Run函数是调度器运行函数,需放到main函数的while(1)中循环调用,主要内容为获取系统当前时间,用当前时间减去上一次执行的时间,若大于等于该线程的执行周期,则执行对应的线程,线程中的用户任务的执行不应占用太长时间,否则会阻塞线程。匿名飞控的调度器是软实时调度,而非FreeRTOS式的硬实时调度。(硬实时是系统执行一个程序,只要规定的时间用完,那么就一定跳出去,不管执行完还是没有执行完。软实时没有硬性的时间限制,它可以推迟一段时间来完成自己的任务。)Scheduler_Run中调用的GetTimeMs()函数位于timer.c文件中,如下。
3.timer.c,存放定时器初始化、定时器中断和GetTimeMs()函数

#include "timer.h"
#include "usart.h"

static uint64_t TimeMs = 0;


//定时器7中断服务程序		    
void TIM7_IRQHandler(void)
{ 	
	if (TIM_GetITStatus(TIM7, TIM_IT_Update) != RESET)//是更新中断
	{	 	
		TimeMs++;
		TIM_ClearITPendingBit(TIM7, TIM_IT_Update  );  //清除TIM7更新中断标志     
	}	    
}


 
//通用定时器中断初始化
//这里始终选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数		 
void TIM7_Int_Init(u16 arr,u16 psc)
{	
	NVIC_InitTypeDef NVIC_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);//TIM7时钟使能    
	
	//定时器TIM7初始化
	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
 
	TIM_ITConfig(TIM7,TIM_IT_Update,ENABLE ); //使能指定的TIM7中断,允许更新中断
   
	TIM_Cmd(TIM7,ENABLE);//使能定时器7
	
	NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;//抢占优先级0
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;		//子优先级1
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
	
}

uint32_t GetTimeMs(void)
{
	return TimeMs;
}


	 

4.main.c,软硬件初始化,调用Scheduler_Run()开启调度器

#include "stm32f4xx.h"
#include "usart.h"
#include "delay.h"
#include "timer.h"
#include "Scheduler.h"


int main(void)
{
	
	uart_init(115200);
	delay_init(168);
	TIM7_Int_Init(10-1,8400-1);
	Scheduler_Setup();
  while(1){
    Scheduler_Run();
	}
}

如有需要,这里提供完整工程可供参考。

https://download.csdn.net/download/qq_45296217/79248632
上一篇:2020冬季西南区MVP活动之走进西南财大


下一篇:<STM32学习>--跑马灯实验