中文字幕 另类精品,亚洲欧美一区二区蜜桃,日本在线精品视频免费,孩交精品乱子片免费

<sup id="3hn2b"></sup>

    1. <sub id="3hn2b"><ol id="3hn2b"></ol></sub><legend id="3hn2b"></legend>

      1. <xmp id="3hn2b"></xmp>

      2. 新聞中心

        EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > WinCE 5.0邊做邊學(5)(6)

        WinCE 5.0邊做邊學(5)(6)

        作者: 時間:2011-02-25 來源:網絡 收藏
        對于實時系統(tǒng),如何調試是一個很難解決的問題,包括對系統(tǒng)內核的調試,對驅動程序的調試,對應用程序的調試等。對于應用程序,通常各集成開發(fā)環(huán)境都提供了常規(guī)的單步跟蹤等調試手段。而對于另兩個的調試,Platform Builder除了為我們提供了常規(guī)的斷點跟蹤等手段以外,還和系統(tǒng)的源程序配合使用了一種新的調試手段——Debug Zones調試區(qū)。
        通常,我們都是利用OutpubDebugString函數(shù)來實現(xiàn)調試信息的輸出的,但是由于系統(tǒng)底層的調試信息非常繁多,如果這樣大量的調試信息用于實時輸出的話一定會影響到系統(tǒng)的性能和實時性,也就影響到了系統(tǒng)的運行。如果有一種方式能允許開發(fā)人員自己選擇輸出哪些調試信息,不輸出哪些調試信息的話,那么就可以讓開發(fā)人員只看到關心的調試信息,而把諸如鍵盤按鍵、鼠標移動等無用的調試信息隱去,則可以更好的提高開發(fā)效率,迅速找到問題所在。
        調試區(qū)就是為了解決以上提出的問題的,對某一個驅動程序,它規(guī)定好自己向外輸出的調試信息的分類,比如初始化時的信息,出錯時的信息,釋放時的信息,激活時的信息等,然后分成幾個調試區(qū),在現(xiàn)有的CE版本中最多允許16個調試區(qū)。開發(fā)人員通過Platform Builder中Target菜單下的CE Debug Zones命令來決定想要得到哪一個或哪幾個調試區(qū)的信息,在驅動程序中則可以根據(jù)開發(fā)人員的選擇來輸出指定調試區(qū)的信息。這就是調試區(qū)大體上的工作原理。
        接下來,我們就來看一下調試區(qū)的定義,聲明,注冊及使用。
        在程序中使用調試區(qū)之前必須先定義它們,一個程序的16個調試區(qū)編號分別為0-15。代碼樣例如下所示:
        #ifdef DEBUG
        //
        // For debug builds, use the real zones.
        //
        #define ZONE_TEST DEBUGZONE(0)
        #define ZONE_PARAMS DEBUGZONE(1)
        #define ZONE_VERBOSE DEBUGZONE(2)
        ……
        #define ZONE_WARN DEBUGZONE(14)
        #define ZONE_ERROR DEBUGZONE(15)

        #else
        //
        // For retail builds, use forced messages based on the zones turned on below.
        //
        #define ZONE_TEST 0
        #define ZONE_PARAMS 0
        #define ZONE_VERBOSE 0
        ……
        #define ZONE_WARN 0
        #define ZONE_ERROR 0

        #endif

        這樣,就可以程序的DEBUG版本中使用調試區(qū)了,而在RELEASE版本中則將其全部定義為0,調試信息即不再輸出。
        在程序中,除了以上的定義以外,還要聲明幾個專用的調試信息輸出函數(shù),這些函數(shù)與OutputDebugString函數(shù)的區(qū)別就在于在調用時需要指定對應的調試區(qū),這些函數(shù)以及以上用到的DEBUGZONE宏的定義都在DbgApi.h頭文件中,因此只要在源程序中包含此頭文件即可。除此以外,還需要一個全局的DEBPARAM類型的變量命名為dpCurSettings,以供集成開發(fā)環(huán)境和調試信息輸出函數(shù)使用。其代碼樣例如下:
        #ifdef DEBUG
        DBGPARAM dpCurSettings = {
        TEXT("WaveDriver"), {
        TEXT("Test") // 0
        ,TEXT("Params") // 1
        ,TEXT("Verbose") // 2
        ,TEXT("Interrupt") // 3
        ,TEXT("WODM") // 4
        ,TEXT("WIDM") // 5
        ,TEXT("PDD") // 6
        ,TEXT("MDD") // 7
        ,TEXT("Regs") // 8
        ,TEXT("Misc") // 9
        ,TEXT("Init") // 10
        ,TEXT("IOcontrol") // 11
        ,TEXT("Alloc") // 12
        ,TEXT("Function") // 13
        ,TEXT("Warning") // 14
        ,TEXT("Error") // 15
        }
        ,
        (1 15) // Errors
        | (1 14) // Warnings
        };
        #endif
        此例中還把ERROR和WARN調試區(qū)作為默認被開發(fā)人員選中的調試區(qū)。
        要想使用調試區(qū),還需要做的最后一件準備的事情就是在程序中進行注冊,也就是在程序啟動時通知集成開發(fā)環(huán)境本程序中要使用調試區(qū),這個注冊很簡單,只要在程序的入口處使用DEBUGREGISTER宏即可,樣例如下:
        DllEntry (
        HANDLE hinstDLL,
        DWORD Op,
        LPVOID lpvReserved
        )
        {
        switch (Op) {

        case DLL_PROCESS_ATTACH :
        DEBUGREGISTER((HINSTANCE)hinstDLL);
        break;
        ……
        至于調試區(qū)的使用,完全是幾個宏的使用而已,我想做程序的人都會用的,常用的宏如下:
        DEBUGMSG(),DEBUGLED(),RETAILMSG(),RETAILLED(),ERRORMSG(),DEBUGCHK()

        好了,調試區(qū)就概要的說了這么多,如此復雜的機制在自己的程序中寫起來是煩瑣了點,不過如果你需要的話,可以從CE現(xiàn)有的例程序中復制過來,這樣就省了很多麻煩事,也不會出錯。下圖是在PB中使用調試區(qū)的截圖,當選中某一個調試區(qū)后,如果該調試區(qū)有調試信息則會在DEBUG窗口輸出的。自己試試吧!


        在學習驅動程序之前,我們還有很多東西要了解。想來想去,可能最重要的還是中斷了,所以,這次我們花點時間來了解一下在Windows CE中的中斷機制。
        凡是學過計算機原理的人都知道中斷是什么東西,所以這些基本知識我們就不再詳述了,我們下面就先看一下CE對中斷的整體處理流程,以方便從全局上有個整體的認識。
        下圖是CE中中斷處理的流程圖示


        我們分布來解釋上圖中的流程:
        1、硬件設備向Kernel發(fā)送中斷異常的代碼,如果檢測到這個中斷異常,就會被Kernel層的異常處理所截獲;
        2、中斷服務調度程序會調用OAL例程中的OEMInterruptDisable函數(shù),這個函數(shù)會通知硬件在處理完這一中斷前關閉特殊的中斷,但其他的中斷仍然處于開放狀態(tài);
        3、中斷服務例程ISR被調用以決定如何來處理這一中斷;
        4、Kernel接收到ISR的返回值以得知如何處理這一中斷。它的響應結果之一是忽略掉這一中斷不作處理(SYSINTR_NOP),另一結果是準備執(zhí)行IST。
        5、Kernel引發(fā)中斷服務調度程序來喚醒中斷服務線程去工作。IST是常規(guī)的Win32線程,一旦啟動后,它會創(chuàng)建必要的EVENT然后等待該EVENT被激發(fā)。中斷服務調度通過調用PulseEvent函數(shù)來激發(fā)EVENT,從而喚醒IST線程運行;
        6、當喚醒以后,IST會對中斷進行必要的處理如將數(shù)據(jù)移動到緩沖區(qū)或其他有意義的事;
        7、如果需要的話,IST會借助于I/O支持例程訪問硬件設備;
        8、當IST處理完成后,它會調用InterruptDone函數(shù)通知Kernel;
        9、Kernel調用OEMInterruptDone函數(shù)完成此次中斷的處理過程,OAL例程通知硬件設備重新啟用中斷。
        以上就是中斷在CE中簡要的處理過程。這其中還涉及到幾個函數(shù)的使用,包括:
        1、供OAL調用的ISR函數(shù)
        HookInterrupt函數(shù)在OEMInit函數(shù)中被調用以關聯(lián)IRQ和ISR;
        UnhookInterrupt函數(shù)用來終止IRQ和ISR的關聯(lián)。
        2、供驅動程序調用的IST函數(shù)
        InterruptInitialize函數(shù)用來將EVENT對象和邏輯中斷號關聯(lián)并允許中斷;
        InterruptDone函數(shù)用來通知中斷處理的結束;
        InterruptDisable函數(shù)被驅動程序調用以關閉中斷同時取消被InterruptInitialize初始化的EVENT對象。
        下面我們再分別來看一下最重要的兩部分,ISR和IST。
        ISR屬于OAL層,通常是用匯編語言編寫的,它可以將CPU寄存器中的數(shù)據(jù)移動到內存緩沖區(qū)中,但是它不能做更多的工作,其中一個原因就是它不能訪問到用戶態(tài)的存儲區(qū),它要把這些工作交給IST來完成。它做的另一項工作是進行物理中斷號和邏輯中斷號的映射。一個物理設備比如鍵盤在一種平臺上可能產生4號中斷,在另一種平臺上可能產生15號中斷,經過ISR以后,它就會把這一物理中斷轉換成CE中標準的SYSINTR_KEYBOARD邏輯中斷。Kernel就會根據(jù)這個邏輯中斷值找到對應的EVENT從而喚醒IST。
        ISR有兩種,一種是單ISR模式, 即全局只有一個ISR,它適用于不支持多中斷的CPU,在這種情況下,OAL會提供一個OEMInterruptHandler的命令ISR。另一種是多ISR模式,即CPU有多個硬件中斷的情況,OAL通過HookInterrupt函數(shù)為每一個中斷調用ISR。
        IST是驅動程序中的用戶態(tài)線程,它來執(zhí)行中斷的處理工作。在啟動后它會空閑等待EVENT的激發(fā)狀態(tài),激發(fā)后處理真正的中斷處理過程,最后調用InterruptDone函數(shù)標識中斷處理完成。它通常通過CeSetThreadPriority函數(shù)設置在較高的優(yōu)先級狀態(tài)。
        以上是對中斷的簡要了解,在WINCE5的驅動程序中,很大的變化就是把很多過程化的東西變成了面向對象的方式,即進行了以類為基礎的封裝,這樣代碼變得非常層次化,如果你想了解以上這些中斷在具體驅動程序中的實現(xiàn),建議還是先來看看CE4中的代碼,似乎更明顯一些。
        好了,此次的內容不多,但是較空洞,最好配合查閱驅動程序的源程序如串口的,鍵盤的,比如鍵盤的驅動中就有非常明顯的IST,很容易看到它是如何設置優(yōu)先級的,如果等待EVENT的,如何處理鍵盤消息的以及如何完成中斷的,代碼附后,這樣才能加強理解。即使自己寫驅動,也不一定完全從頭編寫,在以在別人的架構上修改以縮短開發(fā)周期。
        BOOL
        KeybdIstLoop(
        PKEYBD_IST pKeybdIst
        )
        {
        SETFNAME(_T("KeybdIstLoop"));

        UINT32 rguiScanCode[16];
        BOOL rgfKeyUp[16];
        UINT cEvents;

        DEBUGCHK(pKeybdIst->hevInterrupt != NULL);
        DEBUGCHK(pKeybdIst->pfnGetKeybdEvent != NULL);
        DEBUGCHK(pKeybdIst->pfnKeybdEvent != NULL);

        SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);

        wait_for_keybd_interrupt:
        if (WaitForSingleObject(pKeybdIst->hevInterrupt, INFINITE) == WAIT_OBJECT_0)
        {
        cEvents = (*pKeybdIst->pfnGetKeybdEvent)
        (pKeybdIst->uiPddId, rguiScanCode, rgfKeyUp);

        for (UINT iEvent = 0; iEvent cEvents; iEvent) {
        (*pKeybdIst->pfnKeybdEvent)(pKeybdIst->uiPddId,
        rguiScanCode[iEvent], rgfKeyUp[iEvent]);
        }
        // cEvents could be 0 if this was a partial scan code, like 0xE0

        InterruptDone(pKeybdIst->dwSysIntr_Keybd);
        }

        goto wait_for_keybd_interrupt;

        ERRORMSG(1, (TEXT("KeybdIstLoop: Keyboard driver thread terminating.rn")));
        return TRUE;
        }

        linux操作系統(tǒng)文章專題:linux操作系統(tǒng)詳解(linux不再難懂)


        評論


        相關推薦

        技術專區(qū)

        關閉