嵌入式常用通讯协议详解
📖 目录
基础通讯协议
- 串口通信 (UART/USART)
- SPI通信 (Serial Peripheral Interface)
- I2C通信 (Inter-Integrated Circuit)
- CAN总线 (Controller Area Network)
- RS485通信
应用层协议
无线与物联网协议
选择与设计指南
1. 串口通信 (UART/USART)
1.1 引脚配置及详细作用
-
TX (Transmit): 发送数据引脚 (输出)
- 作用: 串行数据输出,发送数据到外部设备
- 电平: 3.3V/5V TTL电平,空闲时为高电平
- 信号: 起始位(低电平) + 数据位 + 校验位 + 停止位(高电平)
- 连接: 连接到目标设备的RX引脚
-
RX (Receive): 接收数据引脚 (输入)
- 作用: 串行数据输入,从外部设备接收数据
- 电平: 3.3V/5V TTL电平,支持高阻抗输入
- 信号: 检测起始位下降沿,按波特率采样数据
- 连接: 连接到目标设备的TX引脚
-
CTS (Clear To Send): 清除发送引脚 (硬件流控输入)
- 作用: 接收对方的发送许可信号
- 逻辑: 低电平有效,表示可以发送数据
- 流控: 防止接收缓冲区溢出
- 连接: 连接到目标设备的RTS引脚
-
RTS (Request To Send): 请求发送引脚 (硬件流控输出)
- 作用: 向对方发送接收准备信号
- 逻辑: 低电平表示准备接收,高电平表示暂停发送
- 流控: 控制对方的数据发送时机
- 连接: 连接到目标设备的CTS引脚
1.2 工作原理
- 异步串行通信,无时钟信号
- 数据帧格式:起始位 + 数据位 + 校验位 + 停止位
- 双方必须协商相同的波特率和数据格式
UART数据帧格式
空闲态 起始位 数据位(8位) 校验位 停止位 空闲态
___ __ ___ ___ ___ ___ ___
| | | | || | | | | | |
|____| |_____| || |_____| |___| |___|
1 0 D0 D1 D2...D7 P 1 1
波特率时间: T = 1/波特率
例如115200bps: T = 1/115200 ≈ 8.68μs
波特率与误差
常用波特率的实际误差计算:
- 理论值与实际值的误差应<2%
- STM32使用系统时钟分频产生波特率
- 计算公式:实际波特率 = Fclk / (16 × 分频值)
1.3 参数配置
- 波特率: 9600, 115200, 460800, 921600
- 数据位: 8位
- 停止位: 1位
- 校验位: 无校验/奇校验/偶校验
- 流控: 无/硬件流控/软件流控
- 应用: 调试输出、传感器数据传输、模块通信
1.4 引脚连接示意图
设备A 设备B
------ ------
TX ---------> RX (数据发送)
RX <--------- TX (数据接收)
GND ---------> GND (共地)
RTS ---------> CTS (流控-可选)
CTS <--------- RTS (流控-可选)
1.5 注意事项
- 双方波特率必须严格匹配
- 数据格式(数据位、停止位、校验位)要一致
- 确保共地连接,避免地电位差
- 长距离传输需要RS232/RS485转换
- 硬件流控适用于高速或大数据量传输
1.6 参考代码
// UART初始化配置
UART_HandleTypeDef huart1;
void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200; // 波特率
huart1.Init.WordLength = UART_WORDLENGTH_8B; // 8位数据
huart1.Init.StopBits = UART_STOPBITS_1; // 1位停止位
huart1.Init.Parity = UART_PARITY_NONE; // 无校验
huart1.Init.Mode = UART_MODE_TX_RX; // 收发模式
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; // 无流控
HAL_UART_Init(&huart1);
}
// 发送字符串
void UART_SendString(char *str)
{
HAL_UART_Transmit(&huart1, (uint8_t*)str, strlen(str), 1000);
}
// 接收数据
HAL_StatusTypeDef UART_ReceiveData(uint8_t *pData, uint16_t Size)
{
return HAL_UART_Receive(&huart1, pData, Size, 1000);
}
2. SPI通信 (Serial Peripheral Interface)
2.1 引脚配置及详细作用
-
SCLK/SCK (Serial Clock): 串行时钟线 (主机输出)
- 作用: 提供同步时钟信号,控制数据传输时序
- 方向: 只由主机(Master)驱动,从机(Slave)被动接收
- 频率: 1MHz - 50MHz,决定数据传输速度
- 模式: 支持4种时钟模式(CPOL/CPHA组合)
- 空闲态: 根据CPOL设置为高电平或低电平
- 驱动能力: 需要足够驱动力驱动多个从机设备
- 负载: 时钟线负载影响最大传输速度
-
MOSI (Master Out Slave In): 主机输出从机输入数据线
- 作用: 主机向从机发送数据的单向信号线
- 方向: 主机输出 → 从机输入
- 时序: 在时钟边沿(上升/下降)输出数据
- 电平: 3.3V/5V TTL电平
- 别名: 有些芯片称为SDO(Serial Data Out)或DI(Data In)
- 驱动: 推挽输出,可驱动多个从机输入
- 数据格式: MSB或LSB优先,通常MSB在前
-
MISO (Master In Slave Out): 主机输入从机输出数据线
- 作用: 从机向主机发送数据的单向信号线
- 方向: 从机输出 → 主机输入
- 时序: 在时钟边沿(上升/下降)输出数据
- 状态: 未选中的从机应保持高阻态
- 别名: 有些芯片称为SDI(Serial Data In)或DO(Data Out)
- 冲突避免: 多从机共享时需片选控制高阻态
- 上拉: 有时需要弱上拉电阻防止浮空
-
CS/SS (Chip Select/Slave Select): 片选信号线 (主机输出)
- 作用: 选择要通信的特定从机设备
- 逻辑: 通常低电平有效(也有高电平有效的)
- 功能: CS拉低时从机开始响应,拉高时从机进入高阻态
- 多设备: 主机可通过多个CS引脚控制多个从机
- 时序: 必须在时钟开始前拉低,传输结束后拉高
- 保持时间: CS变化到时钟有效需要建立时间
- 独立控制: 每个从机需要独立的CS信号
2.2 工作原理
- 同步串行通信,全双工传输
- 主从模式,主机控制时钟和片选
- 四种工作模式,由CPOL和CPHA决定
- 数据在时钟边沿采样和移位
SPI四种工作模式详解
模式 | CPOL | CPHA | 时钟空闲态 | 数据采样边沿 | 数据变化边沿 | 常用设备 |
---|---|---|---|---|---|---|
0 | 0 | 0 | 低电平 | 上升沿 | 下降沿 | SD卡、W25Q Flash、多数设备 |
1 | 0 | 1 | 低电平 | 下降沿 | 上升沿 | MAX1232、部分ADC |
2 | 1 | 0 | 高电平 | 下降沿 | 上升沿 | 较少使用 |
3 | 1 | 1 | 高电平 | 上升沿 | 下降沿 | TLC549、部分DAC |
CPOL (Clock Polarity 时钟极性):
- CPOL=0: 时钟空闲时为低电平(0V)
- CPOL=1: 时钟空闲时为高电平(Vcc)
CPHA (Clock Phase 时钟相位):
- CPHA=0: 在时钟的第一个边沿采样数据
- CPHA=1: 在时钟的第二个边沿采样数据
2.3 参数配置
- 时钟频率: 1MHz - 50MHz
- 模式: Mode 0-3 (时钟极性和相位)
- 数据位: 8/16位
- 片选: 低电平有效
- 应用: Flash存储器、SD卡、显示屏、ADC/DAC
2.4 引脚连接示意图
主机(MCU) 从机(Flash/传感器)
--------- ------------------
SCK --------> SCLK (时钟同步)
MOSI --------> DI/SDI (主→从数据)
MISO <-------- DO/SDO (从→主数据)
CS --------> CS/SS (片选使能)
GND --------> GND (共地)
VCC --------> VCC (供电)
SPI时序关系 (Mode 0):
CS ----\___________________/----
| |
SCK -----\___/\___/\___/\___/-----
|D7 |D6 |D5 |...|D0 |
MOSI -----| | | | | |----
| | | | | |
MISO -----|D7 |D6 |D5 |...|D0 |----
↑ ↑ ↑ ↑
采样点(上升沿)
多从机连接方案:
主机(MCU) 从机1(Flash) 从机2(ADC) 从机3(DAC)
--------- ----------- ---------- ----------
SCK -------|----+---------|----+--------|----
MOSI -------|----+---------|----+--------|----
MISO -------|----+---------|----+--------|----
CS1 -------| | |
CS2 ---------------------+| |
CS3 ----------------------------------|
2.5 注意事项
- 时钟模式: 主从设备CPOL/CPHA必须匹配
- CS时序: 片选信号的建立/保持时间要满足要求
- 线长匹配: 高速SPI时,时钟线和数据线长度要匹配
- 驱动能力: 时钟信号要有足够驱动能力驱动多个从机
- MISO冲突: 多从机时确保未选中设备MISO为高阻态
- 时钟边沿: 采样边沿和变化边沿要明确区分
- 传输速度: 根据PCB布线质量选择合适的时钟频率
2.6 参考代码
// SPI初始化配置
SPI_HandleTypeDef hspi1;
void MX_SPI1_Init(void)
{
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER; // 主机模式
hspi1.Init.Direction = SPI_DIRECTION_2LINES; // 全双工
hspi1.Init.DataSize = SPI_DATASIZE_8BIT; // 8位数据
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; // CPOL = 0
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; // CPHA = 0 (Mode 0)
hspi1.Init.NSS = SPI_NSS_SOFT; // 软件控制CS
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16; // 分频
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; // MSB优先
HAL_SPI_Init(&hspi1);
}
// SPI读写函数
uint8_t SPI_ReadWriteByte(uint8_t TxData)
{
uint8_t RxData = 0;
HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET);
HAL_SPI_TransmitReceive(&hspi1, &TxData, &RxData, 1, 1000);
HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET);
return RxData;
}
// W25Q128 Flash读取ID示例
uint16_t W25Q128_ReadID(void)
{
uint8_t cmd[4] = {0x90, 0x00, 0x00, 0x00}; // 读ID命令
uint8_t id[2];
HAL_GPIO_WritePin(FLASH_CS_GPIO_Port, FLASH_CS_Pin, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi1, cmd, 4, 1000); // 发送命令和地址
HAL_SPI_Receive(&hspi1, id, 2, 1000); // 接收ID
HAL_GPIO_WritePin(FLASH_CS_GPIO_Port, FLASH_CS_Pin, GPIO_PIN_SET);
return (id[0] << 8) | id[1]; // 组合16位ID
}
3. I2C通信 (Inter-Integrated Circuit)
3.1 引脚配置及详细作用
-
SDA (Serial Data Line): 串行数据线 (双向)
- 作用: 传输数据和地址信息的双向信号线
- 特性: 开漏输出(Open-Drain),需要外部上拉电阻
- 方向: 主机和从机都可以驱动(半双工)
- 电平: 高电平由上拉电阻提供,低电平由设备拉低
- 时序: 在SCL高电平期间数据必须稳定
- 起始/停止: 在SCL高电平时SDA跳变产生起始/停止条件
-
SCL (Serial Clock Line): 串行时钟线 (双向)
- 作用: 提供时钟信号,同步数据传输
- 特性: 开漏输出,需要外部上拉电阻
- 控制: 主机产生时钟,从机可拉低进行时钟延展
- 频率: 100KHz(标准), 400KHz(快速), 1MHz(快速+)
- 仲裁: 多主机环境下支持时钟同步和仲裁
- 延展: 从机可拉低SCL暂停传输(Clock Stretching)
-
上拉电阻: 通常4.7kΩ - 10kΩ
- 作用: 为开漏输出提供高电平
- 选择: 阻值影响上升时间和功耗
- 计算: R = (Vcc - Vol) / (Iol × 设备数量)
- 位置: 连接到电源(Vcc)和信号线之间
- 注意: 总线上只需一组上拉电阻
3.2 工作原理
- 同步串行通信,半双工传输
- 多主多从架构,支持总线仲裁
- 开漏输出,需要外部上拉电阻
- 通过7位或10位地址识别不同设备
- 支持时钟延展和总线仲裁机制
3.3 参数配置
- 时钟频率: 100KHz (标准模式), 400KHz (快速模式), 1MHz (快速模式+)
- 地址位: 7位/10位
- 数据传输: 主从模式,双向传输
- 应用: EEPROM、RTC、传感器、LCD控制器
3.4 引脚连接示意图
VCC
|
4.7kΩ 4.7kΩ (上拉电阻)
| |
MCU ---------|-----|------ 设备1 (地址0x50)
SDA ---------|-----|------ SDA
SCL ---------|-----|------ SCL
| |
设备2 设备3
(地址0x51)(地址0x52)
I2C时序图:
起始 停止
SDA ---|\_______/‾‾‾\_/‾\_____/‾‾‾
SCL ___/‾‾‾‾\___/‾‾‾\___/‾‾‾\___
地址 应答 数据 应答
3.5 注意事项
- 上拉电阻必需: 开漏输出需要外部上拉电阻
- 地址冲突: 同一总线上设备地址不能相同
- 时钟延展: 从机可拉低SCL暂停传输
- 总线仲裁: 多主机时需要仲裁机制
- 电平匹配: 确保所有设备电平兼容
- 传输距离: 受总线电容限制,通常<3米
- 上拉阻值: 根据总线电容和速度选择合适阻值
3.6 参考代码
// I2C初始化配置
I2C_HandleTypeDef hi2c1;
void MX_I2C1_Init(void)
{
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000; // 100KHz标准模式
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; // 占空比2:1
hi2c1.Init.OwnAddress1 = 0; // 主机地址(未使用)
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; // 7位地址
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
HAL_I2C_Init(&hi2c1);
}
// 读取设备数据
HAL_StatusTypeDef I2C_ReadData(uint16_t DevAddress, uint8_t RegAddr,
uint8_t *pData, uint16_t Size)
{
return HAL_I2C_Mem_Read(&hi2c1, DevAddress, RegAddr,
I2C_MEMADD_SIZE_8BIT, pData, Size, 1000);
}
// 写入设备数据
HAL_StatusTypeDef I2C_WriteData(uint16_t DevAddress, uint8_t RegAddr,
uint8_t *pData, uint16_t Size)
{
return HAL_I2C_Mem_Write(&hi2c1, DevAddress, RegAddr,
I2C_MEMADD_SIZE_8BIT, pData, Size, 1000);
}
// EEPROM操作示例
#define EEPROM_ADDR 0xA0 // 24C02地址
uint8_t EEPROM_ReadByte(uint8_t addr)
{
uint8_t data;
HAL_I2C_Mem_Read(&hi2c1, EEPROM_ADDR, addr,
I2C_MEMADD_SIZE_8BIT, &data, 1, 1000);
return data;
}
void EEPROM_WriteByte(uint8_t addr, uint8_t data)
{
HAL_I2C_Mem_Write(&hi2c1, EEPROM_ADDR, addr,
I2C_MEMADD_SIZE_8BIT, &data, 1, 1000);
HAL_Delay(5); // 等待写入完成
}
4. CAN总线 (Controller Area Network)
4.1 引脚配置及详细作用
-
CAN_H (CAN High): CAN高电平信号线
- 作用: 差分信号的正极信号线
- 电平: 显性位时约3.5V,隐性位时约2.5V
- 特性: 与CAN_L形成差分对,提供抗干扰能力
- 连接: 串联连接所有CAN节点
- 线材: 使用双绞线,特征阻抗120Ω
-
CAN_L (CAN Low): CAN低电平信号线
- 作用: 差分信号的负极信号线
- 电平: 显性位时约1.5V,隐性位时约2.5V
- 特性: 与CAN_H共同构成差分信号
- 抗扰: 差分传输可消除共模干扰
- 接地: 通常通过终端电阻中心点接地
-
终端电阻: 120Ω (总线两端)
- 作用: 匹配传输线特征阻抗,防止信号反射
- 位置: 只在CAN总线的两个物理端点安装
- 阻值: 精确120Ω ±1%,功率≥0.25W
- 连接: 连接在CAN_H和CAN_L之间
- 检测: 总线阻抗应为60Ω(两个120Ω并联)
4.2 工作原理
- 差分信号传输,抗干扰能力强
- 多主架构,非破坏性仲裁
- 载波侦听多路访问/冲突检测(CSMA/CD)
- 错误检测和自动重传机制
- 支持标准帧(11位ID)和扩展帧(29位ID)
4.3 参数配置
- 波特率: 125Kbps, 250Kbps, 500Kbps, 1Mbps
- 帧格式: 标准帧(11位ID), 扩展帧(29位ID)
- 仲裁: 非破坏性仲裁,ID越小优先级越高
- 应用: 汽车电子、工业控制、充电桩通信
CAN波特率计算
CAN波特率 = CAN时钟频率 / (预分频器 × (SyncSeg + BS1 + BS2))
- SyncSeg = 1 (固定)
- BS1: 时间段1 (1-16)
- BS2: 时间段2 (1-8)
- 采样点位置 = (SyncSeg + BS1) / (SyncSeg + BS1 + BS2)
- 建议采样点在75%-87.5%位置
CAN错误状态
- 错误主动: 正常工作状态,可发送错误帧
- 错误被动: 发送错误计数≥128,限制发送能力
- 总线关闭: 发送错误计数≥256,停止总线活动
- 错误恢复: 连续监测到128×11个隐性位后恢复
4.4 引脚连接示意图
节点1 节点2 节点3
----- ----- -----
CAN_H ---|---|--- CAN_H
CAN_L ---|---|--- CAN_L
| |
120Ω 120Ω (仅两端安装)
CAN信号电平:
显性位(0): CAN_H=3.5V, CAN_L=1.5V, 差分电压=2V
隐性位(1): CAN_H=2.5V, CAN_L=2.5V, 差分电压=0V
CAN帧格式:
SOF|ID(11)|RTR|IDE|r0|DLC(4)|DATA(0-8字节)|CRC(15)|ACK|EOF
4.5 注意事项
- 终端电阻: 只在总线两端安装,中间节点不安装
- 差分信号: 必须使用双绞线,保持阻抗匹配
- 传输距离: 波特率越高,传输距离越短
- 节点数量: 理论最多110个节点
- 错误处理: 实现错误帧检测和自动重传
- 总线仲裁: ID值越小优先级越高
- 电平匹配: 确保所有节点电平兼容
4.6 参考代码
// CAN初始化配置
CAN_HandleTypeDef hcan1;
void MX_CAN1_Init(void)
{
hcan1.Instance = CAN1;
hcan1.Init.Prescaler = 4; // 预分频器
hcan1.Init.Mode = CAN_MODE_NORMAL; // 正常模式
hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ; // 同步跳转宽度
hcan1.Init.TimeSeg1 = CAN_BS1_13TQ; // 时间段1
hcan1.Init.TimeSeg2 = CAN_BS2_2TQ; // 时间段2
hcan1.Init.TimeTriggeredMode = DISABLE;
hcan1.Init.AutoBusOff = DISABLE;
hcan1.Init.AutoWakeUp = DISABLE;
hcan1.Init.AutoRetransmission = ENABLE; // 自动重传
hcan1.Init.ReceiveFifoLocked = DISABLE;
hcan1.Init.TransmitFifoPriority = DISABLE;
HAL_CAN_Init(&hcan1);
}
// 配置CAN过滤器
void CAN_FilterConfig(void)
{
CAN_FilterTypeDef sFilterConfig;
sFilterConfig.FilterBank = 0;
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterIdHigh = 0x0000;
sFilterConfig.FilterIdLow = 0x0000;
sFilterConfig.FilterMaskIdHigh = 0x0000;
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;
sFilterConfig.FilterActivation = ENABLE;
sFilterConfig.SlaveStartFilterBank = 14;
HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig);
}
// 发送CAN数据
HAL_StatusTypeDef CAN_SendData(uint32_t ID, uint8_t *pData, uint8_t len)
{
CAN_TxHeaderTypeDef TxHeader;
uint32_t TxMailbox;
TxHeader.StdId = ID; // 标准ID
TxHeader.ExtId = 0;
TxHeader.RTR = CAN_RTR_DATA; // 数据帧
TxHeader.IDE = CAN_ID_STD; // 标准帧
TxHeader.DLC = len; // 数据长度
TxHeader.TransmitGlobalTime = DISABLE;
return HAL_CAN_AddTxMessage(&hcan1, &TxHeader, pData, &TxMailbox);
}
// 接收CAN数据
HAL_StatusTypeDef CAN_ReceiveData(uint32_t *ID, uint8_t *pData, uint8_t *len)
{
CAN_RxHeaderTypeDef RxHeader;
HAL_StatusTypeDef status;
status = HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &RxHeader, pData);
if(status == HAL_OK)
{
*ID = RxHeader.StdId;
*len = RxHeader.DLC;
}
return status;
}
5. RS485通信
5.1 引脚配置及详细作用
-
A+ (Data+): 差分信号正极 (发送/接收)
- 作用: 差分数据信号的正极线
- 电平: 逻辑1时为+2V+6V,逻辑0时为-6V-2V
- 连接: 串联连接所有RS485节点的A+端
- 线材: 使用双绞线,建议AWG24或更粗
- 标识: 有些标准称为D+或TxD+/RxD+
-
B- (Data-): 差分信号负极 (发送/接收)
- 作用: 差分数据信号的负极线
- 电平: 逻辑1时为-6V-2V,逻辑0时为+2V+6V
- 连接: 串联连接所有RS485节点的B-端
- 抗扰: 与A+形成差分对,抗共模干扰
- 标识: 有些标准称为D-或TxD-/RxD-
-
DE (Driver Enable): 发送使能引脚 (数字输出)
- 作用: 控制RS485收发器的发送状态
- 逻辑: 高电平使能发送,低电平禁止发送
- 时序: 发送数据前拉高,发送完成后拉低
- 共享: 通常与RE引脚连接,由一个GPIO控制
- 延时: 需要考虑收发切换的建立和保持时间
-
RE (Receiver Enable): 接收使能引脚 (数字输出)
- 作用: 控制RS485收发器的接收状态
- 逻辑: 低电平使能接收,高电平禁止接收
- 状态: 与DE引脚互补,通常由同一信号的反相控制
- 默认: 空闲时应保持接收状态(RE=0, DE=0)
- 冲突: 防止总线上多个节点同时发送
-
终端电阻: 120Ω (总线两端)
- 作用: 匹配传输线特征阻抗,减少反射
- 位置: 仅在RS485总线的两个物理端点
- 连接: 连接在A+和B-之间
- 可选: 中长距离传输建议使用,短距离可省略
- 阻值: 标准120Ω,也有100Ω或150Ω的应用
5.2 工作原理
- 差分信号传输,抗噪声干扰
- 半双工通信,需要收发切换
- 多点通信,支持总线型拓扑
- 电平范围:+2V~+6V (逻辑0), -6V~-2V (逻辑1)
5.3 参数配置
- 传输距离: 最远1200米
- 节点数: 最多32个节点(标准负载)
- 波特率: 9600-115200bps(常用)
- 差分信号: 抗干扰能力强
- 应用: 工业现场总线、多机通信
5.4 引脚连接示意图
节点1 节点2 节点3
----- ----- -----
A+ ----|---|---- A+
B- ----|---|---- B-
| |
120Ω 120Ω (仅两端)
RS485信号电平:
逻辑1: A+电压 > B-电压 (差分电压 > +200mV)
逻辑0: A+电压 < B-电压 (差分电压 < -200mV)
收发控制时序:
DE/RE ___/‾‾‾‾‾‾‾‾\___
发送使能期间
DATA ___/‾\_/‾‾\___/‾\_
串行数据传输
5.5 注意事项
- 收发切换: DE/RE信号需要准确控制收发状态
- 终端电阻: 只在总线两端安装,提高信号质量
- 传输距离: 距离越长,波特率应越低
- 地线连接: 长距离传输建议增加地线连接
- 差分布线: 使用双绞线,保持差分特性
- 节点数量: 标准RS485最多32个节点
- 总线冲突: 避免多个节点同时发送
5.6 参考代码
// RS485相关GPIO定义
#define RS485_DE_RE_PIN GPIO_PIN_8
#define RS485_DE_RE_PORT GPIOA
// RS485方向控制
void RS485_SendMode(void)
{
HAL_GPIO_WritePin(RS485_DE_RE_PORT, RS485_DE_RE_PIN, GPIO_PIN_SET);
HAL_Delay(1); // 等待收发器切换
}
void RS485_ReceiveMode(void)
{
HAL_GPIO_WritePin(RS485_DE_RE_PORT, RS485_DE_RE_PIN, GPIO_PIN_RESET);
HAL_Delay(1); // 等待收发器切换
}
// RS485发送数据
HAL_StatusTypeDef RS485_SendData(uint8_t *pData, uint16_t Size)
{
HAL_StatusTypeDef status;
RS485_SendMode(); // 切换到发送模式
status = HAL_UART_Transmit(&huart1, pData, Size, 1000); // 发送数据
RS485_ReceiveMode(); // 切换到接收模式
return status;
}
// RS485接收数据
HAL_StatusTypeDef RS485_ReceiveData(uint8_t *pData, uint16_t Size)
{
RS485_ReceiveMode(); // 确保接收模式
return HAL_UART_Receive(&huart1, pData, Size, 1000); // 接收数据
}
// Modbus RTU通信示例
typedef struct {
uint8_t slave_addr; // 从机地址
uint8_t function_code; // 功能码
uint16_t start_addr; // 起始地址
uint16_t quantity; // 数量
uint16_t crc; // CRC校验
} ModbusFrame_t;
// 计算CRC16
uint16_t CRC16(uint8_t *pData, uint16_t len)
{
uint16_t crc = 0xFFFF;
for(uint16_t i = 0; i < len; i++)
{
crc ^= pData[i];
for(uint8_t j = 0; j < 8; j++)
{
if(crc & 0x0001)
crc = (crc >> 1) ^ 0xA001;
else
crc = crc >> 1;
}
}
return crc;
}
// Modbus读取保持寄存器(功能码03)
HAL_StatusTypeDef Modbus_ReadHoldingRegisters(uint8_t slave_addr,
uint16_t start_addr,
uint16_t quantity)
{
uint8_t frame[8];
uint16_t crc;
frame[0] = slave_addr; // 从机地址
frame[1] = 0x03; // 功能码
frame[2] = (start_addr >> 8) & 0xFF; // 起始地址高字节
frame[3] = start_addr & 0xFF; // 起始地址低字节
frame[4] = (quantity >> 8) & 0xFF; // 数量高字节
frame[5] = quantity & 0xFF; // 数量低字节
crc = CRC16(frame, 6);
frame[6] = crc & 0xFF; // CRC低字节
frame[7] = (crc >> 8) & 0xFF; // CRC高字节
return RS485_SendData(frame, 8);
}
6. Modbus协议
6.1 协议简介
Modbus是一种应用层的串行通信协议,由Modicon(现为施耐德电气)于1979年为PLC(可编程逻辑控制器)通信而开发。它已经成为工业领域的实际标准,并且是免费、开放的。Modbus通常运行在UART/RS232/RS485等串行链路上,也可以运行在以太网(Modbus TCP)上。
- 特点: 简单、开放、易于实现、应用广泛。
- 通信方式: 主-从(Master-Slave)或客户端-服务器(Client-Server)模式。
- 数据模型: Modbus定义了四种基本的数据对象类型:
- 线圈 (Coil): 1位,可读可写,通常用于控制开关量输出。
- 离散输入 (Discrete Input): 1位,只读,用于读取开关量输入。
- 保持寄存器 (Holding Register): 16位,可读可写,用于存储配置参数或控制数据。
- 输入寄存器 (Input Register): 16位,只读,用于读取测量数据或状态。
6.2 协议数据单元 (PDU)
Modbus协议的核心是PDU(Protocol Data Unit),它独立于底层通信方式。PDU由两部分组成:
- 功能码 (Function Code): 1字节,指示服务器要执行的操作。
- 数据 (Data): N字节,包含执行操作所需的地址、数量、数值等信息。
PDU = 功能码 (1字节) + 数据 (N字节)
6.3 应用数据单元 (ADU)
ADU(Application Data Unit)是在PDU的基础上,根据不同的传输模式增加了地址域和校验域。
- Modbus RTU模式:
ADU = 从机地址(1字节) + PDU + CRC校验(2字节)
- Modbus ASCII模式:
使用ASCII字符表示数据,帧以冒号:
开始,以回车换行CRLF
结束,使用LRC校验。 - Modbus TCP模式:
ADU = MBAP报文头(7字节) + PDU
,运行在TCP/IP网络上,使用TCP端口502。
6.4 常用功能码
功能码 | 功能描述 | 数据对象 | 访问类型 |
---|---|---|---|
0x01 | 读线圈 | 线圈 | 读 |
0x02 | 读离散输入 | 离散输入 | 读 |
0x03 | 读保持寄存器 | 保持寄存器 | 读 |
0x04 | 读输入寄存器 | 输入寄存器 | 读 |
0x05 | 写单个线圈 | 线圈 | 写 |
0x06 | 写单个保持寄存器 | 保持寄存器 | 写 |
0x0F | 写多个线圈 | 线圈 | 写 |
0x10 | 写多个保持寄存器 | 保持寄存器 | 写 |
6.5 Modbus RTU 帧结构
Modbus RTU是嵌入式系统中最常用的模式,它使用二进制表示数据,效率高。
- 从机地址: 1-247 (0为广播地址)。
- 功能码: 定义操作类型。
- 数据: 包含寄存器地址、数量、写入值等。
- CRC校验: 16位CRC,校验整个数据帧(不包括起始和结束符)。
帧间隔: RTU模式规定,帧内字符间隔不能超过1.5个字符时间,帧间间隔必须大于3.5个字符时间,用于区分不同的数据帧。
6.6 注意事项
- 地址映射: Modbus协议地址从0开始,但设备手册中的地址可能从1、30001或40001开始,需要注意转换。
- 字节序: Modbus标准为大端字节序(Big-Endian),即高位字节在前。
- CRC计算: 确保CRC计算的算法和初始值正确,这是通信成功的关键。
- 时间控制: RTU模式对帧间和帧内的时间间隔有严格要求,程序处理不当容易导致丢帧或粘包。
- 广播地址: 地址0为广播地址,所有从机都会接收,但不会响应。
7. MQTT协议 (Message Queuing Telemetry Transport)
7.1 协议简介
MQTT是一种基于发布/订阅 (Publish/Subscribe) 模式的轻量级消息协议,专为低带宽、高延迟或不稳定的网络环境设计。它运行在TCP/IP协议栈之上,已成为**物联网(IoT)**领域事实上的标准通信协议。
- 特点: 轻量、高效、可靠、支持实时消息传递。
- 通信模式: 发布/订阅模型,客户端之间通过一个中心代理(Broker)进行解耦通信。
- 核心概念:
- 代理 (Broker): 消息服务器,负责接收、过滤和分发消息。
- 客户端 (Client): 连接到代理的设备,可以发布消息或订阅主题。
- 主题 (Topic): 消息的分类标签,使用层级结构(如
sensor/living_room/temperature
)。 - 发布 (Publish): 客户端向特定主题发送消息。
- 订阅 (Subscribe): 客户端告诉代理它希望接收哪些主题的消息。
- 服务质量 (QoS):
- QoS 0 (最多一次): 消息尽力投递,可能丢失或重复。
- QoS 1 (至少一次): 保证消息至少到达一次,但可能重复。
- QoS 2 (恰好一次): 保证消息只到达一次,最可靠但开销最大。
7.2 工作原理
- 客户端(如传感器、App)连接到MQTT代理。
- 发布者(如温度传感器)将带有主题(
home/temperature
)和载荷(25.5
)的消息发送给代理。 - 代理将此消息转发给所有订阅了该主题的客户端(如手机App、数据服务器)。
发布者和订阅者无需知道对方的存在,实现了时间和空间的解耦。
7.3 应用场景
- 智能家居: 控制灯光、家电,接收传感器数据。
- 车联网: 车辆状态上报、远程指令下发。
- 工业物联网 (IIoT): 设备监控、数据采集。
- 即时通讯: 移动App的消息推送。
7.4 注意事项
- 代理选择: 需要一个稳定可靠的MQTT代理,可以是云服务(如EMQ X, Mosquitto)或自建。
- 主题设计: 合理规划主题层级结构,便于管理和扩展。
- 安全: 必须使用TLS/SSL加密连接,并进行客户端认证授权。
- 心跳机制: 通过Keep Alive机制维持连接,及时检测断线。
8. BLE (低功耗蓝牙)
8.1 协议简介
BLE (Bluetooth Low Energy) 是蓝牙技术联盟推出的一种专为低功耗、低成本、短距离无线通信设计的技术。它与传统蓝牙不兼容,但可以共存于同一芯片上。
- 特点: 极低功耗、启动连接快、成本低。
- 核心概念:
- GATT (Generic Attribute Profile): 定义了数据交换的结构和方式。是BLE应用开发的核心。
- 服务 (Service): 相关特征的集合,代表设备的一种功能(如“心率服务”)。
- 特征 (Characteristic): 具体的数据项,包含一个值和多个描述符(如“心率测量值”)。
- 角色:
- 中心设备 (Central): 主动扫描并连接外围设备(如手机、电脑)。
- 外围设备 (Peripheral): 被动广播并等待连接(如手环、传感器)。
- 广播 (Advertising): 外围设备向外发送数据包,让中心设备发现自己。
- 连接 (Connection): 中心设备和外围设备建立点对点连接,进行双向数据通信。
8.2 工作原理
外围设备(如智能手环)周期性地广播自身信息。中心设备(如手机)扫描到广播后,可以发起连接请求。连接建立后,中心设备可以通过读写外围设备的GATT特征值来进行数据交互(如读取步数、设置提醒)。
8.3 应用场景
- 可穿戴设备: 智能手表、手环、健康监测器。
- 智能家居: 智能门锁、温湿度传感器。
- 室内定位: 基于蓝牙信标(Beacon)的室内导航。
- 无线外设: 无线鼠标、键盘、遥控器。
8.4 注意事项
- 功耗管理: 合理设置广播间隔、连接间隔是实现低功耗的关键。
- 数据吞吐量: BLE的实际数据传输速率不高(通常几KB/s到几十KB/s),不适合大数据量传输。
- 兼容性: 确保手机或网关的蓝牙版本支持BLE。
- 配对与绑定: 为保证安全,需要进行加密配对和绑定。
9. LoRaWAN (远距离广域网)
9.1 协议简介
LoRaWAN (Long Range Wide Area Network) 是一种低功耗广域网(LPWAN)通信协议,基于LoRa物理层技术。它专为远距离、低速率、低功耗的物联网应用而设计。
- 特点: 传输距离远(市区1-5km,郊区可达15km以上)、功耗极低(电池可工作数年)、节点容量大。
- 网络架构: 星型拓扑结构。
- 终端节点 (End Device): 传感器等设备。
- 网关 (Gateway): 负责接收终端节点的数据,并通过IP网络转发给网络服务器。
- 网络服务器 (Network Server): 管理网络、处理数据、去重等。
- 应用服务器 (Application Server): 最终处理和展示数据的平台。
- 通信类别:
- Class A (必须支持): 双向通信,终端在每次上行后会打开两个短暂的接收窗口。最省电。
- Class B: 在Class A基础上,增加了额外的、可预知的接收窗口。
- Class C: 终端持续打开接收窗口,功耗最高,但延迟最低。
9.2 工作原理
终端节点(如智能水表)在需要时(或定时)唤醒,通过LoRa无线技术将数据发送给一个或多个网关。网关将收到的数据包通过互联网(如4G、以太网)转发到网络服务器。服务器处理后,再交给应用服务器进行分析和展示。
9.3 应用场景
- 智慧城市: 智能停车、智能垃圾桶、环境监测。
- 智慧农业: 土壤墒情、气象监测、牲畜追踪。
- 智能表计: 水、电、气表的自动远程抄送。
- 资产追踪: 对物流、贵重物品进行定位跟踪。
9.4 注意事项
- 数据速率: LoRaWAN的速率非常低(0.3kbps - 50kbps),不适合传输图片、视频等大数据。
- 频率规划: 不同国家和地区使用的ISM频段不同(如中国CN470,欧洲EU868)。
- 网络覆盖: 使用前需确认所在区域有LoRaWAN网关覆盖,或自建网关。
- 信道占用限制: ISM频段有占空比(Duty Cycle)限制,不能无限制地发送数据。
10. NFC (近场通信)
10.1 协议简介
NFC (Near Field Communication) 是一种短距离(通常<10cm)、高频的无线通信技术。它基于RFID技术发展而来,允许电子设备之间进行非接触式点对点数据交换。
- 特点: 连接建立快(小于0.1秒)、安全性高(距离极短)、功耗低。
- 工作模式:
- 读/写模式: NFC设备(如手机)读取或写入NFC标签(Tag)中的信息。
- 点对点模式 (P2P): 两台NFC设备可以相互交换数据。
- 卡模拟模式: 将NFC设备模拟成一张智能卡(如公交卡、门禁卡)。
10.2 工作原理
NFC基于电磁感应原理。当一个主动设备(通常有电源)靠近一个被动设备(无源标签)时,主动设备产生的电磁场可以为被动设备供电并进行数据交换。
10.3 应用场景
- 移动支付: Apple Pay, Google Pay等。
- 身份识别: 门禁卡、电子票务、防伪标签。
- 数据交换: 碰一碰分享图片、联系人。
- 快速配对: 碰一下NFC区域,快速完成蓝牙或Wi-Fi的配对连接。
10.4 注意事项
- 距离限制: 通信距离非常短,必须紧密接触。
- 天线设计: NFC天线的设计对通信性能影响极大。
- 数据量: 只适合传输少量数据。
- 兼容性: 不同的NFC标准(如ISO/IEC 14443 Type A/B)之间可能存在兼容性问题。
11. 通讯协议对比与选择
11.1 详细参数对比表
协议 | 距离 | 速度 | 节点数 | 复杂度 | 成本 | 线数/方式 | 全双工 | 应用场景 |
---|---|---|---|---|---|---|---|---|
UART | <15m | 中等 | 2 | 低 | 低 | 2线 | 是 | 调试、简单通信 |
SPI | <1m | 高 | 多个 | 中等 | 低 | 4线 | 是 | 高速外设、Flash、ADC |
I2C | <3m | 中等 | 127 | 中等 | 低 | 2线 | 否 | 芯片间通信、传感器 |
CAN | <1000m | 中等 | 110 | 高 | 中等 | 2线 | 否 | 汽车、工业控制 |
RS485 | <1200m | 中等 | 32 | 中等 | 中等 | 2线 | 否 | 工业现场总线 |
Modbus | 依赖物理层 | 中等 | 247 | 中(协议) | 低(软件) | 依赖物理层 | 否 | 工业自动化、SCADA |
MQTT | 依赖网络 | 高 | 海量 | 中(协议) | 低(软件) | 无线/有线 | 是 | 物联网(IoT)数据上云 |
BLE | <100m | 低 | 多个 | 高 | 低 | 无线 | 是 | 可穿戴、智能家居 |
LoRaWAN | >5km | 极低 | 海量 | 高 | 中等 | 无线 | 否 | 远距离、低功耗IoT |
NFC | <10cm | 低 | 2 | 中等 | 低 | 无线 | 否 | 移动支付、近场识别 |
12. 通用注意事项
- 电平匹配: 确保通信双方的逻辑电平兼容(如3.3V与5V)。
- 共地处理: 所有参与通信的设备必须有共同的参考地(GND),否则会导致电平判断错误。
- 阻抗匹配: 高速信号线(如CAN、RS485)需要终端电阻来匹配传输线阻抗,防止信号反射。
- EMC/EMI防护: 在恶劣电磁环境下,需要增加TVS管、磁珠、共模电感等防护器件。
- 软件健壮性: 软件设计需要充分考虑超时、错误重传、状态机恢复等异常处理机制。
13. 其他通讯协议简介
- LIN (Local Interconnect Network): 低成本的串行网络,用于汽车电子中对带宽和性能要求不高的场景,如车窗、座椅控制。
- Ethernet (以太网): 高速局域网技术,配合TCP/IP协议栈可实现复杂的网络通信,常用于物联网网关、高端嵌入式设备。
- USB (Universal Serial Bus): 通用的主机与设备连接标准,支持高速数据传输和即插即用,广泛用于消费电子和PC外设。
- 1-Wire (单总线): 仅需一根数据线即可实现通信和供电,适用于温度传感器(如DS18B20)等简单设备。
14. 总结
选择合适的通讯协议是嵌入式系统设计的关键一步。需要综合考虑传输距离、速率、成本、可靠性、节点数量和开发复杂度等因素。
- 芯片级: 优先考虑I2C、SPI。
- 板间短距离: UART是简单可靠的选择。
- 长距离、高可靠: CAN和RS485是工业标准。
- 应用层协议: Modbus是在RS485等物理层上实现可靠数据交换的优秀选择。
- 近距离无线: BLE是可穿戴和智能家居的首选,NFC适用于支付和快速配对。
- 物联网数据上云: MQTT是轻量、高效的标准选择。
- 远距离物联网: LoRaWAN在功耗和距离方面有巨大优势。
深入理解每种协议的物理层特性和协议层规范,是保证通信稳定可靠的基础。