嵌入式視角看OSI模型
OSI 模型這個話題,雖然在教材和網絡上已經被講了無數次,但大多數講解都以計算機網絡為背景,從 HTTP、TCP 等協議展開說明。
說實話作為既非計算機科班出身,也非網絡相關行業從業者的我來說,計算機網絡是十分陌生且晦澀的,對初學者不太友好。當初我看完計算機網絡書籍之后,仍云里霧里的,還是不太理解分層的真正意義和它跟實際開發有什么關系。
經過幾年工作實踐,動手寫協議、調通信、分析數據包,才逐漸理解每一層的價值,所以今天想嘗試拋開傳統的網絡角度,站在“嵌入式通信協議”的視角,重新解釋一下 OSI 模型。
本文內容僅為個人工作實踐總結,能力有限,如有謬誤,歡迎指正,謝謝。
OSI 模型(Open Systems Interconnection Model,開放式系統互聯模型)是一個用于描述網絡通信過程的分層模型,共分為了七層,每層有各自的清晰的職責分工,十分便于系統設計和協議開發。
受限于資源,在嵌入式中通常不會完整實現 OSI 七層,但該模型對于通信協議的設計和開發非常有指導意義,在實際項目中會根據系統需求簡化為3~5層通信協議結構。
完整的模型分層如下圖(圖片來自《嵌入式系統:硬件、軟件及軟硬件協同》,作者Tammy Noergaard):

下層對于上層都是透明的,即在邏輯上兩個設備上對應層之間是可以直接交互的。
第1層:物理層
該層提供電氣和物理規格
關注內容:
- 通信需要通過幾根線相連?
- 工作電壓多少?多少電壓代表“1”,多少電壓代表“0”
- 通信速率是多少?
- 數據支持的傳輸方向?單工、半雙工、雙工?
- 設備連接方式?點對點、一主多從、多主多從?
UART示例:
- 需要Vcc、Tx、Rx、GND四根線;
- 電平標準是RS232或者TTL;
- 通信速率不定,設備雙方約定好即可,常見的速率有115200bps、9600bps等;
- 支持全雙工,即可同時收發數據;
- 設備連接是點對點;
第2層:數據鏈路層
描述字節如何在物理線纜上傳輸。
關注內容:
- 在多設備場景中,當前的數據是要發給誰的?
- 數據幀的bit如何定義?幀頭、幀尾、校驗碼?
- 數據幀有無校驗?什么校驗方式?
- 每幀數據的數據量是多少?
- 數據的傳輸流向如何規定?
UART示例:
- 由于UART設備點對點連接,第一個問題無需考慮,而在支持多設備的協議中,如SPI使用CS進行片選、IIC使用設備地址進行選擇;
- UART數據定義一幀數據有起始位(幀頭)+8位數據位+校驗位(可選)+停止位(幀尾);
- UART可選使用奇偶校驗,不是所有協議都在該層有校驗,如SPI;
- UART每幀10~11.5bits;
- UART數據全雙工,也無需考慮,如半雙工的IIC則是通過ACK來交換數據線的控制權的;
第3層:網絡層
該層負責將一個可變長的信息(包)從一端傳送到另一端。
關注內容:
- 當前信息是要發給誰的?和上層第一個問題不同的是,這里表述的是軟件層面上的地址,而不是物理地址
- 數據幀要如何分包組包?
軟件地址用來指向設備中的抽象主體,這在嵌入式中比較少見,一般就一個主體去處理通信信息。舉個比較相似的例子,一般使用IIC去讀寫外部寄存器時:起始->從設備地址(讀/寫)->寄存器地址->ACK/NACK;其中的寄存器地址就如同軟件地址;
UART一幀數據有效位只有8位,顯然不能滿足大部分應用需求,所以需要接收/發送多幀,最后將多幀數據組合成完整的數據包。這個時候就需要規定哪些幀是屬于同一包的:
- 定長,規定固定8幀或者16幀為一包?
- 超時,規定多久沒有數據流那前面的數據為一包?
- 魔數,特定包頭包尾來進行劃分?
AT指令示例:AT+ID?
一幀數據發送一個ASCII碼,該指令可以分解為 "A" "T" "+" "I" "D" "?" "\r" "\n"共8幀
"AT"可作包頭,"\r\n"可作包尾。
第4層:傳輸層
該層提供可靠的機制來傳輸數據。
關注內容:
- 整包數據是否完整準確?
- 丟包、錯包是否重傳?
基于傳輸效率考慮,數據鏈路層不會提供過于復雜的校驗,甚至是無校驗。那為了保證整包數據的準確性,增加校驗是必要的,常見的校驗方式有CheckSum校驗、CRC校驗;
那校驗后發現個別數據幀錯漏要請求重傳呢?比如,如果有包序信息,那就可以單獨請求該包序號的數據重新發送。
第5層:會話層
負責建立、管理和終止會話。
關注內容:
- 會話的交互流程?如請求—應答—結束三步走流程
我覺得可以把會話換成交互來理解,一次會話就是兩個設備之間一次完整的通信交互。
如AT指令交互:
主設備發送: AT+BATTERY_VOLT?
從設備回復: +BATTERY_VOLT: 3750,40
從設備確認結束: OK
以上就是一次會話,從AT+CMD?開始建立會話,到+CMD:value進行會話交互,最后到OK終止會話。
第6層:表示層
該層定義數據結構,可能還會有壓縮和加密。
關注內容:
- 定義數據結構,轉換 row data 成結構體
- 可能包含加密、壓縮等(高級應用)
以上面的AT指令為例:
接收到的row_data[LEN] = {0xA6,0x0E,0x28};
數據定義結構定義struct {uint16_t volt;uint8_t percent};
經過表示層處理后即可輸出volt = 3750;percent = 40;
第7層:應用層
該層接受用戶交互并形成一個通信請求。
關注內容:
- 提供接口供業務模塊調用,發起通信請求
- 屏蔽底層通信細節
即提供一個調用接口給其他模塊,用來發起通信。
如:send_cmd_to_slave(uint8_t cmd,uint8_t *param);
那當其他模塊,如按鍵模塊,識別到Key1被按下時就查詢從設備電量,可以調用send_cmd_to_slave(CMD_REQUEST_BAT_PERCENT, NULL);發起通信查詢。
這樣,其它模塊就不需要關心底層用的什么協議,什么接口,內部具體什么交互邏輯。
嵌入式常用通信結構
在資源極其有限的mcu中,一般會簡化到3層:
- 物理層:收發數據,例如 UART/SPI/I2C 驅動;
- 數據鏈路層:處理幀結構,分幀/組幀,處理包校驗;
- 應用層:處理數據業務邏輯,如 AT 指令解析;
當項目稍微復雜后,推薦使用 5 層:
- 物理層:收發數據,例如 UART/SPI/I2C 驅動;
- 鏈路層:處理幀結構,分幀/組幀,處理包校驗;
- 網絡層:軟件地址識別,拆包組包;
- 表示層:結構化數據,映射為具體含義的變量;
- 應用層:負責通信業務邏輯,如命令處理、回復響應。
小結
OSI 模型雖然來源于計算機網絡,但其“分層設計”的理念在嵌入式通信中同樣適用。
其實對于嵌入式開發者來說,學習OSI 模型最重要的并不是去死記硬背每一層的具體定義,而是要理解“為什么要分層”、“每層解決什么問題”。清晰的職責劃分才能帶來更好的可維護性、可擴展性。

浙公網安備 33010602011771號