1. 先分清三个层次
日常所说的"串口"经常把三个不同层次混在一起:
text
应用协议:NMEA、AT 指令、Modbus-RTU、厂商二进制协议
UART 帧:波特率、数据位、校验位、停止位
物理接口:TTL/CMOS、RS-232、RS-422、RS-485
三者分别解决不同问题:
- 应用协议:一串字节分别表示什么,怎样判断一条消息结束;
- UART:一个字符怎样转换成起始位、数据位、校验位和停止位;
- 物理接口:逻辑 0 和逻辑 1 在线路上使用什么电压和接线方式传输。
UART、RS-232、RS-485 和 NMEA 不是同一层概念,不能相互替代。
#mermaid-svg-eTUx3jg1rTvP7YAl{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-eTUx3jg1rTvP7YAl .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-eTUx3jg1rTvP7YAl .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-eTUx3jg1rTvP7YAl .error-icon{fill:#552222;}#mermaid-svg-eTUx3jg1rTvP7YAl .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-eTUx3jg1rTvP7YAl .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-eTUx3jg1rTvP7YAl .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-eTUx3jg1rTvP7YAl .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-eTUx3jg1rTvP7YAl .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-eTUx3jg1rTvP7YAl .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-eTUx3jg1rTvP7YAl .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-eTUx3jg1rTvP7YAl .marker{fill:#333333;stroke:#333333;}#mermaid-svg-eTUx3jg1rTvP7YAl .marker.cross{stroke:#333333;}#mermaid-svg-eTUx3jg1rTvP7YAl svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-eTUx3jg1rTvP7YAl p{margin:0;}#mermaid-svg-eTUx3jg1rTvP7YAl .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-eTUx3jg1rTvP7YAl .cluster-label text{fill:#333;}#mermaid-svg-eTUx3jg1rTvP7YAl .cluster-label span{color:#333;}#mermaid-svg-eTUx3jg1rTvP7YAl .cluster-label span p{background-color:transparent;}#mermaid-svg-eTUx3jg1rTvP7YAl .label text,#mermaid-svg-eTUx3jg1rTvP7YAl span{fill:#333;color:#333;}#mermaid-svg-eTUx3jg1rTvP7YAl .node rect,#mermaid-svg-eTUx3jg1rTvP7YAl .node circle,#mermaid-svg-eTUx3jg1rTvP7YAl .node ellipse,#mermaid-svg-eTUx3jg1rTvP7YAl .node polygon,#mermaid-svg-eTUx3jg1rTvP7YAl .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-eTUx3jg1rTvP7YAl .rough-node .label text,#mermaid-svg-eTUx3jg1rTvP7YAl .node .label text,#mermaid-svg-eTUx3jg1rTvP7YAl .image-shape .label,#mermaid-svg-eTUx3jg1rTvP7YAl .icon-shape .label{text-anchor:middle;}#mermaid-svg-eTUx3jg1rTvP7YAl .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-eTUx3jg1rTvP7YAl .rough-node .label,#mermaid-svg-eTUx3jg1rTvP7YAl .node .label,#mermaid-svg-eTUx3jg1rTvP7YAl .image-shape .label,#mermaid-svg-eTUx3jg1rTvP7YAl .icon-shape .label{text-align:center;}#mermaid-svg-eTUx3jg1rTvP7YAl .node.clickable{cursor:pointer;}#mermaid-svg-eTUx3jg1rTvP7YAl .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-eTUx3jg1rTvP7YAl .arrowheadPath{fill:#333333;}#mermaid-svg-eTUx3jg1rTvP7YAl .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-eTUx3jg1rTvP7YAl .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-eTUx3jg1rTvP7YAl .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-eTUx3jg1rTvP7YAl .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-eTUx3jg1rTvP7YAl .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-eTUx3jg1rTvP7YAl .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-eTUx3jg1rTvP7YAl .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-eTUx3jg1rTvP7YAl .cluster text{fill:#333;}#mermaid-svg-eTUx3jg1rTvP7YAl .cluster span{color:#333;}#mermaid-svg-eTUx3jg1rTvP7YAl div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-eTUx3jg1rTvP7YAl .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-eTUx3jg1rTvP7YAl rect.text{fill:none;stroke-width:0;}#mermaid-svg-eTUx3jg1rTvP7YAl .icon-shape,#mermaid-svg-eTUx3jg1rTvP7YAl .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-eTUx3jg1rTvP7YAl .icon-shape p,#mermaid-svg-eTUx3jg1rTvP7YAl .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-eTUx3jg1rTvP7YAl .icon-shape .label rect,#mermaid-svg-eTUx3jg1rTvP7YAl .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-eTUx3jg1rTvP7YAl .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-eTUx3jg1rTvP7YAl .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-eTUx3jg1rTvP7YAl :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 应用协议
NMEA、AT、Modbus、自定义协议
UART 控制器
字符与比特帧转换
电平转换或差分收发器
物理线路
TTL/CMOS、RS-232、RS-422、RS-485
2. 什么是串行通信和 UART
2.1 串行通信
串行通信是指数据按照时间顺序,一个比特或一个符号接一个符号地传输。
它与并行通信的主要区别是:
- 并行通信同时使用多条数据线传输多个比特;
- 串行通信使用较少线路连续传输,布线更简单,也更容易用于较长距离。
串行通信是一个大类,UART、SPI、I²C、USB 和 CAN 都采用串行传输。嵌入式开发中口头所说的"串口",通常特指 UART 异步串口。
2.2 UART
UART 是 Universal Asynchronous Receiver/Transmitter,中文为"通用异步收发器"。
它负责:
- 把 CPU 提供的字符或字节转换成连续比特;
- 发送起始位、数据位、可选校验位和停止位;
- 从接收线上恢复一个字符;
- 检测帧错误、校验错误和接收溢出等异常。
UART 规定的是传输时序和帧格式,不规定线路必须使用 3.3 V、RS-232 或 RS-485。
3. UART 为什么叫"异步"
UART 通常没有单独的时钟线。发送端和接收端各自使用本地时钟,并提前设置相同的波特率。
接收端的基本工作过程是:
- 等待线路处于空闲状态;
- 检测到起始位;
- 按约定波特率计时;
- 在每个数据位的中间附近采样;
- 检查校验位和停止位;
- 将数据位组合成一个字符。
#mermaid-svg-bOvY0LVPtClukNMj{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-bOvY0LVPtClukNMj .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-bOvY0LVPtClukNMj .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-bOvY0LVPtClukNMj .error-icon{fill:#552222;}#mermaid-svg-bOvY0LVPtClukNMj .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-bOvY0LVPtClukNMj .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-bOvY0LVPtClukNMj .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-bOvY0LVPtClukNMj .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-bOvY0LVPtClukNMj .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-bOvY0LVPtClukNMj .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-bOvY0LVPtClukNMj .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-bOvY0LVPtClukNMj .marker{fill:#333333;stroke:#333333;}#mermaid-svg-bOvY0LVPtClukNMj .marker.cross{stroke:#333333;}#mermaid-svg-bOvY0LVPtClukNMj svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-bOvY0LVPtClukNMj p{margin:0;}#mermaid-svg-bOvY0LVPtClukNMj .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-bOvY0LVPtClukNMj .cluster-label text{fill:#333;}#mermaid-svg-bOvY0LVPtClukNMj .cluster-label span{color:#333;}#mermaid-svg-bOvY0LVPtClukNMj .cluster-label span p{background-color:transparent;}#mermaid-svg-bOvY0LVPtClukNMj .label text,#mermaid-svg-bOvY0LVPtClukNMj span{fill:#333;color:#333;}#mermaid-svg-bOvY0LVPtClukNMj .node rect,#mermaid-svg-bOvY0LVPtClukNMj .node circle,#mermaid-svg-bOvY0LVPtClukNMj .node ellipse,#mermaid-svg-bOvY0LVPtClukNMj .node polygon,#mermaid-svg-bOvY0LVPtClukNMj .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-bOvY0LVPtClukNMj .rough-node .label text,#mermaid-svg-bOvY0LVPtClukNMj .node .label text,#mermaid-svg-bOvY0LVPtClukNMj .image-shape .label,#mermaid-svg-bOvY0LVPtClukNMj .icon-shape .label{text-anchor:middle;}#mermaid-svg-bOvY0LVPtClukNMj .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-bOvY0LVPtClukNMj .rough-node .label,#mermaid-svg-bOvY0LVPtClukNMj .node .label,#mermaid-svg-bOvY0LVPtClukNMj .image-shape .label,#mermaid-svg-bOvY0LVPtClukNMj .icon-shape .label{text-align:center;}#mermaid-svg-bOvY0LVPtClukNMj .node.clickable{cursor:pointer;}#mermaid-svg-bOvY0LVPtClukNMj .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-bOvY0LVPtClukNMj .arrowheadPath{fill:#333333;}#mermaid-svg-bOvY0LVPtClukNMj .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-bOvY0LVPtClukNMj .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-bOvY0LVPtClukNMj .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-bOvY0LVPtClukNMj .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-bOvY0LVPtClukNMj .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-bOvY0LVPtClukNMj .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-bOvY0LVPtClukNMj .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-bOvY0LVPtClukNMj .cluster text{fill:#333;}#mermaid-svg-bOvY0LVPtClukNMj .cluster span{color:#333;}#mermaid-svg-bOvY0LVPtClukNMj div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-bOvY0LVPtClukNMj .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-bOvY0LVPtClukNMj rect.text{fill:none;stroke-width:0;}#mermaid-svg-bOvY0LVPtClukNMj .icon-shape,#mermaid-svg-bOvY0LVPtClukNMj .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-bOvY0LVPtClukNMj .icon-shape p,#mermaid-svg-bOvY0LVPtClukNMj .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-bOvY0LVPtClukNMj .icon-shape .label rect,#mermaid-svg-bOvY0LVPtClukNMj .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-bOvY0LVPtClukNMj .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-bOvY0LVPtClukNMj .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-bOvY0LVPtClukNMj :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 线路空闲
检测起始位
按波特率计时
采样数据位
检查校验位和停止位
输出一个字符
常见非反相 UART 的逻辑状态为:
- 空闲状态:逻辑 1;
- 起始位:逻辑 0;
- 停止位:逻辑 1。
接收器常采用多倍于波特率的时钟进行过采样,以提高起始位检测和采样的可靠性。具体过采样倍数由芯片实现决定,常见值包括 8 倍或 16 倍。
4. UART 帧是什么样的
一个 UART 字符通常按以下顺序发送:
text
空闲 → 起始位 → 数据位 → 可选校验位 → 停止位 → 空闲
以最常见的 8N1 为例:
text
1 个起始位 + 8 个数据位 + 无校验位 + 1 个停止位
多数 UART 先发送最低有效位,即 LSB first。
#mermaid-svg-x8dAHDdDybuBWBr1{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-x8dAHDdDybuBWBr1 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-x8dAHDdDybuBWBr1 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-x8dAHDdDybuBWBr1 .error-icon{fill:#552222;}#mermaid-svg-x8dAHDdDybuBWBr1 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-x8dAHDdDybuBWBr1 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-x8dAHDdDybuBWBr1 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-x8dAHDdDybuBWBr1 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-x8dAHDdDybuBWBr1 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-x8dAHDdDybuBWBr1 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-x8dAHDdDybuBWBr1 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-x8dAHDdDybuBWBr1 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-x8dAHDdDybuBWBr1 .marker.cross{stroke:#333333;}#mermaid-svg-x8dAHDdDybuBWBr1 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-x8dAHDdDybuBWBr1 p{margin:0;}#mermaid-svg-x8dAHDdDybuBWBr1 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-x8dAHDdDybuBWBr1 .cluster-label text{fill:#333;}#mermaid-svg-x8dAHDdDybuBWBr1 .cluster-label span{color:#333;}#mermaid-svg-x8dAHDdDybuBWBr1 .cluster-label span p{background-color:transparent;}#mermaid-svg-x8dAHDdDybuBWBr1 .label text,#mermaid-svg-x8dAHDdDybuBWBr1 span{fill:#333;color:#333;}#mermaid-svg-x8dAHDdDybuBWBr1 .node rect,#mermaid-svg-x8dAHDdDybuBWBr1 .node circle,#mermaid-svg-x8dAHDdDybuBWBr1 .node ellipse,#mermaid-svg-x8dAHDdDybuBWBr1 .node polygon,#mermaid-svg-x8dAHDdDybuBWBr1 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-x8dAHDdDybuBWBr1 .rough-node .label text,#mermaid-svg-x8dAHDdDybuBWBr1 .node .label text,#mermaid-svg-x8dAHDdDybuBWBr1 .image-shape .label,#mermaid-svg-x8dAHDdDybuBWBr1 .icon-shape .label{text-anchor:middle;}#mermaid-svg-x8dAHDdDybuBWBr1 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-x8dAHDdDybuBWBr1 .rough-node .label,#mermaid-svg-x8dAHDdDybuBWBr1 .node .label,#mermaid-svg-x8dAHDdDybuBWBr1 .image-shape .label,#mermaid-svg-x8dAHDdDybuBWBr1 .icon-shape .label{text-align:center;}#mermaid-svg-x8dAHDdDybuBWBr1 .node.clickable{cursor:pointer;}#mermaid-svg-x8dAHDdDybuBWBr1 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-x8dAHDdDybuBWBr1 .arrowheadPath{fill:#333333;}#mermaid-svg-x8dAHDdDybuBWBr1 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-x8dAHDdDybuBWBr1 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-x8dAHDdDybuBWBr1 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-x8dAHDdDybuBWBr1 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-x8dAHDdDybuBWBr1 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-x8dAHDdDybuBWBr1 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-x8dAHDdDybuBWBr1 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-x8dAHDdDybuBWBr1 .cluster text{fill:#333;}#mermaid-svg-x8dAHDdDybuBWBr1 .cluster span{color:#333;}#mermaid-svg-x8dAHDdDybuBWBr1 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-x8dAHDdDybuBWBr1 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-x8dAHDdDybuBWBr1 rect.text{fill:none;stroke-width:0;}#mermaid-svg-x8dAHDdDybuBWBr1 .icon-shape,#mermaid-svg-x8dAHDdDybuBWBr1 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-x8dAHDdDybuBWBr1 .icon-shape p,#mermaid-svg-x8dAHDdDybuBWBr1 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-x8dAHDdDybuBWBr1 .icon-shape .label rect,#mermaid-svg-x8dAHDdDybuBWBr1 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-x8dAHDdDybuBWBr1 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-x8dAHDdDybuBWBr1 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-x8dAHDdDybuBWBr1 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 空闲
1
起始位
0
D0
D1
...
D7
可选校验位
停止位
1
4.1 起始位
起始位通知接收端:
一个新字符开始了。
接收端利用空闲态到起始位的跳变建立当前帧的采样时刻。
4.2 数据位
数据位承载实际内容,常见为 7 位或 8 位。现代嵌入式设备大多使用 8 位。
4.3 校验位
常见设置为:
N:无校验;E:偶校验;O:奇校验。
奇偶校验只能发现一部分比特错误,不能代替 CRC 等更可靠的帧校验。
4.4 停止位
停止位让线路回到空闲状态,用于标记帧结束并提供一定时序余量。
常见为 1 位或 2 位。它的主要作用不是"让 CPU 休息",而是帮助接收端识别帧边界和重新同步。
5. 串口参数与有效速率
两个设备必须使用兼容的参数。
| 参数 | 常见值 | 作用 |
|---|---|---|
| 波特率 | 9600、38400、115200 等 | 决定线路符号传输速度 |
| 数据位 | 7、8 | 每帧承载的数据位数 |
| 校验位 | N、E、O | 进行简单错误检测 |
| 停止位 | 1、2 | 标记一帧结束 |
| 流控 | 无、RTS/CTS、XON/XOFF | 接收端忙时控制发送端暂停 |
115200 8N1 表示:
text
波特率 115200
8 个数据位
无校验
1 个停止位
5.1 波特率与比特率
波特率表示每秒传输多少个符号。
普通 UART 每个符号表示一个二进制位,所以波特率和线路比特率通常数值相等。但在一般通信理论中,两者不是永远相同。
5.2 一帧占多少时间
每个 UART 字符占用的总比特时间为:
Nframe=1+Ndata+Nparity+NstopN_{\text{frame}} = 1+N_{\text{data}}+N_{\text{parity}}+N_{\text{stop}}Nframe=1+Ndata+Nparity+Nstop
其中:
- NframeN_{\text{frame}}Nframe:一个字符占用的总比特时间数;
1:一个起始位;- NdataN_{\text{data}}Ndata:数据位数;
- NparityN_{\text{parity}}Nparity:校验位数,无校验时为 0;
- NstopN_{\text{stop}}Nstop:停止位数。
一个字符的理论传输时间为:
Tchar=NframeBT_{\text{char}} = \frac{N_{\text{frame}}}{B}Tchar=BNframe
其中:
- TcharT_{\text{char}}Tchar:一个字符的传输时间,单位为 s;
- BBB:波特率,单位为 Baud。
对 8N1:
Nframe=1+8+0+1=10N_{\text{frame}}=1+8+0+1=10Nframe=1+8+0+1=10
115200 Baud 时,理论最大字符速率约为:
11520010=11520 Byte/s\frac{115200}{10}=11520\ \text{Byte/s}10115200=11520 Byte/s
这个结果还没有扣除 NMEA、RTCM 或自定义协议中的帧头、长度、校验等开销。
5.3 流控
- 无流控:实现简单,但接收程序不及时可能丢数据;
- RTS/CTS:使用额外硬件引脚控制暂停和继续;
- XON/XOFF:在字节流中使用特殊控制字符。
对于任意二进制数据,使用 XON/XOFF 时必须确认协议是否进行了转义,否则有效数据可能被误认为流控字符。
6. 串口是字节流,消息边界要自己定义
从不同层次看:
- 物理线上传输的是比特;
- UART 控制器通常以字符或字节收发;
- 程序看到的是连续字节流;
- 上层协议负责把字节流恢复成完整消息。
串口驱动通常不保留应用程序的消息边界。一次 read() 可能得到:
- 半帧;
- 一帧;
- 多帧;
- 一帧末尾加下一帧开头。
因此:
不能把一次
read()等同于一条完整消息。
6.1 常见分帧方式
文本结束符
例如 NMEA 或 AT 指令常用:
text
\r\n
表示一行结束。
固定长度
每条消息始终包含固定字节数,解析简单,但扩展性较弱。
帧头、长度和校验
典型二进制结构:
text
帧头 | 消息类型 | 长度 | 数据区 | CRC
这是 GNSS 厂商二进制协议和许多自定义协议的常见做法。
6.2 推荐的接收流程
#mermaid-svg-YodqY08KaZAUmaor{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-YodqY08KaZAUmaor .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-YodqY08KaZAUmaor .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-YodqY08KaZAUmaor .error-icon{fill:#552222;}#mermaid-svg-YodqY08KaZAUmaor .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-YodqY08KaZAUmaor .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-YodqY08KaZAUmaor .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-YodqY08KaZAUmaor .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-YodqY08KaZAUmaor .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-YodqY08KaZAUmaor .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-YodqY08KaZAUmaor .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-YodqY08KaZAUmaor .marker{fill:#333333;stroke:#333333;}#mermaid-svg-YodqY08KaZAUmaor .marker.cross{stroke:#333333;}#mermaid-svg-YodqY08KaZAUmaor svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-YodqY08KaZAUmaor p{margin:0;}#mermaid-svg-YodqY08KaZAUmaor .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-YodqY08KaZAUmaor .cluster-label text{fill:#333;}#mermaid-svg-YodqY08KaZAUmaor .cluster-label span{color:#333;}#mermaid-svg-YodqY08KaZAUmaor .cluster-label span p{background-color:transparent;}#mermaid-svg-YodqY08KaZAUmaor .label text,#mermaid-svg-YodqY08KaZAUmaor span{fill:#333;color:#333;}#mermaid-svg-YodqY08KaZAUmaor .node rect,#mermaid-svg-YodqY08KaZAUmaor .node circle,#mermaid-svg-YodqY08KaZAUmaor .node ellipse,#mermaid-svg-YodqY08KaZAUmaor .node polygon,#mermaid-svg-YodqY08KaZAUmaor .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-YodqY08KaZAUmaor .rough-node .label text,#mermaid-svg-YodqY08KaZAUmaor .node .label text,#mermaid-svg-YodqY08KaZAUmaor .image-shape .label,#mermaid-svg-YodqY08KaZAUmaor .icon-shape .label{text-anchor:middle;}#mermaid-svg-YodqY08KaZAUmaor .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-YodqY08KaZAUmaor .rough-node .label,#mermaid-svg-YodqY08KaZAUmaor .node .label,#mermaid-svg-YodqY08KaZAUmaor .image-shape .label,#mermaid-svg-YodqY08KaZAUmaor .icon-shape .label{text-align:center;}#mermaid-svg-YodqY08KaZAUmaor .node.clickable{cursor:pointer;}#mermaid-svg-YodqY08KaZAUmaor .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-YodqY08KaZAUmaor .arrowheadPath{fill:#333333;}#mermaid-svg-YodqY08KaZAUmaor .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-YodqY08KaZAUmaor .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-YodqY08KaZAUmaor .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-YodqY08KaZAUmaor .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-YodqY08KaZAUmaor .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-YodqY08KaZAUmaor .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-YodqY08KaZAUmaor .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-YodqY08KaZAUmaor .cluster text{fill:#333;}#mermaid-svg-YodqY08KaZAUmaor .cluster span{color:#333;}#mermaid-svg-YodqY08KaZAUmaor div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-YodqY08KaZAUmaor .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-YodqY08KaZAUmaor rect.text{fill:none;stroke-width:0;}#mermaid-svg-YodqY08KaZAUmaor .icon-shape,#mermaid-svg-YodqY08KaZAUmaor .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-YodqY08KaZAUmaor .icon-shape p,#mermaid-svg-YodqY08KaZAUmaor .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-YodqY08KaZAUmaor .icon-shape .label rect,#mermaid-svg-YodqY08KaZAUmaor .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-YodqY08KaZAUmaor .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-YodqY08KaZAUmaor .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-YodqY08KaZAUmaor :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否
是
否
是
失败
成功
读取任意数量字节
追加到接收缓冲区
找到合法帧头?
丢弃无效前导字节
完整帧是否到齐?
检查长度和校验
移动位置并重新同步
输出完整帧
工程实现应限制最大帧长,并能在丢字节或校验失败后重新同步。
7. UART 与 TTL、RS-232、RS-422、RS-485
7.1 TTL/CMOS UART
常见 MCU 和 GNSS 模块直接提供 1.8 V、3.3 V 或 5 V 单端 UART。
特点:
- 适合板内或短距离连接;
- 线路简单;
- 抗干扰和远距离能力较弱。
"TTL 串口"是常用口语。许多 3.3 V MCU 实际使用的是 CMOS 电平。
7.2 RS-232
RS-232 使用单端电压,线路逻辑极性与普通 UART 引脚相反,需要专用收发器进行转换。
它通常用于:
- 传统电脑串口;
- 仪器仪表;
- 工控设备;
- 点对点通信。
RS-232 不能直接连接 MCU 的 UART 引脚。
7.3 RS-422
RS-422 使用差分信号,典型用途包括:
- 长距离点对点通信;
- 一发多收;
- 使用两对差分线的全双工通信。
7.4 RS-485
RS-485 也使用差分信号,适合多节点总线。
常见两线 RS-485 为半双工:
- 多个节点共享一对 A/B 线;
- 同一时刻通常只允许一个节点发送;
- 需要控制发送使能;
- 上层协议必须解决地址、应答和总线访问顺序。
| 接口 | 信号形式 | 常见拓扑 | 典型场景 |
|---|---|---|---|
| TTL/CMOS UART | 单端 | 短距离点对点 | MCU、GNSS 模块、调试口 |
| RS-232 | 单端 | 点对点 | 传统仪器、工控设备 |
| RS-422 | 差分 | 点对点或一发多收 | 长距离、全双工 |
| RS-485 | 差分 | 多点总线 | 工业现场、多设备组网 |
A/B 命名在不同厂商资料中可能不一致,接线时应以设备手册为准。
8. RS-485 需要掌握的基础布线原则
推荐使用一条主干总线,节点通过较短分支接入:
text
终端电阻 终端电阻
| |
---+---------+---------+---------+-------+---
| | |
节点1 节点2 节点3
基础原则:
- 终端电阻放在总线物理两端;
- 终端阻值应与线缆特性阻抗匹配,工程中常见约 120 Ω;
- 分支线尽量短;
- 避免长距离星形布线;
- 总线空闲状态不稳定时,应设置合适的偏置;
- 远距离或地电位差较大时,要考虑隔离和浪涌保护。
两线半双工 RS-485 的发送方向切换也很重要:
- 使能发送器;
- 写入数据;
- 等待 UART 最后一个停止位真正发完;
- 关闭发送器并释放总线。
仅等待软件发送缓冲区为空并不一定表示线路已经发送完成。
9. 电脑怎样连接板卡
9.1 先确认物理接口
连接前先确认板卡使用的是:
- 1.8 V、3.3 V 或 5 V UART;
- RS-232;
- RS-422;
- RS-485。
不能只根据"串口"名称或连接器外形判断。DB9 不一定永远是 RS-232,排针也不一定永远是 3.3 V UART。
9.2 USB-UART 接线
TTL/CMOS UART 的常见接线为:
text
USB-UART TX → 板卡 RX
USB-UART RX ← 板卡 TX
USB-UART GND ─ 板卡 GND
注意:
- TX 和 RX 交叉连接;
- 双方需要共同参考地;
- 电压必须兼容;
- 通信通常只需要 TX、RX、GND,不要在不明确用途时随意连接 VCC。
若对方是 RS-232、RS-422 或 RS-485,应使用对应的 USB 转换器,不能直接使用 USB-UART 模块。
9.3 端口名称
Windows 中常见为:
text
COM3、COM4......
Linux 中常见为:
text
/dev/ttyUSB0
/dev/ttyACM0
打不开串口时,应检查端口权限、驱动、占用情况和串口参数。
10. GNSS 设备中的串口数据
10.1 NMEA 文本
NMEA 语句通常为 ASCII 文本,例如:
text
$GNGGA,...*CS\r\n
其中:
$:语句起始;GNGGA:消息类型;*CS:校验字段;\r\n:语句结束。
NMEA 便于人工查看,适合输出位置、时间、卫星数量和定位状态。
10.2 RTCM 与厂商二进制协议
GNSS 接收机还可能通过串口输出:
- RTCM 改正数据;
- 原始观测数据;
- 导航电文;
- 厂商私有二进制消息;
- 组合导航或 IMU 数据。
这类协议通常使用:
text
帧头 + 消息类型 + 长度 + 负载 + 校验
解析程序必须处理半帧、多帧、错误长度、校验失败和重新同步。
10.3 波特率是否够用
115200 8N1 的理论上限约为 11520 Byte/s。
若同时输出:
- 多系统多频原始观测;
- 高频定位结果;
- RTCM 数据;
- 多种调试信息;
应估算总数据量,并预留突发和协议开销。带宽不足时可以:
- 提高波特率;
- 降低输出频率;
- 关闭不需要的消息;
- 改用 USB 或以太网。
NMEA 0183 船舶接口虽然也传输 NMEA 文本,但其物理电气接口通常是差分形式,不能直接等同于 GNSS 模块的 TTL/CMOS UART。
11. 常见错误与排查顺序
11.1 常见 UART 错误
- 帧错误:停止位位置没有检测到正确电平;
- 校验错误:奇偶校验结果不匹配;
- 接收溢出:软件尚未读取旧数据,新数据已经到达;
- Break:线路保持起始位电平超过一个正常字符时间。
11.2 排查顺序
第一步:接口和电平
- 是 UART、RS-232、RS-422 还是 RS-485?
- 电压等级是否匹配?
- 是否需要电平转换或隔离?
第二步:接线
- TX 是否连接 RX?
- 是否共地?
- RS-485 A/B 是否接反?
- 是否有多个节点同时发送?
第三步:参数
- 波特率;
- 数据位;
- 校验位;
- 停止位;
- 流控。
第四步:软件
- 端口是否被占用?
- 接收线程是否及时读取?
- 缓冲区是否溢出?
- 是否错误地把一次
read()当作完整帧? - 是否把二进制数据当作文本字符串处理?
第五步:协议
- 帧头和长度是否正确?
- 字节序是否一致?
- CRC 或校验和算法是否一致?
- 文本结束符是
\r\n、\n还是\r?
必要时使用:
- 回环测试;
- 逻辑分析仪;
- 示波器;
- 原始十六进制日志。
12. 网络串口是什么
串口本身不依赖网络。串口服务器只是把串口字节流封装成 TCP 或 UDP 数据:
#mermaid-svg-kQRnAezmkOjofcQr{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-kQRnAezmkOjofcQr .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-kQRnAezmkOjofcQr .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-kQRnAezmkOjofcQr .error-icon{fill:#552222;}#mermaid-svg-kQRnAezmkOjofcQr .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-kQRnAezmkOjofcQr .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-kQRnAezmkOjofcQr .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-kQRnAezmkOjofcQr .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-kQRnAezmkOjofcQr .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-kQRnAezmkOjofcQr .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-kQRnAezmkOjofcQr .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-kQRnAezmkOjofcQr .marker{fill:#333333;stroke:#333333;}#mermaid-svg-kQRnAezmkOjofcQr .marker.cross{stroke:#333333;}#mermaid-svg-kQRnAezmkOjofcQr svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-kQRnAezmkOjofcQr p{margin:0;}#mermaid-svg-kQRnAezmkOjofcQr .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-kQRnAezmkOjofcQr .cluster-label text{fill:#333;}#mermaid-svg-kQRnAezmkOjofcQr .cluster-label span{color:#333;}#mermaid-svg-kQRnAezmkOjofcQr .cluster-label span p{background-color:transparent;}#mermaid-svg-kQRnAezmkOjofcQr .label text,#mermaid-svg-kQRnAezmkOjofcQr span{fill:#333;color:#333;}#mermaid-svg-kQRnAezmkOjofcQr .node rect,#mermaid-svg-kQRnAezmkOjofcQr .node circle,#mermaid-svg-kQRnAezmkOjofcQr .node ellipse,#mermaid-svg-kQRnAezmkOjofcQr .node polygon,#mermaid-svg-kQRnAezmkOjofcQr .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-kQRnAezmkOjofcQr .rough-node .label text,#mermaid-svg-kQRnAezmkOjofcQr .node .label text,#mermaid-svg-kQRnAezmkOjofcQr .image-shape .label,#mermaid-svg-kQRnAezmkOjofcQr .icon-shape .label{text-anchor:middle;}#mermaid-svg-kQRnAezmkOjofcQr .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-kQRnAezmkOjofcQr .rough-node .label,#mermaid-svg-kQRnAezmkOjofcQr .node .label,#mermaid-svg-kQRnAezmkOjofcQr .image-shape .label,#mermaid-svg-kQRnAezmkOjofcQr .icon-shape .label{text-align:center;}#mermaid-svg-kQRnAezmkOjofcQr .node.clickable{cursor:pointer;}#mermaid-svg-kQRnAezmkOjofcQr .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-kQRnAezmkOjofcQr .arrowheadPath{fill:#333333;}#mermaid-svg-kQRnAezmkOjofcQr .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-kQRnAezmkOjofcQr .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-kQRnAezmkOjofcQr .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kQRnAezmkOjofcQr .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-kQRnAezmkOjofcQr .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kQRnAezmkOjofcQr .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-kQRnAezmkOjofcQr .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-kQRnAezmkOjofcQr .cluster text{fill:#333;}#mermaid-svg-kQRnAezmkOjofcQr .cluster span{color:#333;}#mermaid-svg-kQRnAezmkOjofcQr div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-kQRnAezmkOjofcQr .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-kQRnAezmkOjofcQr rect.text{fill:none;stroke-width:0;}#mermaid-svg-kQRnAezmkOjofcQr .icon-shape,#mermaid-svg-kQRnAezmkOjofcQr .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kQRnAezmkOjofcQr .icon-shape p,#mermaid-svg-kQRnAezmkOjofcQr .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-kQRnAezmkOjofcQr .icon-shape .label rect,#mermaid-svg-kQRnAezmkOjofcQr .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kQRnAezmkOjofcQr .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-kQRnAezmkOjofcQr .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-kQRnAezmkOjofcQr :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} UART/RS-232/RS-485
TCP 或 UDP
串口设备
串口服务器
IP 网络
远程程序
- TCP 保证顺序和可靠传输,但仍然是字节流,不提供应用消息边界;
- UDP 开销小,但可能丢包、重复或乱序。
因此:
本地串口通信不依赖网络;通过串口服务器远程通信时,整体链路才依赖网络质量。
13. 初学者应掌握的核心结论
- 串行通信是大类,嵌入式"串口"通常指 UART。
- UART 没有独立时钟线,依靠起始位和约定波特率同步。
8N1传输 1 Byte 通常需要 10 个比特时间。- 程序看到的是连续字节流,消息边界必须由协议定义。
- UART、TTL/CMOS、RS-232、RS-422、RS-485 分属不同层次。
- TTL/CMOS UART 接线通常需要 TX、RX 和 GND,且电压必须兼容。
- 两线 RS-485 通常为半双工,需要正确的拓扑、终端匹配和方向控制。
- GNSS 的 NMEA、RTCM 和厂商二进制协议都需要正确分帧。
- 排查问题时,依次检查接口、电平、接线、参数、软件缓冲和协议。
一句话概括:
先保证电气接口安全兼容,再保证 UART 参数一致,最后从连续字节流中正确恢复完整协议帧。