2. 串口输出启动信息

任务目标

在Bootloader的启动早期阶段初始化UART外设,实现一个可用的串口调试输出通道,用于打印Bootloader版本、启动阶段标志等基础日志信息。本案例以STM32F407平台为例,使用标准外设库实现,核心目标是建立“初始化→重定向→输出”的最小可用链路。

环境与依赖

  • 硬件:STM32F407开发板(USART2,PA2=TX,PA3=RX),USB转TTL模块
  • 工具链:arm-none-eabi-gcc + Makefile,或Keil MDK
  • 依赖:STM32F4xx标准外设库(提供RCC、GPIO、USART驱动函数)

关键完整代码

#include "stm32f4xx.h"
#include <stdio.h>

/* 板级BSP:USART2 @ 115200-8-N-1 */
static void USART2_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;

    /* 使能时钟 */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

    /* PA2=TX(复用推挽), PA3=RX(复用浮空) */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2);

    /* USART2配置 */
    USART_InitStructure.USART_BaudRate = 115200;
    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_RX | USART_Mode_TX;
    USART_Init(USART2, &USART_InitStructure);

    USART_Cmd(USART2, ENABLE);
}

/* 重定向fputc到USART2(需勾选MicroLIB或使用半主机模式) */
int fputc(int ch, FILE *f)
{
    while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
    USART_SendData(USART2, (uint8_t)ch);
    return ch;
}

/* Bootloader入口 */
int main(void)
{
    /* 1. 初始化调试串口 */
    USART2_Init();

    /* 2. 输出启动日志 */
    printf("\r\n========================================\r\n");
    printf("  Bootloader v1.0.0\r\n");
    printf("  Build: %s %s\r\n", __DATE__, __TIME__);
    printf("  UART2 @ 115200 8N1\r\n");
    printf("========================================\r\n");
    printf("> Boot Start...\r\n");

    /* 3. 后续Bootloader流程(跳转APP等) */
    while (1)
    {
        /* 主循环暂空,实际Bootloader在此处执行跳转逻辑 */
    }
}

编译与运行

  1. 工程配置:新建STM32F407标准外设库工程,将上述代码放入main.c,确保启动文件与系统时钟已配置(默认使用外部8MHz晶振,系统时钟168MHz)。
  2. 编译选项:若使用gcc,需在链接选项中加入--specs=nano.specs --specs=nosys.specs以支持printf重定向;若使用Keil,需勾选“Use MicroLIB”。
  3. 烧录与连接:编译生成hex文件后烧录至开发板。将USB转TTL模块的TX接PA3(板载RX),RX接PA2(板载TX),GND相连。
  4. 打开串口终端:PC端使用任意串口工具(如PuTTY、sscom),设置波特率115200、8数据位、1停止位、无校验、无流控。

验证方法与通过标准

  • 现象:开发板上电或复位后,串口终端应立即收到上述格式的启动日志,包含版本号、编译时间与Boot Start提示。
  • 判定通过:终端完整显示5行日志且无乱码,说明UART初始化正确、时钟配置无误、printf重定向生效。
  • 常见问题排查:若完全无输出,先检查PA2/PA3接线是否交叉连接;若输出乱码,检查串口终端波特率是否与代码一致(115200),并确认系统时钟频率与USART2挂载的APB1时钟(默认42MHz)配置正确。
Bootloader printf("Boot Start...") USART2 TX: PA2 115200 8N1 串口终端 显示启动日志 数据流向:Bootloader 通过 USART2_TX(PA2) 发送 ASCII 字符至 PC 串口终端

关键点说明

  • 时钟树前提:USART2挂载在APB1总线上(默认42MHz),波特率寄存器由该时钟驱动。若修改系统时钟,需同步调整APB1分频系数。
  • 重定向机制:fputc是C库printf输出字符的底层钩子,通过轮询TXE标志位确保每个字节发送完成,避免数据覆盖。
  • 最小闭环:本案例仅实现UART初始化和日志输出,不包含接收中断或DMA,后续Bootloader的跳转、校验等功能在此基础上扩展即可。