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


相关推荐
想搞嵌入式的小白32 分钟前
STM32 NVIC中断控制器
stm32·单片机·嵌入式硬件·nvic
A-花开堪折1 小时前
Android7 Input(十)View 处理Input事件pipeline
android·嵌入式硬件
深圳市尚想信息技术有限公司1 小时前
【深尚想】OPA855QDSGRQ1运算放大器IC德州仪器TI汽车级高速8GHz增益带宽的全面解析
单片机·嵌入式硬件
陕西艾瑞科惯性技术有限公司2 小时前
让飞行姿态 “可感知”:为什么无人机需要三轴陀螺仪?
嵌入式硬件·机器学习·机器人·无人机·pcb工艺
代码总长两年半2 小时前
STM32----IAP远程升级
stm32·单片机·嵌入式硬件
广药门徒3 小时前
STM32手册上标称的18MHz GPIO翻转速度和你实际测量到的速度之间的差异是预期之内且合理的
单片机·嵌入式硬件
广药门徒3 小时前
在使用一些不用驱动大电流的设备就可以用stm32的自己的上下拉但是本身上下拉不就是给iicspi这些他通信给信号的吗中怎么还跟驱动能力扯上了有什么场景嘛
stm32·单片机·fpga开发
jz_ddk4 小时前
[zynq] Zynq Linux 环境下 AXI BRAM 控制器驱动方法详解(代码示例)
linux·运维·c语言·网络·嵌入式硬件
天天爱吃肉82184 小时前
【十年技术演进深度解构:车载充电机(OBC)将成为新能源汽车的“能源大脑”】
python·嵌入式硬件·算法·汽车·能源
most diligent12 小时前
蓝桥杯_DS18B20温度传感器---新手入门级别超级详细解析
单片机·嵌入式硬件