一、为什么要配置 USART

        在嵌入式系统开发中,USART(通用同步 / 异步收发传输器)是一种非常重要的通信接口,它可以实现单片机与其他设备(如电脑、传感器、显示屏等)之间的数据传输。通过配置 USART,我们可以:

  1. 实现调试信息输出:在开发过程中,将程序运行状态和调试信息通过串口发送到电脑,方便开发者进行调试和故障排查。

  2. 与外部设备通信:通过串口与其他设备进行数据交换,实现更复杂的功能,如传感器数据采集、远程控制等。

  3. 实现设备间的数据传输:在多设备系统中,串口可以作为设备间通信的桥梁,实现数据的共享和协同工作。

二、硬件连接与引脚配置

1. 原理图分析

根据原理图可知,我们需要配置 STM32 芯片的 PA9 和 PA10 引脚来实现 USART 通信:

  • PA9(TX):用于发送数据,需要配置为复用推挽输出模式()
  • PA10(RX):用于接收数据,需要配置为浮空输入模式(完全由外部信号驱动,引脚为高阻抗状态)

2. GPIO 引脚配置

        首先,我们需要启用 GPIOA 的时钟,并配置 PA9 和 PA10 引脚:

// 寄存器方式
// 启用GPIOA时钟
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;  

// PA9 (TX) 配置为复用推挽输出
GPIOA->CRH &= ~(0xF << 4);  // 清除原来的配置
GPIOA->CRH |= (0xB << 4);   // 配置为复用推挽输出,50MHz

// PA10 (RX) 配置为浮空输入
GPIOA->CRH &= ~(0xF << 8);  // 清除原来的配置
GPIOA->CRH |= (0x4 << 8);   // 配置为浮空输入
// 库函数方式
// 时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

// PA9 (TX) 配置
GPIO_InitTypeDef pa9;
pa9.GPIO_Mode = GPIO_Mode_AF_PP;    // 复用推挽输出
pa9.GPIO_Pin = GPIO_Pin_9;
pa9.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &pa9);

// PA10 (RX) 配置
GPIO_InitTypeDef pa10;
pa10.GPIO_Mode = GPIO_Mode_IN_FLOATING;  // 浮空输入
pa10.GPIO_Pin = GPIO_Pin_10;
GPIO_Init(GPIOA, &pa10);

三、USART 配置步骤

1. 启用 USART 时钟

// 寄存器方式
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;  // 启用USART1时钟

// 库函数方式
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

2. 设置数据位、停止位和校验位

// 寄存器方式
USART1->CR1 &= ~(USART_CR1_M);    // 8个数据位
USART1->CR2 &= ~(USART_CR2_STOP);  // 1个停止位
USART1->CR1 &= ~(USART_CR1_PCE);   // 无校验

// 库函数方式
USART_InitTypeDef usart1;
usart1.USART_BaudRate = 9600;  // 波特率设置为9600
usart1.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  // 无硬件流控制
usart1.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;  // 同时启用接收和发送
usart1.USART_Parity = USART_Parity_No;  // 无校验
usart1.USART_StopBits = USART_StopBits_1;  // 1个停止位
usart1.USART_WordLength = USART_WordLength_8b;  // 8个数据位
USART_Init(USART1, &usart1);

3. 配置波特率

        波特率是串口通信的重要参数,表示每秒传输的比特数。在 STM32 中,可以通过设置 USART_BRR 寄存器来配置波特率。

// 寄存器方式
// 设置波特率为9600(假设系统时钟为72MHz)
USART1->BRR = (72000000 / 9600);

// 库函数方式
// 在上面的USART_InitTypeDef结构体中已经设置了波特率
// usart1.USART_BaudRate = 9600;

4. 使能 USART

// 寄存器方式
USART1->CR1 |= USART_CR1_TE;  // 使能发送
USART1->CR1 |= USART_CR1_UE;  // 使能USART

// 库函数方式
USART_Cmd(USART1, ENABLE);  // 使能USART1

四、数据发送函数

1. 发送单个字符

// 寄存器方式
void USART1_SendChar(char data) {
    // 等待发送缓冲区为空
    while(!(USART1->SR & USART_SR_TXE));
    // 发送数据
    USART1->DR = data;
}

// 库函数方式
void USART1_SendChar(char data) {
    // 等待发送缓冲区为空
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    // 发送数据
    USART_SendData(USART1, (uint8_t)data);
}

2. 发送字符串

void USART1_SendString(char* str) {
    while(*str) {
        USART1_SendChar(*str++);
    }
}

五、数据接收函数

1. 接收单个字符

// 寄存器方式
char USART1_ReceiveChar(void) {
    // 等待接收缓冲区非空
    while(!(USART1->SR & USART_SR_RXNE));
    // 返回接收到的数据
    return (uint8_t)(USART1->DR & 0xFF);
}

// 库函数方式
char USART1_ReceiveChar(void) {
    // 等待接收缓冲区非空
    while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
    // 返回接收到的数据
    return (uint8_t)USART_ReceiveData(USART1);
}

2. 接收字符串

void USART1_ReceiveString(char* buffer, uint8_t length) {
    uint8_t i = 0;
    char c;
    
    while(i < length - 1) {
        c = USART1_ReceiveChar();
        if(c == '\r' || c == '\n') {
            break;
        }
        buffer[i++] = c;
    }
    buffer[i] = '\0';  // 添加字符串结束符
}

六、完整代码示例

        下面是一个完整的 USART1 配置和使用示例:

#include "stm32f10x.h"

// 初始化USART1
void USART1_Init(void) {
    // 使能GPIOA和USART1时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);
    
    // 配置PA9 (TX)为复用推挽输出
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    // 配置PA10 (RX)为浮空输入
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    // 配置USART1
    USART_InitTypeDef USART_InitStructure;
    USART_InitStructure.USART_BaudRate = 9600;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
    USART_Init(USART1, &USART_InitStructure);
    
    // 使能USART1
    USART_Cmd(USART1, ENABLE);
}

// 发送单个字符
void USART1_SendChar(char data) {
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    USART_SendData(USART1, (uint8_t)data);
}

// 发送字符串
void USART1_SendString(char* str) {
    while(*str) {
        USART1_SendChar(*str++);
    }
}

// 接收单个字符
char USART1_ReceiveChar(void) {
    while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
    return (uint8_t)USART_ReceiveData(USART1);
}

int main(void) {
    char receivedChar;
    
    // 初始化USART1
    USART1_Init();
    
    // 发送欢迎信息
    USART1_SendString("Hello, this is a USART1 test program!\r\n");
    
    while(1) {
        // 接收字符
        receivedChar = USART1_ReceiveChar();
        
        // 回显接收到的字符
        USART1_SendString("You sent: ");
        USART1_SendChar(receivedChar);
        USART1_SendString("\r\n");
    }
}

七、实验验证

配置好 USART 后,你可以使用串口调试助手(如 Putty、XCOM 等)来验证通信是否正常:

  1. 将 STM32 开发板通过 USB 转串口模块连接到电脑
  2. 打开串口调试助手,设置波特率为 9600,数据位 8 位,停止位 1 位,无校验
  3. 复位 STM32 开发板,应该能在串口调试助手中看到欢迎信息
  4. 在串口调试助手中输入字符,开发板会将接收到的字符回显回来

0voice · GitHub

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐