UART通信原理深度解析:从物理层到寄存器配置
1. 这不是“串口调试助手”里的简单收发——UART是嵌入式系统里最沉默却最频繁的呼吸节奏你拆开手边任何一块智能硬件智能电表、工业PLC、车载T-BOX、甚至你刚买的蓝牙耳机主板几乎都能在芯片边缘找到几组标着TX/RX的焊盘。它们不发光、不发热、不显眼但每秒都在完成数十万次数据吞吐——这就是UARTUniversal Asynchronous Receiver/Transmitter在工作。它不像USB那样需要枚举、握手、协议栈也不像以太网那样要处理MAC地址、CRC校验、冲突检测它只做一件事把并行数据按固定时序一字节一字节地“推”出去再一字节一字节地“接”回来。这种极致的简洁让它成为MCU与传感器、MCU与Wi-Fi模块、MCU与PC之间最底层、最可靠、最省资源的通信纽带。我做过三年工控设备固件开发手上经手过27款不同主控芯片STM32F4/F7/H7、NXP i.MX RT系列、GD32E50x、ESP32-C3所有项目启动的第一步永远是配置UART1作为调试日志输出通道——不是因为它是最快的而是因为它最“诚实”只要波特率对得上、电平匹配、线没接反它就一定有回响。今天这讲我们不讲“怎么用串口助手发AT指令”而是回到芯片引脚和逻辑电平的物理层一层层剥开异步串行通信的骨架为什么叫“异步”起始位/停止位到底在“同步”什么为什么8N1是默认配置波特率误差超过3%就会丢包FT232R和CP2104驱动安装失败根源其实在Windows内核的串口资源仲裁机制里。这些细节教科书不会写但你在产线上调通第一块板子时全靠它们救命。2. 异步串行通信的本质没有时钟线靠约定和守时达成默契2.1 “异步”的真实含义——不是“不守时”而是“不共享时钟”很多人一看到“异步”下意识觉得是“时间不严格”“可以随便发”。这是最大误区。UART恰恰是最讲时间纪律的通信方式之一。所谓“异步”指的是发送方和接收方不共享同一根时钟信号线对比SPI的SCLK、I2C的SCL。没有这根“指挥棒”双方必须各自拥有一块足够精准的“手表”并提前约定好“看表”的节奏——也就是波特率Baud Rate。这个约定就是整个通信成立的前提。我们来算一笔账假设波特率设为115200bps意味着每秒传输115200个比特bit。那么每个比特持续的时间就是T_bit 1 / 115200 ≈ 8.68μs接收方内部有一个采样时钟通常是波特率的16倍或32倍它会在每个比特周期的中间位置比如第8个采样点对RX线电平进行采样。如果发送方和接收方的时钟偏差太大采样点就会逐渐漂移最终落在比特的上升沿或下降沿附近——那里电平不稳定极易误判。行业经验表明当双方时钟误差总和超过±3%时第10位停止位前的最后一位数据位的采样就可能出错。这也是为什么单片机手册里反复强调选择晶振频率时要优先考虑能否生成标准波特率的整数倍分频值。例如用8MHz晶振生成115200bps分频系数是8,000,000 / (16 × 115200) ≈ 4.34非整数必然引入误差而换成7.3728MHz晶振计算结果正好是4误差为0。提示实测中STM32F4系列使用HSI16MHz内部RC时115200bps波特率误差约2.1%勉强可用但若用HSI生成921600bps误差飙升至15%根本无法通信。务必查对应芯片的《Reference Manual》中USART章节的“Baud rate generation”表格。2.2 帧结构起始位、数据位、校验位、停止位——一个字节的“护照”全要素UART传输的最小单位不是字节而是一帧Frame。一帧数据就像一张完整的“电子护照”包含身份识别、内容主体、防伪校验和出境盖章四个部分起始位Start Bit固定为逻辑低电平0持续1个比特时间。它的唯一作用是告诉接收方“注意新数据来了”——相当于敲门声。没有它接收方永远不知道该从哪一刻开始计时采样。数据位Data Bits5~9位最常用的是8位即一个标准字节。数据从最低位LSB开始发送。比如发送字符‘A’ASCII码0x41二进制01000001实际在线路上的顺序是1→0→0→0→0→0→1→0注意反转。校验位Parity Bit可选用于简单错误检测。奇校验Odd Parity要求整帧数据位校验位中1的个数为奇数偶校验Even Parity则要求为偶数。现代应用中因CRC校验更可靠校验位多被禁用即“None”缩写为N形成“8N1”这一黄金组合。停止位Stop Bit1~2个比特时间的高电平1标志本帧结束。它不仅是“句号”更是为接收方争取时间从采样最后一个数据位到准备接收下一帧的起始位需要足够时间重置内部状态机。实践中1位停止位足够只有在极低速如1200bps或长距离RS-485通信时才考虑2位以增强抗干扰能力。我们用逻辑分析仪抓取一段真实UART波形115200bps, 8N1[Start] [D0] [D1] [D2] [D3] [D4] [D5] [D6] [D7] [Stop] 0 1 0 0 0 0 0 1 0 1你会发现起始位后紧跟的是D0LSB而非D7。这个“低位先行”规则是所有UART硬件的铁律也是初学者最容易写反的地方——如果你在Verilog里实现UART TX忘了对数据总线做bit-reversal发出去的永远是乱码。2.3 电平标准TTL、RS-232、RS-485——同一协议三种“方言”UART协议本身只定义了逻辑时序何时采样、如何组织帧不规定物理电平。这就导致同一套UART逻辑在不同场景下需要“翻译”成不同的电压语言TTL电平MCU直连最常见于芯片间通信。逻辑1 3.3V或5V逻辑0 0V。特点是成本低、速度快可达几Mbps但传输距离短1米抗干扰差。你用杜邦线直接连STM32的PA9(TX)到CH340的RX引脚用的就是TTL。RS-232电平传统PC串口逻辑1 -3V ~ -15V逻辑0 3V ~ 15V。通过电平转换芯片如MAX232实现。优点是抗干扰强、支持15米传输缺点是功耗大、需双电源±12V。现在虽已淘汰但老式工控设备、医疗仪器仍大量使用。注意RS-232的“TX/RX”定义与TTL相反——PC的TX是输出接MCU的RXPC的RX是输入接MCU的TX。接反必不通。RS-485电平工业总线采用差分信号A/B两线逻辑1 AB200mV逻辑0 AB-200mV。最大优势是共模抑制比高、支持1200米传输、可挂载32个节点加中继器可扩展。但它不是点对点协议需要额外的使能控制DE/RE引脚来切换发送/接收状态。很多开发者第一次用RS-485通电后发现所有节点都在“抢麦”——就是因为忘了在发送前拉高DE发送后拉低DE。注意FT232R/FT231X/CP2104这类USB转UART芯片本质是“USB协议栈 UART控制器 TTL电平驱动”。它们输出的RX/TX是标准TTL电平不能直接接RS-232或RS-485。想连老式设备必须加MAX232想连PLC必须加SP3485。驱动安装失败90%是因为Windows把USB设备识别成了“未知设备”根源在于INF文件未正确签名或USB描述符VID/PID不匹配——这不是UART协议问题而是Windows驱动模型的权限问题。3. UART硬件架构与寄存器级配置从外设到代码的完整映射3.1 MCU内部UART模块的“五脏六腑”以STM32F407为例其USART外设并非简单收发器而是一个高度集成的状态机系统核心组件包括波特率发生器BRR由APB总线时钟PCLK分频得到。BRR寄存器值 DIV_Mantissa DIV_Fraction/16。其中DIV_Mantissa是整数部分DIV_Fraction是小数部分4位。计算公式为USARTDIV (PCLK / (16 * BaudRate)) BRR (DIV_Mantissa 4) | DIV_Fraction例如PCLK42MHz目标波特率115200USARTDIV 42,000,000 / (16 * 115200) ≈ 22.88 → DIV_Mantissa22, DIV_Fraction0.88*16≈14 → BRR0x16E发送移位寄存器TDR与发送数据寄存器TDRCPU写入TDR的数据会先缓存在发送保持寄存器THR再由移位寄存器逐位推出TX线。当TDR为空时TXETransmit Data Register Empty标志置1当移位寄存器也空时TCTransmission Complete标志置1。接收移位寄存器RDR与接收数据寄存器RDRRX线上的比特流被移入RDR当一帧接收完毕RXNERead Data Register Not Empty标志置1CPU可读取RDR获取数据。状态寄存器SR这是调试UART的灵魂。除了TXE/RXNE/TC还有OREOverrun Error新数据到达时RDR尚未被读取旧数据被覆盖。说明你的中断服务程序ISR响应太慢或未及时清空RDR。FEFraming Error停止位不是高电平。原因可能是波特率严重不匹配、线路干扰、或对方发送端异常复位。PEParity Error校验失败。仅在校验位使能时有效。3.2 配置流程四步走缺一不可我总结了一套“UART初始化四步法”在所有ARM Cortex-M芯片上通用第一步使能时钟与GPIO复用// STM32 HAL库示例 __HAL_RCC_USART1_CLK_ENABLE(); // 使能USART1时钟 __HAL_RCC_GPIOA_CLK_ENABLE(); // 使能PA端口时钟 GPIO_InitStruct.Pin GPIO_PIN_9 | GPIO_PIN_10; // PA9TX, PA10RX GPIO_InitStruct.Mode GPIO_MODE_AF_PP; // 复用推挽输出 GPIO_InitStruct.Pull GPIO_PULLUP; // RX线需上拉防干扰 GPIO_InitStruct.Speed GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate GPIO_AF7_USART1; // AF7对应USART1 HAL_GPIO_Init(GPIOA, GPIO_InitStruct);关键细节RX引脚必须配置为GPIO_PULLUP否则在空闲时高电平线路易受电磁干扰翻转导致接收方误触发起始位。我曾为一个野外监测站调试连续三天收不到数据最后发现是PCB上RX焊盘漏了上拉电阻——加一颗10kΩ贴片电阻问题立解。第二步配置USART参数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.CLKPhase UART_PHASE_1EDGE; // 采样边沿通常默认 huart1.Init.CLKPolarity UART_POLARITY_LOW; // 时钟极性同上 huart1.Init.HwFlowCtl UART_HWCONTROL_NONE; // 硬件流控关闭 huart1.Init.OverSampling UART_OVERSAMPLING_16;// 16倍过采样标准 if (HAL_UART_Init(huart1) ! HAL_OK) { Error_Handler(); // 初始化失败处理 }实操心得OverSampling设为16还是8直接影响抗干扰能力。16倍采样在噪声环境下更稳但会略微降低最大波特率上限8倍采样允许更高波特率如3Mbps但对PCB布线要求苛刻。我的原则是工业现场一律用16消费类高速产品如蓝牙音频才考虑8。第三步使能中断或DMA// 中断方式适合低速、小数据量 HAL_UART_Receive_IT(huart1, rx_buffer, 1); // 单字节接收中断 // 或DMA方式适合高速、大数据量如固件升级 hdma_usart1_rx.Instance DMA2_Stream2; hdma_usart1_rx.Init.Channel DMA_CHANNEL_4; hdma_usart1_rx.Init.Direction DMA_PERIPH_TO_MEMORY; hdma_usart1_rx.Init.FIFOMode DMA_FIFOMODE_DISABLE; HAL_DMA_Init(hdma_usart1_rx); __HAL_LINKDMA(huart1, hdmarx, hdma_usart1_rx); HAL_UART_Receive_DMA(huart1, rx_buffer, BUFFER_SIZE);警告DMA接收必须配合环形缓冲区Ring Buffer否则数据溢出时DMA会自动停止。我见过太多项目用DMA接收GPS NMEA语句因未处理缓冲区满导致定位信息丢失——解决方案是在DMA传输完成中断TCIE中将hdma-Instance-NDTR剩余数据数与hdma-Init.BufferSize比较动态调整下一个DMA传输长度。第四步编写中断服务程序ISRvoid USART1_IRQHandler(void) { uint32_t isrflags __HAL_USART_GET_FLAG(huart1, USART_FLAG_RXNE); uint32_t cr1its __HAL_USART_GET_IT_SOURCE(huart1, USART_IT_RXNE); if (isrflags cr1its) { uint8_t data (uint8_t)(huart1.Instance-RDR 0xFFU); // 将data存入环形缓冲区 ring_buffer_push(rx_ring, data); // 清除RXNE标志读RDR自动清除 } }核心原则ISR里只做最轻量操作绝不在此解析协议、不调用printf、不操作外设。所有复杂逻辑放到主循环或RTOS任务中处理。我曾优化过一个电机控制器将原本在ISR里做的Modbus CRC校验移到任务中中断响应时间从8.2μs降至1.3μs彻底解决了PWM波形抖动问题。4. USB转UART桥接芯片深度解析FT232R、CP2104、FT231X的选型实战4.1 三款主流芯片的核心差异与适用场景特性FT232R (FTDI)CP2104 (Silicon Labs)FT231X (FTDI)USB协议版本USB 2.0 Full SpeedUSB 2.0 Full SpeedUSB 2.0 Full Speed最大波特率3Mbps2Mbps3Mbps供电能力5V 50mA (VCCIO)3.3V 100mA (VDD)3.3V 100mA (VDD)GPIO数量3个CBUS4个GPIO3个CBUS驱动兼容性Windows/macOS/Linux全平台但Win10需手动禁用驱动签名强制Windows 10/11原生支持无需额外驱动同FT232R但Win11需更新驱动关键优势成熟稳定文档齐全支持EEPROM定制PID/VID成本最低集成度高内置LDO封装更小QFN-20功耗更低选型决策树量产产品成本敏感且需快速上市→ 选CP2104。它的BOM成本比FT232R低40%且Windows 10/11免驱极大降低客户支持压力。我负责的一款智能插座用CP2104替代FT232R单台BOM节省1.2年出货200万台直接省下240万元。工业设备要求长期供货、极端环境稳定性→ 选FT232R。FTDI芯片的工业级型号如FT232RL工作温度范围-40℃~85℃而CP2104商业级仅0℃~70℃。某油田RTU项目CP2104在-25℃环境下批量失效换FT232RL后零故障。便携设备空间极度受限如TWS耳机调试板→ 选FT231X。其QFN-20封装尺寸仅3mm×3mm比FT232R的SSOP-2810.2mm×5.3mm小85%。但要注意FT231X的VDD必须严格为3.3V不能像FT232R那样接受4.35V~5.25V宽压输入。4.2 驱动安装失败的终极排查指南网络上90%的“FT232R驱动安装失败”问题其实都源于同一个Windows机制驱动程序强制签名验证Driver Signature Enforcement。尤其在Win10 1809之后和Win11微软默认开启此功能而FTDI官方驱动v2.12.28.4之前未通过WHQL认证会被系统拦截。三步强制安装法亲测有效临时禁用驱动签名开机时按F8或Shift重启→疑难解答→高级选项→启动设置→重启→按7进入“禁用驱动程序强制签名”模式此时运行FTDI官网下载的CDM v2.12.28.4.exe安装成功永久解决推荐下载最新版驱动v2.12.28.4它已通过WHQL认证或使用Silicon Labs官网的CP2104驱动v6.15.0同样免驱注册表终极方案管理员权限Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CI\Policy] CertEnforcementPolicydword:00000000注意修改注册表有风险务必先导出备份。此操作等效于全局关闭驱动签名仅建议在开发机使用生产环境切勿如此。硬件级故障排除设备管理器显示“未知设备”用USBlyzer工具抓包看VID/PID是否为0403:6001FT232R或10C4:EA60CP2104。若显示FFFF:FFFF说明芯片损坏或焊接虚焊。端口能识别但无法通信用万用表测TX/RX对地电压。正常空闲时应为3.3VTTL高电平。若为0V检查芯片VCC是否供电、RESET引脚是否被拉低、或PCB上TX/RX线是否短路。4.3 从USB到UART的信号链路与时序真相很多人以为USB转UART只是“协议转换”实际上它是一条三级流水线USB端Host侧PC操作系统通过USB协议栈将数据打包成USB Bulk Transfer数据包最大64字节发送给FT232R。桥接芯片内部FT232RFT232R的USB控制器接收数据包存入内部FIFO1KB再由UART控制器以设定波特率逐字节推出TX引脚。UART端Device侧MCU的RX引脚接收比特流经采样、帧校验后存入RDR寄存器。这个过程引入了确定性延迟USB Bulk传输的调度延迟Windows下平均2~5msFT232R内部FIFO填充/清空延迟取决于数据量1字节约10μs1KB满载时达10ms因此从PC发出一个字节到MCU收到典型延迟为3~15ms。这意味着你用串口助手发“ATRST”ESP32收到后执行重启再返回“OK”整个过程至少要等30ms以上。若你的协议设计成“发一帧等一帧应答”这个延迟会累积——这就是为什么工业Modbus RTU要求从站响应时间≤100ms而USB转UART方案常被诟病“实时性差”。实战技巧若需降低延迟可在FT232R的EEPROM中配置FTDI Latency Timer默认16ms。将其改为1ms需用FT_PROG工具可将平均延迟压缩至2~3ms。但代价是CPU占用率升高——这是用计算资源换时间的典型trade-off。5. UART协议栈实战从裸机轮询到RTOS消息队列的演进路径5.1 裸机开发轮询、中断、DMA——三种模式的性能与适用边界轮询模式Pollingwhile (1) { if (__HAL_UART_GET_FLAG(huart1, UART_FLAG_RXNE)) { uint8_t data huart1.Instance-RDR; process_byte(data); } }优点代码极简无中断开销确定性高缺点CPU 100%忙等无法处理其他任务波特率115200时可能漏字节适用场景超低成本MCU如STM8、单功能设备如温控器、教学演示中断模式Interrupt// 在ISR中仅存入环形缓冲区 void USART1_IRQHandler(void) { if (__HAL_UART_GET_FLAG(huart1, UART_FLAG_RXNE)) { uint8_t data huart1.Instance-RDR; ring_buffer_push(rx_buf, data); } } // 主循环中解析 while (ring_buffer_available(rx_buf) FRAME_LEN) { uint8_t frame[FRAME_LEN]; ring_buffer_read(rx_buf, frame, FRAME_LEN); parse_modbus_frame(frame); }优点CPU利用率高可同时处理多个外设缺点高波特率下1Mbps频繁中断导致上下文切换开销大缓冲区管理不当易溢出适用场景中等复杂度产品如智能家居网关、实时性要求不苛刻的场合DMA模式Direct Memory Access// 配置双缓冲DMA实现无缝接收 hdma_usart1_rx.Init.MemInc DMA_MINC_ENABLE; hdma_usart1_rx.Init.PeriphInc DMA_PINC_DISABLE; HAL_DMA_Start(hdma_usart1_rx, (uint32_t)huart1.Instance-RDR, (uint32_t)rx_buffer_a, BUFFER_SIZE); // 在DMA半传输中断中处理buffer_a的前半部分 // 在DMA全传输中断中处理buffer_a的后半部分并切换到buffer_b优点CPU完全解放理论吞吐量达波特率极限适合大数据流如图像传输、固件OTA缺点代码复杂调试困难需精确计算缓冲区大小避免DMA溢出适用场景高速数据采集如示波器、无线模块透传如LoRaWAN网关我的选型经验在FreeRTOS项目中中断消息队列是最佳平衡点。将每个接收到的字节或一帧通过xQueueSendFromISR()发送到队列由独立任务解析。这样既保证了实时性又实现了模块解耦。曾有一个项目用中断模式处理Modbus当网络风暴导致大量请求涌入时ISR堆积导致系统卡死改用消息队列后任务可主动限流系统稳定性提升300%。5.2 协议解析引擎状态机设计的黄金法则UART本身不定义应用层协议但几乎所有实际项目都需要解析特定协议Modbus RTU、NMEA-0183、自定义AT指令。这里分享一个经过20项目验证的分层状态机设计法Layer 1字节接收层Byte-Level FSM职责过滤掉帧头/帧尾之外的垃圾数据确保输入到解析层的数据是“干净”的一帧。typedef enum { IDLE, WAIT_START, IN_FRAME, WAIT_STOP } rx_state_t; rx_state_t state IDLE; uint8_t frame[256]; uint8_t len 0; void byte_received(uint8_t data) { switch(state) { case IDLE: if (data 0xAA) { // 自定义帧头 frame[0] data; len 1; state WAIT_START; } break; case WAIT_START: if (data 0x55) { frame[len] data; state IN_FRAME; } else { state IDLE; // 重置 } break; case IN_FRAME: if (len sizeof(frame)) { frame[len] data; if (len expected_length) { state WAIT_STOP; } } break; case WAIT_STOP: if (data 0xCC) { // 帧尾 process_frame(frame, len); } state IDLE; break; } }Layer 2帧解析层Frame-Level FSM职责校验CRC、提取命令字、分发到具体处理函数。void process_frame(uint8_t *frame, uint8_t len) { uint16_t crc_calc calc_crc16(frame, len-2); uint16_t crc_recv (frame[len-2] 8) | frame[len-1]; if (crc_calc crc_recv) { uint8_t cmd frame[2]; switch(cmd) { case CMD_READ_TEMP: send_temp_response(); break; case CMD_SET_LED: set_led_state(frame[3]); break; } } }Layer 3业务逻辑层Application Layer职责执行具体操作与硬件驱动交互。这一层应完全 unaware of UART只接收结构化参数。关键心得永远不要在状态机里写业务逻辑我曾接手一个遗留项目其Modbus解析代码里混杂了LED控制、电机启停等操作导致协议升级时牵一发而动全身。重构后状态机只负责“喂数据”业务层只负责“干活”两者通过结构体解耦后续增加CAN协议支持只需替换状态机业务层0修改。5.3 常见问题与硬核排查技巧实录问题1串口助手能发但MCU收不到任何数据排查路径用示波器看MCU的TX引脚——若有波形说明MCU程序跑飞或UART未初始化若TX无波形测TX引脚对地电压——应为3.3V空闲高电平。若为0V检查HAL_UART_Transmit()是否被阻塞如超时参数设为HAL_MAX_DELAYGPIO复用功能是否配置错误如AF编号错配晶振是否起振用示波器测OSC_IN若TX有波形但PC收不到测PC端USB转UART芯片的RX引脚——应有相同波形。若无则线缆RX线断路。问题2数据偶尔错乱表现为某几个字节固定位置出错根源波特率误差累积。例如用8MHz晶振生成115200bps误差2.1%在10字节帧中第10位采样点偏移达2.1%×10≈0.21比特时间接近采样阈值。解决方案更换晶振如7.3728MHz在MCU中启用OVER818倍过采样提高容错率或在协议层增加重传机制如Modbus的超时重发。问题3高波特率下1Mbps通信不稳定物理层检查清单PCB走线TX/RX线必须等长、远离电源/时钟线、添加100Ω串联电阻靠近MCU端终端电阻TTL电平无需终端电阻但若走线10cm建议在接收端加1kΩ上拉电源滤波UART芯片VCC旁必须有0.1μF陶瓷电容10μF电解电容否则高频噪声导致电平抖动。问题4使用USB转UART后设备偶尔“失联”根本原因Windows USB电源管理策略。当USB设备空闲时系统会自动挂起以省电导致FT232R进入低功耗模式TX/RX线电平异常。永久修复设备管理器→端口→右键属性→电源管理→取消勾选“允许计算机关闭此设备以节约电源”在FT232R的EEPROM中禁用Suspend功能用FT_PROG设置Chip Configuration→Suspend Pull-down为Disabled。最后分享一个血泪教训某次量产前测试100台设备中有3台在客户现场无法通信。反复排查无果最终发现是PCB厂在蚀刻时将FT232R的CBUS2引脚默认为TXDEN用于RS-485方向控制误连到了GND。这个引脚在TTL模式下本应悬空但被强制拉低后导致内部逻辑异常。解决方案在原理图中明确标注“CBUS2: NC”并在BOM中注明“此引脚不得连接”。6. UART的未来在万物互联时代它为何依然不可替代有人问我“现在都用Wi-Fi、BLE、Zigbee了UART是不是过时了”我的回答是UART不是过时了而是退居幕后成为所有无线协议的基石。你看ESP32模块它内部有Wi-Fi/BLE射频单元但你与它交互的接口依然是UART——AT指令集就是跑在这条“古老”的总线上。同样nRF52840的BLE协议栈调试输出用的还是SWO或UART。为什么因为UART满足了嵌入式世界最底层的三个刚需确定性、低开销、可预测性。确定性UART的时序是硬编码在硬件里的不受操作系统调度影响。一个115200bps的帧从第一个起始位到停止位结束时间误差小于1微秒。而TCP/IP栈在Linux上一次socket write()的延迟可能从100μs