在了解完I2C通信后,不免會接觸到到SPI通信。而一開始,可能會覺得兩者好似沒什么區別。為什么要學SPI呢,I2C和SPI有什么區別呢。為此我詳細展開說說。
1.什么是 SPI?
SPI,全稱 Serial Peripheral Interface,中文翻譯為串行外設接口,是一種 主從式、同步、全雙工 的串行通信協議。
三個關鍵詞:
主從式:一個主機控制多個從設備(主發起,從響應)
同步式:數據傳輸由時鐘信號(SCK)控制同步
全雙工:可以邊發送邊接收,MOSI/MISO 兩條獨立數據線
2.SPI 的 4 根基本信號線結構
名稱 | 主機作用方向 | 描述 |
---|---|---|
SCK | 主機 → 從機 | 同步時鐘線,主機輸出時鐘,控制數據采樣節奏 |
MOSI | 主機 → 從機 | 主機輸出、從機輸入,主機發數據給從機 |
MISO | 從機 → 主機 | 從機輸出、主機輸入,從機回傳數據給主機 |
CS | 主機 → 從機 | 片選信號(Chip Select),低電平有效,用來告訴從機“你被選中通信了” |
注意:
SCK、MOSI、CS 都是主機控制輸出;
MISO 是主機讀取輸入;
SPI 是一種基于邊沿的協議 —— 數據變化和數據采樣都是“在時鐘跳變沿發生”。
3.SPI 是怎么工作的?(核心機制)
接下來我來對比 SPI 四種模式(Mode 0~3)的行為差異,包括:
CPOL(時鐘空閑電平)
CPHA(數據采樣邊沿)
MOSI 數據什么時候改變
從機什么時候采樣數據
這四種模式是 SPI 協議中最核心也最容易混淆的部分。我現在徹底講明白它們的邏輯區別、時序差異、電平行為和通信節奏。
CPOL 與 CPHA 是什么含義?
CPOL:決定 SCK 在“空閑狀態”的電平(即不傳數據時 SCK 是高還是低)
CPOL = 0 → 空閑時 SCK = 低電平
CPOL = 1 → 空閑時 SCK = 高電平
CPHA:決定 在哪一個邊沿采樣數據
CPHA = 0 → 第一個邊沿采樣
CPHA = 1 → 第二個邊沿采樣
注意:這里是邊沿,不是具體到上升沿還是下降沿,第一個邊沿可能是上升沿也可能是下降沿。
第一個邊沿 = 從空閑態開始的第一個跳變(比如 CPOL=0,SCK 從 0→1 是第一個邊沿)
模式 | CPOL | CPHA | SCK 空閑狀態 | 采樣邊沿 | 傳輸邊沿(MOSI 改變時刻) |
---|---|---|---|---|---|
Mode 0 | 0 | 0 | 低電平 | 上升沿 | 下降沿 |
Mode 1 | 0 | 1 | 低電平 | 下降沿 | 上升沿 |
Mode 2 | 1 | 0 | 高電平 | 下降沿 | 上升沿 |
Mode 3 | 1 | 1 | 高電平 | 上升沿 | 下降沿 |
我以發送一個字節數據(0xA5 = 10100101)為例,分析 SPI 每一位是如何傳輸的。
Step by Step 時序過程(?SPI Mode 0 )
通信準備階段:
主機將 CS 拉低,激活目標從機(W25Q64)
數據準備完畢,等待時鐘同步
第一位傳輸(發送 bit 7:1)
主機將 MOSI 設置為 1
主機將 SCK 從低拉高(上升沿)
從機在上升沿采樣 MOSI 上的值(記錄 bit7=1)
主機將 SCK 拉低,完成本位傳輸
第二位傳輸(bit6 = 0)
主機將 MOSI=0
SCK 上升沿
從機采樣 0
SCK 下降沿結束
重復 8 次后,完整發送 1 字節
發送完后,主機將 CS 拉高,表示結束通信
若是讀取數據,主機會在每一位 SCK 上升沿讀 MISO 上的電平
SPI Mode 1(CPOL = 0,CPHA = 1)
空閑時 SCK 為低,采樣在下降沿,數據改變在上升沿
通信準備階段:
主機將 CS 拉低,激活目標從機(W25Q64)
SCK 處于空閑低電平(CPOL = 0)
數據準備完畢,等待時鐘同步
第一位傳輸(發送 bit7 = 1)
主機將 SCK 拉高(上升沿)
主機將 MOSI 設置為 1
主機將 SCK 拉低(下降沿)
從機在 下降沿采樣 MOSI 上的值(記錄 bit7 = 1)
第二位傳輸(bit6 = 0)
主機將 SCK 拉高
主機將 MOSI 設置為 0
主機將 SCK 拉低
從機在下降沿采樣 0
重復 8 次后,完整發送 1 字節
主機將 CS 拉高,表示通信結束
若是讀取數據:
主機會在 每一位的 SCK 下降沿 讀取 MISO 上的電平
?SPI Mode 2(CPOL = 1,CPHA = 0)
空閑時 SCK 為高,采樣在下降沿,數據改變在上升沿
通信準備階段:
主機將 CS 拉低,激活目標從機
SCK 初始為高電平(CPOL = 1)
數據準備完畢,等待同步
第一位傳輸(bit7 = 1)
主機將 MOSI 設置為 1
主機將 SCK 從高拉低(下降沿)
從機在 下降沿采樣 MOSI = 1
主機將 SCK 拉高(恢復空閑)
第二位傳輸(bit6 = 0)
主機將 MOSI = 0
主機將 SCK 拉低
從機采樣 0
主機將 SCK 拉高
重復 8 次后,完整發送 1 字節
主機將 CS 拉高,結束通信
若是讀取數據:
主機會在 每一位 SCK 下降沿 讀取 MISO 電平
SPI Mode 3(CPOL = 1,CPHA = 1)
空閑時 SCK 為高,采樣在上升沿**,數據改變在下降沿
通信準備階段:
主機將 CS 拉低,激活從機
SCK 初始為高電平(CPOL = 1)
數據準備完畢,等待同步
第一位傳輸(bit7 = 1)
主機將 SCK 拉低
主機將 MOSI 設置為 1
主機將 SCK 從低拉高(上升沿)
從機在 上升沿采樣 MOSI = 1
第二位傳輸(bit6 = 0)
主機將 SCK 拉低
主機將 MOSI 設置為 0
主機將 SCK 拉高
從機采樣 0
重復 8 次后,完整發送 1 字節
主機將 CS 拉高,結束通信
若是讀取數據:
主機會在 每一位 SCK 上升沿 讀取 MISO 電平
W25Q64 是什么?
W25Q64 是一款 64M-bit(8MB)SPI NOR Flash 存儲芯片,常用于存儲配置文件、圖片、數據日志等。它支持:
SPI Mode 0/3 接口
支持標準讀、頁寫、扇區擦除等
支持寫保護、掉電保護
多種容量(如 Q32、Q64、Q128)
W25Q64 內部結構概覽
參數 | 數值 |
---|---|
總容量 | 64Mbit = 8MB |
頁大小(Page) | 256 字節 |
扇區大小(Sector) | 4KB(16 頁) |
塊大小(Block) | 64KB |
地址范圍 | 0x000000 ~ 0x7FFFFF |
寫數據前必須先擦除所在頁或扇區!否則寫入無效。寫數據前必須先擦除所在頁或扇區!否則寫入無效。
W25Q64 使用的 SPI 協議模式
默認使用 SPI Mode 0(CPOL = 0,CPHA = 0)
通信速率支持高達 80MHz(我們軟件模擬約幾十 KHz)
通信格式:主機發送 命令 + 地址 + 數據,從機響應結果或接收寫入
4.舉一個SPI讀寫W25Q64(軟件)例子
從 STM32F103 使用 GPIO 模擬 SPI 信號,實現:
初始化 GPIO
與 W25Q64 通信(讀ID、擦除扇區、寫數據、讀數據)
OLED 顯示驗證數據讀寫是否成功
通信的整體邏輯步驟(功能流程)
初始化 SPI 引腳(MySPI_Init)
啟動 SPI 通信(CS 拉低,MySPI_Start)
發送命令(如讀 ID,擦除、寫數據)
可選:寫入地址或數據內容
讀取或寫入數據
結束通信(CS 拉高,MySPI_Stop)
在 OLED 上顯示通信結果
第一階段:軟件 SPI 的本質與引腳配置
SPI 是什么?
SPI 是一種同步串行通信協議,使用 4 根信號線:
CS:片選(低電平有效)
SCK:時鐘,由主機控制
MOSI:主出從入,主機發給從機
MISO:主入從出,從機回應主機
在 Mode 0 模式下(CPOL=0,CPHA=0):
SCK 空閑為低電平
在 SCK 上升沿采樣輸入數據(MISO)
MOSI 數據必須在 SCK 上升沿前準備好
軟件模擬 SPI 的基本操作函數
模擬 SPI 片選信號 CS(/SS)
void MySPI_W_SS(uint8_t BitValue)
{GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)BitValue);
}
使用 PA4 模擬 SPI 的 CS(Chip Select)信號線
BitValue = 0 表示選中從機(W25Q64)
BitValue = 1 表示釋放從機
W25Q64 是在 CS 低電平有效 時才響應 SPI 命令。這個函數用于 SPI 通信的開始與結束。
模擬時鐘線 SCK
void MySPI_W_SCK(uint8_t BitValue)
{GPIO_WriteBit(GPIOA, GPIO_Pin_5, (BitAction)BitValue);
}
使用 PA5 模擬 SPI 的時鐘線 SCK(Serial Clock)
SPI 模式 0 規定:空閑時為低電平,在 上升沿采樣
?模擬 MOSI 輸出
uint8_t MySPI_R_MISO(void)
{return GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6);
}
使用 PA7 作為 MOSI(主出從入)
STM32 控制這根線向 W25Q64 發送數據位(高位先發)
?引腳初始化:MySPI_Init引腳初始化:?
模擬讀取 MISO(主入從出)
void MySPI_W_MOSI(uint8_t BitValue)
{GPIO_WriteBit(GPIOA, GPIO_Pin_7, (BitAction)BitValue);
}
使用 PA6 作為 MISO,從 W25Q64 讀取回來的每一位數據就在這里被讀取。
讀取的是從機在時鐘上升沿送出的位電平。
// 1. 打開 GPIOA 的時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);// 2. 配置 MOSI(PA7)、SCK(PA5)、CS(PA4)為推挽輸出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);// 3. 配置 MISO(PA6)為上拉輸入
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_Init(GPIOA, &GPIO_InitStructure);// 4. 初始狀態:SS = 1 表示未選中,SCK = 0 表示時鐘空閑
MySPI_W_SS(1);
MySPI_W_SCK(0);
推挽能拉高/拉低,速度快,適合 SPI?
SPI 通信控制函數
void MySPI_Start(void)
{MySPI_W_SS(0); // 選中從機(CS 拉低)
}
void MySPI_Stop(void)
{MySPI_W_SS(1); // 釋放從機(CS 拉高)
}
第二階段:模擬傳輸一個字節的過程(MySPI_SwapByte)
實現原理
SPI 每傳輸 1 個字節(8 位):
每一位數據在 MOSI 上輸出(主機發)
在 SCK 上升沿讓從機采樣(主出)
同時主機也在上升沿讀取 MISO(主入)
uint8_t MySPI_SwapByte(uint8_t ByteSend)
{uint8_t i, ByteReceive = 0x00;for (i = 0; i < 8; i++){// 第 i 位:先將 MOSI 輸出(最高位先)MySPI_W_MOSI(ByteSend & (0x80 >> i)); // 將第 i 位送到 MOSIMySPI_W_SCK(1); // SCK 拉高(上升沿)// 在上升沿采樣 MISO 線,主機讀取從機的回應位if (MySPI_R_MISO() == 1) ByteReceive |= (0x80 >> i);MySPI_W_SCK(0); // SCK 拉低,準備下一位}return ByteReceive;
}
初始化變量:i
為循環索引;ByteReceive
用來存儲收到的數據。?
例如 ByteSend = 0b10100001
第一次發送 bit7:ByteSend & 0x80 = 0x80
輸出對應位電平到 MOSI
SPI Mode 0:從機在 SCK 上升沿采樣數據
主機此時也應從 MISO 線上采樣數據
若當前位為高電平,則置 ByteReceive 的對應位為 1
第三階段:JEDEC ID 的讀取過程(讀取芯片型號)
第三階段:JEDEC ID 的讀取過程(讀取芯片型號)
void W25Q64_ReadID(uint8_t *MID, uint16_t *DID)
{MySPI_Start(); // CS = 0,激活 FlashMySPI_SwapByte(0x9F); // 發送 JEDEC ID 指令*MID = MySPI_SwapByte(0x00); // 接收廠商 ID(通常為 0xEF)*DID = MySPI_SwapByte(0x00); // 高位 Device ID(如 0x40)*DID <<= 8;*DID |= MySPI_SwapByte(0x00); // 低位 Device ID(如 0x17)MySPI_Stop(); // CS = 1,結束通信}
?每個字節都通過 MySPI_SwapByte() 傳輸,從機 MISO 返回對應 ID 信息。
第四階段:擦除操作(扇區擦除)
寫使能
void W25Q64_WriteEnable(void)
{MySPI_Start();MySPI_SwapByte(W25Q64_WRITE_ENABLE); // 0x06MySPI_Stop();
}
?所有寫操作前必須執行該命令。否則寫入失敗。
等待芯片空閑
void W25Q64_WaitBusy(void)
{uint32_t Timeout;MySPI_Start();MySPI_SwapByte(W25Q64_READ_STATUS_REGISTER_1); // 0x05,讀取狀態寄存器Timeout = 100000;while ((MySPI_SwapByte(W25Q64_DUMMY_BYTE) & 0x01) == 0x01) // bit0=WIP=1表示忙{Timeout --;if (Timeout == 0) break;}MySPI_Stop();
}
為什么要擦除?
W25Q64 的 NOR Flash 寫入特性:
不能直接改寫為 0 → 1
必須先將 1 全部清零(擦除為 0xFF),才能寫入
void W25Q64_SectorErase(uint32_t Address)
{W25Q64_WriteEnable(); // 必須先寫使能(WEL=1)MySPI_Start(); // CS = 0MySPI_SwapByte(0x20); // 發送擦除指令:Sector EraseMySPI_SwapByte(addr >> 16); // 地址高8位MySPI_SwapByte(addr >> 8); // 地址中8位MySPI_SwapByte(addr); // 地址低8位MySPI_Stop(); // CS = 1W25Q64_WaitBusy(); // 等待擦除完成(最多100ms)}
地址不需要對齊 0x000;芯片內部按地址所在扇區處理(每 4KB 為一個)
第五階段:寫入數據(頁寫)
寫前必須:
寫使能(0x06)
地址不要跨頁(每頁 256 字節)
void W25Q64_PageProgram(uint32_t Address, uint8_t *DataArray, uint16_t Count)
{W25Q64_WriteEnable(); // 打開寫使能(WEL=1)MySPI_Start(); // 開始通信MySPI_SwapByte(0x02); // Page Program 指令MySPI_SwapByte(addr >> 16); // 地址高8位MySPI_SwapByte(addr >> 8); // 地址中8位MySPI_SwapByte(addr); // 地址低8位for (i = 0; i < Count; i++){MySPI_SwapByte(DataArray[i]); // 發送要寫入的數據(MOSI)}MySPI_Stop(); // 結束通信W25Q64_WaitBusy(); // 等待寫入完成}
第六階段:讀取數據(Read Data)
void W25Q64_ReadData(uint32_t Address, uint8_t *DataArray, uint32_t Count)
{MySPI_Start();MySPI_SwapByte(0x03); // Read Data 指令MySPI_SwapByte(addr >> 16); // 地址高8位MySPI_SwapByte(addr >> 8); // 中8位MySPI_SwapByte(addr); // 低8位for (i = 0; i < Count; i++){DataArray[i] = MySPI_SwapByte(0x00); // 每讀取一個字節,發一個 dummy byte}MySPI_Stop();}
?主機在 每個 SCK 上升沿讀取 MISO,從機按地址返回數據。
?5.指令函數
#ifndef __W25Q64_INS_H
#define __W25Q64_INS_H#define W25Q64_WRITE_ENABLE 0x06
#define W25Q64_WRITE_DISABLE 0x04
#define W25Q64_READ_STATUS_REGISTER_1 0x05
#define W25Q64_READ_STATUS_REGISTER_2 0x35
#define W25Q64_WRITE_STATUS_REGISTER 0x01
#define W25Q64_PAGE_PROGRAM 0x02
#define W25Q64_QUAD_PAGE_PROGRAM 0x32
#define W25Q64_BLOCK_ERASE_64KB 0xD8
#define W25Q64_BLOCK_ERASE_32KB 0x52
#define W25Q64_SECTOR_ERASE_4KB 0x20
#define W25Q64_CHIP_ERASE 0xC7
#define W25Q64_ERASE_SUSPEND 0x75
#define W25Q64_ERASE_RESUME 0x7A
#define W25Q64_POWER_DOWN 0xB9
#define W25Q64_HIGH_PERFORMANCE_MODE 0xA3
#define W25Q64_CONTINUOUS_READ_MODE_RESET 0xFF
#define W25Q64_RELEASE_POWER_DOWN_HPM_DEVICE_ID 0xAB
#define W25Q64_MANUFACTURER_DEVICE_ID 0x90
#define W25Q64_READ_UNIQUE_ID 0x4B
#define W25Q64_JEDEC_ID 0x9F
#define W25Q64_READ_DATA 0x03
#define W25Q64_FAST_READ 0x0B
#define W25Q64_FAST_READ_DUAL_OUTPUT 0x3B
#define W25Q64_FAST_READ_DUAL_IO 0xBB
#define W25Q64_FAST_READ_QUAD_OUTPUT 0x6B
#define W25Q64_FAST_READ_QUAD_IO 0xEB
#define W25Q64_OCTAL_WORD_READ_QUAD_IO 0xE3#define W25Q64_DUMMY_BYTE 0xFF#endif
類別 | 宏定義 | 指令碼 | 用途說明 |
---|---|---|---|
?寫控制 | W25Q64_WRITE_ENABLE | 0x06 | 使能寫操作(寫/擦前必須執行) |
W25Q64_WRITE_DISABLE | 0x04 | 禁止寫操作,防止誤寫 | |
?狀態寄存器 | W25Q64_READ_STATUS_REGISTER_1 | 0x05 | 讀取狀態寄存器1(BUSY/寫使能位) |
W25Q64_READ_STATUS_REGISTER_2 | 0x35 | 讀取狀態寄存器2(包含QE位) | |
W25Q64_WRITE_STATUS_REGISTER | 0x01 | 同時寫SR1 和 SR2(共2字節) | |
寫入操作 | W25Q64_PAGE_PROGRAM | 0x02 | 頁編程(最多256字節) |
W25Q64_QUAD_PAGE_PROGRAM | 0x32 | 四線頁編程(用于Quad SPI) | |
?擦除操作 | W25Q64_SECTOR_ERASE_4KB | 0x20 | 擦除一個 4KB 扇區 |
W25Q64_BLOCK_ERASE_32KB | 0x52 | 擦除一個 32KB 塊 | |
W25Q64_BLOCK_ERASE_64KB | 0xD8 | 擦除一個 64KB 塊 | |
W25Q64_CHIP_ERASE | 0xC7 | 整片擦除(耗時較久) | |
W25Q64_ERASE_SUSPEND | 0x75 | 暫停擦除操作(用于多任務) | |
W25Q64_ERASE_RESUME | 0x7A | 恢復擦除操作 | |
電源管理 | W25Q64_POWER_DOWN | 0xB9 | 進入低功耗待機模式 |
W25Q64_RELEASE_POWER_DOWN_HPM_DEVICE_ID | 0xAB | 喚醒 + 讀取設備ID | |
模式控制 | W25Q64_HIGH_PERFORMANCE_MODE | 0xA3 | 啟用高性能模式(某些版本支持) |
W25Q64_CONTINUOUS_READ_MODE_RESET | 0xFF | 重置連續讀模式 | |
識別ID | W25Q64_MANUFACTURER_DEVICE_ID | 0x90 | 讀取制造商 + 設備ID(需發送地址) |
W25Q64_READ_UNIQUE_ID | 0x4B | 讀取唯一芯片ID(64-bit) | |
W25Q64_JEDEC_ID | 0x9F | JEDEC 標準ID(1字節廠商 + 2字節設備) | |
讀取數據 | W25Q64_READ_DATA | 0x03 | 標準讀取(低速,最兼容) |
W25Q64_FAST_READ | 0x0B | 快速讀取(需發送 Dummy Byte) | |
W25Q64_FAST_READ_DUAL_OUTPUT | 0x3B | 雙線輸出快速讀 | |
W25Q64_FAST_READ_DUAL_IO | 0xBB | 雙線輸入輸出快速讀 | |
W25Q64_FAST_READ_QUAD_OUTPUT | 0x6B | 四線輸出快速讀 | |
W25Q64_FAST_READ_QUAD_IO | 0xEB | 四線輸入輸出快速讀 | |
W25Q64_OCTAL_WORD_READ_QUAD_IO | 0xE3 | 八線 32-bit 快速讀取(部分芯片支持) | |
占位字節 | W25Q64_DUMMY_BYTE | 0xFF | 常用于讀取時“填充”MOSI |
6.main函數
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "W25Q64.h"uint8_t MID;
uint16_t DID;uint8_t ArrayWrite[] = {0x01, 0x02, 0x03, 0x04};
uint8_t ArrayRead[4];int main(void)
{OLED_Init();W25Q64_Init();OLED_ShowString(1, 1, "MID: DID:");OLED_ShowString(2, 1, "W:");OLED_ShowString(3, 1, "R:");W25Q64_ReadID(&MID, &DID);OLED_ShowHexNum(1, 5, MID, 2);OLED_ShowHexNum(1, 12, DID, 4);W25Q64_SectorErase(0x000000);W25Q64_PageProgram(0x000000, ArrayWrite, 4);W25Q64_ReadData(0x000000, ArrayRead, 4);OLED_ShowHexNum(2, 3, ArrayWrite[0], 2);OLED_ShowHexNum(2, 6, ArrayWrite[1], 2);OLED_ShowHexNum(2, 9, ArrayWrite[2], 2);OLED_ShowHexNum(2, 12, ArrayWrite[3], 2);OLED_ShowHexNum(3, 3, ArrayRead[0], 2);OLED_ShowHexNum(3, 6, ArrayRead[1], 2);OLED_ShowHexNum(3, 9, ArrayRead[2], 2);OLED_ShowHexNum(3, 12, ArrayRead[3], 2);while (1){}
}
擦除第一個扇區(地址 0x000000 起始的 4KB)
NOR Flash 寫入前必須擦除,否則無法從 0 改寫為 1!(擦除后,所有數據位變為1)
7.SPI通信與I2C區別
對比項 | SPI(Serial Peripheral Interface) | I2C(Inter-Integrated Circuit) |
---|---|---|
通信方式 | 全雙工,主從同步通信 | 半雙工,主從同步通信 |
信號線數量 | 通常需要 4 根線:MISO, MOSI, SCLK, CS(每個從機單獨 CS) | 只需 2 根線:SCL(時鐘), SDA(數據) |
通信速率 | 較高,可達幾十 Mbps | 較低,一般為 100kHz、400kHz,最多幾 Mbps |
引腳數量 | 多(每個從機需獨立 CS 引腳) | 少(多個從機共用總線) |
總線架構 | 一主多從,但每個從機需要獨立片選 | 一主多從,多個從機可共享 2 根線 |
地址機制 | 無地址,主機用 CS 選中具體從機 | 有 7 位或 10 位設備地址 |
傳輸控制 | 主機控制時鐘(SCLK)與片選 | 主機控制時鐘(SCL),通過地址訪問從機 |
數據方向 | MOSI、MISO 分別用于寫入和讀取(全雙工) | SDA 單線收發數據(半雙工) |
硬件成本 | 較高(線多,占用 GPIO 多) | 較低(線少,占用 GPIO 少) |
軟件協議復雜度 | 簡單,無握手或仲裁 | 較復雜,有起始/停止位、ACK/NACK、仲裁機制等 |
常見應用場景 | Flash、SD 卡、屏幕、W25Q64 等高速外設 | EEPROM、RTC、傳感器、OLED、MPU6050 等低速外設 |
具體外設舉例?
外設 | 使用通信協議 | 原因簡述 |
---|---|---|
W25Q64 | SPI | 高速讀寫需求,SPI 支持頁寫、塊擦除等 |
MPU6050 | I2C | 內置 I2C 接口,低速傳感器,節省引腳 |
OLED (SSD1306) | I2C 或 SPI | 小數據量,I2C 節省引腳,SPI 提高速度 |
SD 卡 | SPI | 大容量文件操作,SPI 高速全雙工性能優越 |