<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 嵌入式系統 > 設計應用 > 一種基于C51單片機的非搶占式的操作系統架構

一種基于C51單片機的非搶占式的操作系統架構

作者: 時(shí)間:2016-12-19 來(lái)源:網(wǎng)絡(luò ) 收藏

  摘 要:從Keil 的內存空間管理方式入手,著(zhù)重討論實(shí)時(shí)在任務(wù)調度時(shí)的重入問(wèn)題,分析一些解決重入的基本方式與方法:分析實(shí)時(shí)任務(wù)調度的占先性,提出非占先的任務(wù)調度是能更適合于Keil 的一種調度方式。為此,構造這一實(shí)時(shí),并有針對性地介紹此系統的堆管理方法、任務(wù)的建立以廈任務(wù)的切換等。

本文引用地址:http://dyxdggzs.com/article/201612/341756.htm

  關(guān)鍵詞:51單片機 實(shí)時(shí)操作系統 任務(wù)重八調度

  目前,大多數的產(chǎn)品開(kāi)發(fā)是在基于一些小容量的單片機上進(jìn)行的。51系列單片機,是我國目前使用最多的單片機系列之一,有非常廣大的應用環(huán)境與前景,多年來(lái)的資源積累,使51系列單片機仍是許多開(kāi)發(fā)者的首選。針對這種情況,近幾年涌現出許多基于51內核的擴展芯片,功能越來(lái)越齊全,速度越來(lái)越快,也從一個(gè)側面說(shuō)明了51系列單片機在國內的生命力。

  多年來(lái)我們一直想找一個(gè)合適的實(shí)時(shí)操作系統,作為自己的開(kāi)發(fā)基礎。根據開(kāi)發(fā)需求,整合一些常用的嵌入式構件,以節約開(kāi)發(fā)時(shí)間,盡最大可能地減少開(kāi)發(fā)工作量;另外,要求這個(gè)實(shí)時(shí)操作系統能非常容易地嵌入到小容量的芯片中。畢竟,大系統是少數的,而小應用是多數而廣泛的。顯而易見(jiàn),μC/OS—II是不太適合于以上要求的,而Keil C所帶的RTX Tiny不帶源代碼,不具透明性,至于其FULL版本就更不用說(shuō)了。

  1 KeiI 與重入問(wèn)題

  說(shuō)到實(shí)時(shí)操作系統,就不能不考慮重入問(wèn)題。對于PC機這樣的大內存處理器而言,這似乎并不是一個(gè)很麻煩的問(wèn)題,借用μC/OS—II RTOS的說(shuō)法,即要求在重入的函數內,使用局部變量。但5l系列單片機堆??臻g很小,僅局限在256字節之內,無(wú)法為每個(gè)函數都分配一個(gè)局部堆空間。正是由于這個(gè)原因,Keil C51使用了所謂的可覆蓋技術(shù):

 ?、倬植孔兞看鎯υ谌諶AM空間(不考慮擴展外部存儲器的情況);

 ?、谠诰幾g鏈接時(shí),即已經(jīng)完成局部變量的定位;

 ?、廴绻骱瘮抵g沒(méi)有直接或間接的調用關(guān)系,則其局部變量空間便可覆蓋。

  正是由于以上的原因,在Keil C51環(huán)境下,純粹的函數如果不加處理(如增加一個(gè)模擬棧),是無(wú)法重人的。那么在Keil C5l環(huán)境下,如何使其函數具有可重人性呢?下面分析在實(shí)時(shí)操作系統下面,任務(wù)的基本結構與模式:

  vold TaskA(void*ptr){

  UINT8 vaL_a;

  //其他一些變量定義

  do{

  //實(shí)際的用戶(hù)任務(wù)處理代碼

  }while(1);

  }

  void TaskB(void*ptr){

  UINT8 vaLb;

  //其他一些變量定義

  do{

  Funcl();

  //其他實(shí)際的用戶(hù)任務(wù)處理代碼

  )while(1);

  void Funcl(){

  UlNT8 v al_fa;

  //其他變量的定義

  //函數的處理代碼

  }

  在上面的代碼中,TaskA與TaskB并不存在直接或間接的調用關(guān)系,因而其局部變量val_a與val_b便是可以被互相覆蓋的,即其可能都被定位于某一個(gè)相同的RAM空間。這樣,當TaskA運行一段時(shí)間,改變了val_a后,TaskB取得CPU控制權并運行時(shí),便可能會(huì )改變val_b。由于其指向相同的RAM空間,導致TaskA重新取得CPU控制權時(shí),val—a的值已經(jīng)改變,從而導致程序運行不正確,反過(guò)來(lái)亦然。另一方面,Funcl()與TaskB有直接的調用關(guān)系,因而其局部變量val_fa與val_b不會(huì )被互相覆蓋,但也不能保證其局部變量val_fa不會(huì )與TaskA或其他任務(wù)的局部變量形成可覆蓋關(guān)系。

  將val_a、val_b以及val_fa等局部變量定義為靜態(tài)變量(加上static指示符)可以解決這一問(wèn)題。但問(wèn)題是,定義大量的static類(lèi)型變量,將導致RAM空間的大量占用,有可能直接導致RAM空間不夠用。尤其是在一些小容量的單片機內,一般只有128或256字節,大量的靜態(tài)變量定義,在如此小的RAM資源狀況下顯然就不太合適了。由此而有了另一種的解決方法,如下代碼所示:

  void TaskC(void){

  UINT8 x,v;

  whlk(1){

  OS_ENTER_CRITICAL();

  x=GetX(); (1)

  y=GetY(); (2)

  //任務(wù)的其他代碼

  OS_EXIT_CRITICAL(); (3)

  0SSleep(100); (4)

  }

  }

  以上代碼TaskC中使用了臨界保護的方法來(lái)保護代碼不被中斷占先,確實(shí)有效地解決了RAM空間太小,不宜大量定義靜態(tài)變量的問(wèn)題。然而如果每個(gè)任務(wù)都采用此種結構,任務(wù)一開(kāi)始,就關(guān)閉中斷,將使實(shí)時(shí)性得不到保證。事實(shí)證明,這種延時(shí)是相當可觀(guān)的。用一個(gè)實(shí)例來(lái)說(shuō)明,如果想在系統中使用一個(gè)動(dòng)態(tài)刷新的LED顯示器,就難以保證顯示的穩定與連續,哪怕在系統中是使用一個(gè)單獨的定時(shí)器來(lái)做這一工作(進(jìn)入臨界區后,EA=0)。其次,這種結構事實(shí)上將占先的任務(wù)調度轉化為非占先的任務(wù)調度。實(shí)際上如果在(3)與(4)之間沒(méi)有碰巧發(fā)生中斷并導致一個(gè)任務(wù)調度,那就可以理解為是任務(wù)主動(dòng)放棄CPU的控制。如果在(3)和(4)之間碰巧產(chǎn)生了一個(gè)中斷并導致了一個(gè)任務(wù)調度,只是執行了一次多余的任務(wù)調度而已,而且并不希望在(3)之后發(fā)生2次甚至多次的任務(wù)調度,相信讀者也有這一愿望。

  除此之外,還可以發(fā)現任務(wù)的一個(gè)特點(diǎn):當任務(wù)從(1)重新開(kāi)始時(shí),局部變量x和y是一個(gè)什么值并不在乎,即x和y即使在(3)之后改變了,也已經(jīng)不再重要,不會(huì )影響程序的正確性。其實(shí)這一特點(diǎn)也是大部分任務(wù),至少是太部分任務(wù)的大部分局部變量的一個(gè)共性——如果任務(wù)在整個(gè)執行過(guò)程中,不會(huì )(被占先)放棄CPU控制權,則其局部變量大多數并不需要進(jìn)行特別的保護,即其作用域只是任務(wù)的當次執行,針對上面的代碼,就是臨界保護區內的代碼區域。

  2 實(shí)時(shí)操作系統要不要占先

  由上面的分析,如果要保持一個(gè)函數可重人,就得使用靜態(tài)變量,系統的RAM資源將是一個(gè)嚴峻的考驗;如果使用臨界區來(lái)保護運行環(huán)境,系統的實(shí)時(shí)性又得不到保證,而且有將占先式任務(wù)調度轉為非占先任務(wù)調度之虞。顯然,使用靜態(tài)變量簡(jiǎn)單,但有更多的不適用性,對將來(lái)功能的調整也是一個(gè)阻礙,一般不被采用。那么,就只能從環(huán)境保護上來(lái)下功夫了,但是果真只能以進(jìn)入臨界區犧牲系統的實(shí)時(shí)性來(lái)保證任務(wù)不被占先?下面看看臨界保護這一方法的基本思路:

 ?、僭谝粋€(gè)任務(wù)中,如果局部變量在其作用域內不被占先切換,則這些變量在任務(wù)被剝奪了CPU控制權后,不關(guān)心其值也不會(huì )影響任務(wù)的正確執行;

 ?、谑褂门R界區保護,可以達到上面所提到的要求;

 ?、塾纱藢е碌膶?shí)時(shí)性能與占先切換的減弱可以接受。由此可知,不被占先是任務(wù)保護局部變量的關(guān)鍵。既然如此,何不舍棄占先式的任務(wù)調度?這不失為一個(gè)好的出發(fā)點(diǎn)。針對Keil C51,非占先式任務(wù)調度,可能是一種更好的方法,更能協(xié)調51系列單片機的既定資源。下面編寫(xiě)這樣一個(gè)系統:

 ?、偈褂梅钦枷仁饺蝿?wù)調度;

 ?、诳梢栽谛∪萘康男酒惺褂?,開(kāi)發(fā)目標是,即使是8051這樣小的芯片,也可使用這個(gè)實(shí)時(shí)操作系統;

 ?、壑С謨?yōu)先級調度,盡可能保證其實(shí)時(shí)性。

  3 實(shí)時(shí)操作系統的實(shí)現

  基于以上的分析與目的,近日完成了這個(gè)操作系統。在堆棧上借用RTx的管理方法,即當前任務(wù)使用全部的堆空間,如圖1所示。

  3.1 堆棧的初始化與任務(wù)的創(chuàng )建

  堆棧的初始化實(shí)際是初始化0STaskStackBotton數組,并將當前任務(wù)指定為空閑任務(wù),下一個(gè)運行任務(wù)指定為最高優(yōu)先級任務(wù),即優(yōu)先級為零的任務(wù)。初始化時(shí),將SP的值存人OSTaslkStackBotton[O],SP+2的值存入OSTaskStacKBotton[1],依此類(lèi)推。而任務(wù)是調用0STa-skCreate函數建立的。實(shí)際上只是將任務(wù)(假設為n號任務(wù))的地址填人到對應OSTaskStackBotton[n]所指向的位置,并將SP向后移動(dòng)2個(gè)字節,如圖2所示。

  為什么要以這樣一種規律而不是其他的方式呢?這是由于在任務(wù)建立后,還未進(jìn)行任務(wù)調度之前,各任務(wù)的堆棧實(shí)際上是它們自身的地址,因而其堆棧深度為2,為了程序的簡(jiǎn)便而直接填入。

  void main(void){

  OSInit(); /*初始化OSTaskStackBcBotton隊列*/

  TMOD=(TMOD&0XFO)│ 0XOl;

  TL0=0xBF;

  TH0=0xFC;

  TRO=1;

  ETO=1;

  TFO=O:

  OSTaskCreate(TaskA,NULL,0);

  OSTaskCreate(TaskB.NULL,1);

  OSTaskCreate(TaskC,NULL,2);

  OSStart();

  上面這段代碼中,所有任務(wù)建立后,便調用OSStart()開(kāi)始任務(wù)調度。OSStart()是一個(gè)宏定義,如下所示:

  #deflne OSStart() d0{

  OSTaskCreate(TaskIdle,NULL,OS_MAX_TASKS);

  EA=l:

  return;

  }while(O)

  首先,它創(chuàng )建了一個(gè)空閑任務(wù)并打開(kāi)中斷,然后便返回。返回到哪里了呢?我們知道,空閑任務(wù)是優(yōu)先級最低的任務(wù),當調OSTaskCreate建立時(shí),會(huì )將其地址填人到SP的位置,并把SP向后移動(dòng)2個(gè)字節(見(jiàn)圖2及說(shuō)明),因而此時(shí)處在堆棧頂端的,一定是空閑任務(wù)Taslddle。這就使得這里的return一定會(huì )返回到空閑任務(wù)。至此,系統進(jìn)入正常運行狀態(tài)。

  3.2 任務(wù)的切換

  任務(wù)的切換分兩種情況,在當前任務(wù)優(yōu)先級低于下一個(gè)取得CPU控制權的任務(wù)時(shí),將下一個(gè)取得CPU控制權的任務(wù)的棧頂到當前任務(wù)的棧頂之間的內容向RAM空間的高端搬移,以空出全部的RAM空間作下一個(gè)任務(wù)的堆空間,同時(shí)更新對應的OSTaskStackBotton,使其指向新的正確任務(wù)的堆棧棧底。如果當前任務(wù)的優(yōu)先級高于下一個(gè)任務(wù)的優(yōu)先級,則作相反的搬移,如圖3與圖4所示。

  所有任務(wù)必須主動(dòng)調用OSSleep,放棄CPU的控制權。任務(wù)調用OSSleep后,將選擇優(yōu)先級最高的就緒任務(wù)運行。

  結 語(yǔ)

  系統完成后,內核的代碼量在400多個(gè)字節左右,占用1個(gè)定時(shí)器中斷及小量的內存空間。系統設置容量為8個(gè)任務(wù),用戶(hù)實(shí)際可用任務(wù)為7個(gè),能夠滿(mǎn)足一般需求,也達到了在小容量芯片中應用的開(kāi)發(fā)要求。由于沒(méi)有采用占先式的任務(wù)調度,除開(kāi)全程相關(guān)的個(gè)別任務(wù)的一些局部變量外,其他局部變量已經(jīng)不存在覆蓋關(guān)系,由于是任務(wù)主動(dòng)放棄CPU控制權,對于個(gè)別需要保護的變量單獨進(jìn)行處理也變得容易。在系統中,全程不需要反復地開(kāi)關(guān)中斷,實(shí)時(shí)性能也很好。對個(gè)別時(shí)序要求嚴格的外設(如DSl8820)除外。



關(guān)鍵詞: C51 操作系統

評論


相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>