news 2026/11/3 2:24:03

串行通信入门之 UART 通信原理与实际使用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
串行通信入门之 UART 通信原理与实际使用

前言

随着嵌入式系统与物联网技术的快速发展,设备之间的数据交互越来越依赖串行通信。UART 作为最基础、最常用的异步串行通信协议,是每一位嵌入式开发者必须掌握的核心技能。


一、UART 是什么?

UART(Universal Asynchronous Receiver/Transmitter,通用异步收发器)是一种异步串行通信协议,它通过两根数据线(TX 发送、RX 接收)实现设备间的全双工通信。与 SPI、I2C 不同,它没有同步时钟线,依靠双方预先约定的参数完成数据收发,广泛用于调试打印、传感器、RS485 总线等场景。

二、UART 通信原理

1. 帧格式

UART 以帧为单位传输数据,一帧数据通常包含:起始位(1 位低电平)、数据位(5-8 位)、校验位(可选)、停止位(1-2 位高电平)。通信双方必须配置相同的帧格式才能正确解析数据。

数据位的发送顺序是低位先行从最低位(LSB)到最高位(MSB)。

起始位-->数据位(5-8bit)-->校验位(可选)-->停止位

2. 校验位

校验位是附加的1bit,用来简单检测传输过程中有没有出现1位比特翻转错误,不能纠错,也不能检测偶数个bit同时出错。

偶校验:数据位加校验位,1的总数为偶数。假设数据位中1的个数为奇数那么校验位为1,如果数据位中1的个数为偶数那么校验位为0。

奇校验:数据位加校验位,1的总数为奇数。假设数据位中1的个数为奇数那么校验位为0,如果数据位中1的个数为偶数那么校验位为1。

3. 波特率

波特率表示每秒传输的码元数,常见值有 9600、115200 等。发送方和接收方必须使用相同的波特率,否则会出现乱码或丢帧。波特率由外设时钟和 USART 分频寄存器(含小数分频)共同决定。

4. UART时序图

下图是使用逻辑分析仪对115200bps、无校验、一个停止位配置的UART的发送端抓的时序图。

4. 硬件连接

UART 通信只需三根线:TX(发送)、RX(接收)、GND(共地)。注意交叉连接:设备 A 的 TX 接设备 B 的 RX,设备 A 的 RX 接设备 B 的 TX。、

三、UART 数据收发实战(以GD32F303RET6为硬件平台)

1. UART的配置

下面配置的是USART1外设,UART的中断优先级要根据实际的优先级分组和应用来分配 。

#define TX_RS485_PIN GPIO_PIN_2 #define TX_RS485_GPIO_PORT GPIOA #define RX_RS485_PIN GPIO_PIN_3 #define RX_RS485_GPIO_PORT GPIOA static void (*uart1_callback)(uint8_t byte) = NULL; /** * @brief Initialize USART1. * * @param[in] bound Baudrate of USART1. * @param[in] Parity Parity of USART1. * * @note This function is used to initialize USART1, which is used for RS485 communication. * The function initializes the GPIO ports, USART clock. */ static void usart1_init(uint32_t bound, uint32_t Parity) { /* enable GPIO clock */ rcu_periph_clock_enable(RCU_GPIOA); /* enable USART clock */ rcu_periph_clock_enable(RCU_USART1); /* connect port to USARTx_Tx */ /* connect port to USARTx_Rx */ gpio_init(TX_RS485_GPIO_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, TX_RS485_PIN); gpio_init(RX_RS485_GPIO_PORT, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, RX_RS485_PIN); /* USART configure */ /* reset USART1 */ usart_deinit(USART1); /* USART1 configure */ usart_baudrate_set(USART1, bound); if(Parity==USART_PM_EVEN || Parity==USART_PM_ODD) usart_word_length_set(USART1, USART_WL_9BIT); else usart_word_length_set(USART1, USART_WL_8BIT); usart_stop_bit_set(USART1, USART_STB_1BIT); usart_parity_config(USART1, Parity); usart_hardware_flow_rts_config(USART1, USART_RTS_DISABLE); usart_hardware_flow_cts_config(USART1, USART_CTS_DISABLE); usart_receive_config(USART1, USART_RECEIVE_ENABLE); usart_transmit_config(USART1, USART_TRANSMIT_ENABLE); /* USART1 IRQn */ nvic_irq_enable(USART1_IRQn, 2, 1); usart_interrupt_enable(USART1, USART_INT_RBNE); /* enable USART1 */ usart_enable(USART1); } void bsp_uart1_callback_set(void (*callback)(uint8_t byte)) { uart1_callback = callback; }

2. 发送数据

发送数据时,将待发送的字节写入数据寄存器即可。下面给出一个简单的for循环发送函数。
备注:简单场景可用;大数据量建议改用DMA发送避免阻塞。

/** * @brief Send data through USART1. * * @param[in] data Pointer to the data to be sent. * @param[in] len Length of the data to be sent. * * @note This function is used to send data through USART1. */ void bsp_uart1_send(uint8_t *data, uint16_t len) { usart_flag_clear(USART1, USART_FLAG_TBE); for (uint16_t i = 0; i < len; i++) { usart_data_transmit(USART1, data[i]); while(RESET == usart_flag_get(USART1, USART_FLAG_TBE)); } usart_flag_clear(USART1, USART_FLAG_TBE); }

3. 接收数据(中断方式)

实际项目中通常使用中断方式接收数据,避免阻塞 CPU。下面给出中断接收的配置与处理示例。
uart1_callback是一个函数指针,想要接收数据需要调用bsp_uart1_callback_set函数给指针赋值。

void USART1_IRQHandler(void) { uint8_t byte = 0; if(RESET != usart_interrupt_flag_get(USART1, USART_INT_FLAG_RBNE)) { byte = (uint8_t)usart_data_receive(USART1); if(uart1_callback != NULL) uart1_callback(byte); } if(RESET != usart_interrupt_flag_get(USART1, USART_INT_FLAG_IDLE)) { byte = USART_STAT0(USART1); byte = USART_DATA(USART1); } if(RESET != usart_interrupt_flag_get(USART1, USART_INT_FLAG_ERR_ORERR)) { byte = USART_STAT0(USART1); byte = USART_DATA(USART1); } }

四、常见问题与调试技巧

在实际调试 UART 通信时,经常会遇到以下问题,这里给出对应的排查思路:

  • 乱码:检查波特率是否一致,帧格式(数据位、停止位、校验位)是否匹配。
  • 收不到数据:检查 TX/RX 是否交叉连接,GND 是否共地,引脚配置是否正确。
  • 丢帧:接收缓冲区溢出或中断处理不及时,可增大缓冲区或使用 DMA。
  • 电平不匹配:TTL 电平与 RS-232 电平不同,需使用 MAX3232 等电平转换芯片。
  • 快速验证:可以使用杜邦线或者跳线帽短接RX和TX让它自发自收,这样快速验证基本的配置和硬件是否OK。

总结

本文从 UART 的基本概念、帧格式、波特率、硬件连接入手,结合 STM32 给出了初始化、发送和中断接收的完整代码示例,并总结了常见调试问题。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/3 2:23:50

蛋糕销售系统|基于springboot + vue蛋糕销售系统(源码+数据库+文档)

蛋糕销售系统 目录 基于springboot vue蛋糕销售系统 一、前言 二、系统功能演示 三、技术选型 四、其他项目参考 五、代码参考 六、测试参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 基于springboot vue蛋糕销售系统 一、前言 博主介绍&#xff1a;✌…

作者头像 李华
网站建设 2026/11/3 2:23:06

Mysql学习(1):揭秘数据库:十大核心优势与架构全解析

&#x1f525;keyipatience:个人主页 &#x1f3ac;作者简介&#xff1a;C/C后端开发学习者 &#x1f31f;专栏传送门&#xff1a;《c》《linux》《c高阶数据结构》《c数据结构与算法》《前端学习》 《Git》《Mysql》 ⭐️patience is key in life 什么是数据库 数据库是20世纪…

作者头像 李华
网站建设 2026/11/3 2:22:41

01 检索下载文献并生成 MD

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/11/3 2:18:06

收集容器日志脚本

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华