<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è) > 嵌入式系統 > 牛人業(yè)話(huà) > 51單片機多任務(wù)操作系統的原理與實(shí)現

51單片機多任務(wù)操作系統的原理與實(shí)現

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

  前言

本文引用地址:http://dyxdggzs.com/article/201701/342566.htm

  想了很久,要不要寫(xiě)這篇文章?最后覺(jué)得對感興趣的人還是很多,寫(xiě)吧.我不一定能造出玉,但我可以?huà)伋龃u.

  包括我在內的很多人都對使用呈悲觀(guān)態(tài)度,因為的片上資源太少.但對于很多要求不高的系統來(lái)說(shuō),使用可以使代碼變得更直觀(guān),易于維護,所以在上仍有操作系統的生存機會(huì ).

  流行的uCos,Tiny51等,其實(shí)都不適合在2051這樣的片子上用,占資源較多,唯有自已動(dòng)手,以不變應萬(wàn)變,才能讓51也有操作系統可用.這篇貼子的目的,是教會(huì )大家如何現場(chǎng)寫(xiě)一個(gè)OS,而不是給大家提供一個(gè)OS版本.提供的所有代碼,也都是示例代碼,所以不要因為它沒(méi)什么功能就說(shuō)LAJI之類(lèi)的話(huà).如果把功能寫(xiě)全了,一來(lái)估計你也不想看了,二來(lái)也失去靈活性沒(méi)有價(jià)值了.

  下面的貼一個(gè)示例出來(lái),可以清楚的看到,OS本身只有不到10行源代碼,編譯后的目標代碼60字節,任務(wù)切換消耗為20個(gè)機器周期.相比之下,KEIL內嵌的TINY51目標代碼為800字節,切換消耗100~700周期.唯一不足之處是,每個(gè)任務(wù)要占用掉十幾字節的堆棧,所以任務(wù)數不能太多,用在128B內存的51里有點(diǎn)難度,但對于52來(lái)說(shuō)問(wèn)題不大.這套代碼在36M主頻的STC12C4052上實(shí)測,切換任務(wù)僅需2uS.

  #include

  #define MAX_TASKS 2 //任務(wù)槽個(gè)數.必須和實(shí)際任務(wù)數一至

  #define MAX_TASK_DEP 12 //最大棧深.最低不得少于2個(gè),保守值為12.

  unsigned char idata task_stack[MAX_TASKS][MAX_TASK_DEP]; //任務(wù)堆棧.

  unsigned char task_id; //當前活動(dòng)任務(wù)號

  //任務(wù)切換函數(任務(wù)調度器)

  void task_switch(){

  task_sp[task_id] = SP;

  if(++task_id == MAX_TASKS)

  task_id = 0;

  SP = task_sp[task_id];

  }

  //任務(wù)裝入函數.將指定的函數(參數1)裝入指定(參數2)的任務(wù)槽中.如果該槽中原來(lái)就有任務(wù),則原任務(wù)丟失,但系統本身不會(huì )發(fā)生錯誤.

  void task_load(unsigned int fn, unsigned char tid)

  {

  task_sp[tid] = task_stack[tid] + 1;

  task_stack[tid][0] = (unsigned int)fn & 0xff;

  task_stack[tid][1] = (unsigned int)fn >> 8;

  }

  //從指定的任務(wù)開(kāi)始運行任務(wù)調度.調用該宏后,將永不返回.

  #define os_start(tid) {task_id = tid,SP = task_sp[tid];return;}

  /*======================以下為測試代碼======================*/

  void task1()

  {

  static unsigned char i;

  while(1){

  i++;

  task_switch(); //編譯后在這里打上斷點(diǎn)

  }

  }

  void task2()

  {

  static unsigned char j;

  while(1){

  j+=2;

  task_switch(); //編譯后在這里打上斷點(diǎn)

  }

  }

  void main()

  {

  //這里裝載了兩個(gè)任務(wù),因此在定義MAX_TASKS時(shí)也必須定義為2

  task_load(task1, 0); //將task1函數裝入0號槽

  task_load(task2, 1); //將task2函數裝入1號槽

  os_start(0);

  }

  這樣一個(gè)簡(jiǎn)單的多任務(wù)系統雖然不能稱(chēng)得上真正的操作系統,但只要你了解了它的原理,就能輕易地將它擴展得非常強大,想知道要如何做嗎?

  一.什么是操作系統?

  人腦比較容易接受"類(lèi)比"這種表達方式,我就用"公交系統"來(lái)類(lèi)比"操作系統"吧.

  當我們要解決一個(gè)問(wèn)題的時(shí)候,是用某種處理手段去完成它,這就是我們常說(shuō)的"方法",計算機里叫"程序"(有時(shí)候也可以叫它"算法").

  以出行為例,當我們要從A地走到B地的時(shí)候,可以走著(zhù)去,也可以飛著(zhù)去,可以走直線(xiàn),也可以繞彎路,只要能從A地到B地,都叫作方法.這種從A地到B的需求,相當于計算機里的"任務(wù)",而實(shí)現從A地到B地的方法,叫作"任務(wù)處理流程"

  很顯然,這些走法中,并不是每種都合理,有些傻子都會(huì )采用的,有些是傻子都不采會(huì )用的.用計算機的話(huà)來(lái)說(shuō)就是,有的任務(wù)處理流程好,有的任務(wù)處理流程好,有的處理流程差.

  可以歸納出這么幾種真正算得上方法的方法:

  有些走法比較快速,適合于趕時(shí)間的人;有些走法比較省事,適合于懶人;有些走法比較便宜,適合于窮人.

  用計算機的話(huà)說(shuō)就是,有些省CPU,有些流程簡(jiǎn)單,有些對系統資源要求低.

  現在我們可以看到一個(gè)問(wèn)題:

  如果全世界所有的資源給你一個(gè)人用(單任務(wù)獨占全部資源),那最適合你需求的方法就是好方法.但事實(shí)上要外出的人很多,例如10個(gè)人(10個(gè)任務(wù)),卻只有1輛車(chē)(1套資源),這叫作"資源爭用".

  如果每個(gè)人都要使用最適合他需求的方法,那司機就只好給他們一人跑一趟了,而在任一時(shí)刻里,車(chē)上只有一個(gè)乘客.這叫作"順序執行",我們可以看到這種方法對系統資源的浪費是嚴重的.

  如果我們沒(méi)有法力將1臺車(chē)變成10臺車(chē)來(lái)送這10個(gè)人,就只好制定一些機制和約定,讓1臺車(chē)看起來(lái)像10臺車(chē),來(lái)解決這個(gè)問(wèn)題的辦法想必大家都知道,那就是制定公交線(xiàn)路.

  最簡(jiǎn)單的辦法是將所有旅客需要走的起點(diǎn)與終點(diǎn)串成一條線(xiàn),車(chē)在這條線(xiàn)上開(kāi),乘客則自已決定上下車(chē).這就是最簡(jiǎn)單的公交線(xiàn)路.它很差勁,但起碼解決客人們對車(chē)爭用.對應到計算機里,就是把所有任務(wù)的代碼混在一起執行.

  這樣做既不優(yōu)異雅,也沒(méi)效率,于是司機想了個(gè)辦法,把這些客戶(hù)叫到一起商量,將所有客人出行的起點(diǎn)與終點(diǎn)羅列出來(lái),統計這些線(xiàn)路的使用頻度,然后制定出公交線(xiàn)路:有些路線(xiàn)可以合并起來(lái)成為一條線(xiàn)路,而那些不能合并的路線(xiàn),則另行開(kāi)辟行車(chē)車(chē)次,這叫作"任務(wù)定義".另外,對于人多路線(xiàn),車(chē)次排多點(diǎn),時(shí)間上也優(yōu)先安排,這叫作"任務(wù)優(yōu)先級".

  經(jīng)過(guò)這樣的安排后,雖然仍只有一輛車(chē),但運載能力卻大多了.這套車(chē)次/路線(xiàn)的按排,就是一套"公交系統".哈,知道什么叫操作系統了吧?它也就是這么樣的一種約定.

  操作系統:

  我們先回過(guò)頭歸納一下:

  汽車(chē) 系統資源.主要指的是CPU,當然還有其它,比如內存,定時(shí)器,中斷源等.

  客戶(hù)出行 任務(wù)

  正在走的路線(xiàn) 進(jìn)程

  一個(gè)一個(gè)的運送旅客 順序執行

  同時(shí)運送所有旅客 多任務(wù)并行

  按不同的使用頻度制定路線(xiàn)并優(yōu)先跑較繁忙的路線(xiàn) 任務(wù)優(yōu)先級

  計算機內有各種資源,單從硬件上說(shuō),就有CPU,內存,定時(shí)器,中斷源,I/O端口等.而且還會(huì )派生出來(lái)很多軟件資源,例如消息池.

  操作系統的存在,就是為了讓這些資源能被合理地分配.

  最后我們來(lái)總結一下,所謂操作系統,以我們目前權宜的理解就是:為"解決計算機資源爭用而制定出的一種約定".

  二.51上的操作系統

  對于一個(gè)操作系統來(lái)說(shuō),最重要的莫過(guò)于并行多任務(wù).在這里要澄清一下,不要拿當年的DOS來(lái)說(shuō)事,時(shí)代不同了.況且當年IBM和小比爾著(zhù)急將PC搬上市,所以才抄襲PLM(好象是叫這個(gè)名吧?記不太清)搞了個(gè)今天看來(lái)很"粗制濫造"的DOS出來(lái).看看當時(shí)真正的操作系統---UNIX,它還在紙上時(shí)就已經(jīng)是多任務(wù)的了.

  對于我們PC來(lái)說(shuō),要實(shí)現多任務(wù)并不是什么問(wèn)題,但換到MCU卻很頭痛:

  1.系統資源少

  在PC上,CPU主頻以G為單位,內存以GB為單位,而MCU的主頻通常只有十幾M,內存則是Byts.在這么少的資源上同時(shí)運行多個(gè)任務(wù),就意味著(zhù)操作系統必須盡可能的少占用硬件資源.

  2.任務(wù)實(shí)時(shí)性要求高

  PC并不需要太關(guān)心實(shí)時(shí)性,因為PC上幾乎所有的實(shí)時(shí)任務(wù)都被專(zhuān)門(mén)的硬件所接管,例如所有的聲卡網(wǎng)卡顯示上都內置有DSP以及大量的緩存.CPU只需坐在那里指手劃腳告訴這些板卡如何應付實(shí)時(shí)信息就行了.

  而MCU不同,實(shí)時(shí)信息是靠CPU來(lái)處理的,緩存也非常有限,甚至沒(méi)有緩存.一旦信息到達,CPU必須在極短的時(shí)間內響應,否則信息就會(huì )丟失.

  就拿串口通信來(lái)舉例,在標準的PC架構里,巨大的內存允許將信息保存足夠長(cháng)的時(shí)間.而對于MCU來(lái)說(shuō)內存有限,例如51僅有128字節內存,還要扣除掉寄存器組占用掉的8~32個(gè)字節,所以通常都僅用幾個(gè)字節來(lái)緩沖.當然,你可以將數據的接收與處理的過(guò)程合并,但對于一個(gè)操作系統來(lái)說(shuō),不推薦這么做.

  假定以115200bps通信速率向MCU傳數據,則每個(gè)字節的傳送時(shí)間約為9uS,假定緩存為8字節,則串口處理任務(wù)必須在70uS內響應.

  這兩個(gè)問(wèn)題都指向了同一種解決思路:操作系統必須輕量輕量再輕量,最好是不占資源(那當然是做夢(mèng)啦).

  可用于MCU的操作系統很多,但適合51(這里的51專(zhuān)指無(wú)擴展內存的51)幾乎沒(méi)有.前陣子見(jiàn)過(guò)一個(gè)"圈圈操作系統",那是我所見(jiàn)過(guò)的操作系統里最輕量的,但仍有改進(jìn)的余地.

  很多人認為,51根本不適合使用操作系統.其實(shí)我對這種說(shuō)法并不完全接受,否則也沒(méi)有這篇文章了.

  我的看法是,51不適合采用"通用操作系統".所謂通用操作系統就是,不論你是什么樣的應用需求,也不管你用什么芯片,只要你是51,通通用同一個(gè)操作系統.

  這種想法對于PC來(lái)說(shuō)沒(méi)問(wèn)題,對于嵌入式來(lái)說(shuō)也不錯,對AVR來(lái)說(shuō)還湊合,而對于51這種"貧窮型"的MCU來(lái)說(shuō),不行.

  怎樣行?量體裁衣,現場(chǎng)根據需求構建一個(gè)操作系統出來(lái)!

  看到這里,估計很多人要翻白眼了,大體上兩種:

  1.操作系統那么復雜,說(shuō)造就造,當自已是神了?

  2.操作系統那么復雜,現場(chǎng)造一個(gè)會(huì )不會(huì )出BUG?

  哈哈,看清楚了?問(wèn)題出在"復雜"上面,如果操作系統不復雜,問(wèn)題不就解決了?

  事實(shí)上,很多人對操作系統的理解是片面的,操作系統不一定要做得很復雜很全面,就算僅個(gè)多任務(wù)并行管理能力,你也可以稱(chēng)它操作系統.

  只要你對多任務(wù)并行的原理有所了解,就不難現場(chǎng)寫(xiě)一個(gè)出來(lái),而一旦你做到了這一點(diǎn),為各任務(wù)間安排通信約定,使之發(fā)展成一個(gè)為你的應用系統量身定做的操作系統也就不難了.

  為了加深對操作系統的理解,可以看一看<<演變>>這份PPT,讓你充分了解一個(gè)并行多任務(wù)是如何一步步從順序流程演變過(guò)來(lái)的.里面還提到了很多人都在用的"狀態(tài)機",你會(huì )發(fā)現操作系統跟狀態(tài)機從原理上其實(shí)是多么相似.會(huì )用狀態(tài)機寫(xiě)程序,都能寫(xiě)出操作系統.

  三.我的第一個(gè)操作系統

  直接進(jìn)入主題,先貼一個(gè)操作系統的示范出來(lái).大家可以看到,原來(lái)操作系統可以做得么簡(jiǎn)單.

  當然,這里要申明一下,這玩意兒其實(shí)算不上真正的操作系統,它除了并行多任務(wù)并行外根本沒(méi)有別的功能.但凡事都從簡(jiǎn)單開(kāi)始,搞懂了它,就能根據應用需求,將它擴展成一個(gè)真正的操作系統.

  好了,代碼來(lái)了.

  將下面的代碼直接放到KEIL里編譯,在每個(gè)task?()函數的"task_switch();"那里打上斷點(diǎn),就可以看到它們的確是"同時(shí)"在執行的.

  #include

  #define MAX_TASKS 2 //任務(wù)槽個(gè)數.必須和實(shí)際任務(wù)數一至

  #define MAX_TASK_DEP 12 //最大棧深.最低不得少于2個(gè),保守值為12.

  unsigned char idata task_stack[MAX_TASKS][MAX_TASK_DEP];//任務(wù)堆棧.

  unsigned char task_id; //當前活動(dòng)任務(wù)號


上一頁(yè) 1 2 3 下一頁(yè)

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

評論


相關(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>