c語言嵌入式軟體架構

2021-05-22 08:20:24 字數 4029 閱讀 2979

模組 劃分的"劃"是規劃的意思,意指怎樣合理的將乙個很大的軟體 劃分為一系列功能 獨 立的部分合作完成系統 的需求。c語言作為一種結構化的程式 設計 語言,在 模組的劃分上主要依據功能(依功能進行劃分在物件導向設計中成為乙個錯誤,牛頓定律遇到了相對論),c語言模組化程式設計需理解如下概念:

(1) 模組即是乙個.c檔案 和乙個.h檔案的結合,標頭檔案(.h)中是對於該模組接 口 的宣告;

(2) 某模組提供給其它模組呼叫的外部函式及資料 需 在.h中檔案中冠以extern關鍵字宣告;

(3) 模組內的函式和全域性變數需在.c檔案開頭冠以static關鍵字宣告;

(4) 永遠不要在.h檔案中定義變數!定義變數和宣告變數的區別在於定義會產生記憶體分配的操作,是彙編階段的概念;而宣告則只是告訴包含該宣告的模組在連線階段 從其它模組尋找外部函式和變數。如:

/*module1.h*/

int a = 5; /* 在模組1的.h檔案中定義int a */

/*module1 .c*/

#include "module1.h" /* 在模組1中包含模組1的.h檔案 */

/*module2 .c*/

#include "module1.h" /* 在模組2中包含模組1的.h檔案 */

/*module3 .c*/

#include "module1.h" /* 在模組3中包含模組1的.h檔案 */

/*module1.h*/

extern int a; /* 在模組1的.h檔案中宣告int a */

/*module1 .c*/

#include "module1.h" /* 在模組1中包含模組1的.h檔案 */

int a = 5; /* 在模組1的.c檔案中定義int a */

/*module2 .c*/

#include "module1.h" /* 在模組2中包含模組1的.h檔案 */

/*module3 .c*/

#include "module1.h" /* 在模組3中包含模組1的.h檔案 */

這樣如果模組1、2、3操作a的話,對應的是同一片記憶體 單元。

乙個嵌入式 系統通常包括兩類模組:

(1)硬體 驅動 模組,一種特定硬體對應乙個模組;

(2)軟體功能模組,其模組的劃分應滿足低偶合、高內聚的要求。

多 任務還是單任務

所謂"單任務系統"是指該系統 不能支援多工併發操作,巨集觀序列地執行乙個任務。而多工系統則可以巨集觀並行(微觀上可能序列)地"同時"執行多個任務。

多工的併發執行通常依賴於乙個多工作業系統(os),多工os的核心是系統排程器,它使用任務控制塊(tcb)來管理任務 排程功能。tcb包括任務的當前狀態、優先順序、要等待的事件或資源、任務程式碼的起始位址、初始堆疊指標等資訊。排程器在任務被啟用時,要用到這些資訊。 此外,tcb還被用來存放任務的"上下文"(context)。任務的上下文就是當乙個執行中的任務被停止時,所要儲存的所有資訊。通常,上下文就是計算 機當前的狀態,也即各個暫存器的內容。當發生任務切換時,當前執行的任務的上下文被存入tcb,並將要被執行的任務的上下文從它的tcb中取出,放入各個 暫存器中。

嵌入式多工os的典型例子有vxworks、uclinux等。嵌入式os並非遙不可 及的神壇之物,我們可以用不到1000行** 實現乙個針對80186處理器的功能最簡單的os核心,作者正準備進行此項工作, 希望能將心得貢獻給大家。

究竟選擇多工還是單任務方式,依賴於軟體的體系是否龐大。例如,絕大多 數手機程式都是多工的,但也有一些小靈通的協議棧是單任務的,沒有作業系統,它們的主程式輪流呼叫各個軟體模組的處理程式,模擬 多 任務環境。

單任務程式典型架構

(1)從cpu復位時的指定位址開始執行;

(2)跳轉至彙編**startup處執行;

(3)跳轉至使用者主程式main執行,在main中完 成:

a.初試化各硬體裝置;

b.初始化各 軟體模組;

c.進入死迴圈(無限迴圈),呼叫各模組的處理函式

使用者主程式和各模組的處理函式都以c語言完成。使用者主程式最後都進入了乙個死迴圈,其首選方案 是:

while(1)

有的程式設計師這樣寫:

for(;;)

這個語法沒有確切表達**的含義,我們從for(;;)看不出什麼,只有弄明白for(;;)在c語言中意味著無條件迴圈才明白 其意。

下面是幾個"著名"的死迴圈:

(1) 作業系統是死迴圈;

(2)win32程式是死迴圈;

(3)嵌入式系統軟體是死迴圈;

(4)多執行緒程式的執行緒處理函式是死迴圈。

你可能會辯駁,大聲說:"凡事都不是絕對的,2、3、4都可以不是死迴圈"。yes,you are right,但是你得不到鮮花和掌聲。實際上,這是乙個沒有太大意義的牛角尖,因為這個世界從來不需要乙個處理完幾個訊息就喊著要os殺死它的win32 程式,不需要乙個剛開始run就自行了斷的嵌入式系統,不需要莫名其妙啟動乙個做一點事就乾掉自己的執行緒。有時候,過於嚴謹製造的不是便利而是麻煩。君不 見,五層的tcp/ip協議棧超越嚴謹的iso/osi七層協議棧大行其道成為事實上的標準?

經常 有網友討論 :

printf("%d,%d",++i,i++); /* 輸出 是什麼?*/

c = a+++b; /* c=? */

等類似問題。面對這些問題,我們只能發出由衷的感慨:世界上還有很多有意義的事情等 著我們去消化攝入的食物。

實際上,嵌入式系統要執行到世界末日。

中斷服務程式

中斷是嵌入式系統中重要的組成部分,但是在標準c中不包含中斷。許多編譯 開發 商在標準c上增加了 對中斷的支援,提供新的關鍵字用於標示中斷服務程式(isr),類似於__interrupt、#program interrupt等。當乙個函式被定義為isr的時候,編譯器會自動為該函式增加中斷服務程式所需要的中斷現場入棧和出棧**。

中斷服務程式需要滿足如下要求:

(1)不能返回值;

(2)不能向isr傳遞引數;

(3) isr應該盡可能的短小精悍;

(4) printf(char * lpformatstring,…)函式會帶來重入和效能問題,不能在isr中採用。

在某項 目 的開發中,我們設計了乙個佇列,在中斷服務程式中,只是將中斷型別新增入該佇列中,在主程式的死迴圈中不斷掃瞄中斷佇列是否有中斷,有則 取出佇列中的第乙個中斷型別,進行相應處理。

/* 存放中斷的佇列 */

typedef struct tagintqueue

intqueue;

intqueue lpintqueuehead;

__interrupt isrexample ()

在主程式迴圈中判 斷是否有中斷:

while(1)}}

按上述方法設計的中斷服務程式很小,實際的工 作都交由主程式執行了。

硬體驅動模組

乙個硬體驅動模組通常應包括如下函式:

(1)中斷服務程式isr

(2)硬體初始化

a.修改暫存器,設定 硬體引數(如uart應設定其波特率,ad/da裝置應設定其取樣速率等);

b.將中斷服務程式入口位址寫入中斷向量表:

/* 設定中斷向量表 */

m_myptr = make_far_pointer(0l); /* 返回void far型指標void far * */

m_myptr += itype_uart; /* itype_uart: uart中斷服務程式 */

/* 相對於中斷向量表首位址的偏移 */

*m_myptr = &uart _isr; /* uart _isr:uart的中斷服務程式 */

(3)設定cpu針對該硬體的控制線

a.如果控制線可作pio(可程式設計i/o)和控制訊號 用,則設定cpu內部對應暫存器使其作為控制訊號;

b.設定cpu內部的針對該裝置的中斷遮蔽位,設定中斷方式(電平觸發還是邊緣觸發)。

(4)提供一系列針對該裝置的操作介面函式。例如,對於lcd ,其驅動模組應提供繪製像 素、畫線、繪製矩陣、顯示字元點陣等函式;而對於實時鐘 ,其驅動模組則需提供獲取時間、設定時間等函式。

嵌入式學習(二) 嵌入式系統C 語言

1 從 cpu 復位時的指定位址開始執行 2 跳轉至彙編 startup 處執行 3 跳轉至使用者主程式 main 執行,在 main 中完成 a.初試化各硬體裝置 b.初始化各軟體模組 c.進入死迴圈 無限迴圈 d呼叫各模組的處理函式 下面是幾個 著名 的死迴圈 1 作業系統是死迴圈 2 win3...

高階嵌入式軟體架構設計

了解嵌入式架構的常見問題和解決策略 了解嵌入式架構設計過程 了解嵌入式架構質量評估方法 了解常見的嵌入式設計問題的解決方法 o 嵌入式子系統設計 o 嵌入式層次框架設計 o 嵌入式系統介面設計 o 嵌入式效能架構設計 o 嵌入式可靠性架構設計 o 嵌入式可擴充套件架構設計 培訓物件 嵌入式應用軟體設...

嵌入式系統架構

驅動介面 核心 系統呼叫 shell 庫函式 應用軟體 作業系統通過裝置驅動介面呼叫相對應的硬體。linux不是乙個作業系統 linux是作業系統中的核心,即linux kernel gnu linux 採用linux核心的gnu作業系統 程序排程是核心的核心,所有的模組都與程序排程模組存在依賴關係...