跳转至

STM32 USART 外设


 USART 是 STM32 内部集成的硬件外设,可以根据数据寄存器的一个字节数据自动生成数据帧时序,通过 TX 引脚发送,也可以自动接收 RX 引脚的数据帧时序,拼接为一个字符数据,存放至数据寄存器中。

STM32 内置的 USART 外设技术参数:

  • 自带波特率发生器: 最大值4.5Mbits/s
  • 可配置数据位长度 (8或9)、停止位长度 (0.5/1/1.5/2)
  • 可选校验位:无校验/奇校验/偶校验
  • 支持同步模式、硬件流控制、DMA、智能卡、lrDA、LIN

STM32F103C8T6 拥有三个 USART 资源: USART1、USART2、USART3 (USART1挂载在 APB1 总线,其余挂载在 APB2 总线)

STM32 USART 结构


 STM32 USART 外设当发送数据寄存器向发送位移寄存器传输完毕数据后会置一个 TXE 标志位,通过判断该标志位即可判断是否可以写入下一个数据;接收部分与发送同理,包含一个 RXNE 标志位(1)。

  1. 该标志位也可以连接&申请中断。

数据帧


STM32 USART 外设在配置数据帧长度(字长)的时候,共有 4 种选择:

  • 9 位字长
    • 有校验位
    • 无校验位
  • 8 位字长
    • 有校验位
    • 无校验位

波特率发生器

发送器和接收器的波特率由波特率寄存器 BRR 中的 DIV 确定,其计算公式如下:

\[ Baud = \frac{f_{PCLK2/1}}{(16 * DIV)} \]

标准库操作 USART 外设

初始化 USART 外设


  1. 开启时钟: USART 外设时钟、 GPIO 时钟

分别开启需要使用的 GPIO 端口和 USART 外设的时钟:

  • RCC_APB2Periph_USART1
  • RCC_APB2Periph_GPIOA
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  1. GPIO 初始化

    1. 将 TX 引脚配置为复用推挽输出
      1
      2
      3
      4
      5
      GPIO_InitTypeDef GPIO_InitStructure;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(GPIOA, &GPIO_InitStructure);
      
    2. 将 RX 引脚配置为复用输入

      引脚输入模式可以设置为: 上拉输入、浮空输入。

      1
      2
      3
      4
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
      GPIO_InitStructure.GPIO_Pin = SERIAL_RX_PIN;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(SERIAL_TRX_GROUP, &GPIO_InitStructure);
      
  2. 配置 USART 结构体

1
2
3
4
5
6
7
8
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1, &USART_InitStructure);

USART 配置结构体功能对照表

结构体成员 功能
USART_BaudRate 波特率
USART_HardwareFlowControl 硬件流控制
USART_Mode 串口模式
USART_Parity 校验位
USART_StopBits 停止位
USART_WordLength 字长

不同结构体成员的配置选择

Usart_hardwareflowcontrol

  • USART_HardwareFlowControl_None —— 不适用硬件流控制
  • USART_HardwareFlowControl_RTS —— 仅使用 RTS
  • USART_HardwareFlowControl_CTS —— 仅使用 CTS
  • USART_HardwareFlowControl_RTX_CTS —— 同时使用 RTS 和 CTS

Usart_mode

  • USART_Mode_Tx —— 仅发送模式
  • USART_Mode_Rx —— 仅接收模式

如果需要同时使用发送和接收功能,使用 | 或运算符将二者连接即可。

Usart_parity

  • USART_Parity_No —— 无校验
  • USART_Parity_Even —— 偶校验
  • USART_Parity_Odd —— 奇校验

Usart_stopbits

  • USART_StopBits_0_5 —— 0.5 校验位长度
  • USART_StopBits_1 —— 1 校验位长度
  • USART_StopBits_1_5 —— 1.5 校验位长度
  • USART_StopBits_2 —— 2 校验位长度

Usart_wordlength

  • USART_WordLength_8b —— 8 位字长
  • USART_WordLength_9b —— 9 位字长
  1. 开启 USART 功能

如果需要使用 USART 接收功能,则需要 在开启 USART 功能前配置中断相关代码。

USART_Cmd(USART1, ENABLE);

发送&接收数据


发送相关功能函数

  • 发送一个字节的数据
1
2
3
4
5
void Serial_SendByte(uint8_t DByte){
    USART_SendData(USART1, DByte);
    // wait USART Flag to TEX 
    while (USART_GetFlagStatus(USART1, USART_FLAG_TXE)){}
}
  • 发送数组
1
2
3
4
5
void Serial_SendArray(uint8_t* Array, uint16_t Length){
    for (uint16_t i = 0; i < Length; i++){
        Serial_SendByte(Array[i]);
    }
}
  • 发送字符串
1
2
3
4
5
void Serial_SendString(char* String){
    for (uint8_t i = 0; String[i] != '\0'; i++){
        Serial_SendByte(String[i]);
    }
}
  • 字符串形式发送数字
1
2
3
4
5
6
7
// String Send Number
void Serial_SendNumber(uint32_t Number, uint8_t Length){
    for (uint8_t i = 0; i < Length; i++){
        // Function: Serial_Pow —— 指数计算函数
        Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
    }
}
  • 封装 printf 函数
1
2
3
4
5
6
7
void Serial_Printf(char *format, ...){
    char String[MAX_BUFFER];
    va_list arg;
    va_start(arg, format);
    vsprintf(String, format, arg);
    Serial_SendString(String);
}

轮询判断接收


通过重复判断接收标志位,判断是否有数据输入。

  • 判断是否有数据输入

USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET)

  • 将存入寄存器的数据读出

USART_ReceiveData(USART1);

中断接收


如果需要使用中断接收数据,则需要在初始化流程中加入配置中断的相关代码。

在 USART 配置函数中新增如下代码

// USART IT Config Init
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

// NVIC Init
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;

NVIC_Init(&NVIC_InitStructure);

 中断初始化完毕后,当 RX 引脚接收到数据后,会向 NVIC 申请中断,数据读取操作可以在回调函数内进行操作。

uint8_t USART_RxFlage;
uint8_t USART_RxData;
1
2
3
4
5
6
7
void USART1_IRQHandler(void){
    if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET){
        USART_RxData = USART_ReceiveData(USART1);
        USART_RxFlage = 1;
        USART_ClearITPendingBit(USART1, USART_IT_RXNE);
    }
}

封装外部函数,读取寄存器数据和标志位。

uint8_t Get_RxFlage (void){
    if (USART_RxFlage == 1){
        USART_RxFlage = 0;
        return 1;
    }
    else{
        return 0;
    }
}

uint8_t Get_RxData(void){
    return USART_RxData;
}

发送&接收数据包