SPI

SPI(Serial Peripheral Interface)是一种高速串行通信协议。

  • 用于连接显示屏、Flash 存储、ADC 等高速设备
  • 支持全双工通信
  • 通常需要 4 根线:SCLK(时钟)、MOSI(主机发送)、MISO(主机接收)、CS(片选)

基本用法

from machine import SPI, Pin

# 创建 SPI 对象
spi = SPI(
    0,                      # SPI 端口号
    baudrate=1000000,       # 波特率(1 MHz)
    polarity=0,             # 时钟极性(0 或 1)
    phase=0,                # 时钟相位(0 或 1)
    bits=8,                 # 数据位
    firstbit=SPI.MSB,       # 高位先行
    sck=Pin(18),            # 时钟引脚
    mosi=Pin(19),           # 主机发送引脚
    miso=Pin(16)            # 主机接收引脚
)

# 片选引脚
cs = Pin(17, Pin.OUT, value=1)  # 初始高电平(未选中)

# 发送数据
cs.value(0)  # 选中设备
spi.write(b'\x01\x02\x03')  # 发送数据
cs.value(1)  # 取消选中

# 接收数据
cs.value(0)
data = spi.read(3)  # 读取 3 字节
cs.value(1)
print('读取到:', data)

# 同时收发
cs.value(0)
data = spi.read(3, write=b'\x00\x00\x00')  # 发送 0 并读取 3 字节
cs.value(1)

配置参数

参数 说明 可选值
baudrate 波特率 1000000 等
polarity 时钟极性 0 (空闲低), 1 (空闲高)
phase 时钟相位 0 (第一个边沿采样), 1 (第二个边沿采样)
bits 数据位 8, 16 等
firstbit 位顺序 SPI.MSB, SPI.LSB

常用操作

1. 写入数据
def spi_write(device_cs, data):
    """向 SPI 设备写入数据"""
    device_cs.value(0)  # 选中设备
    spi.write(data)
    device_cs.value(1)  # 取消选中

# 使用
cs = Pin(17, Pin.OUT, value=1)
data = b'Hello SPI'
spi_write(cs, data)
2. 读取数据
def spi_read(device_cs, length):
    """从 SPI 设备读取数据"""
    device_cs.value(0)  # 选中设备
    data = spi.read(length)
    device_cs.value(1)  # 取消选中
    return data

# 使用
data = spi_read(cs, 4)
print(data)
3. 写入后读取
def spi_write_read(device_cs, write_data):
    """写入数据并读取相同长度的返回数据"""
    device_cs.value(0)  # 选中设备
    data = spi.read(len(write_data), write=write_data)
    device_cs.value(1)  # 取消选中
    return data

# 使用
response = spi_write_read(cs, b'\x01\x02')
print('响应:', response)

示例1:控制 7 段数码管

from machine import SPI, Pin
import time

# 假设使用 SPI 控制的 7 段数码管
spi = SPI(0, baudrate=1000000, sck=Pin(18), mosi=Pin(19), miso=Pin(16))
cs = Pin(17, Pin.OUT, value=1)

# 数字 0-9 的段码(共阴极,根据实际硬件调整)
segments = [
    0b11111100,  # 0
    0b01100000,  # 1
    0b11011010,  # 2
    0b11110010,  # 3
    0b01100110,  # 4
    0b10110110,  # 5
    0b10111110,  # 6
    0b11100000,  # 7
    0b11111110,  # 8
    0b11110110   # 9
]

def display_digit(digit):
    """显示数字"""
    if 0 <= digit <= 9:
        cs.value(0)
        spi.write(bytes([segments[digit]]))
        cs.value(1)

# 测试
while True:
    for i in range(10):
        display_digit(i)
        time.sleep(1)

示例2:读取 SPI Flash

from machine import SPI, Pin

# 假设使用 W25Qxx 系列 Flash
spi = SPI(0, baudrate=10000000, sck=Pin(18), mosi=Pin(19), miso=Pin(16))
cs = Pin(17, Pin.OUT, value=1)

# 读取 Flash ID
def read_flash_id():
    cs.value(0)
    # 发送命令 0x9F(读取 ID)
    data = spi.read(3, write=b'\x9F')
    cs.value(1)
    return data

# 读取 Flash 数据
def read_flash(address, length):
    cs.value(0)
    # 发送命令 0x03(读取数据) + 24 位地址
    cmd = b'\x03' + address.to_bytes(3, 'big')
    data = spi.read(length, write=cmd)
    cs.value(1)
    return data

# 测试
id_data = read_flash_id()
print(f'Flash ID: 0x{id_data.hex().upper()}')

# 读取前 16 字节
data = read_flash(0x000000, 16)
print('前 16 字节:', data)

示例3:控制 TFT 显示屏

from machine import SPI, Pin
import time

# 假设使用 SPI 接口的 TFT 显示屏
spi = SPI(0, baudrate=10000000, sck=Pin(18), mosi=Pin(19), miso=Pin(16))
cs = Pin(17, Pin.OUT, value=1)    # 片选
dc = Pin(20, Pin.OUT, value=0)    # 数据/命令
reset = Pin(21, Pin.OUT, value=1)  # 复位

# 复位显示屏
def reset_display():
    reset.value(0)
    time.sleep_ms(10)
    reset.value(1)
    time.sleep_ms(100)

# 发送命令
def send_command(cmd):
    dc.value(0)  # 命令模式
    cs.value(0)
    spi.write(bytes([cmd]))
    cs.value(1)

# 发送数据
def send_data(data):
    dc.value(1)  # 数据模式
    cs.value(0)
    spi.write(data)
    cs.value(1)

# 初始化显示屏
def init_display():
    reset_display()
    # 这里添加具体的初始化命令,根据显示屏型号调整
    send_command(0x01)  # 软件复位
    time.sleep_ms(100)
    # 其他初始化命令...

# 清屏
def clear_screen(color=0x0000):  # 黑色
    # 这里添加清屏代码
    pass

# 初始化
init_display()
clear_screen()

print('TFT 显示屏初始化完成')
# 注:完整的 TFT 驱动需要更多代码,这里仅作示例

注意事项

  • 波特率:SPI 支持很高的波特率,具体取决于设备和连线质量
  • 极性和相位:必须与设备要求一致,常见组合是 (0,0) 或 (1,1)
  • 片选:每次操作前必须拉低片选,操作后拉高
  • 时序:某些设备需要特定的命令和数据时序,参考设备 datasheet
  • 接线:确保 MOSI、MISO、SCLK 正确连接,避免交叉
  • 噪声:高速 SPI 容易产生噪声,建议使用屏蔽线和适当的去耦电容