RTX51 Tiny

RTX51 Tiny

RTX51 Tiny是一種實時操作系統(RTOS),可以用它來建立多個任務(函數)同時執行的應用。

簡介


嵌入式應用系統經常有這種需求。RTOS可以提供調度、維護、同步等功能。
實時操作系統能靈活的調度系統資源,像CPU存儲器,並且提供任務間的通信。RTX51 Tiny是一個功能強大的RTOS,且易於使用,它用於8051系列的微控制器
RTX51 Tiny的程序用標準的C語言構造,由Keil C51 C編譯器編譯。用戶可以很容易的定義任務函數,而不需要進行複雜的棧和變數結構配置,只需包含一個指定的頭文件。

產品規格


參數範圍
最大任務數16
最大活動任務16
代碼空間需求900位元組最大
數據空間需求7位元組
棧空間需求3位元組/任務
外部RAM需求0位元組
定時器
系統時鐘因子1000~65535
中斷等待20個周期或更少
上下文切換時間100~700個周期

工具需求


以下為使用RTX51 Tiny需要的應用軟體:
C51編譯器
A51宏彙編器
BL51連接器或LX51連接器
RTX51TNY.LIB和RTX51BT.LIB庫文件必須保存於庫路徑下,通常,該路徑是"KEIL"C51"LIB文件夾。RTX51TNY.H必須保存在包含路徑下,通常是"KEIL"C51"INC文件夾。

目標需求


RTX51 Tiny運行於大多數8051兼容的器件及其變種上。RTX51 Tiny應用程序可以訪問外部數據存儲器,但內核無此需求。
RTX51 Tiny支持Keil C51編譯器全部的存儲模式。存儲模式的選擇隻影響應用程序對象的位置,RTX51 Tiny系統變數和應用程序棧空間總是位於8051的內部存儲區(DATA或IDATA區),一般情況下,應用程序應使用小(SMALL)模式。
RTX51 Tiny執行協作式任務切換(每個任務調用一個操作系統常式)
和時間片輪轉任務切換(每個任務在操作系統切換到下一個任務前運行一個固定的時間段),不支持搶先式任務切換以及任務優先順序。RTX51 Full支持搶先式任務切換。

中斷

RTX51 Tiny與中斷函數并行運作,中斷服務程序可以通過發送信號(用isr_send_signal函數)或設置任務的就序標誌(用isr_set_redy函數)與RTX51 Tiny的任務進行通信。
如同在一個標準的,沒有RTX51 Tiny的應用中一樣,中斷常式必須在RTX51Tiny應用中實現並允許,RTX51 Tinyim 沒有中斷服務程序的管理。
RTX51 Tiny使用定時器0、定時器0中斷,和寄存器組1。如果在程序中使用了定時器0,則RTX51 Tiny將不能正常運轉。你可以在RTX51 Tiny定時器0的中斷服務程序后追加自己的定時器0中斷服務程序代碼(參見硬體定時器)。
RTX51 Tiny假設總中斷總是允許(EA=1)。RTX51 Tiny庫常式在需要時改變中斷系統(EA)的狀態,以確保RTX51 Tiny的內部結構不被中斷破壞。當允許或禁止總中斷時,RTX51 Tiny只是簡單的改變EA的狀態,不保存並重裝EA,EA只是簡單的被置位或清除。因此,如果你的程序在調用RTX51常式前某止了中斷,RTX51可能會失去響應。
在程序的臨界區,可能需要在短時間內禁止中斷。但是,在中斷禁止后,不能調用任何RTX51 Tiny的常式。如果程序確實需要禁止中斷,應該持續很短的時間。

再入函數

C51編譯器提供對再入函數的支持,再入函數在再入堆棧中存儲參數和局部變數,從而保護遞歸調用或并行調用。RTX51 Tiny不支持對C51再入棧的任何管理。因此,如果在程序中使用再入函數,必須確保這此函數不調用任何RTX51 Tiny系統函數,且不被循環任務切掉所打斷。
僅用寄存器傳遞參數和保存自動變數的C函數具有內在的再入性,可以無限制的調用RTX51 Tiny。
非可再入C函數不能被超過一個以上的任務或中斷過程調用。非再入C51函數在靜態存儲區段保存參數和自動變數(局部數據),該區域在函數被多個任務同時調用或遞歸調用時可能會被修改。
如果確定多個任務不會遞歸(或同時)調用,則多個任務可以調用非再入函數。通常,這意味著必須禁止循環任務調度,且該非再入函數不能調用任何RTX51 Tiny系統函數。
附註:
l 如果希望在多個任務或中斷中調用再入或非再入函數,應當禁止循
環任務調度。

C庫常式

可再入C51庫函數可在任何任務中無限制的使用。對於非再入的C51庫函數,同樣有非可再入C函數的限制。

多數據指針

Keil C51編譯器允許使用多數據指針(存在於許多8051的派生晶元中), RTX51 Tiny不提供對它們的支持。因此,在RTX51 Tiny的應用程序中應小心使用多數據指針。
從本質上說,必須確保循環任務切換不會在執行改變數據指針選擇器的代碼時發生。
附註:
l 如果要使用多數據指針,應該禁止循環任務切換。

運算單元

Keil C51編譯器允許使用運算單元(存在於許多8051的派生晶元中)。RTX51 Tiny不提供對它們的支持。
因此,在RTX51 Tiny的應用程序中須小心使用運算單元。
從本質上說,必須確保循環任務切換不會在執行用運算單元的代碼時發生。
附註:
l 如果希望使用運算單元,應禁止循環任務切換。

寄存器組

RTX51 Tiny分配所有的任務到寄存器0,因此,所有的函數必須用C51的默認設置進行編譯,REGISTERBANK(0)。
中斷函數可以使用剩餘的寄存器組。然而,RTX51 Tiny需要寄存器組區域中的6個永久性的位元組,用於這些位元組的寄存器組在配置文件中指定。

實時程序


實時程序必須對實時發生的事件快速響應。事件很少的程序不用實時操作系統也很容易實現。隨著事件的增加,編程的複雜程度和難度也隨之增大,這正是RTOS的用武之地。

單任務程序

嵌入式程序和標準C程序都是從main函數開始執行的,在嵌入式應用中,main通常是一個無限循環,可以認為是一個持續執行的單個任務,例如:
void main (void)
﹛while(1)
do_something();
在這個例子里,do_something函數可以認為是一個單任務,由於僅有一個任務在執行,所以沒有必要進行多任務處理或使用多任務操作系統。

多任務程序

許多C程序通過在一個循環里調用服務函數(或任務)來實現偽多任務調度。如:
void main(void)
int counter="0";
while(1)
check_serial_io();
process_serial_cmds() ;
check_kbd_io();
process_kbd_cmds();
adjust|ctrlr_parms();
counter++;
該例中,每個函數執行一個單獨的操作或任務,函數(或任務)按次序依次執行。
當任務越來越多,調度問題就被自然而然的提出來了。例如,如果process_kbd_cmds函數執行時間較長,主循環就可能需要較長的時間才能返回來執行check_sericd_io函數,導致串列數據可能被丟失。當然,可以在主循環中更
頻繁的調用check_serial_io函數以糾正這個問題,但最終這個方法還是會失效

RTX51 Tiny 程序

當使用Rtx51Tiny時,為每個任務建立獨立的任務函數,例如:
void check_serial_io_task(void) _task_ 1
﹛﹜
void process_serial_cmds_task(void) _task_ 2
﹛﹜
void check_kbd_io_task(void) _task_ 3
﹛﹜
void process_kbd_cmds_task(void) _task_ 4
﹛﹜
void startup-_task(void) _task_ 0
os_create_task(1);
os_create_task(2);
os_create_task(3);
os_create_task(4);
os_delete_task(0);
該例中,每個函數定義為一個RTX51 Tiny任務。RTX51 Tiny程序不需要main函數,取而代之,RTX51 Tiny從任務0開始執行。在典型的應用中,任務0簡單的建立所有其他的任務。

原理


RTX51 Tiny 用於管理目標系統的資源,本章討論RTX51 Tiny如何使用這些資源。

定時器滴答中斷

RTX51 Tiny 用標準8051的定時器0(模式1)生產一個周期性的中斷。該中斷就是RTX51 Tiny的定時滴答(Timer Tick)。庫函數中的超時和時間間隔就是基於該定時滴答來測量的。
默認情況下,RTX51每10000個機器周期產生一個滴答中斷,因此,對於運行於12MHZ的標準8051來說,滴答的周期是0.01秒,也即頻率是100HZ(12MHz/12/10000)。該值可以在CONF_TNY.A51配置文件中修改。
附註:
l可以在RTX51的定時滴答中斷里追加自己的代碼。參見CONF_TNY.A51 配置文件。
l關於RTX51 Tiny如何使用中斷可以參考概述中中斷一節的敘述。

任務

RTX51 Tiny本質上是一個任務切換器,建立一個RTX51 Tiny程序,就
是建立一個或多個任務函數的應用程序。下面的信息可以幫助你快速的理解
RTX51 。
l任務用新的關鍵字由C語言定義,該關鍵字是Keic C51 所支持的。
lRTX51 Tiny維護每個任務的正確狀態(運行、就緒、等待、刪除、超時)。
l某個時刻只有一個任務處於運行態。
l任務可能處於就緒態、等待態、刪除態或超時態。
l空閑任務(Idle_Task)總是處於就緒態,當定義的所有任務處於阻 塞狀態時,運行該任務。

任務管理

每個RTX51 Tiny 任務總是處於下述狀態中的一種狀態中。
狀態描述
運行
正在運行的任務處於運行態。某個時刻只能有一個任務處於該狀態。
os_running_task_id 函數返回當前正在運行的任務編號。
就緒準備運行的任務處於就緒態。一旦運行的任務完成了處理,RTX51 Tiny選擇一個就緒的任務執行。一個任務可以通過用os_set_ready或os_set_ready函數設置就緒標誌來使其立即就緒(即便該任務正在等待超時或信號)。
等待正在等待一個事件的任務處於等待態。一旦事件發生,任務切換到就緒態。Os_wait函數用於將一個任務置為等待態。
刪除沒有被啟動或已被刪除的任務處於刪除態。Os-delete-task函數將一個已經啟動(用os_create_task)的任務置為刪除態。
超時被超時循環中斷的任務處於超時態,在循環任務程序中,該狀態相當於就緒態。

事件

在實時操作系統中,事件可用於控制任務的執行,一個任務可能等待一個事件,也可能向其他任務發送任務標誌。
os_wait函數可以使一個任務等待一個或多個事件。
l超時是一個任務可以等待的公共事件。超時就是一些時鐘滴答數,當一個任務等待超時時,其他任務可以執行。一旦到達指定數量的滴答數,任務就可以繼續執行。
l時間間隔(Interval)是一個超時(Timeout)的變種。時間間隔與超
時類似,不同的是時間間隔是相對於任務上次調用os_wait函數的指定數量的時鐘滴答數。
l信號是任務間通信的方式。一個任務可以等待其他任務給它發信號(用os_send_signal和isr_send_signal函數)。
l每個任務都有一個可被其它任務設置的就緒標誌(用os_set_ready和
isr_set_ready函數)。一個個等待超時、時間間隔或信號的任務可以通過設置它的就緒標誌來啟動。
lisr_set_ready函數)。一個等待超時、時間間隔或信號的任務可以通 過設置它的就緒標誌來啟動。
下表是os_wait函數等待的事件:
K_IVL等待制定的時間
隔K_SIG等待一個信號
K_TMO等待指定的超時
os-wait返回時,返回值表明發生了的事件:
返回值意義
RDY_EVENT任務的就緒標誌被置位
SIG_EVENT收到一個信號
TMO_EVENT超時完成或時間間隔到達。
os_wait可以等待下面的事件組合:
lK_SIG︱K_TMO:任務延遲直到有信號發給它或者指定數量的時鐘滴答
到達。
lK_SIG︱K_IVL:任務延遲直到有信號到來或者指定的時間間隔到達。
附註:
lK_IVL和K_TMO事件不能組合

任務調度程序

任務調度程序給任務分配處理器,RTX51 Tiny調度程序用下列規則確定
哪個任務要被運行:
當前任務被中斷如果:
1、任務調用了os_switch_task且另一個任務正準備運行。
2、任務調用了os_wait且指定的事件沒有發生。
3、任務執行了比輪轉時間片更長的時間。
另一個任務啟動如果:
1、無其它任務運行。
2、要啟動的任務處於就緒態或超時態。

循環任務切換

RTX51 Tiny可以配置為用循環法進行多任務處理(任務切換)。循環法允許
并行的執行若干任務。任務並非真的同時執行,而是分時間片執行的(CPU時間分
成時間片,RTX51 Tiny給每個任務分配一個時間片)。由於時間片很短(幾毫秒),
看起來好象任務在同時執行。
任務在它的時間片內持續執行(除非任務的時間片用完)。然後,RTX51 Tin
g切換到下一個就緒的任務運運行。時間片的持續時間可以通過RTX51 Ting配置
定義。
下面是一個RTX51 Tiny程序的例子,用循環法多任務處理,程序中的兩個任務
是計數器循環。RTX51 Tiny在啟動時執行函數名為job0的任務0,該函數建立了另
一個任務job1,在job0執行完它的時間片后, RTX51 Tiny切換到job1。在job1執
行完它的時間片后,RTX51 Ting又切換到job0,該過程無限重複。
int counter0;
int counter1;
void job0(void) _task_ 0
os_create(1);
while(1)
counter0++;
}
}
void job1(void) _task_1
while(1)
counter++;
}
}
附註:
l可以用os_wait 或os_switch_task讓RTX51 Tiny切換到另一個任務而不是
等待任務的時間片用完。 os_wait函數掛起當前的任務(使之變為等待態)直
到指定的事件發生(接著任務變為就緒態)。在此期間,任意數量的其他任務
可以運行。

協作任務切換

如果禁止了循環任務處理,就必須讓任務以協作的方式運作,在每個任務
里調用os_wait或os_switch_task,以通知RTX51 Tingy切換到另一個任務。
os_wait與os_switch_task的不同是,os_wait是讓任務等待一個事件,而
os_switch_task是立即切換到另一個就緒的任務。

空閑任務

沒有任務準備運行時,RTX51 Ting執行一個空閑任務。空閑任務就是一個
無限循環。如:
有些8051兼容的晶元提供一種降低功耗的空閑模式,該模式停止程序的執
行,直到有中斷產生。在該模式下,所有的外設包括中斷系統仍在運行。
RTX51 Tiny允許在空閑任務中啟動空閑模式(在沒有任務準備執行時)。當
RTX51 Tiny的定時滴答中斷(或其它中斷)產生時,微控制器恢復程序的執行。
空閑任務執行的代碼在CONF_TNY.A51配置文件中允許和配置。

棧管理

RTX51 Tiny為每個任務在8051的內部RAM區(IDATA)維護一個棧。任務
運行時,將得到可能得到的最大數量的棧空間。任務切換時,先前的任務棧被
壓縮並重置,當前任務的棧被擴展和重置。
下圖表明一個三任務應用的內部存儲器的布局。
圖略…… :-)
?STACK表示棧的起始地址。該例中,位於棧下方的對象包括全局變數、寄存器和位定址存儲器,剩餘的存儲器用於任務棧。存儲器的頂部可在配置中指定

使用RTX51 Tiny


一般地,下面三步是使用RTX51 Tiny要實現的
l 編寫RTX51程序
l 編譯並連接程序
l 測試和調試程序
一、編寫程序
寫RTX51 Tiny程序時,必須用關鍵字對任務進行定義,並使用在RTX51TNY.H中聲明的RTX51 Tiny核心常式。
1、包含文件
RTX51 Tiny僅需要包含一個文件:RTX51TNY.H。所有的庫函數和常數都在該頭文件中定義。你可以在你的源文件中包含它:
#include
2、編程原則
以下是建立RTX51 Tiny程序時必須遵守的原則:
①、確保包含了RTX51TNY.H頭文件。
②、不要建立main函數,RTX51 Tiny有自己的mian函數。
③、程序必須至少包含一個任務函數。
④、中斷必須有效(EA=1),在臨界區如果要禁止中斷時一定要小心。參見概述中的中斷一節。
⑤、程序必須至少調用一個RTX51 Tiny庫函數(象os_wait)。否則,連接起將不包含RTX51 Tiny庫。
⑥、Task 0是程序中首先要執行的函數,必須在任務0中調用os_create_task 函數以運行其餘任務。
⑦、任務函數必須是從不退出或返回的。任務必須用一個while(1)或類似的結構重複。用os_delete_task函數停止運行的任務。
⑧、必須在uvison中指定RTX51 Tiny,或者在連接器命令行中指定。更多技術文檔參見keil軟體知識庫。
3、定義任務
實時或多任務應用是由一個或多個執行具體操作的任務組成的,RTX51 Tiny支持最多16個任務。
任務就是一個簡單的C函數,返回類型為void,參數列表為void,並且用_task_聲明函數屬性。例如:
void func (void)_task_task_id
這裡,func是任務函數的名字,task_id是從0到15的一個任務ID號。
下面的例子定義函數job0編號為0的任務。該任務使一個計數器遞增並不斷重複。
void job0(void)_task_0
{
while(1)
{
Counter0++;
}
}
附註:
l 所有的任務都應該是無限循環,任務一定不能返回。
l 任務不能返回一個函數值,它們的返回類型必須是void。
l 不能對一個任務傳遞參數,任務的形參必須是void。
l 每個任務必須賦予一個唯一的,不重複的ID。
l 為了最小化RTX51 Tiny的存儲器需求,從0開始對任務進行順序編號。
二、編譯和連接
有兩種方法編譯和連接RTX51 Tiny應用程序。
l 用uvison集成開發環境
l 用命令行工具
1、命令行工具
RTX51 Tiny已經完全集成到了C51編譯語言中,這使得生成RTX51 Tiny應
用非常容易。建立RTX51 Tiny程序只需編寫C函數,無需使用彙編。
從命令行編譯RTX51 Tiny程序…
按常規方式調用編譯器,無需特別的編譯指示。例如:
C51 RTXPROG.C DEBUG OBJECTEXTEND
產生的RTXPROG.OBJ文件中包含C代碼和定義的RTX51 Tiny任務。
從命令行連接RTX51 Tiny程序:
l 在連接器命令行內指定RTX51TNY指示
l 在目標文件列表中包含RTX_CONF.OBJ文件(如果改變了配置)
例如:BL51 RTPROG.OBJ, RTX_CONF.OBJ RTX51TNY
RTX51TNY指示命令連接器連接RTPROG.OBJ和TX_CONF.OBJ並且包含RTX51 Tiny庫。這樣就建立了RTX51 Tiny程序。
附註:
l 不要在RTX51 Tiny程序中建立mian函數,只建立任務函數就可以。main函數包含在RTX51 Tiny庫中,它啟動操作系統和任務0。如果在程序中包含了main函數,將產生一個連接錯誤指示有多個main被定義。
l 程序中至少建立一個任務函數。
l 必須至少調用一個RTX51 Tiny函數(象os_wait或os_create_task),這樣,連接器才會包含RTX51 Tiny庫。
2、uvison集成開發環境
用uvison建立RTX51 Tiny程序。
1) 打開目標對話框選項(從project菜單選擇Options for Target)。
2) 選擇目標標籤。
3) 從操作系統選項列表選擇RTX51 Tiny。
三、調試
uvison模擬器允許運行和測試RTX51 Tiny應用程序。RTX51 Tiny程序的載入和無RTX51 Tiny程序的載入是一樣的。無需指定特別的命令和選項。
一個核心的對話框顯示RTX51 Tiny核心和程序中任務的所有特徵。從Peripherals菜單選擇RTX51 Tiny Tasklist顯示該對話框。
該對話框中:
l TID是在任務定義中指定的任務ID。
l Task Name是任務函數的名字。
l State是任務當前的狀態。
l Wait for Event指出任務正在等待什麼事件。
l Sig顯示任務信號標誌的狀態(1為置位)。
l Timer指示任務距超時的滴答數,這是一個自由運行的定時器,僅在任務等待超時和時間間隔時使用。
l Stack指示任務棧的起始地址