<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 中斷多任務(wù)+狀態(tài)機(jī) 單片機(jī)軟件結(jié)構(gòu)設(shè)計(jì)

          中斷多任務(wù)+狀態(tài)機(jī) 單片機(jī)軟件結(jié)構(gòu)設(shè)計(jì)

          作者: 時(shí)間:2016-11-27 來源:網(wǎng)絡(luò) 收藏

          本文引用地址:http://www.ex-cimer.com/article/201611/322212.htm

          以下是一個(gè)鍵盤掃描的例子,這里假設(shè)tick = 20 ms, ScanKeyboard()函數(shù)控制口線的輸出掃描,并檢測(cè)輸入轉(zhuǎn)換為鍵碼,利用每個(gè)state之間20 ms的間隔去抖動(dòng)。

          enum EnumKey {

          EnumKey_NoKey =0,

          };

          struct StructKey {

          intkeyValue;

          boolkeyPressed;

          } ;

          struct StructKeyProcess key;

          void ProcessKey() { (*states[state])(); }

          void state0() { }

          void state1() { key.keyPressed = false; state++; }

          void state2() { if (ScanKey() != EnumKey_NoKey) state++; }//next state if a key pressed

          void state3()

          {//debouncing state

          key.keyValue = ScanKey();

          if (key.keyValue == EnumKey_NoKey)

          state--;

          else {

          key.keyPressed = true;

          state++;

          }

          }

          void state4() {if (ScanKey() == EnumKey_NoKey) state++; }//next state if the key released

          void state5() {ScanKey() == EnumKey_NoKey? state = 1 : state--; }

          上面的鍵盤處理過程顯然比通常使用標(biāo)志去抖的程序簡(jiǎn)潔清晰,而且沒有軟件延時(shí)去抖的困擾。以此類推,各個(gè)任務(wù)都可以劃分成一個(gè)個(gè)的state,每個(gè)state實(shí)際上占用不多的處理時(shí)間。某些任務(wù)可以劃分成若干個(gè)子任務(wù),每個(gè)子任務(wù)再劃分成若干個(gè)狀態(tài)。

          (題外話:對(duì)于常數(shù)類型,建議使用enum分類組織,避免使用大量#define定義常數(shù))

          對(duì)于一些完全不能分割,必須獨(dú)占的任務(wù)來說,比如我以前一個(gè)低成本應(yīng)用中紅外遙控器的軟件解碼任務(wù),這時(shí)只能犧牲其他的任務(wù)了。兩種做法:一種是關(guān)閉中斷,完全的獨(dú)占;

          void RunTaskN()

          {

          Disable_Interrupt;

          Enable_Interrupt;

          }

          第二種,允許定時(shí)中斷發(fā)生,保證某些時(shí)基register得以更新;

          void Timer_Interrupt()

          {

          SetTimer();

          Enable_Timer_Interrupt;

          UpdateTimingRegisters();

          if (watchDogCounter = 0) {

          ResetStack();

          for (i=0; i

          (*tasks[i])();

          while (1) IDLE;

          }

          else

          watchDogCounter--;

          }

          只要watchDogCounter不為0,那么中斷正常返回到中斷點(diǎn),繼續(xù)執(zhí)行先前被中斷的任務(wù),否則,復(fù)位stack,重新進(jìn)行任務(wù)循環(huán)。這種狀況下,中斷處理過程極短,對(duì)獨(dú)占任務(wù)的影響也有限。

          中斷驅(qū)動(dòng)多任務(wù)配合狀態(tài)機(jī)的使用,我相信這是mcu下無os系統(tǒng)較好的設(shè)計(jì)結(jié)構(gòu)。對(duì)于絕大多數(shù)mcu程序設(shè)計(jì)來說,可以極大的減輕程序結(jié)構(gòu)的安排,無需過多的考慮各個(gè)任務(wù)之間的時(shí)間安排,而且可以讓程序簡(jiǎn)潔易懂。缺點(diǎn)是,程序員必須花費(fèi)一定的時(shí)間考慮如何切分任務(wù)。

          下面是一段用C改寫的CD Player中檢測(cè)disc是否存在的偽代碼,用以展示這種結(jié)構(gòu)的設(shè)計(jì)技巧,原源代碼為Z8 mcu匯編,基于Sony的DSP, Servo and RF處理芯片,通過送出命令字來控制主軸/滑板/聚焦/尋跡電機(jī),并讀取狀態(tài)以及CD的sub Q碼。這個(gè)處理任務(wù)只是一個(gè)大任務(wù)下用state machine切開的一個(gè)二級(jí)子任務(wù),tick = 20 ms。

          state1() { InitializeMotor(); state++; }

          state2() {

          if (innerSwitch != ON) {

          SendCommand(EnumCommand_SlidingMotorBackward);

          timeout = MILLISECOND(10000);

          state++;//滑板電機(jī)向內(nèi)運(yùn)動(dòng),直至觸及最內(nèi)開關(guān)。

          }

          else

          state +=2;

          }

          state3() {

          if ((--timeout) == 0) {//note: some C compliers do not support (--timeout) ==

          SendCommand(EnumCommand_SlidingMotorStop)

          systemErrorCode = EnumErrorCode_InnerSwitch;

          state = 0;// 10 s超時(shí)錯(cuò)誤,

          }

          else {

          if (innerSwitch == ON) {

          SendCommand(EnumCommand _SlidingMotorStop)

          timeout = MILLISECOND(200);// 200ms電機(jī)停止時(shí)間

          state++;

          }

          }

          }

          state4() { if ((--timeout) == 0) state++; }//等待電機(jī)完全停止

          state5() {

          SendCommand(EnumCommand_SlidingMotorForward);

          timeout = MILLISECOND(2000);

          state++;

          }//滑板電機(jī)向外運(yùn)動(dòng),脫離inner switch

          state6() {

          if ((--timeout) == 0) {

          SendCommand(EnumCommand_SlidingMotorStop)

          systemErrorCode = EnumErrorCode_InnerSwitch;

          state = 0;// 2 s超時(shí)錯(cuò)誤,

          }

          else {

          if (innerSwitch == OFF) {

          SendCommand(EnumCommand_SlidingMotorStop)

          timeout = MILLISECOND(200);// 200ms電機(jī)停止時(shí)間

          state++;

          }

          }

          }

          state7() { state4(); }

          state8() { LaserOn(); state++; retryCounter = 3;}//打開激光器

          state9() {

          SendCommand(FocusUp);

          state++;

          timeout = MILLISECOND(2000);

          }//光頭上舉,檢測(cè)聚焦過零3次,判斷cd是否存在

          state10() {

          if (FocusCrossZero){

          systemStatus.Disc = EnumStatus_DiscExist;

          SendCommand(EnumCommand_AutoFocusOn);//有cd,打開自動(dòng)聚焦。

          state = 0;//本任務(wù)結(jié)束。

          playProcess.state = 1;//啟動(dòng)play任務(wù)

          }

          else if ((--timeout) == 0) {

          SendCommand(EnumCommand_ FocusClose);//光頭聚焦復(fù)位

          if ((--retryCounter) == 0) {

          systemStatus.Disc = EnumStatus_Nodisc;//無盤

          displayProcess.state = EnumDisplayState_NoDisc;//顯示閃爍的無盤

          LaserOff();

          state = 0;//任務(wù)停止

          }

          else

          state--;//再試

          }

          }

          stateStop() {

          SendCommand(EnumCommand_SlidingMotorStop);

          SendCommand(EnumCommand_FocusClose);

          state = 0;

          }


          上一頁 1 2 下一頁

          評(píng)論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();