嵌入式UART和USART技术详解
UART与USART技术详解:UART仅支持异步通信,通过波特率同步;USART支持同步/异步两种模式,同步模式下需要时钟信号。UART帧结构包含起始位、数据位、校验位和停止位。USART相比UART增加了硬件流控功能,适用于高速通信场景。UART多用于传感器等中低速通信,USART则更适合工业控制等要求更高的应用。
·
UART与USART技术详解
一、技术原理
1.1 UART与USART的区别
UART(通用异步收发器)和USART(通用同步异步收发器)是两种常见的串行通信接口,它们的主要区别如下:
-
通信模式:UART仅支持异步通信,而USART支持同步和异步两种通信模式。 -
时钟信号:UART不需要时钟信号,通过波特率同步;USART在同步模式下需要额外的时钟线(SCK)。 -
硬件流控:USART支持硬件流控(RTS/CTS),而UART通常不支持。 -
应用场景:UART适用于中低速异步通信,如传感器数据传输;USART适用于高速同步通信,如工业控制、SPI接口替代等。
1.2 UART帧结构
UART数据帧由以下部分组成:
-
起始位:1位,低电平,表示数据传输开始。 -
数据位:5-9位,通常为8位,传输实际数据。 -
校验位:可选,用于错误检测,包括奇校验、偶校验、无校验等。 -
停止位:1-2位,高电平,表示数据传输结束。
1.3 USART同步通信
USART同步模式下,主设备通过SCK引脚提供时钟信号,数据在时钟边沿采样。同步通信的优势在于:
-
更高的传输速率,可达4.5Mbps。 -
更精确的时序控制,减少波特率不匹配导致的错误。 -
可替代SPI接口,减少硬件资源占用。
二、硬件实现
2.1 微控制器UART/USART外设
以STM32为例,USART外设主要包括:
-
波特率发生器:支持分数波特率,提高精度。 -
发送/接收缓冲区:支持FIFO,减少CPU中断次数。 -
中断系统:支持发送完成、接收完成、错误中断等。 -
DMA接口:支持DMA传输,提高数据吞吐量。
2.2 接口电路设计
2.2.1 TTL电平转RS-232
使用MAX232芯片实现TTL电平到RS-232电平的转换,电路连接如下:
-
STM32 TX → MAX232 T1IN -
STM32 RX → MAX232 R1OUT -
MAX232 T1OUT → RS-232 TX -
MAX232 R1IN → RS-232 RX
2.2.2 RS-485接口设计
RS-485支持多节点通信,电路设计要点:
-
使用MAX485芯片,A、B线之间接120Ω终端电阻。 -
控制引脚(DE/RE)连接MCU GPIO,实现收发方向切换。 -
差分信号传输,提高抗干扰能力。
2.3 FPGA实现UART
FPGA实现UART的主要模块包括:
-
波特率发生器:通过分频产生所需波特率时钟。 -
发送器:将并行数据转换为串行数据,添加起始位、停止位等。 -
接收器:将串行数据转换为并行数据,检测起始位、校验位等。 -
FIFO缓冲区:减少数据丢失,提高系统稳定性。
三、软件编程
3.1 STM32 HAL库实现
3.1.1 UART初始化
UART_HandleTypeDef huart1;
void MX_USART1_UART_Init(void) {
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
if (HAL_UART_Init(&huart1) != HAL_OK) {
Error_Handler();
}
}
3.1.2 DMA接收实现
使用DMA+空闲中断实现不定长数据接收:
uint8_t rx_buf[100];
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle) {
if (uartHandle->Instance == USART1) {
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
hdma_usart1_rx.Instance = DMA1_Channel5;
hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_usart2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart1_rx.Init.Mode = DMA_CIRCULAR;
hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK) {
Error_Handler();
}
__HAL_LINKDMA(uartHandle, hdmarx, hdma_usart1_rx);
HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
}
}
void USART1_IRQHandler(void) {
HAL_UART_IRQHandler(&huart1);
}
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) {
if (huart->Instance == USART1) {
// 处理接收到的数据
process_data(rx_buf, Size);
// 重新启动DMA接收
HAL_UARTEx_ReceiveToIdle_DMA(&huart1, rx_buf, sizeof(rx_buf));
}
}
3.2 Arduino串口编程
Arduino UART初始化和数据收发示例:
void setup() {
Serial.begin(115200); // 初始化串口,波特率115200
}
void loop() {
if (Serial.available()) {
char c = Serial.read(); // 读取串口数据
Serial.print("Received: ");
Serial.println(c); // 发送数据
}
}
3.3 Linux系统串口编程
Linux下使用C语言实现串口通信:
#include <stdio.h>
#include <fcntl.h>
#include <termios.h>
int uart_open(const char *dev) {
int fd = open(dev, O_RDWR | O_NOCTTY | O_NDELAY);
if (fd < 0) {
perror("open");
return -1;
}
struct termios options;
tcgetattr(fd, &options);
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
tcsetattr(fd, TCSANOW, &options);
return fd;
}
int main() {
int fd = uart_open("/dev/ttyUSB0");
if (fd < 0) return -1;
char buf[100] = "Hello, UART!";
write(fd, buf, sizeof(buf));
read(fd, buf, sizeof(buf));
printf("Received: %s\n", buf);
close(fd);
return 0;
}
三、应用案例
3.1 工业传感器数据采集
硬件架构:STM32F4 + RS-485 + 温湿度传感器
软件实现:Modbus RTU协议
抗干扰设计:
-
使用屏蔽双绞线 -
终端电阻120Ω -
光电隔离
3.3 低功耗串口设计
项目:基于nRF52840的低功耗UART通信
优化措施:
-
使用低功耗模式(LPCOMP)唤醒 -
关闭未使用外设时钟 -
缩短通信时间,增加休眠周期
四、调试技巧
4.1 常见故障及解决方案
| 故障现象 | 可能原因 | 解决方案 |
|---|---|---|
| 数据乱码 | 波特率不匹配 | 检查双方波特率设置 |
| 接收不到数据 | TX/RX接线错误 | 交叉连接TX和RX |
| 数据丢失 | 缓冲区溢出 | 启用FIFO或DMA |
| 校验错误 | 校验位设置不一致 | 统一校验位配置 |
4.2 使用示波器调试
-
测量波特率:测量相邻两个数据位的时间间隔,计算波特率。 -
观察波形:检查起始位、数据位、停止位是否正常。 -
检测干扰:观察信号是否有毛刺、噪声。
4.3 逻辑分析仪应用
使用逻辑分析仪抓取UART信号,分析时序是否正确,例如:
-
起始位下降沿是否清晰 -
数据位采样是否在中间时刻 -
停止位是否为高电平
五、开源项目
5.1 ZipUART32
-
简介:FPGA UART IP核,支持同步/异步模式。 -
特点:可配置波特率、数据位、校验位。 -
应用:嵌入式系统调试接口、工业控制。
5.2 AVR-UART-lib
-
简介:AVR单片机UART库。 -
功能:支持中断、DMA、环形缓冲区。 -
示例代码:
#include "uart.h"
int main(void) {
uart_init(9600);
uart_puts("Hello, UART!");
while (1) {
if (uart_available()) {
char c = uart_getc();
uart_putc(c);
}
}
}
六、未来发展趋势
-
高速串口:支持更高波特率,如10Mbps以上。 -
智能化:自动波特率检测、自适应噪声过滤。 -
集成化:与无线通信融合,如LoRa、NB-IoT。 -
低功耗:优化休眠模式,降低待机电流。"]
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐

所有评论(0)