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在此处执行跳转逻辑 */
}
}
编译与运行
- 工程配置:新建STM32F407标准外设库工程,将上述代码放入main.c,确保启动文件与系统时钟已配置(默认使用外部8MHz晶振,系统时钟168MHz)。
- 编译选项:若使用gcc,需在链接选项中加入
--specs=nano.specs --specs=nosys.specs以支持printf重定向;若使用Keil,需勾选“Use MicroLIB”。 - 烧录与连接:编译生成hex文件后烧录至开发板。将USB转TTL模块的TX接PA3(板载RX),RX接PA2(板载TX),GND相连。
- 打开串口终端:PC端使用任意串口工具(如PuTTY、sscom),设置波特率115200、8数据位、1停止位、无校验、无流控。
验证方法与通过标准
- 现象:开发板上电或复位后,串口终端应立即收到上述格式的启动日志,包含版本号、编译时间与Boot Start提示。
- 判定通过:终端完整显示5行日志且无乱码,说明UART初始化正确、时钟配置无误、printf重定向生效。
- 常见问题排查:若完全无输出,先检查PA2/PA3接线是否交叉连接;若输出乱码,检查串口终端波特率是否与代码一致(115200),并确认系统时钟频率与USART2挂载的APB1时钟(默认42MHz)配置正确。
关键点说明
- 时钟树前提:USART2挂载在APB1总线上(默认42MHz),波特率寄存器由该时钟驱动。若修改系统时钟,需同步调整APB1分频系数。
- 重定向机制:
fputc是C库printf输出字符的底层钩子,通过轮询TXE标志位确保每个字节发送完成,避免数据覆盖。 - 最小闭环:本案例仅实现UART初始化和日志输出,不包含接收中断或DMA,后续Bootloader的跳转、校验等功能在此基础上扩展即可。