一、什么是“自定义协议”
通信协议(Protocol)本质上就是数据交流的规则和格式。
比如两台设备通过串口、CAN、TCP、蓝牙等方式通信时,需要约定:
- • 数据包的结构是什么样的;• 数据的意义(哪个字节表示命令、哪个是数据);• 校验、长度、结束符等怎么定义;• 出错后如何重传或应答。
简单地说:
自定义协议 = 自己制定一套通信“语言”格式,让设备之间能正确理解彼此。
二、为什么要自定义协议
虽然已经有很多成熟的协议(如:Modbus、MQTT、HTTP、CANopen…),但嵌入式系统往往资源有限、功能定制化强,这时就需要自定义协议,原因主要有:
| 原因 | 说明 |
|---|---|
| 1. 系统资源受限 | 标准协议太复杂,占用内存大,单片机实现困难(如HTTP、MQTT)。 |
| 2. 功能需求独特 | 自己的系统需要传输特定数据,比如传感器值、命令、状态等,不在标准协议中。 |
| 3. 速度和效率要求高 | 需要通信简洁、高速响应,去掉多余开销。 |
| 4. 硬件接口简单 | 串口、485、I2C、SPI等通信接口不自带高级协议,需要自己封装。 |
| 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 案例背景
在智能控制或监测类系统中,例如:
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)应用场景
3. SPI(Serial Peripheral Interface,串行外设接口)
(1)基本原理
SPI是一种全双工、同步串行通信协议,由Motorola提出。采用主从结构,由主机控制时钟信号。典型四线制:•
MOSI(主出从入)
MISO(主入从出)
SCK(时钟线)
CS/SS(片选信号)
(2)特性
- • 通信方式:全双工• 通信速率:几MHz至几十MHz• 主从通信:一主多从(由片选线决定)
(3)优点与缺点
| 优点 | 缺点 |
|---|---|
| 通信速度快 | 需要多根连线,硬件复杂 |
| 通信稳定、抗干扰强 | 没有标准的多主机制 |
(4)应用场景
4. CAN(Controller Area Network,控制器局域网)
(1)基本原理
CAN总线是一种多主机通信协议,广泛用于工业与汽车电子中。它通过差分信号(CAN_H、CAN_L)传输数据,具有优先级仲裁和错误检测机制。
(2)特性
(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 总结
嵌入式系统中的芯片级通信协议是系统设计的关键环节。不同协议在速率、距离、成本、可靠性等方面各有优劣。工程设计中,应根据应用场景、硬件资源和系统需求综合选择最合适的通信方式。
2351