嵌入式常用通讯协议详解

嵌入式常用通讯协议详解

📖 目录

基础通讯协议

  1. 串口通信 (UART/USART)
  2. SPI通信 (Serial Peripheral Interface)
  3. I2C通信 (Inter-Integrated Circuit)
  4. CAN总线 (Controller Area Network)
  5. RS485通信

应用层协议

  1. Modbus协议

无线与物联网协议

  1. MQTT协议 (Message Queuing Telemetry Transport)
  2. BLE (低功耗蓝牙)
  3. LoRaWAN (远距离广域网)
  4. NFC (近场通信)

选择与设计指南

  1. 通讯协议对比与选择
  2. 通用注意事项
  3. 其他通讯协议简介
  4. 总结

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四种工作模式详解
模式CPOLCPHA时钟空闲态数据采样边沿数据变化边沿常用设备
000低电平上升沿下降沿SD卡、W25Q Flash、多数设备
101低电平下降沿上升沿MAX1232、部分ADC
210高电平下降沿上升沿较少使用
311高电平上升沿下降沿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 工作原理

  1. 客户端(如传感器、App)连接到MQTT代理。
  2. 发布者(如温度传感器)将带有主题(home/temperature)和载荷(25.5)的消息发送给代理。
  3. 代理将此消息转发给所有订阅了该主题的客户端(如手机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中等22线调试、简单通信
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<10cm2中等无线移动支付、近场识别

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在功耗和距离方面有巨大优势。

深入理解每种协议的物理层特性和协议层规范,是保证通信稳定可靠的基础。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值