在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<menu id="6qfwx"><li id="6qfwx"></li></menu>
    1. <menu id="6qfwx"><dl id="6qfwx"></dl></menu>

      <label id="6qfwx"><ol id="6qfwx"></ol></label><menu id="6qfwx"></menu><object id="6qfwx"><strike id="6qfwx"><noscript id="6qfwx"></noscript></strike></object>
        1. <center id="6qfwx"><dl id="6qfwx"></dl></center>

            新聞中心

            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ò) 收藏
            mcu由于內(nèi)部資源的限制,軟件設(shè)計(jì)有其特殊性,程序一般沒有復(fù)雜的算法以及數(shù)據(jù)結(jié)構(gòu),代碼量也不大,通常不會(huì)使用OS (Operating System),因?yàn)閷?duì)于一個(gè)只有若干K ROM,一百多byte RAM的mcu來說,一個(gè)簡(jiǎn)單OS也會(huì)吃掉大部分的資源。

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

            對(duì)于無os的系統(tǒng),流行的設(shè)計(jì)是主程序(主循環(huán)) +(定時(shí))中斷,這種結(jié)構(gòu)雖然符合自然想法,不過卻有很多不利之處,首先是中斷可以在主程序的任何地方發(fā)生,隨意打斷主程序。其次主程序與中斷之間的耦合性(關(guān)聯(lián)度)較大,這種做法使得主程序與中斷纏繞在一起,必須仔細(xì)處理以防不測(cè)。

            那么換一種思路,如果把主程序全部放入(定時(shí))中斷中會(huì)怎么樣?這么做至少可以立即看到幾個(gè)好處:系統(tǒng)可以處于低功耗的休眠狀態(tài),將由中斷喚醒進(jìn)入主程序;如果程序跑飛,則中斷可以拉回;沒有了主從之分(其他中斷另計(jì)),程序易于模塊化。

            (題外話:這種方法就不會(huì)有何處喂狗的說法,也沒有中斷是否應(yīng)該盡可能的簡(jiǎn)短的爭(zhēng)論了)

            為了把主程序全部放入(定時(shí))中斷中,必須把程序化分成一個(gè)個(gè)的模塊,即任務(wù),每個(gè)任務(wù)完成一個(gè)特定的功能,例如掃描鍵盤并檢測(cè)按鍵。設(shè)定一個(gè)合理的時(shí)基(tick),例如5, 10或20 ms,每次定時(shí)中斷,把所有任務(wù)執(zhí)行一遍,為減少復(fù)雜性,一般不做動(dòng)態(tài)調(diào)度(最多使用固定數(shù)組以簡(jiǎn)化設(shè)計(jì),做動(dòng)態(tài)調(diào)度就接近os了),這實(shí)際上是一種無優(yōu)先級(jí)時(shí)間片輪循的變種。來看看主程序的構(gòu)成:

            void main()

            {

            ….// Initialize

            while (true) {

            IDLE;//sleep

            }

            }

            這里的IDLE是一條sleep指令,讓mcu進(jìn)入低功耗模式。中斷程序的構(gòu)成

            void Timer_Interrupt()

            {

            SetTimer();

            ResetStack();

            Enable_Timer_Interrupt;

            ….

            進(jìn)入中斷后,首先重置Timer,這主要針對(duì)8051, 8051自動(dòng)重裝分頻器只有8-bit,難以做到長時(shí)間定時(shí);復(fù)位stack,即把stack指針賦值為棧頂或棧底(對(duì)于pic,TI DSP等使用循環(huán)棧的mcu來說,則無此必要),用以表示與過去決裂,而且不準(zhǔn)備返回到中斷點(diǎn),保證不會(huì)保留程序在跑飛時(shí)stack中的遺體。Enable_Timer_Interrupt也主要是針對(duì)8051。8051由于中斷控制較弱,只有兩級(jí)中斷優(yōu)先級(jí),而且使用了如果中斷程序不用reti返回,則不能響應(yīng)同級(jí)中斷這種偷懶方法,所以對(duì)于8051,必須調(diào)用一次reti來開放中斷:

            _Enable_Timer_Interrupt:

            acall_reti

            _reti:reti

            下面就是任務(wù)的執(zhí)行了,這里有幾種方法。第一種是采用固定順序,由于mcu程序復(fù)雜度不高,多數(shù)情況下可以采用這種方法:

            Enable_Timer_Interrupt;

            ProcessKey();

            RunTask2();

            RunTaskN();

            while (1) IDLE;

            可以看到中斷把所有任務(wù)調(diào)用一遍,至于任務(wù)是否需要運(yùn)行,由程序員自己控制。另一種做法是通過函數(shù)指針數(shù)組:

            #define CountOfArray(x) (sizeof(x)/sizeof(x[0]))

            typedef void (*FUNCTIONPTR)();

            const FUNCTIONPTR[] tasks = {

            ProcessKey,

            RunTask2,

            RunTaskN

            };

            void Timer_Interrupt()

            {

            SetTimer();

            ResetStack();

            Enable_Timer_Interrupt;

            for (i=0; i

            (*tasks[i])();

            while (1) IDLE;

            }

            使用const是讓數(shù)組內(nèi)容位于code segment(ROM)而非data segment (RAM)中,8051中使用code作為const的替代品。

            (題外話:關(guān)于函數(shù)指針賦值時(shí)是否需要取地址操作符&的問題,與數(shù)組名一樣,取決于compiler.對(duì)于熟悉匯編的人來說,函數(shù)名和數(shù)組名都是常數(shù)地址,無需也不能取地址。對(duì)于不熟悉匯編的人來說,用&取地址是理所當(dāng)然的事情。Visual C++ 2005對(duì)此兩者都支持)

            這種方法在匯編下表現(xiàn)為散轉(zhuǎn),一個(gè)小技巧是利用stack獲取跳轉(zhuǎn)表入口:

            movA, state

            acallMultiJump

            ajmpstate0

            ajmpstate1

            ...

            MultiJump:popDPH

            popDPL

            rlA

            jmp@A+DPTR

            還有一種方法是把函數(shù)指針數(shù)組(動(dòng)態(tài)數(shù)組,鏈表更好,不過在mcu中不適用)放在data segment中,便于修改函數(shù)指針以運(yùn)行不同的任務(wù),這已經(jīng)接近于動(dòng)態(tài)調(diào)度了:

            FUNCTIONPTR[COUNTOFTASKS] tasks;

            tasks[0] = ProcessKey;

            tasks[0] = RunTaskM;

            tasks[0] = NULL;

            ...

            FUNCTIONPTR pFunc;

            for (i=0; i< COUNTOFTASKS; i++){

            pFunc = tasks[i]);

            if (pFunc != NULL)

            (*pFunc)();

            }

            通過上面的手段,一個(gè)中斷驅(qū)動(dòng)的框架形成了,下面的事情就是保證每個(gè)tick內(nèi)所有任務(wù)的運(yùn)行時(shí)間總和不能超過一個(gè)tick的時(shí)間。為了做到這一點(diǎn),必須把每個(gè)任務(wù)切分成一個(gè)個(gè)的時(shí)間片,每個(gè)tick內(nèi)運(yùn)行一片。這里引入了狀態(tài)機(jī)(state machine)來實(shí)現(xiàn)切分。關(guān)于state machine,很多書中都有介紹,這里就不多說了。

            (題外話:實(shí)踐升華出理論,理論再作用于實(shí)踐。我很長時(shí)間不知道我一直沿用的方法就是state machine,直到學(xué)習(xí)UML/C++,書中介紹tachniques for identifying dynamic behvior,方才豁然開朗。功夫在詩外,掌握C++,甚至C# JAVA,對(duì)理解嵌入式程序設(shè)計(jì),會(huì)有莫大的幫助)

            狀態(tài)機(jī)的程序?qū)崿F(xiàn)相當(dāng)簡(jiǎn)單,第一種方法是用swich-case實(shí)現(xiàn):

            void RunTaskN()

            {

            switch (state) {

            case 0: state0(); break;

            case 1: state1(); break;

            case M: stateM(); break;

            default:

            state = 0;

            }

            }

            另一種方法還是用更通用簡(jiǎn)潔的函數(shù)指針數(shù)組:

            const FUNCTIONPTR[] states = { state0, state1, …, stateM };

            void RunTaskN()

            {

            (*states[state])();

            }

            下面是state machine控制的例子:

            void state0() { }

            void state1() { state++; }//next state;

            void state2() { state+=2; }//go to state 4;

            void state3() { state--; }//go to previous state;

            void state4() { delay = 100; state++; }

            void state5() { delay--; if (delay <= 0) state++; }//delay 100*tick

            void state6() { state=0; }//go to the first state

            一個(gè)小技巧是把第一個(gè)狀態(tài)state0設(shè)置為空狀態(tài),即:

            void state0() { }

            這樣,state =0可以讓整個(gè)task停止運(yùn)行,如果需要投入運(yùn)行,簡(jiǎn)單的讓state = 1即可。


            上一頁 1 2 下一頁

            評(píng)論


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

            關(guān)閉