模擬函數的使用 (Stub Function)

有時,在嵌入式系統軟體開發的過程當中,為了加速開發時程,會在硬體還沒開發出來時就開始撰寫程式。然而,既然還沒有硬體可以使用,那麼,軟體應該如何測試與執行呢?此時就可以依靠模擬器進行模擬。例如,我們可以在桌上型電腦上,撰寫一個模擬器環境,讓桌上型電腦模擬嵌入式系統的行為,這種程式就稱為模擬器 (Simulator)。

舉例而言,假如我們希望開發出一個電子字典,但是其硬體還沒有設計好,此時,我們可以利用像 Visual Studio 這樣的整合開發工具,直接在個人電腦上設計出一個模擬電子字典界面的程式。然後,當程式呼叫介面相關的顯示函數時,實際上是呼叫該模擬程式的函數,如此,即可達成模擬系統行為的功能。

通常,此種暫時用來代替某些功能的模擬函數稱為 Stub,舉例而言,假如我們有一個裝置可以偵測溫度,但是該裝置的硬體尚未製作完成,此時,我們可以利用類似範例 9.3的函數,暫時先傳回一個溫度值,以讓後續的程式可以順利的進行測試,此種函數就稱為 Stub。

範例 9.3 用來取得溫度的 Stub 函數

void Thermometer() {
#ifdef _SIMULATOR _
  return 28;
#else
#endif
}

利用 stub 函數,可以讓未完成的系統得以進行測試,其展現的行為類似於目標系統。如此,程式開發人員可以在硬體未完成之前就進行程式撰寫與測試工作,因此,能有效加快系統的開發時程,以使專案提早完成。

甚至,對於某些具有使用者介面的應用,也可以透過 stub 函數,先呼叫桌上型電腦的對應函數,讓桌上型電腦呈現出與目標系統相似的介面狀況。如此,就能在硬體尚未完成之前先給目標使用者進行試用,如有不符合使用者需求的地方就可以立刻修改。這樣的做法符合軟體工程上的螺旋式開發模式,可以大幅降低專案失敗的風險,並開發出更符合使用者需求的軟體或裝置。因此,模擬器在嵌入式裝置開發的過程當中,具有相當程度的重要性。

舉例而言,假如有一個嵌入式裝置,具有 LCD 顯示器,其解析度為 320 * 240。如此,我們可以撰寫一個 drv_draw_pixel(int X, int Y, int Color) 這樣的 stub 函數,如範例 9.4所示。然後,在其中利用 C 語言當中的 #ifdef 等條件式編譯的方式,讓該程式先顯示在桌上型電腦的模擬環境當中。等到硬體開發完成之後,再將 _SIMULATOR_ 這個定義值取消,如此,就可以先行在桌上型電腦上開發程式。而且,此種方式有一個極大的好處,那就是桌上型電腦通常會提供很好的除錯環境,因此,可以讓程式師輕易的找出大部分的邏輯錯誤,等到硬體裝置完成時,只要在目標板上測試相容性、記憶體與資源的限制等問題即可。

範例 9.4 用來在銀幕上畫一個點的 Stub 函數

void drv_draw_pixel(int X, int Y, int Color) {
#ifdef _SIMULATOR _
  drv_draw_pixel_on_simulator(X, Y, Color);
#else
  drv_draw_pixel_on_device(X, Y, Color);
#endif
}

利用這樣的技術,我們可以完全在個人電腦上開發出應用程式,並且測試執行並完成除錯動作之後,再重新進行編譯,放到目標電腦上執行,如此,可以讓嵌入式系統的開發過程,變得較為順利。

如果,將模擬器與虛擬機兩種技術結合,也就是撰寫一種既可以解譯指令集的虛擬機,而且讓該虛擬機可以模擬輸出入的行為,成為一種模擬器。那麼,我們就可以在個人電腦與嵌入式裝置中都裝設這樣一種虛擬機器,然後在個人電腦上開發並編譯為虛擬機的目的碼後,再放入嵌入式裝置中去執行,這樣就不需要再透過重新編譯的動作,讓目的碼可以跨越平台,並且在行為模式與使用者介面上都具有相同的效果,這種作法雖然可能會造成執行速度較慢,但是跨平台的效果卻較好。

在CPU速度越來越快的今天,許多廠商都開始採用這種模式,像是 Google 與微軟都有這種類型的產品。我們可以利用微軟的 Visual Studio 開發 C# 程式,然後編譯為 .NET平台的 CLR 虛擬目的碼,然後在將這些目的碼放到Pocket PC掌上型電腦或Smart Phone手機上執行,完全不需要進行重新編譯的動作。這使得我們可以輕易的在個人電腦上開發出手機的程式,讓小型裝置的程式開發變得相當容易。

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License