---
# System prepended metadata

title: 通訊傳輸協定
tags: [FW]

---

# 通訊傳輸協定

## 概述

### 1. 串列與並列通訊

並列通訊指的是匯流排有多根數據線，訊號可以一次性的透過匯流排上的多根數據線傳遞。串列通訊中匯流排只有一根數據線，每次只能通過這跟數據線傳送一個電位訊號。

![image](https://hackmd.io/_uploads/SJbPzLo-gx.png)

並列通訊的速度通常比較快(一次傳送較多內容)但同時在佈線方面會比較困難，且每個數據線之間可能會有訊號干擾。嵌入式系統中比較常用串列通訊。

### 2. 單工與雙工

依照數據傳送的方向可以分為

* 單工(simplex)
* 雙工(duplex)

單工通訊只能有發送方(transmiter)傳送給接收方(receiver)，每個硬體零件只能擔任一種角色。

<img src="https://hackmd.io/_uploads/BkLxILi-eg.png" width=400>

雙工通訊中每個設備可以同時作為發送方與接收方，可以從設備 A 傳送訊息至設備 B，也可反過來從設備 B 傳送訊息給設備 A。

雙工通訊又分為半雙工(half-duplex)與全雙工(full-duplex)。半雙工中，發送與接收訊息無法同時進行，每次只能進行一種模式。全雙工中發送與接收可以同時進行。
 
![image](https://hackmd.io/_uploads/r1cLSIiWxg.png)

### 3. 傳輸率

資料傳輸中有兩種常用的單位

* 位元率(bit rate)
* 鮑率(baud rate)

位元率指的是每秒傳輸多少個位元。以 1000 bps 的傳輸速率來說，每秒傳送 1000 個 bit。

鮑率則是定義每秒傳輸的符號(symbol)數量，符號指的是不同電壓或訊號的相位變化。根據調變技術的不同，每個符號可以攜帶一位或多位資訊。以常見的電壓訊號來說，每個符號會攜帶一位元的資訊。

<img src="https://hackmd.io/_uploads/rJuaqLobel.png" width=300>

因此，以 baud rate = 1000 的傳輸速率為例，表示每秒可以傳輸 1000 個符號。

一般來說 bit rate $\ge$ baud rate。兩者的轉換關係式如下 :

bit rate = baud rate $\times$ 每個符號攜帶的位元數資訊

> [!Note]
> 電位傳輸中，每個符號攜帶一個位元資訊(1/0)，因此 bit rate = baud rate。

## UART

### 1. UART 簡介

通用非同步收發器(**U**niversal **A**synchronous **R**eceiver **T**ransmitter)，簡稱 UART，是一種用於不同計算機之間通訊的協定

> [!Important]
> UART 是一種通用的串列，非同步通訊匯流排，該匯流排總共有兩條數據線，可以實現全雙工的發送和接收訊息。通常用於主機與周邊裝置之間的通訊。一般如果沒有特別說明的串列通訊埠(serial port)指的都是 UART。

### 3. UART 通訊協定

> [!Note]
> UART 在傳送資料時是最低位元(bit-0)先傳送，所以從示意圖或示波器上看的時候需要反過來解讀(左側是最低位元)

UART 通訊的過程有以下幾個重點

* 起始位元(start bit)
* 資料內容(data frame)
* 校正位元(check bit): 可有可無
* 停止位元(stop bit)

![image](https://hackmd.io/_uploads/Hy9UPviZex.png)

**(1) 閒置狀態與起始位元**
UART 通訊協定規定在沒有傳送資料時的閒置(idle)狀態下，輸出高電位訊號。開始傳送資料前會先有一個低電位訊號的起始位元

**(2) 資料內容**
UART 通訊協定在資料傳輸過程中從最低位元(LSB)開始依序傳輸到最高位元(MSB)，且每個 data frame 可以選擇傳出 5 到 8 個 bits。(但習慣上是以 8 bits 為單位)

**(3) 校正位元**
校正位元的用意是檢查數據傳輸的正確性，常見的校正方式有兩種

* 檢查和(check sum): 把傳輸資料相加後檢查總和
* 同位位元(parity bit): 又稱奇偶校正，檢查資料中 1 個個數是奇數個還是偶數個
    * 如果同位位元 = 1，表示資料中的高電位訊號有奇數個
    * 如果同位位元 = 0，表示資料中的高電位訊號有偶數個

校正位元不一定要使用，不使用的話傳輸速度為比較快。

**(4) 停止位元**
用來表示這筆 data frame 傳輸完成，是一個 1 到 2 個 bits 的高電位訊號。

![image](https://hackmd.io/_uploads/B1fowwi-xx.png)

以一個 0x5D 的資料傳輸，舉例如下

![image](https://hackmd.io/_uploads/HJCIsDoZeg.png)

但如果有多個連續的相同訊號傳輸，區分這些相同連續訊號的方式是設定傳輸的 baud rate。因為 baud rate = 每秒傳送的符號數量，因此 baud rate 的倒數就是傳送每個符號的所需要的時間(又稱信號時間)。

所以在使用 UART 通訊傳輸時，發送方與接收方必須要設置相同的資料傳輸速率。

> [!Note]
> UART 中的非同步傳輸，指的是不會共用一個時脈(clock)訊號，而是設定相同的資料傳輸速率，並依靠 start bit 來取樣對時，確保 data frame 在誤差範圍內正確取樣。

### 4. UART 硬體接線

UART 屬於全雙工模式，兩個設備的發送端(Tx)與接收斷(Rx)要交叉連接，且兩邊需要共地。

<img src="https://hackmd.io/_uploads/SJqfx_jZgg.png" width=400>

## 電氣位準: TTL/RS232/RS485

### 1. TTL
電晶體 - 電晶體邏輯(**T**ransistor **T**ransistor **L**ogic, TTL)是一種電路類型，早期電路設計多使用這種，現今與之相對的 CMOS 電路。TTL 的電壓標準定義 2V - 5V 為高電位(邏輯1)，0V ~ 0.8V 為低電位(邏輯0)。現今的 IC 設計幾乎沒有使用 TTL 設計，都是採用 C-MOS 或 N-MOS 設計。只是因為歷史因素與習慣使然，所以現今的 MCU/SoC 還是會稱 5V/0V 這種電位標準為 TTL。

> [!Note]
> TTL 現今有兩種意義
> 1. 一種早期的電路類型
> 2. 電位標準

像 UART 這種通訊協定，只是規定傳輸/接收的資料要如何去做解讀，並沒有規定要怎麼去做傳輸，所以可以使用不同的電位標準標準(TTL/RS232/RS485)進行資料傳輸。

##### 參考

* [TTL介绍](#https://blog.csdn.net/guoqx/article/details/137612843)
* [UART、TTL和RS232的区别](#https://blog.csdn.net/muxi_huang/article/details/106746825)
* [電晶體-電晶體邏輯](#https://zh.wikipedia.org/zh-tw/%E9%9B%BB%E6%99%B6%E9%AB%94-%E9%9B%BB%E6%99%B6%E9%AB%94%E9%82%8F%E8%BC%AF)

### 2. RS232 協議

RS232 協議直接規定了標準的連接器，且規定了連接器上每個腳針的用途，不過一般只會使用 RX、TX 與 GND 這三條線。

![image](https://hackmd.io/_uploads/By9WkitGll.png)
(圖片來源: [TTL、RS232、485传输距离到底有多远？](https://www.eet-china.com/mp/a148560.html))

RS232 協議除了接線與接口外，也對訊號的傳輸型式做了規定

* 以 -5V ~ -15V 作為高電位(邏輯1)
* 以 +5V ~ +15V 作為低電位(邏輯0)

這種設計可以增加傳輸過程的抗干擾能力，且傳輸距離也比較長(約 15 公尺左右)

>  [!Note]
>  UART 一般是採用 TTL 電位標準進行傳輸，使用 TTL 標準會有以下幾個問題
>
> * 抗干擾能力插，傳輸過程易出錯
> * 通訊距離短，一般在 1 公尺以內

因為 UART 常用傳輸規定是 TTL 標準，如果要採用 RS232 協議的標準進行傳輸，則必須在傳輸後/接收前加上一個轉換裝置(通常是一個 IC 裝置)，Ex. MAX232 EPE

<img src="https://hackmd.io/_uploads/BklDAXiKGgx.png" width=500>

但 RS232 也有一些問題 :

* 接後的電位訊號比較高，容易損壞電路晶片
* 與 TTL 電位不兼容，需要依靠轉換器
* 通訊速度低共模干擾
* 傳輸距離不夠長

> [!Note]
> RS232 只是在傳輸訊號上做了增強，與軟體(程式碼)上的實作無關

### 3. RS485 協議

與 RS2323 協議類似，特點是 RS485 協議可以允許連接多個收發器(Ex. 一個伺服器主機與多個客戶端主機)，反之 TTL/RS232 都是點對點的通訊，而 RS485 可以形成一個網路。

訊號方面，RS485 採用的是差分訊號進行資料傳輸，使用兩根電線來表示一個位元，假設一根電線 H 另一根電線是 L，則兩根電線之間的電位差為 d = H - L

* 若電位差 d 的範圍介在 +2V ~ +6V 則表示高電位(邏輯1)
* 若電位差 d 的範圍介在 -2V ~ -6V 則表示低電位(邏輯0)

![image](https://hackmd.io/_uploads/SkiaOjtzgl.png)

此外兩個電線是纏繞在一起的雙絞線設計，這種設計搭配差分訊號可以抵抗干擾，因為在受到干擾時，兩根電線的電壓會同時上升或下降，電線之間的電位差值不會受到影響

因為 RS485 是使用兩根電線表示一個位元的兩線設計，所以這兩根電線不能同時進行傳送與發送，也就是說 RS485 是半雙工的設計。在軟體方面程式碼要注意的是接收資料的時候不能傳輸資料，反之亦然。

UART 要使用 RS485 進行資料傳輸勢必也需要使用一個轉換器(Ex. MAX485)

RS485 優點

* 接口的電位訊號較低，不容易損壞晶片
* 通訊速度快
* 抗干擾能力強
* 傳輸距離遠(約 1500 公尺)
* 可實現多節點的網路系統

![image](https://hackmd.io/_uploads/BkUpistzxe.png)

##### 參考

* [串口（UART/COM/TTL/RS232/RS485）](https://blog.csdn.net/ARM_qiao/article/details/125103127)
* [SPI、UART、RS232、RS485、IIC 5种嵌入式经典通信总线协议精讲](https://www.bilibili.com/video/BV1SK4y1X7jp?spm_id_from=333.788.videopod.episodes&vd_source=013aadbea8bdf3cae80ef10a80420d71&p=6)

## I2C/IIC

I2C(Inter-Integrated Circuit)通訊是 Philips 在 80 年代推出的一種串列、半雙工的通訊協議，主要用於近距離且低速的晶片之間的通訊。

I2C 總共有兩根雙向的訊號線，一根是數據線(serial data, SDA)，用於傳輸/接收資料，另一根是時脈線(serial clock, SCL)，用於通訊雙方時脈的同步。

I2C 是一種多主機的設計，連接在 I2C 匯流排上的裝置可分為主機(master)與從機(slave)，主機可以開啟和結束通訊，但從機只能被主機呼叫。此外，因為 I2C 協議允許多個裝置，因此連接在匯流排上的裝置都會有一個唯一的地址(7-bit)，也因為 I2C 的匯流排上會有多個主機，所以 I2C 協定會有衝突檢測，防止當多個主機同時使用匯流排。

![image](https://hackmd.io/_uploads/S1yNCRpmel.png)

### 1. 通訊過程

I2C 的大略通訊過程如下 :

1. 主機發送起始訊號並啟用匯流排(透過 SDA 線)
    * 此時匯流排上的所有裝置都能收到此訊號，並知道有某個主機準備開始發送訊息
    * 因此其他的主機不能發送訊號，因為匯流排被佔據了
2. 主機發送一個 byte 的數據指出欲通訊的從機的位址(7 bit)與後續資料的傳輸方向(1 bit)(見下圖)
    * bit 1 到 bit 7 決定從機位址
    * bit 0 表示傳輸方向
        * 0 : 寫入資料，方向為主機到從機
        * 1 : 讀取資料，方向為從機到主機
    * 匯流排上的所有從機都會收到訊號，並透過 bit 1 到 bit 7 判斷自己是不是被呼叫裝置
3. 被呼叫的從機接收到訊號後，回傳一個回應訊號(ACK)給主機
4. 發送器發送一個 byte 的資料給接收器
    * 這邊沒有規定發送/接收的是主機還是從機
    * 因為不論是主機或從機都有可能擔任發送方或接收方
    * 依據前面所說 bit 0 的資料傳輸方向決定誰是接收/發送
5. 接收器回應一個訊號(A)給發送器
    * 這邊沒有規定發送/接收的是主機還是從機
    * 因為不論是主機或從機都有可能擔任發送方或接收方
    * 依據前面所說 bit 0 的資料傳輸方向決定誰是接收/發送

重複循環 4. 與 5. 步驟，直到主機發送停止訊號。

![image](https://hackmd.io/_uploads/ryELe19Gex.png)
(圖片來源: [2C Primer: What is I2C? (Part 1)](https://www.google.com/search?sxsrf=AE3TifNct9rd7A95l4EL9KAzsRa-Khjp8A:1748786826823&q=i2c&udm=2#vhid=gmX2OP1MDCSENM&vssid=mosaic))

### 2. I2C 傳輸協定

#### 2.1 起始訊號與停止訊號

I2C 的 SDA 與 SCL 兩根電線在閒置狀態下都是保持高電位

* 當 SCL 為高電位，且 SDA 由高轉低表示起始訊號(S)
* 當 SCL 為高電位，且 SDA 由低轉高表示停止訊號\(P)

> [!Note]
> 不論是起始訊號或結束訊號都是由主機發出，起始訊號發出後代表總線處於忙碌狀態度，無法讓其他主機發送訊號。

![image](https://hackmd.io/_uploads/S1-yJycfle.png)
(圖片來源: [2C Primer: What is I2C? (Part 1)](https://www.google.com/search?sxsrf=AE3TifNct9rd7A95l4EL9KAzsRa-Khjp8A:1748786826823&q=i2c&udm=2#vhid=gmX2OP1MDCSENM&vssid=mosaic))

#### 2.2 資料傳輸與回應
I2C 資料傳輸時每次傳輸一個 byte，過程中會先傳送最高位，再傳送最低位。發送器每傳送完一個 byte 的資料後接收器必須發送 1-bit 的回應訊息，且回應訊息是低電位，兩者結合在一起就是 9-bit 的資料。

直到所有資料傳輸完畢後再由主機發送一個結束訊號。

> [!Note]
> 回顧 UART 的傳輸過程，每次傳輸的資料不一定是 8-bit 的長度。

#### 2.3 同步訊號
 
在訊號傳輸的過程，接收方會面臨到 2 個問題 :

* 何時知道發送器開始傳送訊息 ?
* 如何判斷一個位元的長度(Ex. 分辨 10 訊號與 1100 訊號)

> [!Note]
> 以 UART 來說，第一個問題是透過發送一個起始訊號解決，第二個問題透過傳輸率(baud rate)解決

對於 I2C 來說，第一個問題一樣可以透過起始訊號解決。第二個問題是透過連接兩個裝置的時脈線(SCL)解決。SCL 可以保證接收方與發送方兩者間的時脈訊號一致。在 I2C 協議透過 SDA 線進行通訊時 :

* SCL 在低電位期間，發送器向 SDA 發送 1-bit 的資料
    * 在此期間允許 SDA 線上的訊號發生改變
* SCL 在高電位期間，接收器從 SDA 讀取 1-bit 的資料
    * 在此期間不允許 SDA 線上的訊號發生改變，必須保持穩定

因為有 SCK 保持兩者傳輸與接收訊息的時間基準，所以 I2C 可以不受限的傳輸任意長度(以 byte 為單位)的資料，不像 UART 只能傳送固定長度的資料，避免資料傳輸造成的時間誤差。

> [!Note]
> I2C 與 UART 傳輸資料時其實都是以 byte 為單位，差別在於 UART 傳輸一個 byte 的資料後必須跟著一個結束訊號，但 I2C 可以連續不間斷的傳輸，直到資料傳輸完畢才發送結束訊號，因此才會說 I2C 的資料長度不受限制。

![image](https://hackmd.io/_uploads/Bk4z6yqflg.png)


#### 2.4 傳輸實例

I2C 的傳輸過程可以分為三種

* 主機向從機連續寫入數據
* 從機向主機連續讀取數據
* 主機向從機寫入，從機再向主機讀取

以第 3 種來說，因為 I2C 在傳輸過程必須保持資料傳輸方向的一致性，因此當主機向從機寫完數據且下一次從機開始讀取資料前，主機必須再次發送一個起始訊號，才能變更資料傳輸的方向，保持 I2C 的訊號一致。

但特別的是，在轉換資料的過程中，主機其實不需要發送結束訊號\(P)，可以直接開始起始訊號(S)並接著發出從機位址與讀寫訊號(AD+R)。因為一旦在中間發送了結束訊號，代表這次的通訊結束，那麼匯流排可能就會被其他的主機與從機佔據。

![image](https://hackmd.io/_uploads/BJH21gqzxx.png)

## SPI

### 1. SPI 概述
串列週邊介面(**S**erial **P**eripheral **I**nterface, SPI)是一種: (1)高速(相較 UART 與 I2C 而言) (2) 全雙工 (3) 同步的串列通訊傳輸方式。SPI 與 I2C 類似，都是採用主從(master-slave)機制，通常會有一個主機與多個從機。

![image](https://hackmd.io/_uploads/rJmXzWTXxx.png)

SPI 通訊時至少需要 4 根線(從機越多線越多):

* SCLK : 用於提供主從雙方統一時脈
* MOSI: 主機輸出從機輸入(Master Output Slave Input)
* MISO: 主機輸入從機輸出(Master Input Slave Output)
* CS/SS: 用於定址(chep  select)

因為 SPI 可以有一台主機對應多個從機，因此它的最後一根引線(SS/CS)用作定址，用來選擇主機現在要跟哪一個從機開始做通訊。

在 SPI 開始傳輸前，主機會透過 CS/SS 線發送一個訊號用來選擇現在要使用哪一個從機進行傳輸。這個訊號有可能是高電位或低電位，具體要根據從機而定，有些從機使用高電位認定，有些則使用低電位。如果是 $\text{SS}$ 則表示從機使用高電位定址，如果是 $\overline{\text{SS}}$ 則表示該從機使用低電位定址。

<img src="https://hackmd.io/_uploads/HJEhvbpmxg.png" width=350>

### 2. 通訊過程

SPI 傳送資料時會先傳送最高有效位元(MSB)再傳送最低有效位元(LSB)，這點與 I2C 相同但與 UART 不同。

與 I2C 不同的是 :

* SPI 沒有起始訊號與結束訊號
* SPI 每傳送完一個 byte 的資料後，不用等待對方的回覆訊息(ACK)就可以直接傳送下一個 byte 的資料

SPI 採用同步方式進行傳輸，需要有一個時脈協調主從雙方的傳送與接收。

* 每一個時脈的正緣/負緣，發送方(transmitter)向數據線發送數據
* 同時脈後面的負緣/正緣，接收方(receiver)從數據線讀取數據

簡單來說，在每一個時脈的第一個邊緣會進行發送/讀取，下一個邊緣會進行讀取/發送，因此一個 byte 的資料只要 8 個時脈就可以傳輸完成。

### 3. 相位與極性

SPI 協定總共有 4 種工作模式(mode 0/1/2/3)，取決於它的急極性(CPOL)與相位(CPHL)。

* 極性表示閒置期間的時脈狀態
    * CPOL = 0 表示閒置期間 SCLK 為低電位
    * CPOL = 1 表示閒置期間 SCLK 為高電位
* 相位表示採樣數據的時間點
    * CPHA = 0 表示每個週期的第 1 個邊緣採樣(第 2 個邊緣傳輸)
    * CPHA = 1 表示每個週期的第 2 個邊緣採樣(第 1 個邊緣傳輸)

對 SPI 來說極性跟相位是可以改變的，但 I2C 的極性跟相位是固定的。但一般在進行 SPI 傳輸時工作模式並不是任意選擇，而是要根據從機的設計選擇對應的模式，從機要使用哪一種模式可以查閱它的 data sheet 或 user manual，主機可以透過設定暫存器來選擇要使用對應從機的模式。

> [!Note]
> * 採樣(sample)指的是從數據線上讀取位元資料
> * 傳輸(shift)指的是把資料從暫存器送到數據線上

#### 3.1 SPI 模式對照表（SPI Mode Table）

| SPI 模式 | CPOL | CPHA | 閒置狀態下的時鐘極性       | 用來取樣與/或傳輸資料的時鐘相位                      |
|:-:|:-:|:-:|:-:|:-:|
| 0        | 0    | 0    | 低電位（Logic low）         | 上升緣取樣、下降緣傳輸                              |
| 1        | 0    | 1    | 低電位（Logic low）         | 下降緣取樣、上升緣傳輸                              |
| 2        | 1    | 0    | 高電位（Logic high）        | 下降緣取樣、上升緣傳輸                              |
| 3        | 1    | 1    | 高電位（Logic high）        | 上升緣取樣、下降緣傳輸                              |

#### 3.2 SPI 傳輸模式(圖示)
![image](https://hackmd.io/_uploads/SJ8krfTQlg.png)

![image](https://hackmd.io/_uploads/B1TGBzamgg.png)

![image](https://hackmd.io/_uploads/S1NIrM6Qle.png)

![image](https://hackmd.io/_uploads/HypDSzamex.png)
(圖片來源: [Introduction to SPI Interface](https://www.analog.com/en/resources/analog-dialogue/articles/introduction-to-spi-interface.html))

> [!Warning]
> Q: 在 mdoe 0 與 mode 2 有個會讓人疑惑的點。在 mode 0 與 mode 2 的時候都會在第 1 個邊緣就採樣，但理論上在這之前並沒有資料傳輸，那又要如何採樣(讀取)資料 ?
> 
> A: 實際上在這兩種模式下，在時脈第一次開始震動之前資料就會被傳輸到數據線之上，一旦開始震度產生第 1 個邊緣，對方就會開始採樣。

#### 4. 與 I2C 比較

* 相同點
    * 都是串列與同步傳輸
    * 都採用 TTL 電位標準，傳輸距離和場景類似
    * 都採用主從模式
* 相異點
    * I2C 為半雙工，SPI 為全雙工
    * I2C 有回應機制，SPI 沒有
    * I2C 需要先通過匯流排向從機發送位址(所以時間較慢但佈線簡單)，SPI 直接使用 C/S 線決定從機(所以速度較快但佈線複雜)
    * I2C 的相位和極性固定，SPI 可以選擇


