DSP芯片,也稱數字信號處理器,是一種具有特殊結構的微處理器。它的內部采用程序和數據分開的哈佛結構,具有專門的乘法器,廣泛采用流水線結構,提供特殊的DSP指令,在一個周期內完成一次乘法和一次加法。在國外,DSP芯片已經被廣泛地應用于當今技術革命的各個領域;在我國,DSP技術也正以極快的速度被應用在通信、電子系統、信號處理系統、自動控制、雷達、軍事、航空航天、醫療、家用電器、電力系統等許多領域中,而且新的應用領域在不斷地被發掘。因此基于DSP技術的開發應用正成為數字時代的應用技術潮流。相對于單片機,它速度更快,外設集成度更高,程序存儲器更大。在《時間觸發嵌入式系統設計模式》一書中詳細介紹了基于單片機的軟件設計方法,而本文基于DSP對這種設計進行了擴展,使這種設計方法更為靈活,有效。
二.調度器介紹
可以從兩方面來看調度器:一方面:調度器可以看作是一個簡單的操作系統,允許以周期性或單次方式調用任務;另一方面:從底層角度來看,調度器可以看作是一個由許多不同任務共享的定時器中斷服務程序。
1. 調度器的組成
(1)調度器數據結構
調度器的核心是調度器數據結構。這是一種用戶自定義的數據類型,集中了每個任務所需的信息。
typedef struct
{
void ( * pTask)(void); 指向任務的指針(必須是一個void(void)函數)。
unsigned int Delay; 延時時標數:直到任務將下一次運行所剩時標數。時標,是硬件定時器周期中斷設定的時間間隔,它是調度器的驅動者。
unsigned int Period; 周期時標數:任務連續運行所間隔的時標數。
unsigned int DelCounter; 若不為周期任務,表示任務運行次數;若為周期函數,則無意義。
char PrdOrTemp; 若PrdOrTemp=1,則為周期任務;若PrdOrTemp=0,則為非周期任務。
char RunMe; 當任務需要運行時(由調度器)加1
} sTask;
另外,還需要定義一些全局變量:unsigned int Task_Index 記錄當前所添加任務索引變量,對于每一個任務都要定義一個任務索引變量,以便對任務進行查找。例如:可以利用任務索引變量對任務進行刪除。任務隊列sTask SCH_tasks_G [SCH_MAX_TASKS]記錄所有任務數據結構的全局變量,其中SCH_MAX_TASKS為定義的最大任務數。雖然在系統運行時,任務有添加或刪除,但系統不是很復雜,給出的SCH_MAX_TASKS一定要大于運行的任務數。
(2) 初始化函數(void SCH_Init_T(void))
這個函數主要的作用是設置定時器,用來產生驅動調度器的定期時標。一般的DSP都有多個定時器,它們中的任何一個都可以用來驅動調度器。對于調度器來說,要在不同地微處理器運行,主要是初始化函數不同(即微處理器的定時器初始化不同)。時標設定的大小關系到CPU的利用率和系統的精度,它的大小與具體的系統有關,例如微處理器的速度,執行任務的大小,執行任務周期的大小等。TI 公司推出的2000 系列的DSP與一般51系列的單片機時標的設定有所不同:DSP的CPU頻率可達到40M,而且采用流水線結構,基本上一個時鐘周期執行一條指令;一般單片機頻率為10M,而且遠不能達到一個時鐘周期執行一條指令。在《時間觸發嵌入式系統設計模式》一書中,單片機時標設定為1ms,可獲得很高的CPU利用率;而調度器應用在交流數據采集和控制系統中(采用TMS320LF2407), 時標設定為200us,CPU利用率也不小于百分之九十五。
(3) 添加任務的函數
unsigned int SCH_Add_Task(void ( * pFunction)( DELAY, PERIOD, DELCOUNTER, PRDORTEMP)
添加任務函數首先開始檢查任務隊列sTask SCH_tasks_G[SCH_MAX_TASKS]記錄所有任務數據結構的全局變量哪一個空閑,然后將所添加任務的地址,延時執行時標數,周期時標數,任務運行次數,周期任務指示標志賦給任務隊列那一個空閑全局變量。再記錄下當前任務索引變量,以便在需要的情況下賦給任務自身索引變量,對任務進行跟蹤。
(4) 刪除任務的函數
void SCH_Del_Task(const unsigned int TASK_INDEX)
刪除任務函數從 TASK_INDEX得到所要刪除任務的任務索引變量。然后將對應的任務數據結構的全局變量清除。刪除任務時,對應的任務數據結構的全局變量的內容清除,但變量并沒有撤銷,當再次執行添加任務函數時,此任務數據結構的全局變量有可能分配給其他任務。
(5) 刷新函數 void SCH_Update(void)
刷新函數是調度器的中斷服務程序,用一定的時間間隔刷新調度器。它是由定時器溢出激活的,刷新函數并不復雜。當刷新函數確定某個任務需要運行時,將這個任務Runme標志加一,然后該任務將由調度函數執行。刷新函數的執行流程如圖1所示。
(6) 調度函數 void SCH_Dispatch_Tasks(void)
調度函數是用來執行任務的函數,而刷新函數并不執行任務。我們之所把刷新函數與調度函數分開,是處于與系統安全考慮的。如果刷新函數與調度函數合并,而一個任務出現異常在一個時標中沒有執行完,那么定時器中斷將被忽略,下一個任務將不能在預定的時間內執行。調度函數不僅可以運行所需要運行的任務,而且可以刪除運行完畢的非周期任務。在調度函數中可加入一些其他功能,可以是系統在任務執行完畢后沒有任務執行是進入低功耗狀態,以節省電能。調度函數的執行流程如圖2所示。
2. 任務的運行
任務的運行過程也是調度器運行的過程。這里調度LED兩秒閃爍一次的任務來說明任務void LED_Flash(void)的運行過程。設定時標為200us。系統初始化System_Init( ),對于任務LED_Flash(),DSP僅僅設置時鐘和相應的I/O引腳;SCH_Init_T()前已詳細講明;添加任務函數
SCH_Add_Task(LED_Flash, 0, 5000,0,PERIOD_TASK ),其中LED_Flash為任務的地址,第一個零表示從系統運行第一個時標就開始執行任務,5000表示每5000個時標(5000×200us=1s)執行一次任務,PERIOD_TASK表示這是一個周期任務,第二個零周期任務時無意義;啟動定時器SCH_Start(),注意添加任務后再啟動定時器;進入超循環(即while(1){}語句)執行調度函數SCH_Dispatch_Tasks(),任務LED_Flash()在其中被執行:點亮或熄滅LED;任務執行完畢,定時器中斷到來時,進入中斷并立刻對定時器清零,以保證時標的精確,再執行刷新函數SCH_Update(),然后中斷返回執行調度函數 SCH_Dispatch_Tasks()。
三. 應用
在V/F控制異步電動機調速系統中,用運調度器對程序進行編程,實現了對電機的開環控制。
主程序部分代碼:
Void Main.c(void)
{
System_init(); 系統初始化
Sch_init_t1();調度器初始化
AD——Sample();電流、電壓采樣
Svpwm_init();SVPWM波生成初始化
Led_flash_update();刷新函數
Sch_add_task(led_flash_update,0,1000);添加任務1
Sch_add_task(uf_control,0,1);添加任務2
Ash_add_task(svpwm_control,0,1);添加任務3
Sch_start();
While(1)
{
Sch_dispatch_tasks(); 執行任務
}
中斷程序略。
}
四. 總結
這種調度器的特點首先是結構簡單,運行安全可靠:調度器的大小只有450個字,分配給每個任務的RAM也只有6個字;其次,由于調度器很小,運行時間很短,CPU的利用率高;簡化軟件設計。在直接轉矩控制系統中(采用TMS320LF2407A)已使用這種調度器進行軟件設計,在仔細設計的前提下系統是可以非??煽窟\行:首先,必須知道每個任務運行的最長時間,而所有任務運行最長時間的總和最好小于時標,這樣最為安全,而實際中常常達不到這樣要求,那么就讓周期的任務在不同的時標中運行;其次,任務的大小可能參差不齊,有時還可能相差較大,這就要根據實際情況把大任務分解成小任務或把小任務合并為大任務。
責任編輯:gt
評論
查看更多