SPI、I2C、UART 详解

SPI、I2C 和 UART 是三种常见的串行通信协议,广泛应用于嵌入式系统、传感器、外设通信等领域。它们各有特点,适用于不同的场景。以下是对这三种协议的详细解释和比较:


1. SPI(Serial Peripheral Interface)

1.1 基本特性
  • 全双工通信:可以同时发送和接收数据。
  • 高速传输:通常支持几 Mbps 到几十 Mbps 的传输速率。
  • 主从架构:一个主设备可以连接多个从设备,通过片选信号(SS)选择通信的从设备。
  • 同步通信:使用时钟信号(SCLK)同步数据传输。
  • 硬件简单:需要较多的引脚(至少4根:SCLK、MOSI、MISO、SS)。
1.2 信号线
  • SCLK(Serial Clock):时钟信号,由主设备生成。
  • MOSI(Master Out Slave In):主设备发送数据,从设备接收数据。
  • MISO(Master In Slave Out):从设备发送数据,主设备接收数据。
  • SS(Slave Select):片选信号,用于选择从设备。
1.3 通信过程
  1. 主设备拉低目标从设备的 SS 信号。
  2. 主设备生成时钟信号(SCLK)。
  3. 主设备通过 MOSI 发送数据,同时通过 MISO 接收数据。
  4. 通信结束后,主设备拉高 SS 信号。
1.4 优点
  • 高速传输。
  • 全双工通信。
  • 硬件实现简单。
1.5 缺点
  • 需要较多的引脚。
  • 不支持多主设备。
1.6 应用场景
  • 高速数据传输(如存储器、显示屏、传感器)。
  • 需要全双工通信的场景。

2. I2C(Inter-Integrated Circuit)

2.1 基本特性
  • 半双工通信:同一时间只能发送或接收数据。
  • 低速传输:通常支持 100kbps(标准模式)、400kbps(快速模式)和 3.4Mbps(高速模式)。
  • 多主多从架构:支持多个主设备和多个从设备。
  • 同步通信:使用时钟信号(SCL)同步数据传输。
  • 硬件简单:只需要两根信号线(SDA、SCL)。
2.2 信号线
  • SDA(Serial Data):数据线,用于发送和接收数据。
  • SCL(Serial Clock):时钟信号,由主设备生成。
2.3 通信过程
  1. 主设备发送起始条件(START)。
  2. 主设备发送从设备地址和读写位。
  3. 从设备发送应答信号(ACK)。
  4. 主设备发送或接收数据。
  5. 通信结束后,主设备发送停止条件(STOP)。
2.4 优点
  • 硬件简单,只需要两根信号线。
  • 支持多主设备和多从设备。
  • 地址机制灵活,支持多个设备。
2.5 缺点
  • 传输速率较低。
  • 半双工通信。
2.6 应用场景
  • 低速数据传输(如传感器、EEPROM)。
  • 需要连接多个设备的场景。

3. UART(Universal Asynchronous Receiver/Transmitter)

3.1 基本特性
  • 异步通信:不需要时钟信号,通过起始位和停止位同步数据传输。
  • 全双工通信:可以同时发送和接收数据。
  • 点对点通信:通常用于两个设备之间的通信。
  • 硬件简单:只需要两根信号线(TX、RX)。
3.2 信号线
  • TX(Transmit):发送数据。
  • RX(Receive):接收数据。
3.3 通信参数
  • 波特率:数据传输速率,如9600、19200、115200等。
  • 数据位:每个数据包的位数,通常为5、6、7或8位。
  • 停止位:每个数据包结束的标志,通常为1或2位。
  • 校验位:用于错误检测,可以是无校验、奇校验或偶校验。
3.4 通信过程
  1. 发送设备在空闲状态下保持高电平。
  2. 发送设备拉低电平(起始位)表示数据传输开始。
  3. 发送设备发送数据位。
  4. 发送设备发送校验位(可选)。
  5. 发送设备拉高电平(停止位)表示数据传输结束。
3.5 优点
  • 硬件简单,只需要两根信号线。
  • 全双工通信。
  • 异步通信,不需要时钟信号。
3.6 缺点
  • 传输速率较低。
  • 点对点通信,不支持多设备。
3.7 应用场景
  • 计算机与外部设备通信(如调试接口、GPS模块)。
  • 需要简单点对点通信的场景。

4. SPI、I2C、UART 的比较

特性 SPI I2C UART
通信方式 同步 同步 异步
传输速率 高速(几 Mbps 到几十 Mbps) 低速(100kbps 到 3.4Mbps) 低速(通常 115200bps)
信号线 4根(SCLK、MOSI、MISO、SS) 2根(SDA、SCL) 2根(TX、RX)
通信模式 全双工 半双工 全双工
设备连接 主从架构,支持多从设备 多主多从架构 点对点
硬件复杂度 较高 较低 最低
应用场景 高速数据传输 低速多设备通信 简单点对点通信

5. 选择指南

  • 选择 SPI

    • 需要高速数据传输。
    • 需要全双工通信。
    • 设备数量较少,且引脚资源充足。
  • 选择 I2C

    • 需要连接多个设备。
    • 引脚资源有限。
    • 数据传输速率要求不高。
  • 选择 UART

    • 需要简单的点对点通信。
    • 不需要时钟信号。
    • 数据传输速率要求不高。

6. 编程示例

6.1 SPI 示例(基于 Linux)
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>

int main() {
    int fd;
    unsigned char tx_buffer[] = {0x01, 0x02, 0x03};
    unsigned char rx_buffer[3];

    // 打开 SPI 设备
    fd = open("/dev/spidev0.0", O_RDWR);
    if (fd < 0) {
        perror("open");
        return -1;
    }

    // 发送和接收数据
    struct spi_ioc_transfer tr = {
        .tx_buf = (unsigned long)tx_buffer,
        .rx_buf = (unsigned long)rx_buffer,
        .len = sizeof(tx_buffer),
    };
    ioctl(fd, SPI_IOC_MESSAGE(1), &tr);

    // 打印接收到的数据
    for (int i = 0; i < sizeof(rx_buffer); i++) {
        printf("Received: 0x%02X\n", rx_buffer[i]);
    }

    // 关闭 SPI 设备
    close(fd);
    return 0;
}
6.2 I2C 示例(基于 Linux)
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>

int main() {
    int fd;
    unsigned char buffer[2];

    // 打开 I2C 设备
    fd = open("/dev/i2c-1", O_RDWR);
    if (fd < 0) {
        perror("open");
        return -1;
    }

    // 设置从设备地址
    int addr = 0x50;
    if (ioctl(fd, I2C_SLAVE, addr) < 0) {
        perror("ioctl");
        return -1;
    }

    // 发送数据
    buffer[0] = 0x00;  // 寄存器地址
    buffer[1] = 0x55;  // 数据
    write(fd, buffer, 2);

    // 接收数据
    read(fd, buffer, 1);
    printf("Received: 0x%02X\n", buffer[0]);

    // 关闭 I2C 设备
    close(fd);
    return 0;
}
6.3 UART 示例(基于 Linux)
#include <stdio.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <string.h>

int main() {
    int fd;
    struct termios options;

    // 打开串口
    fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
    if (fd == -1) {
        perror("open");
        return -1;
    }

    // 配置串口
    tcgetattr(fd, &options);
    cfsetispeed(&options, B9600);  // 设置波特率
    cfsetospeed(&options, B9600);
    options.c_cflag |= (CLOCAL | CREAD);  // 启用接收
    options.c_cflag &= ~PARENB;           // 无校验
    options.c_cflag &= ~CSTOPB;           // 1位停止位
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS8;               // 8位数据位
    tcsetattr(fd, TCSANOW, &options);

    // 发送数据
    char tx_buffer[] = "Hello UART!";
    write(fd, tx_buffer, strlen(tx_buffer));

    // 接收数据
    char rx_buffer[256];
    int n = read(fd, rx_buffer, sizeof(rx_buffer));
    if (n > 0) {
        rx_buffer[n] = '\0';
        printf("Received: %s\n", rx_buffer);
    }

    // 关闭串口
    close(fd);
    return 0;
}

总结

  • SPI:适合高速、全双工通信,但需要较多引脚。
  • I2C:适合低速、多设备通信,硬件简单。
  • UART:适合简单的点对点通信,无需时钟信号。

根据具体需求选择合适的通信协议,可以更好地满足项目要求。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐