摘 要:主要討論了ucos在196kc單片機上的移植,編譯器為tasking c,并給出了一個實例,經實測與理論分析一致,說明移植成功。
關鍵詞:196kc ucos tasking c 移植
abstact: this paper discusses porting ucos rtos to 196kc chip by using tasking c compiler,and also gives the instance which is proved successful through practice.
keywords: 196kc ucos tasking c porting
引 言
intel的80196kc系列單片機在國內有很大一批用戶,且已有很長一段歷史。支持196kc的c編譯器生產廠商主要有tasking和iar。但國內使用tasking公司的c編譯器用戶較多。ucos為源碼公開的實時操作系統。在嵌入式系統中采用實時操作系統已成為當前嵌入式系統開發的主要方法。在ucos網站上沒有現成的移植案例。有必要進行一次移植。操作系統為ucos,處理器為80196kc,編譯器為tasking c 196.
1 ucos的工作原理
ucos是一個源碼公開的實時多任務操作系統,其主要工作流程如圖1示。其任務切換的核心是利用出棧指令將各個任務的工作現場再現,并利用子程序返回指令改變pc指針完成任務的切換。移植的關鍵就是如何構造任務堆棧及任務切換時的出棧順序。任務區堆棧初始化主要是模擬任務被中斷后的堆棧內容。在這個流程中我們可以看到我們要編寫的幾個子程序的工作位置。
2 196kc的工作狀態表示方法
196kc是intel的16位單片機,和程序運行密切相關的寄存器有指令計數器pc、堆棧指針sp、程序狀態寄存器psw,中斷屏蔽寄存器intmask和intmask1,窗口寄存器wsr(以下將程序狀態寄存器psw,中斷屏蔽寄存器intmask和intmask1,窗口寄存器wsr統稱為程序狀態字)。執行子程序調用call指令時自動將pc進棧,子程序返回調用ret指令時自動將pc出棧。由于196kc有16位的尋址能力,故這一動作有2個字節進(出)棧。pusha指令將程序狀態字進棧,popa指令將程序狀態字出棧,這一動作共有4個字節進(出)棧。另外pusha動作會將psw中的中斷允許位清零,故我們用pusha關閉中斷,用popa將用來恢復中斷允許。時鐘節拍是一個特定的周期性中斷,在每個時鐘節拍到來時對任務延時做一次裁決。在此時鐘節拍我們采用196kc中的軟件定時器中斷。
3 tasking c編譯器的工作細節
帶參數的函數調用編譯后主要操作是先將參數進棧,然后執行call指令。在函數入口處將堆棧中的參數倒入寄存器tmp0,tmp2,tmp4和tmp6進行操作(以下稱臨時寄存器),這主要是堆棧一般在ram區,對ram區操作不如對寄存器操作快。如果該函數有局部變量,局部變量也是分配在堆棧中。tasking c編譯器用一寄存器?<i>frame</i>01(以下稱框架寄存器)對局部變量進行訪問,這也是為了提高程序運行效率。函數返回時執行ret操作,并對sp指針進行調整,跳過函數的參數在堆棧中的位置。中斷調用和函數調用類似,中斷本身雖沒有參數,但進中斷后也要對臨時寄存器進行保護。另外進中斷后執行pusha操作。中斷返回時臨時寄存器出棧(注意出棧順序),再執行popa和ret操作。
4 移植的細節
在ostaskstkinit()中任務堆棧區的構造。196kc的堆棧區由高向低增長,首先高處是任務的入口參數,接著是pc指針,程序狀態字,如前述,任務切換時要對臨時寄存器和框架寄存器進行保護。明確了任務堆棧的構造后,編寫任務啟動函數(指osstaart函數)和任務切換函數(指os_taask_sw和osintctxsw函數)的關鍵就是,當得到了優先級的任務堆棧指針后,如何按正確的順序出棧,直到pc指針。其中os_task_sw()函數在切換任務之前還要編寫對當前任務的現場進行保護程序,而osintctxsw()不用,因為我們的中斷函數用c寫成,osintctxsw()是在中斷中調用的,tasking c編譯器在進中斷時已自動對其保護。但同時還應注意,在中斷服務程序中我們沒有定義局部變量,故tasking c編譯器沒有對框架寄存器進行保護,對這一寄存器的保護我們自己加上。
#pragma interrupt
(ostickisr=os_tick_isr_vector)
void ostickisr(void)
{
asm push ?<i>frame</i>01;
osintnesting++;
hso_command=0x19;
ad_timer_count+=5000;
hso_time = ad_timer_count;
ostimetick();
osintexit();
asm pop ?<i>frame</i>01;
}
在此還應提醒一下,在其它中斷服務程序中如果沒有定義局部變量,也應加上對框架寄存器的保護。如果有局部變量,編譯器會自動對框架寄存器保護。
在編寫osintctxsw()函數時應當注意,由于osintctxsw()是在osintexit()中調用的,在調用osintctxsw()之前又有一個關中斷的操作。如前述,我們采用pusha的方式關中斷,也就是說如果切換另一高優先級的任務后會在當前任務中留下在osintctxsw()和osintexit()調用的返回地址4個字節的垃圾和pusha關中斷時進棧的4個字節垃圾,共8個字節,為保證下次切換到該任務的正確性,要將sp指針加8,然后再進行任務切換。為加深對此的理解,我們做一假設,如果196kc是24位(3個字節)尋址能力,在當前任務中會留下osintctxsw()和osintexit()調用的返回地址6個字節的垃圾,如果關中斷直接采用asm di方式,而不牽扯到堆棧操作,此時sp要調整6個字節而不是8個字節。
5 正確性檢驗
設計一點燈程序。其6個燈,每一個點燈操作用一個單獨任務。任務流程如圖3示。個燈每兩個時鐘節拍做一次異或操作。如果led1每執行2次異或操作向任務2發一信號量2,每執行3次異或操作向任務3發一信號量3,每執行4次異或操作向任務4發一信號量4,每執行5次異或操作向任務5發一信號量5,每執行6次異或操作向任務6發一信號量6。任務2到任務6接到相應的信號量時對自已控制的燈進行一次異或操作。理論分析,led2到led6的波形周期為led1的2到6 倍。用示波器對6 個燈的波形進行觀察,與分析相符合,連續運行n 天沒有發現down 機和復位,證明移植成功。
參考文獻
1 labrosse jean j.microc/os-ⅱthe real-time kernel.
2 邵貝貝譯. uc/os-ⅱ-源碼公開的實時嵌入式操作系統. 北京: 中國電力出版社, 2001