• 正文
  • 相关推荐
申请入驻 产业图谱

单片机开发中通信协议定制讲解

10/15 11:36
2351
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

一、什么是“自定义协议”

通信协议(Protocol)本质上就是数据交流的规则和格式
比如两台设备通过串口、CAN、TCP蓝牙等方式通信时,需要约定:

    • 数据包的结构是什么样的;• 数据的意义(哪个字节表示命令、哪个是数据);• 校验、长度、结束符等怎么定义;• 出错后如何重传或应答。

简单地说:

自定义协议 = 自己制定一套通信“语言”格式,让设备之间能正确理解彼此。


二、为什么要自定义协议

虽然已经有很多成熟的协议(如:Modbus、MQTT、HTTP、CANopen…),但嵌入式系统往往资源有限功能定制化强,这时就需要自定义协议,原因主要有:

原因 说明
1. 系统资源受限 标准协议太复杂,占用内存大,单片机实现困难(如HTTP、MQTT)。
2. 功能需求独特 自己的系统需要传输特定数据,比如传感器值、命令、状态等,不在标准协议中。
3. 速度和效率要求高 需要通信简洁、高速响应,去掉多余开销。
4. 硬件接口简单 串口、485、I2CSPI通信接口不自带高级协议,需要自己封装
5. 多设备配合工作 主控与多个节点或模块通信时,需要统一自定义格式。

🧠 举个例子:
你用 STM32 通过串口和ESP8266通信,想上传温湿度和报警状态到上位机
你可以自定义一个数据格式,比如:

$TEMP,25.6,HUM,60.2,ALARM,0#

上位机根据 $ 开头、# 结束、逗号分隔来解析。
这就是一个简单的“自定义协议”。


三、什么场景下需要自定义协议

常见的应用场景包括:

场景 说明
① 单片机与传感器节点通信 如主控STM32与多个从设备通信(I2C/SPI/UART)。
② 主机与上位机通信 例如STM32通过串口/WiFi发送数据给Qt或PC端软件。
③ 多机协同系统 例如路灯控制系统中主控与多个节点通讯。
无线通信模块中数据封装 比如LoRa、nRF24L01、蓝牙模块,自己规定帧结构。
⑤ 网关或云端上传前的数据整合 物联网系统中,网关在上传数据前封装成统一协议格式。

四、如何设计一个自定义通信协议

(1)定义帧格式(Frame Format)

最常见结构如下:

字段 含义 示例
帧头 表示数据包开始 0xAA 0x55 或 $
长度 表示数据长度 1字节或2字节
命令字 表示数据类型/功能 例如 0x01=上传温度,0x02=设置阈值
数据区 实际数据内容 比如 25.6℃
校验 校验错误检测 常用CRC8/CRC16/校验和
帧尾 表示数据包结束 0x0D 0x0A 或 #

示例:

AA 55 05 01 19 32 2A 0D 0A

说明:

AA 55:帧头

05:数据长度

01:命令字(上传温度)

19 32:温度数据(25.62℃)

2A:校验

0D 0A:帧尾


(2)命令字定义

每种数据类型或操作定义一个命令字(类似函数编号):

命令字 含义
0x01 上传温湿度数据
0x02 上传报警状态
0x10 设置报警阈值
0x11 查询设备状态

(3)定义校验机制

校验是防止传输错误的关键。常用方法:

累加和校验:简单快速(所有字节求和取低8位)

CRC16:工业级常用(例如Modbus CRC16)


(4)定义通信逻辑

明确:

    • 一帧数据的接收规则(开始、结束、超时、校验)• 是否需要应答(ACK/NACK)• 出错重发机制

(5)编写解析与打包代码 

发送端:打包函数,把数据组装成协议格式后发送;•

接收端:解析函数,从接收缓存中提取完整帧并校验解析。


五、实际示例:STM32 ↔ 上位机 串口通信协议

5.1 案例背景

在智能控制或监测类系统中,例如:

    • • STM32 负责采集温湿度、气体浓度、火焰等数据;
    • • 上位机(Qt编写)负责显示实时数据、发送控制命令(如控制继电器蜂鸣器、设置阈值等);
      • • 通信方式:

    串口(UART)双向通信

5.2 为什么要自定义协议?

串口传输的数据只是原始字节流,没有边界或含义区分。
如果不自定义协议,会出现:

    • 收到数据时无法判断一帧从哪开始到哪结束;• 多条命令粘包或分包;• 无法判断指令类型;• 校验不可靠。

因此,自定义通信协议是确保 STM32 和上位机可靠通信的关键。


5.3 通信协议设计

✅ 总体设计

定义固定的帧格式,包含:

    • 帧头、设备ID、命令字、数据长度、数据区、校验、帧尾。

✅ 通信帧格式定义

字段 字节数 说明
帧头 2B 固定 0xAA 0x55,用于识别帧起始
设备ID 1B 用于区分不同设备
命令字 1B 表示数据类型或控制类型
数据长度 1B 数据区长度
数据区 N字节 实际数据
校验和 1B 从帧头到数据区所有字节累加和
帧尾 2B 固定 0x0D 0x0A 表示帧结束

5.4 功能码定义

功能码 含义 方向
0x01 上传温湿度数据 STM32 → 上位机
0x02 上传报警状态 STM32 → 上位机
0x10 设置温度阈值 上位机 → STM32
0x11 控制继电器开关 上位机 → STM32
0x12 请求实时数据 上位机 → STM32

5.5 通信数据示例

示例1:STM32上传温湿度

AA 55  01  01  04  19 28 00 64  D1  0D 0A
字段 说明
帧头 AA 55 起始标志
设备ID 01 设备编号
命令字 01 上传温湿度
数据长度 04 数据区4字节
数据区 19 28 00 64 温度 25.0℃,湿度 100%
校验 D1 校验和
帧尾 0D 0A 结束标志

5.6 STM32端实现

1️⃣ 打包发送函数

#include "stdint.h"
#include "string.h"

#define FRAME_HEAD1  0xAA
#define FRAME_HEAD2  0x55
#define FRAME_TAIL1  0x0D
#define FRAME_TAIL2  0x0A

uint8_t tx_buf[64];

// 累加和校验函数
uint8_t Get_Sum(uint8_t *data, uint8_t len)
{
    uint8_t sum = 0;
    for (uint8_t i = 0; i < len; i++)
        sum += data[i];
    return sum;
}

// 打包上传温湿度数据
uint8_t Pack_Temp_Humi(uint8_t id, float temp, float hum)
{
    uint8_t len = 0;
    uint16_t t = (uint16_t)(temp * 10);
    uint16_t h = (uint16_t)(hum * 10);

    tx_buf[len++] = FRAME_HEAD1;
    tx_buf[len++] = FRAME_HEAD2;
    tx_buf[len++] = id;
    tx_buf[len++] = 0x01;    // 功能码:上传温湿度
    tx_buf[len++] = 0x04;    // 数据长度

    tx_buf[len++] = (t >> 8) & 0xFF;
    tx_buf[len++] = t & 0xFF;
    tx_buf[len++] = (h >> 8) & 0xFF;
    tx_buf[len++] = h & 0xFF;

    uint8_t sum = Get_Sum(tx_buf, len);
    tx_buf[len++] = sum;

    tx_buf[len++] = FRAME_TAIL1;
    tx_buf[len++] = FRAME_TAIL2;

    return len;
}

// 串口发送函数
void UART_Send(uint8_t *data, uint8_t len)
{
    for(uint8_t i=0; i<len; i++)
    {
        USART_SendData(USART1, data[i]);
        while(USART_GetFlagStatus(USART1, USART_FLAG_TC)==RESET);
    }
}

调用:

uint8_t len = Pack_Temp_Humi(1, 25.3, 60.2);
UART_Send(tx_buf, len);

2️⃣ 接收数据解析函数

uint8_t rx_buf[64];
uint8_t rx_index = 0;
uint8_t frame_ok = 0;

void USART1_IRQHandler(void)
{
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
    {
        uint8_t data = USART_ReceiveData(USART1);
        rx_buf[rx_index++] = data;

        if(rx_index >= 2 && rx_buf[rx_index-2]==0x0D && rx_buf[rx_index-1]==0x0A)
        {
            frame_ok = 1; // 一帧完整数据
        }
    }
}

void Frame_Parse(void)
{
    if(frame_ok)
    {
        frame_ok = 0;

        if(rx_buf[0]==0xAA && rx_buf[1]==0x55)
        {
            uint8_t cmd = rx_buf[3];
            uint8_t len = rx_buf[4];
            uint8_t checksum = rx_buf[5+len];
            uint8_t sum = Get_Sum(rx_buf, 5+len);

            if(sum == checksum)
            {
                switch(cmd)
                {
                    case 0x10: // 设置阈值
                        // 解析数据区
                        break;

                    case 0x11: // 控制继电器
                        if(rx_buf[5]==1)
                            Relay_On();
                        else
                            Relay_Off();
                        break;
                }
            }
        }

        rx_index = 0;
        memset(rx_buf, 0, sizeof(rx_buf));
    }
}

5.7 上位机(Qt C++)端实现

1️⃣ 串口初始化

QSerialPort serial;
serial.setPortName("COM3");
serial.setBaudRate(QSerialPort::Baud115200);
serial.setDataBits(QSerialPort::Data8);
serial.setParity(QSerialPort::NoParity);
serial.setStopBits(QSerialPort::OneStop);
serial.open(QIODevice::ReadWrite);

2️⃣ 接收并解析帧

connect(&serial, &QSerialPort::readyRead, [&](){
    static QByteArray buffer;
    buffer.append(serial.readAll());

    // 查找帧头和帧尾
    int start = buffer.indexOf(QByteArray::fromHex("AA55"));
    int end   = buffer.indexOf(QByteArray::fromHex("0D0A"), start);

    if (start >= 0 && end > start)
    {
        QByteArray frame = buffer.mid(start, end - start + 2);
        buffer.remove(0, end + 2);

        if (frame.size() >= 8)
        {
            quint8 cmd = (quint8)frame[3];
            quint8 len = (quint8)frame[4];

            if (cmd == 0x01 && len == 0x04)
            {
                int temp = ((quint8)frame[5] << 8) | (quint8)frame[6];
                int hum  = ((quint8)frame[7] << 8) | (quint8)frame[8];
                qDebug() << "温度:" << temp/10.0 << "℃ 湿度:" << hum/10.0 << "%";
            }
        }
    }
});

3️⃣ 上位机发送命令(例如控制继电器)

QByteArray packRelayCmd(quint8 id, bool state)
{
    QByteArray data;
    data.append(0xAA);
    data.append(0x55);
    data.append(id);
    data.append(0x11);     // 控制继电器
    data.append(0x01);     // 数据长度
    data.append(state ? 0x01 : 0x00);

    quint8 sum = 0;
    for(int i=0;i<data.size();i++) sum += (quint8)data[i];
    data.append(sum);
    data.append(0x0D);
    data.append(0x0A);
    return data;
}

// 发送控制命令
serial.write(packRelayCmd(1, true));

5.8 协议设计总结

项目 设计要点
通信方式 串口 UART 双向
可靠性 帧头+帧尾+校验确保完整帧
功能扩展 功能码分配灵活,可继续拓展
同步机制 上位机和设备帧结构统一
易调试 可以用串口助手查看十六进制帧

六、实际示例:STM32 ↔ 上位机 网络通信协议

6.1 案例背景说明

系统:基于STM32 ↔ 上位机(Qt/PC软件)的TCP网络通信系统

    • • STM32 端通过 4G 模块(Air724)或 WiFi 模块(ESP8266/W5500)建立 TCP 连接。• 上位机作为

TCP 服务器

    •  或

客户端

    (取决于项目),与 STM32 双向通信。• 通信内容包括:

    • • STM32 → 上位机:上传温湿度、报警状态、设备ID等;• 上位机 → STM32:下发控制指令,如修改阈值、远程控制继电器等。

6.2 为什么要自定义协议(在TCP通信中)

虽然TCP本身是可靠传输协议,但它不关心内容结构
TCP只保证“字节流传输”,不会告诉你一帧数据从哪里开始、哪里结束。
因此,你必须自定义一层应用层协议,来告诉对方:

“我这一帧数据是完整的,代表一个具体的指令或上传包。”

否则,上位机可能一次收到半帧或多帧拼接在一起。


6.3 自定义协议总体设计

✅ 协议层次:

物理层:WiFi/4G/Ethernet
传输层:TCP
应用层:自定义协议(本文重点)

✅ 协议帧格式定义

字段 字节数 说明
帧头 2B 固定为 0xAA 0x55
设备ID 2B 区分不同设备,例如 0x01 0x02
功能码 1B 表示命令类型(上传、设置、控制等)
数据长度 1B 后面数据区长度
数据区 N字节 实际数据内容
校验 1B 累加和校验(从帧头到数据区)
帧尾 2B 固定为 0x0D 0x0A

✅ 示例数据帧(STM32 上传温湿度)

AA 55  00 01  01  04  19 32 00 50  A5  0D 0A

含义说明:

字段 说明
帧头 AA 55 数据帧起始标志
设备ID 00 01 设备编号 1
功能码 01 上传温湿度数据
数据长度 04 数据区4字节
数据区 19 32 00 50 温度=25.6℃ 湿度=80%
校验 A5 累加和校验结果
帧尾 0D 0A 结束标志

6.4 功能码设计示例

功能码 含义 方向
0x01 上传温湿度数据 STM32 → 上位机
0x02 上传报警信息 STM32 → 上位机
0x10 设置报警阈值 上位机 → STM32
0x11 控制继电器开关 上位机 → STM32
0x20 请求设备状态 上位机 → STM32
0x21 响应设备状态 STM32 → 上位机

6.5 通信流程图

┌───────────────────────────┐
│         上位机(Qt)       │
│  TCP客户端/服务器           │
│  ↓  发送控制命令包         │
│  ↑  接收设备上传数据       │
└───────────────────────────┘
             ↑
             │ TCP通信(Socket)
             ↓
┌───────────────────────────┐
│         STM32设备端        │
│  打包 → 发送数据包         │
│  解析 ← 接收命令包         │
│  处理命令 → 控制执行器     │
└───────────────────────────┘

6.6 STM32端实现逻辑(简化示例)

1️⃣ 数据打包发送函数(C语言示例)

#include "string.h"
#include "stdint.h"

#define FRAME_HEAD1  0xAA
#define FRAME_HEAD2  0x55
#define FRAME_TAIL1  0x0D
#define FRAME_TAIL2  0x0A

uint8_t tcp_tx_buf[64];

// 累加和校验
uint8_t Get_Sum(uint8_t *data, uint8_t len)
{
    uint8_t sum = 0;
    for(uint8_t i=0; i<len; i++)
        sum += data[i];
    return sum;
}

// 打包温湿度上传帧
uint8_t TCP_Pack_TempHumi(uint16_t id, float temp, float hum)
{
    uint8_t len = 0;
    uint16_t t = (uint16_t)(temp * 10);
    uint16_t h = (uint16_t)(hum * 10);

    tcp_tx_buf[len++] = FRAME_HEAD1;
    tcp_tx_buf[len++] = FRAME_HEAD2;

    tcp_tx_buf[len++] = (id >> 8) & 0xFF;
    tcp_tx_buf[len++] = id & 0xFF;

    tcp_tx_buf[len++] = 0x01;       // 功能码:上传温湿度
    tcp_tx_buf[len++] = 0x04;       // 数据长度4字节

    tcp_tx_buf[len++] = (t >> 8) & 0xFF;
    tcp_tx_buf[len++] = t & 0xFF;
    tcp_tx_buf[len++] = (h >> 8) & 0xFF;
    tcp_tx_buf[len++] = h & 0xFF;

    uint8_t sum = Get_Sum(tcp_tx_buf, len);
    tcp_tx_buf[len++] = sum;

    tcp_tx_buf[len++] = FRAME_TAIL1;
    tcp_tx_buf[len++] = FRAME_TAIL2;

    return len;
}

然后通过 send(socket_fd, tcp_tx_buf, len, 0); 发给上位机。


2️⃣ 数据接收与解析函数

void TCP_Parse_Recv(uint8_t *buf, uint16_t len)
{
    if(len < 8) return;  // 最小长度检查

    if(buf[0]==0xAA && buf[1]==0x55)
    {
        uint8_t cmd = buf[4];
        uint8_t datalen = buf[5];
        uint8_t checksum = buf[6 + datalen];
        uint8_t sum = Get_Sum(buf, 6 + datalen);

        if(checksum == sum && buf[7 + datalen] == 0x0D && buf[8 + datalen] == 0x0A)
        {
            switch(cmd)
            {
                case 0x10:  // 设置阈值
                    // buf[6], buf[7]等解析
                    break;

                case 0x11:  // 控制继电器
                    if(buf[6] == 0x01)
                        Relay_On();
                    else
                        Relay_Off();
                    break;
            }
        }
    }
}

6.7 上位机(Qt/C++)接收解析逻辑(示意)

void TcpClient::onReadyRead()
{
    QByteArray data = socket->readAll();
    parseTcpFrame(data);
}

void TcpClient::parseTcpFrame(const QByteArray &data)
{
    if (data.startsWith(QByteArray::fromHex("AA55")) &&
        data.endsWith(QByteArray::fromHex("0D0A")))
    {
        quint8 cmd = (quint8)data[4];
        quint8 len = (quint8)data[5];

        if (cmd == 0x01 && len == 0x04)
        {
            int temp = (quint8)data[6] * 256 + (quint8)data[7];
            int hum  = (quint8)data[8] * 256 + (quint8)data[9];
            qDebug() << "温度:" << temp/10.0 << "℃ 湿度:" << hum/10.0 << "%";
        }
    }
}

6.8 协议设计要点总结

项目 说明
设计原则 简洁、固定长度、易扩展、可校验
数据边界 TCP是字节流,必须自定义帧头+帧尾来分割帧
校验机制 建议使用累加和或CRC16防止误传
命令规划 功能码区分不同类型消息
扩展性 保留长度字段,方便今后加功能
可靠性 TCP层已保证传输可靠,不需额外重发机制

七、单片机与嵌入式开发中的芯片级通信协议

7.1 什么是芯片级通信协议?

简单来说,芯片级通信协议就是:

在电子系统中,用来让不同芯片(比如单片机、传感器、存储器、通信模块等)之间进行数据交换的一套规则。

在一个嵌入式系统里,不同芯片之间需要“对话”,比如:

• STM32 要从 温湿度传感器 读取数据;

• 要把数据通过 WIFI模块 上传;

• 或者把数据显示在 OLED屏幕 上。

这些“对话”不是随便发送电信号就能完成的,必须有统一的通信方式和格式,才能确保数据正确传输和理解。

这套方式和格式,就是通信协议

而在芯片与芯片之间直接传输数据的这种协议,就叫 芯片级通信协议(Chip-level Communication Protocol)

芯片级通信协议就是不同芯片之间交流的“语言和规则”,

它规定了“谁说话”“什么时候说”“说什么”“怎么听”,

让整个嵌入式系统能够稳定、高效地协同工作。

常见的芯片级通信协议包括:

协议名称 线数 特点
UART 2根线(TX、RX) 点对点异步通信,常用于调试和模块通信
I²C 2根线(SCL、SDA) 多主多从、结构简单、适合传感器通信
SPI 4根线(MOSI、MISO、SCK、CS) 通信速度快、常用于屏幕、Flash存储
CAN 2根线(CAN_H、CAN_L) 抗干扰强、适合工业与汽车总线
1-Wire 1根线 极简总线,如DS18B20温度传感器
RS485 2根线(差分) 远距离通信、工业控制常用

7.2 通信协议的分类

分类 通信方式 常见协议 特点
并行通信 同时传输多位数据 GPIO并行总线、外扩SRAM/FLASH接口 速度快、引脚
串行通信 逐位传输数据 UART、SPI、I²C、CAN、1-Wire、USB、LIN、RS485 线路简单、抗干扰强

7.3 常见芯片级串行通信协议

1. UART(Universal Asynchronous Receiver/Transmitter,通用异步收发器)

(1)基本原理

UART是一种异步串行通信协议,通信双方不共享时钟信号,而是通过约定的**波特率(baud rate)**来同步。数据格式通常为:

起始位(1位) + 数据位(7或8位) + 校验位(可选) + 停止位(1或2位)
(2)特性
    • 通信方式:全双工• 同步方式:异步,无需时钟线• 连接线:TX(发送)、RX(接收)、GND• 波特率常用:9600、115200 bps
(3)优点与缺点
优点 缺点
硬件简单,只需两根线 无法多机通信(点对点)
软件实现容易 传输速度受限
(4)应用场景
    • STM32 ↔ 电脑(通过USB转串口)• STM32 ↔ GPS模块 / 蓝牙模块 / WIFI模块(ESP8266)通信

2. I²C(Inter-Integrated Circuit,集成电路间总线)

(1)基本原理

I²C是一种由Philips提出的双线同步串行通信协议,使用**SCL(时钟线)SDA(数据线)**两根信号线即可实现多主多从通信。

(2)特性
    • 通信方式:半双工• 通信线:2根(SCL、SDA)• 同步方式:同步• 通信速率:标准100kHz、快速400kHz、高速1MHz+• 每个设备有唯一的7位或10位地址
(3)优点与缺点
优点 缺点
占用引脚少 通信距离短,抗干扰能力较弱
可挂载多个从设备 总线驱动能力有限(需上拉电阻
(4)应用场景
    • 连接传感器(DHT20、BH1750、SHT30等)• EEPROM、RTC(实时时钟)等外设通信

3. SPI(Serial Peripheral Interface,串行外设接口)

(1)基本原理

SPI是一种全双工、同步串行通信协议,由Motorola提出。采用主从结构,由主机控制时钟信号。典型四线制:•

MOSI(主出从入)

MISO(主入从出)

SCK(时钟线)

CS/SS(片选信号)

(2)特性
    • 通信方式:全双工• 通信速率:几MHz至几十MHz• 主从通信:一主多从(由片选线决定)
(3)优点与缺点
优点 缺点
通信速度快 需要多根连线,硬件复杂
通信稳定、抗干扰强 没有标准的多主机制
(4)应用场景
    • SPI Flash / SD卡存储通信• OLED显示屏、LCD屏幕驱动• MPU6050、MAX30102、NRF24L01模块通信

4. CAN(Controller Area Network,控制器局域网)

(1)基本原理

CAN总线是一种多主机通信协议,广泛用于工业与汽车电子中。它通过差分信号(CAN_H、CAN_L)传输数据,具有优先级仲裁错误检测机制

(2)特性
    • 通信方式:多主总线型• 通信速率:10kbps ~ 1Mbps• 拓扑结构:线型总线• 采用差分信号传输,提高抗干扰能力
(3)优点与缺点
优点 缺点
抗干扰能力强、可靠性高 协议复杂、成本高
支持多节点通信 通信距离有限(速率越高距离越短)
(4)应用场景

5. 1-Wire(单总线协议)

(1)基本原理

1-Wire由Dallas公司提出,仅用一根数据线实现主从通信。主机通过时序控制实现数据传输与供电。

(2)特性
    • 通信线:单根数据线(+GND)• 速率较低(16kbps左右)• 每个设备具有唯一的64位ID
(3)优点与缺点
优点 缺点
硬件连接极简 通信速率低
可实现总线供电 时序要求严格
(4)应用场景
    • 温度传感器(DS18B20)• 简单识别系统(电子标签)

6. LIN(Local Interconnect Network,本地互连网络)

(1)基本原理

LIN是为汽车内部的低速通信而设计的单主多从串行网络,用于补充CAN总线。使用单根信号线和固定帧格式。

(2)特性
    • 通信方式:主从结构• 通信速率:最高20kbps• 通信线:1根(LIN线)
(3)应用场景
    • 汽车内部低速设备:车窗、电动后视镜、车灯控制

7. RS-485(推荐标准485)

(1)基本原理

RS-485是一种差分信号的物理层通信标准,支持多机通信。它定义了电气特性,而不规定通信协议(常与Modbus、DL/T等协议结合使用)。

(2)特性
    • 通信方式:半双工• 通信距离:最长1200米• 支持多节点(32台设备)
(3)优点与缺点
优点 缺点
抗干扰能力强,距离远 通信协议需自定义或搭配上层协议
成本低,应用广泛 半双工通信
(4)应用场景

8. USB(Universal Serial Bus,通用串行总线)

(1)基本原理

USB是一种高速串行通信总线,支持热插拔与即插即用,具有主从架构。嵌入式中常见的有USB-Device(从机)模式。

(2)特性
    • 通信方式:主从• 速率等级:Low-Speed(1.5Mbps)、Full-Speed(12Mbps)、High-Speed(480Mbps)• 支持即插即用与自动识别
(3)应用场景

7.4 协议选择参考

应用需求 推荐协议 说明
简单点对点通信 UART 常用于模块通信或调试输出
多传感器低速总线 I²C 占线少、易扩展
高速外设通信 SPI 屏幕、存储模块优选
工业环境、多节点通信 RS-485 / CAN 抗干扰强、传输远
单线简单传感器 1-Wire 典型如DS18B20
计算机接口 USB 通用性强,传输快

7.5 总结

嵌入式系统中的芯片级通信协议是系统设计的关键环节。不同协议在速率、距离、成本、可靠性等方面各有优劣。工程设计中,应根据应用场景硬件资源系统需求综合选择最合适的通信方式。

相关推荐