匿名四轴(任务管理第一篇)

任务初始化

//任务开始
void Scheduler_Setup(void)
{
	uint8_t index = 0;
	//初始化任务表
	for(index=0;index < TASK_NUM;index++)
	{
	//interval_ticks 计算每个任务的延时周期数就是上面说的延时周期
	//你可以把它想想成两次任务开始间隔的时间,
	//这里的TICK_PER_SECOND为1000,
	//猜测(如果时钟频率发生改变,应该直接改这里就可以了,
	//如果猜测正确的化后续的操作都和这个参数有关而和频率没有太大关系)
		sched_tasks[index].interval_ticks = 
		TICK_PER_SECOND/sched_tasks[index].rate_hz;
	//最短周期为1,也就是1ms,
	//限制了最小周期为1ms也就是说在TICK_PER_SECOND = 1000时
	//频率2000和1000是一样的
		if(sched_tasks[index].interval_ticks < 1)
		{
			sched_tasks[index].interval_ticks = 1;
		}
	}
}

任务开始

//我们现来看两个函数
//SysTick_Handler在startup启动文件中有写道,
//类似于定时器中断,时间到了就会执行,
//这个函数不会影响主函数正常执行,硬件支持
void SysTick_Handler(void)
{
	sysTickUptime++;
	sys_time();
	LED_1ms_DRV();
}
void sys_time()
{
	systime_ms++;
}
u32 SysTick_GetTick(void)
{
	return systime_ms;
}
//这几个函数实现可以记录系统时间,
//这个时间和你配置的滴答计时器的时钟有关系

//这个函数放到main函数的while(1)中,不停判断是否有线程应该执行
void Scheduler_Run(void)
{
	uint8_t index = 0;
	//循环判断所有线程,是否应该执行	
	for(index=0;index < TASK_NUM;index++)
	{
		//获取系统当前时间,单位MS
		uint32_t tnow = SysTick_GetTick();
//进行判断,如果当前时间减去上一次执行的时间,
//大于等于该线程的执行周期,则执行线程
//interval_ticks为两次任务开始之间所相差的时间,
//如果现在的时间距离上次任务开始的时间超过这个值或等于这个值就执行任务
		if(tnow - sched_tasks[index].last_run 
		>= sched_tasks[index].interval_ticks)
		{
			
	//更新线程的执行时间,用于下一次判断,
	//记录时间在前,执行任务在后,先记录时间,
	//然后执行可见记录的是任务开始的时间,
	//并不是任务做完之后的时间,其实应该差别不大
			sched_tasks[index].last_run = tnow;
//执行线程函数,使用的是函数指针
//利用函数指针来执行函数,
//这里task_func存放的时Loop_1000Hz等函数指针,这样可以直接调用这个函数
			sched_tasks[index].task_func();
		}	 
		
	}
}

任务分析

任务前言介绍

/*
volatile是“易变的”,应该解释为“直接存取原始内存地址”比较合适。
volatile提醒编译器它后面所定义的变量随时都有可能改变,
因此编译后的程序每次需要存储或读取这个变量的时候,
告诉编译器对该变量不做优化,都会直接从变量内存地址中读取数据,
从而可以提供对特殊地址的稳定访问。。如果没有volatile关键字,
则编译器可能优化读取和存储,可能暂时使用寄存器中的值,
如果这个变量由别的程序更新了的话,将出现不一致的现象(参考网上)
*/
volatile uint32_t sysTickUptime = 0;//sysTickUptime是易变的
uint32_t GetSysTime_us ( void )
{
/*
register修饰符暗示编译程序相应的变量将被频繁地使用,
如果可能的话,应将其保存在CPU的寄存器中,
以加快其存储速度。register是C语言中的关键字,
加快访问速度,偏向底层用的很多。
*/
    register uint32_t ms;
    u32 value;
	do
	{
    ms = sysTickUptime;
 /*
sysTickUptime是上面定义的易变类型,
还记得SysTick_Handler函数吗,就是我们上面滴答定时器讲到的函数,
如果单单的这个函数函数怎么能实现sysTickUptime的改变,
我们回到SysTick_Handler函数中有些到sysTickUptime++,
这样我们就明白了,
滴答定时器每滴答一次systime_ms和sysTickUptime都实现了+1操作
*/
    value = ms * TICK_US + ( SysTick->LOAD - SysTick->VAL )
     * TICK_US / SysTick->LOAD;
/*SysTick->LOAD - SysTick->VAL,这个是寄存器操作
我先来介绍一下SysTick这个寄存器
LOAD指的是SysTick Reload Value Register,
就是指重装载值,什么是重装载值在定时器中我们计数到一个最大数然后发生中断,
这个就是重装载值。
SysTick->VAL(SysTick Current Value Register )
很显然就是当前记录的值
滴答定时器是一个递减定时器,
最大值减去当前值就是已经经过的时间,就是过去的记录的时间
这样写可能不明显,
你把后面的写成分数可能就会明显
( SysTick->LOAD - SysTick->VAL )/SysTick->LOAD
就是当前记录时间所占总共能记录时间的百分比,
后面乘以TICK_US(那个数我们可以猜测是记录的最大时间,
也就是LOAD递减到0的时间),ms类似作用是当滴答计时器递减到零时,
ms实现+1,然后滴答定时器从新开始计时
     */
	}
	while(ms != sysTickUptime);
	//这个函数不是滴答定时器,
	//程序是要退出的,不能一直卡在那当ms=sysTickUptime就会退出,
	//当出现ms的值不能更新,就会在循环中
	return value;
}
//为什么讲上面的呢因为下面有GetSysTime_us函数
//看到1000你应该就明白了每1ms执行一次
u32 test_dT_1000hz[3],test_rT[6];
static void Loop_1000Hz(void)	//1ms执行一次
{
	test_dT_1000hz[0] = test_dT_1000hz[1];
	test_rT[3] = test_dT_1000hz[1] = GetSysTime_us ();
	test_dT_1000hz[2] = 
	(u32)(test_dT_1000hz[1] - test_dT_1000hz[0]) ;
	/*传感器数据读取*/
	Fc_Sensor_Get();
	
	/*惯性传感器数据准备*/
	Sensor_Data_Prepare(1);
	
	/*姿态解算更新*/
	IMU_Update_Task(1);
	
	/*获取WC_Z加速度*/
	WCZ_Acc_Get_Task();
	WCXY_Acc_Get_Task();
	
	/*飞行状态任务*/
	Flight_State_Task(1,CH_N);
	
	/*开关状态任务*/
	Swtich_State_Task(1);
	
	/*光流融合数据准备任务*/
	ANO_OF_Data_Prepare_Task(0.001f);


	/*数传数据交换*/
	ANO_DT_Data_Exchange();

			test_rT[4]= GetSysTime_us ();
			test_rT[5] = (u32)(test_rT[4] - test_rT[3]) ;	
}
//剩下的我可能会在后续讲到

个人的理解,如有错误的地方,很希望你在评论区留言指出
如果看到也希望去评论去看看错误的地方
排版不是很好

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章