匿名四軸(任務管理第一篇)

任務初始化

//任務開始
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]) ;	
}
//剩下的我可能會在後續講到

個人的理解,如有錯誤的地方,很希望你在評論區留言指出
如果看到也希望去評論去看看錯誤的地方
排版不是很好

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