二十九、STM32的USART (串口发送)

前言:在 STM32 的开发过程中,串口通信(USART) 是我们最常接触的外设之一。

它不仅是调试信息输出的"窗口",更是 MCU 与外部模块(如蓝牙、GPS、WiFi 模块等)进行数据交换的主要方式。本篇文章将带你从 初始化 USART 外设 开始,逐步讲解 STM32C8T6 串口发送的完整实现过程,包括底层函数封装、常用接口说明以及 printf 的重定向方法,帮助你全面掌握串口发送的核心原理与应用。

目录

[一、USART 外设的基本介绍](#一、USART 外设的基本介绍)

二、接线图

三、串口发送初始化过程

四、串口发送函数的封装

[五、printf 的重定向与串口打印](#五、printf 的重定向与串口打印)

六、完整测试程序

七、总结


一、USART 外设的基本介绍

USART(Universal Synchronous Asynchronous Receiver Transmitter,通用同步/异步收发器)是 STM32 内部的重要通信外设。

它可以在 异步模式 下实现经典的 UART 通信,也能在 同步模式 下通过时钟信号实现精确同步。

本文重点讲解 USART 的发送部分,即 MCU 如何将数据从寄存器中输出到 TX 引脚上。

在 STM32 标准外设库中,USART 模块提供了丰富的配置接口,例如:

这些函数由 标准外设库(stm32f10x_usart.c) 提供,能帮助我们快速完成串口初始化与发送配置。

二、接线图

三、串口发送初始化过程

在 STM32 中使用串口发送前,需要完成以下几个步骤:

  1. 开启外设时钟

    • 开启 GPIOA 与 USART1 的时钟。
  2. 配置引脚功能

    • 将 TX 引脚(PA9)设置为复用推挽输出。
  3. 配置 USART 参数

    • 设置波特率、数据位、停止位、校验位、模式等。
  4. 使能 USART 外设

对应的初始化函数如下:

复制代码
void Serial_Init(void)
{
    /* 开启时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); // 开启USART1时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  // 开启GPIOA时钟

    /* GPIO 初始化 */
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        // 复用推挽输出
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;              // TX引脚:PA9
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* USART 参数配置 */
    USART_InitTypeDef USART_InitStructure;
    USART_InitStructure.USART_BaudRate = 9600;             // 波特率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;  // 1位停止位
    USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 8位数据位
    USART_Init(USART1, &USART_InitStructure);

    /* USART 使能 */
    USART_Cmd(USART1, ENABLE);
}

此时,USART1 已经完成初始化,可以正式进行数据发送。

四、串口发送函数的封装

为了让串口发送更加方便,我们对标准库函数进行了进一步封装。

  1. 发送一个字节

    void Serial_SendByte(uint8_t Byte)
    {
    USART_SendData(USART1, Byte); // 将数据写入数据寄存器
    while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    }

解释:

  • USART_SendData() 会把一个字节写入发送数据寄存器。

  • USART 会自动将该字节按时序输出到 TX 引脚。

  • USART_FLAG_TXE 表示发送寄存器为空,等待其置位表示当前字节已发送完成。

  1. 发送数组

    void Serial_SendArray(uint8_t *Array, uint16_t Length)
    {
    for (uint16_t i = 0; i < Length; i++)
    Serial_SendByte(Array[i]);
    }

适用于一次性发送多个连续数据,如传感器数据或帧结构。

  1. 发送字符串

    void Serial_SendString(char *String)
    {
    for (uint8_t i = 0; String[i] != '\0'; i++)
    Serial_SendByte(String[i]);
    }

通过检测 '\0'(字符串结束符)来决定发送停止位置。

  1. 发送数字

    void Serial_SendNumber(uint32_t Number, uint8_t Length)
    {
    for (uint8_t i = 0; i < Length; i++)
    Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
    }

用于直接发送整数值,内部将数字转换为对应的 ASCII 字符。

五、printf 的重定向与串口打印

在 C 语言中,printf() 默认输出到标准输出(如电脑终端),

而在嵌入式环境中,我们可以通过重定向函数 fputc() 把它改为通过串口发送。

  1. 重定向 printf()

    int fputc(int ch, FILE *f)
    {
    Serial_SendByte(ch); // 将字符通过串口发送
    return ch;
    }

只需实现该函数,之后 printf("Hello STM32!"); 的输出就会从串口发出。

  1. 封装自定义 Serial_Printf()

    #include <stdarg.h>
    void Serial_Printf(char *format, ...)
    {
    char String[100];
    va_list arg;
    va_start(arg, format);
    vsprintf(String, format, arg);
    va_end(arg);
    Serial_SendString(String);
    }

这样即可在任意位置方便地打印格式化字符串:

Serial_Printf("\r\nTemp=%d C, Humidity=%d%%", 25, 60);

六、完整测试程序

复制代码
int main(void)
{
    OLED_Init();       
    Serial_Init();      

    Serial_SendByte(0x41);             // 发送单字节数据
    uint8_t MyArray[] = {0x42, 0x43, 0x44, 0x45};
    Serial_SendArray(MyArray, 4);      // 发送数组
    Serial_SendString("\r\nNum1=");    
    Serial_SendNumber(111, 3);         // 发送数字

    printf("\r\nNum2=%d", 222);        // 方法1:标准printf重定向
    char String[100];
    sprintf(String, "\r\nNum3=%d", 333);
    Serial_SendString(String);         // 方法2:sprintf + SendString
    Serial_Printf("\r\nNum4=%d", 444); // 方法3:自定义封装

    while (1);
}

运行后可以在串口调试助手中依次看到发送的数据,验证 USART 发送功能是否正常。

七、总结

通过本篇内容,我们完成了 STM32C8T6 串口发送的完整流程:

  • 了解了 USART 外设的基本接口函数;

  • 完成了串口的初始化与配置;

  • 封装了多种发送函数(字节、数组、字符串、数字);

  • 实现了 printf() 的重定向与自定义打印。

在嵌入式开发中,USART 是最基础也最实用的通信外设。

掌握串口发送后,你可以轻松实现调试输出、设备通信、数据上报等功能,为后续学习接收与中断通信打下坚实基础。

相关推荐
d111111111d3 小时前
STM32外设学习-串口数据包笔记-(数据包的了解)
笔记·stm32·单片机·嵌入式硬件·学习
EVERSPIN3 小时前
MCU单片机,常用32位单片机,低功耗单片机MM32L系列
单片机·mcu单片机·32位单片机·低功耗单片机·mm32l系列
idcardwang4 小时前
esp32-s3-supermini使用arduio IDE进行mpu6050的数据读取
ide·单片机
纳祥科技8 小时前
方案分享:一款基于低功耗单片机的腰腹甩脂机方案
单片机·嵌入式硬件
点灯小铭12 小时前
基于单片机的电子琴设计与乐曲存储播放实现
单片机·嵌入式硬件·毕业设计·课程设计·期末大作业
hemama_12 小时前
STM32F103VET6开发板例程(一)-LED
stm32·单片机·嵌入式硬件
夜月yeyue12 小时前
Linux 内核驱动加载机制
linux·服务器·stm32·嵌入式硬件
炸膛坦客12 小时前
FreeRTOS 学习:(十七)“外部中断”和“内核中断”的差异,引入 FreeRTOS 中断管理
stm32·freertos·实时操作系统
奋斗的牛马12 小时前
FPGA--zynq学习 PS与PL交互(二) HP接口
单片机·嵌入式硬件·学习·fpga开发·信息与通信