楊一萌,楊勇,楊遠聰
(中國地質大學 數學與物理學院,武漢 430074)
?
Protothreads在提高系統(tǒng)響應方面的應用*
楊一萌,楊勇,楊遠聰
(中國地質大學 數學與物理學院,武漢 430074)
采用基于Protothreads的輕量靈活的多任務編程方式,使資源緊張的小型微控制器可支持多任務,改善了系統(tǒng)綜合性能。測試證明,運用該技術后C51系統(tǒng)對按鍵響應的速度最高提高了10倍。該方法為在小型微控制器上運行多任務系統(tǒng)提供了一種新的思路。
Protothreads;多任務;低延遲;STC90C516RD+
基于微控制器的儀器設備在進行數據采集時,往往還需要支持通信、顯示和按鍵等,這要求微控制器能夠在短時間內處理多個任務,并且具有較好的實時性。Free RTOS和μC/OS II等完整的嵌入式操作系統(tǒng),往往需要較多的硬件資源,對于小型微控制器來說,其過于龐大。許多應用既希望采用輕巧價廉的微控制器,又希望響應迅速,尤其是航天和交通等系統(tǒng)更是如此[1]。這種情況下,需根據任務和微控制器的特點來設計編寫控制程序,才能充分發(fā)揮微控制器的性能。在輕量級多任務框架中,由Protothreads衍生出了各具特點的修改版本[2],但對某些微控制器來說仍然有些復雜,使用受限。本文結合已有的采集系統(tǒng),嘗試使用簡單的Protothreads框架來提升系統(tǒng)實時性能,并評估Protothreads框架在資源緊張的多任務嵌入式系統(tǒng)中的可行性。
Protothreads由瑞典皇家理工學院的Adam Dunkels博士開發(fā),在BSD許可證下發(fā)行[3]。它是一個非常輕量的協(xié)程庫,被應用到很多開源軟件中,例如嵌入式網絡操作系統(tǒng)Contiki、TCP/IP協(xié)議棧μIP和LwIP等。
1.1Protothreads特點及基本函數
Protothreads具有如下優(yōu)點:①完全由C語言實現,沒有匯編代碼,不依賴任何庫和系統(tǒng)特性,在任何平臺都可移植;②極少的資源需求,每個Protothreads函數僅需要2個字節(jié);③支持條件阻塞機制和協(xié)程間通信等功能;④不存在調用開銷,沒有棧切換,系統(tǒng)資源占用極少。
Protothreads十分輕量的特點使它非常適合用于內存受限系統(tǒng)、事件驅動協(xié)議棧、深度嵌入式系統(tǒng)和傳感器網絡節(jié)點等場景[4]。Protothreads進入阻塞狀態(tài)時,不保存堆棧和局部變量,這意味著,在使用Protothreads的系統(tǒng)中要謹慎對待本地變量,如果不確定是否可行,就使用全局變量[5]。
1.2用于定義協(xié)程的函數主體
Protothreads協(xié)程由4種基本操作組成,初始化:PT_INIT();執(zhí)行:PT_BEGIN();條件阻塞:PT_WAIT_UNTIL(),PT_WAIT_WHILE();退出:PT_END()。
這4個基本操作函數均是宏,在代碼預編譯階段會展開為實際代碼。每一次發(fā)生調用時,Protothreads將一直運行,直到它主動進入阻塞狀態(tài)或退出。因此,由使用Protothreads的應用程序完成Protothreads的調度[5]。
Protothreads使用pt.lc記錄阻塞位置,協(xié)程剛初始化和任務結束時,pt.lc均等于0。
該數據采集系統(tǒng)主要用于電流檢測,結構圖如圖1所示。
圖1 采樣系統(tǒng)基本結構
微控制器使用STC90C516RD+,系統(tǒng)主要任務有A/D轉換和數據處理、結果顯示、量程切換、PC通信、菜單處理、快捷按鍵處理和數據記錄。A/D轉換使用AD7710芯片,可以設置10 Hz或50 Hz陷波頻率。不同陷波頻率下的轉換速度不同,單片機對轉換結果進一步處理。菜單鍵按下會觸發(fā)外部中斷,中斷函數置位標志位,然后在主函數中處理該事件。
2.1存在的問題
經過后期測試發(fā)現,單片機大部分時間花費在A/D獲取數據及處理這個部分。在不同的設置下,花費的時間在20~4 000 ms。由于系統(tǒng)任務是順序執(zhí)行,導致其他任務響應很慢,最壞的情況下,按下菜單鍵后幾秒鐘后屏幕才會顯示出來。
如圖2描述的情況,在任務A執(zhí)行過程中,黑色標記處相繼發(fā)生了任務B、C對應的事件,發(fā)生事件后進入相應中斷,置位相應標志位,但是要等到任務A結束之后才會執(zhí)行任務B、C。
圖2 CPU使用情況
2.2解決方法
A/D轉換和數據處理任務使用Protothreads協(xié)程,其他任務不變。A/D轉換和數據處理任務,下文均稱作任務A。任務A每運行200 ms就會主動進入阻塞狀態(tài),讓出CPU使用權,然后檢查是否有事件需要處理,相關任務處理完成后,任務A獲得CPU使用權,繼續(xù)執(zhí)行。任務A每次停留在阻塞狀態(tài)的時間是不固定的,例如,當把保存的數據從儀器發(fā)送到上位機時,任務A在發(fā)送完畢前將一直處于阻塞狀態(tài)。改善后的CPU的使用情況如圖3所示。
圖3 改善后CPU使用情況
圖4描述了任務A的內部流程。任務A主要由采集數據和處理數據兩個子任務構成。這兩個子任務都不是一次性完成的,每次運行一小部分,然后阻塞任務A,讓出CPU使用權。如圖4所示,任務A運行后,首先根據pt.lc的值判斷運行狀態(tài),如果是從阻塞態(tài)恢復,將回到上次結束位置繼續(xù)運行。當pt.lc值對應采集任務程序塊(行號在采集任務程序塊)時,進入采集任務;當pt.lc值對應數據處理程序塊(行號在數據處理程序塊)時,進入數據處理任務。采集數據和處理數據兩個子任務按順序先后運行,子任務運行超過200 ms后,阻塞任務A。當數據處理結束后,任務A結束。
圖4 任務A流程圖
系統(tǒng)中使用定時器計時,每10 ms觸發(fā)定時中斷,作為系統(tǒng)的TickClock,變量sclk記錄中斷次數。當sclk等于20時,表示至少已經過去了200 ms。程序如下:
void Timer0_ISR() interrupt 1{
sclk++;
}
使用PT_THREAD()宏聲明任務A的主體函數。當從A/D轉換器中讀出一個轉換結果后檢測sclk的值,當sclk大于等于20時,主動阻塞自己,讓出CPU使用權。程序如下:
PT_THREAD(dataobj_acquire(dataobj *dataobj, struct pt *pt)){
//變量聲明及初始化…
sclk=0;//重置計時
PT_BEGIN(pt);
if (dataobj->number_to_average >= 4){
for (i = dataobj_raw_data_start_addr; i < dataobj->raw_data_end_addr;){
AD7710Read();
/*如果已經運行至少200 ms,阻塞自己,退出本函數。當再進入本函數時,從當前位置繼續(xù)執(zhí)行*/
PT_WAIT_WHILE(pt, (sclk > 20));
}
數據處理……
PT_END(pt);
}
在主函數中,通過pt.lc的值是否為0來判斷任務A是否已經執(zhí)行完成。某些任務,比如顯示數據只有在任務A正常結束后才能刷新。某些任務執(zhí)行后會改變系統(tǒng)當前設置,已經采集到的緩存數據需要重新開始采集,可以通過PT_INIT()宏重置任務A。程序如下:
void main(){
變量聲明及初始化…
PT_INIT(&data_acquire_pt);
模塊初始化…
while (1){
if (deviceobj->key_isr_happen){
KeyInterruptProc(dataobj, deviceobj, uartobj);
deviceobj->key_isr_happen = 0;
/*重置任務A,使其從頭開始執(zhí)行*/
PT_INIT(&data_acquire_pt);
}
dataobj_acquire (dataobj, deviceobj, &data_acquire_pt);
if (data_acquire_pt.lc == 0){
RangeCheckProc(dataobj, deviceobj, uartobj);
}
if (deviceobj->range_changed){
deviceobj->range_changed = 0;
/*重置任務A,使其從頭開始執(zhí)行*/
PT_INIT(&data_acquire_pt);
dataobj_acquire (dataobj, deviceobj, &data_acquire_pt);
}
if (deviceobj->over_range == 0 && data_acquire_pt.lc == 0){
LCDDisplay (dataobj);
}
if (deviceobj->autotest_run && data_acquire_pt.lc == 0){
AutoTestProc(&tmp_addr, &toi2c_num, dataobj, deviceobj, uartobj);
}
uart_loop:
if (uartobj->command_received){
EX0=0;
UARTProcessComm(dataobj, deviceobj, uartobj, &data_acquire_pt);
EX0=1;
}
if (uartobj->uartloop_flag){ goto uart_loop;}
if (QuicKeyProc(dataobj, deviceobj, uartobj)){
/*重置任務A,使其從頭開始執(zhí)行*/
PT_INIT(&data_acquire_pt);
}
}
}
根據不同的設置,在沒有事件發(fā)生時,任務A總的執(zhí)行時間在20~4 000 ms之間,使用Protothreads之后總的執(zhí)行時間并沒有明顯增加。在沒有使用Protothreads協(xié)程框架之前,按下按鍵使按鍵標志位置位后,要等待較長時間才能獲得響應。使用框架后,從最嚴重的延遲3 060 ms下降到270 ms。比較結果見表1。
表1 使用Protothreads前后結果比較
每個Protothreads協(xié)程僅需要2字節(jié)的存儲空間,使用協(xié)程的函數內的局部變量全部要改為靜態(tài)變量。任務A相比之前增加20字節(jié)的內存占用,程序大小增加1 KB左右。
本文分析了數據采集系統(tǒng)中存在任務響應不及時的問題,并根據其使用的微控制器資源緊缺和采集系統(tǒng)的特點,提出了使用Protothreads來實現多任務的編程方式;簡要介紹了Protothreads基本功能,詳細闡述了改進系統(tǒng)響應性能的實現方法。結合改進前后的數據,經過對比發(fā)現,該方法可以明顯提升系統(tǒng)性能,并且沒有明顯增加內存和程序空間占用,對于更復雜的系統(tǒng)需求,可以根據情況設計一個調度程序。本文對于其他嵌入式軟件開發(fā)具有較高的參考價值。
[1] 榮國平,劉天宇,謝明娟,等.嵌入式系統(tǒng)開發(fā)中敏捷方法的應用研究綜述[J].軟件學報,2014(2):267-283.
[2] 樓亮亮,周苗,鮑星合.一種適用于物聯(lián)網節(jié)點的高效輕量級嵌入式系統(tǒng)設計[J].單片機與嵌入式系統(tǒng)應用,2014(11):67-70.
[3] Dunkels A,Schmidt O,Voigt T,et al.Protothreads: Simplifying event-driven programming of memory-constrained embedded systems[C]//Proceedings of the Fourth ACM Conference on Embedded Networked Sensor Systems,2006:29-42.
[4] Dunkels A,Schmidt O.Protothreads-lightweight stackless threads in C [EB/OL].[2016-03].http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.60.2455&rep=repl&type=pdf.
[5] 閆石,馬潮.時間觸發(fā)模式下的Protothreads設計應用[J].單片機與嵌入式系統(tǒng)應用,2009(1):15-17.
楊一萌(研究生),研究方向為光電信號檢測與嵌入式系統(tǒng)應用;楊勇(教授),主要從事微弱信號檢測相關工作;楊遠聰(研究生),研究方向為光電信號檢測。
(責任編輯:薛士然收修改稿日期:2016-03-26)
Protothreads Application in Terms of Improving System Response
Yang Yimeng,Yang Yong,Yang Yuancong
(China University of Geosciences,Wuhan 430074,China)
The resource intensive small microcontroller can support multitasking by using the lightweight flexible multitask programming based on Protothreads,that improves the performance of the system.The experiment results show that the method can speed up 10 times maximum for the button response on a C51 system obviously.The method provides a new idea for running multitask on small microcontroller.
Protothreads;multitask;low-latency;STC90C516RD+
TP311
A