嵌入式硬件篇---UART


文章目录


前言

UART(Universal Asynchronous Receiver/Transmitter)是一种异步串行通信协议 ,广泛应用于嵌入式设备与传感器、蓝牙模块、GPS等外设的通信。以下是UART协议的详细解析及在STM32F103RCT6上的完整代码实现。


1. UART协议基础

1.1 物理层特性

两根信号线

TX(Transmit):数据发送线(输出)。

RX(Receive):数据接收线(输入)。

无时钟信号

无时钟信号:依赖预定义的波特率(Baud Rate)同步。

电平标准

TTL UART

TTL UART:0V(逻辑0),3.3V/5V(逻辑1)。

RS-232

RS-232:±12V(需电平转换芯片如MAX232)。

1.2 数据帧格式

起始位\] \[数据位(5-9位)\] \[校验位(可选)\] \[停止位(1-2位)

起始位:1位低电平(逻辑0)。

数据位:通常8位(如ASCII字符)。

校验位(可选):

奇校验:数据位中1的个数为奇数时置1。

偶校验:数据位中1的个数为偶数时置1。

停止位:1或2位高电平(逻辑1)。

1.3 波特率计算

波特率

波特率(Baud Rate)表示每秒传输的符号数(1符号=1位)。

常见波特率:9600、115200等。

STM32的UART时钟源为APB2(默认72MHz),波特率计算公式:

波特率=APB2时钟USARTDIV

其中USARTDIV是一个16位寄存器值(整数部分 + 小数部分)。

2. STM32F103RCT6的UART配置

2.1 硬件连接

UART信号 STM32引脚 说明
USART1_TX PA9 发送数据
USART1_RX PA10 接收数据

GND 共地 确保电平参考一致

2.2 CubeMX配置

启用USART1

模式:Asynchronous(异步模式)。

波特率:115200。

数据位:8位。

校验位:None。

停止位:1位。

引脚分配

PA9 → USART1_TX

PA10 → USART1_RX

中断启用(可选)

接收中断(RXNE)。

3. HAL库代码实现

3.1 UART初始化

c 复制代码
#include "stm32f1xx_hal.h"

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;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  
  if (HAL_UART_Init(&huart1) != HAL_OK) {
    Error_Handler();
  }
}

3.2 发送数据(阻塞模式)

c 复制代码
void UART_SendString(uint8_t *str) {
  HAL_UART_Transmit(&huart1, str, strlen((char *)str), 100); // 阻塞式发送
}

// 示例:发送"Hello World!"
UART_SendString((uint8_t *)"Hello World!\r\n");

3.3 接收数据(中断模式)

c 复制代码
uint8_t rx_data;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
  if (huart == &huart1) {
    // 处理接收到的数据(如回显)
    HAL_UART_Transmit(&huart1, &rx_data, 1, 100);
    HAL_UART_Receive_IT(&huart1, &rx_data, 1); // 重新启用接收中断
  }
}

// 主函数中启用接收中断
int main(void) {
  HAL_Init();
  MX_USART1_UART_Init();
  HAL_UART_Receive_IT(&huart1, &rx_data, 1); // 启动接收中断
  while (1) { /* 其他任务 */ }
}

3.4 DMA传输(高效大数据量)

c 复制代码
uint8_t dma_tx_buffer[] = "DMA Transmission Test!\r\n";

// 初始化DMA
void MX_DMA_Init(void) {
  __HAL_RCC_DMA1_CLK_ENABLE();
}

// 通过DMA发送数据
HAL_UART_Transmit_DMA(&huart1, dma_tx_buffer, sizeof(dma_tx_buffer));

4. 自定义协议设计

4.1 帧格式示例

字段 长度 说明
帧头 2字节 0xAA 0x55
数据长度 1字节 后续数据长度(N)
数据 N字节 有效载荷
CRC校验 1字节 校验和(数据字节累加和)

4.2 帧解析代码

c 复制代码
uint8_t rx_buffer[64];
uint8_t frame_state = 0;
uint8_t data_len = 0;
uint8_t crc = 0;

void Process_UART_Byte(uint8_t byte) {
  static uint8_t idx = 0;
  
  switch (frame_state) {
    case 0: // 等待帧头1
      if (byte == 0xAA) frame_state = 1;
      break;
    case 1: // 等待帧头2
      if (byte == 0x55) frame_state = 2;
      else frame_state = 0;
      break;
    case 2: // 读取数据长度
      data_len = byte;
      idx = 0;
      crc = byte;
      frame_state = 3;
      break;
    case 3: // 读取数据
      rx_buffer[idx++] = byte;
      crc += byte;
      if (idx >= data_len) frame_state = 4;
      break;
    case 4: // 校验CRC
      if (crc == byte) {
        // 帧处理(如控制LED)
        if (rx_buffer[0] == 0x01) HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
      }
      frame_state = 0;
      break;
  }
}

// 在中断回调中调用
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
  Process_UART_Byte(rx_data);
  HAL_UART_Receive_IT(&huart1, &rx_data, 1);
}

5. 常见问题与调试

5.1 通信失败原因

波特率不匹配

波特率不匹配:确保双方波特率一致(如115200)。

电平不兼容

电平不兼容:TTL UART不能直接接RS-232设备。

接线错误

接线错误:检查TX/RX是否交叉连接。

中断为启用

中断未启用:若使用中断接收 ,需调用HAL_UART_Receive_IT()。

5.2 逻辑分析仪抓包

使用工具(如Saleae Logic)观察:

  1. 起始位是否为低电平?
  2. 数据位是否符合预期?
  3. 停止位是否为高电平?

6. 完整示例:与PC通信

STM32代码

c 复制代码
int main(void) {
  HAL_Init();
  MX_USART1_UART_Init();
  HAL_UART_Receive_IT(&huart1, &rx_data, 1); // 启用接收中断

  while (1) {
    // 每隔1秒发送数据
    UART_SendString((uint8_t *)"STM32 UART Test\r\n");
    HAL_Delay(1000);
  }
}

PC端(Python脚本)

python 复制代码
import serial
ser = serial.Serial('COM3', 115200, timeout=1)  # 根据实际端口修改
while True:
    if ser.in_waiting:
        data = ser.readline().decode('utf-8').strip()
        print("Received:", data)

7.总结

基本配置

基本配置:波特率、数据位、停止位需匹配。

通信模式

通信模式:阻塞、中断、DMA按需选择

协议设计

协议设计:自定义帧格式提升可靠性

调试工具

调试工具:逻辑分析仪、串口助手 是关键。

通过上述代码,STM32F103RCT6可实现稳定的UART通信,适用于传感器数据采集、无线模块控制等场景。


相关推荐
逆小舟17 小时前
【STM32】手把手教你完成“天气预报项目”
stm32·单片机·嵌入式硬件
cjy_Somnr21 小时前
keil5报错显示stm32的SWDIO未连接不能烧录
stm32·单片机·嵌入式硬件
Lay_鑫辰1 天前
西门子诊断-状态和错误位(“轴”工艺对象 V1...3)
服务器·网络·单片机·嵌入式硬件·自动化
无垠的广袤1 天前
【工业树莓派 CM0 NANO 单板计算机】本地部署 EMQX
linux·python·嵌入式硬件·物联网·树莓派·emqx·工业物联网
雲烟1 天前
嵌入式设备EMC安规检测参考
网络·单片机·嵌入式硬件
泽虞1 天前
《STM32单片机开发》p7
笔记·stm32·单片机·嵌入式硬件
田甲1 天前
【STM32】 数码管驱动
stm32·单片机·嵌入式硬件
up向上up1 天前
基于51单片机垃圾箱自动分类加料机快递物流分拣器系统设计
单片机·嵌入式硬件·51单片机
纳祥科技1 天前
Switch快充方案,内置GaN,集成了多个独立芯片
单片机
单片机日志2 天前
【单片机毕业设计】【mcugc-mcu826】基于单片机的智能风扇系统设计
stm32·单片机·嵌入式硬件·毕业设计·智能家居·课程设计·电子信息