嵌入式硬件篇---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通信,适用于传感器数据采集、无线模块控制等场景。


相关推荐
走错路的程序员10 分钟前
stm32测频率占空比最好的方案
stm32·单片机·嵌入式硬件
Ronin-Lotus2 小时前
嵌入式硬件篇---SPI
单片机·嵌入式硬件
白天学嵌入式2 小时前
STM32f103 标准库 零基础学习之按键点灯(不涉及中断)
stm32·单片机·学习
Ronin-Lotus3 小时前
嵌入式硬件篇---陀螺仪|PID
单片机·嵌入式硬件
小智学长 | 嵌入式3 小时前
单片机-STM32部分:12、I2C
单片机·嵌入式硬件
四夕白告木贞3 小时前
stm32week15
stm32·单片机·嵌入式硬件·学习
Ronin-Lotus4 小时前
嵌入式硬件篇---TOF|PID
单片机·嵌入式硬件·c·pid·tof
摞代码的猴哥5 小时前
单片机调用printf概率性跑飞解决方法
单片机·printf·ucos·跑飞
weixin_452813095 小时前
如何根据HardFault中断抛出的寄存器值排查数组越界
单片机·嵌入式硬件·嵌入式软件
sword devil9006 小时前
stm32实战项目:无刷驱动
arm开发·stm32·单片机·嵌入式硬件