1. 项目概述
在嵌入式开发中,串口打印是最基础也最实用的调试手段之一。最近我在使用STM32L562E-DK开发板进行项目开发时,发现这块基于Cortex-M33内核的低功耗开发板在串口配置上与常规STM32有些差异。今天我就把整个串口打印功能的实现过程整理出来,包括从硬件连接到软件配置的全套方案。
STM32L5系列是ST推出的首款基于Arm Cortex-M33内核的微控制器,主打安全与低功耗特性。L562E-DK开发板搭载了STM32L562QE微控制器,支持TrustZone安全机制,最高主频可达110MHz。板载ST-LINK调试器和虚拟串口功能,特别适合物联网终端设备开发。
2. 硬件准备与连接
2.1 开发板串口资源确认
STM32L562E-DK开发板提供了多种串口连接方式:
- 板载ST-LINK的虚拟串口(通过USB连接)
- 扩展接口的硬件串口引脚
最方便的是使用板载的虚拟串口功能,对应硬件连接如下:
- USART1_TX: PA9 (连接至ST-LINK的VCP)
- USART1_RX: PA10 (连接至ST-LINK的VCP)
注意:开发板上的CN3跳线帽必须保持连接状态,这样才能将USART1信号路由至ST-LINK。
2.2 终端软件准备
推荐使用以下任意一款串口终端软件:
- Tera Term (Windows)
- PuTTY (跨平台)
- CoolTerm (Mac)
连接参数配置:
- 波特率:115200(与代码配置一致)
- 数据位:8
- 停止位:1
- 校验位:无
- 流控:无
3. 软件开发环境搭建
3.1 工具链选择
我使用的是STM32CubeIDE 1.8.0,这是ST官方提供的免费开发环境,集成了:
- GCC工具链
- STM32CubeMX配置工具
- 调试支持
当然你也可以选择Keil MDK或IAR EWARM等商业工具。
3.2 新建工程步骤
- 启动STM32CubeIDE,选择"Start new STM32 project"
- 在板卡选择器中输入"STM32L562E-DK"并选择
- 工程命名(如"UART_Printf_Demo")
- 选择"TrustZone disabled"(除非你需要安全功能)
- 点击Finish完成工程创建
4. 外设配置详解
4.1 USART1配置
在CubeMX界面中:
- 左侧Pinout视图找到USART1
- 工作模式选择"Asynchronous"
- 参数配置:
- Baud Rate: 115200
- Word Length: 8 Bits
- Parity: None
- Stop Bits: 1
- Over Sampling: 16 samples
- 开启USART1全局中断(NVIC Settings)
提示:STM32L5的USART时钟源来自PCLK2,默认系统时钟配置下为110MHz。波特率计算公式为:
BaudRate = fCK / (8 * (2 - OVER8) * USARTDIV)
其中OVER8=0表示16倍过采样
4.2 GPIO配置
USART1的TX(PA9)和RX(PA10)会自动配置为Alternate Function模式:
- Mode: Alternate Function Push Pull
- Pull-up/Pull-down: No pull
- Speed: Medium
4.3 时钟树配置
确保系统时钟配置正确:
- MSI作为PLL源(4MHz)
- PLL配置为110MHz
- HCLK = 110MHz
- PCLK1 = 110MHz
- PCLK2 = 110MHz
5. 代码实现
5.1 重定向printf
在工程中添加以下代码实现printf重定向:
c复制#include <stdio.h>
int __io_putchar(int ch)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
int _write(int file, char *ptr, int len)
{
HAL_UART_Transmit(&huart1, (uint8_t *)ptr, len, HAL_MAX_DELAY);
return len;
}
5.2 主程序实现
c复制int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
printf("\r\n===== STM32L562E-DK UART Demo =====\r\n");
printf("System Clock: %lu Hz\r\n", HAL_RCC_GetSysClockFreq());
while (1)
{
printf("Hello from STM32L5! Tick: %lu\r\n", HAL_GetTick());
HAL_Delay(1000);
}
}
5.3 编译配置
确保工程设置中启用了semihosting和microLIB:
- 右键工程 -> Properties
- C/C++ Build -> Settings
- Tool Settings -> MCU Settings
- 勾选"Use float with printf"
- 勾选"Use microLIB"
6. 常见问题排查
6.1 无输出或乱码
可能原因及解决方案:
-
波特率不匹配
- 检查终端软件和代码中的波特率设置
- 使用示波器测量实际波特率
-
时钟配置错误
- 确认SystemClock_Config()正确执行
- 检查USART时钟源频率
-
硬件连接问题
- 确认CN3跳线帽连接
- 检查USB线是否插稳
6.2 输出不完整或丢失字符
-
增加发送超时时间
c复制HAL_UART_Transmit(&huart1, (uint8_t *)ptr, len, 1000); -
检查缓冲区溢出
- 确保接收端及时读取数据
- 增加流控(硬件或软件)
6.3 低功耗模式下的串口问题
STM32L5支持多种低功耗模式,需要注意:
- 在STOP模式下USART会停止工作
- 可通过LPUART实现低功耗串口通信
- 唤醒后需要重新初始化USART
7. 高级应用技巧
7.1 DMA传输优化
对于大量数据输出,可以使用DMA提高效率:
c复制// 在CubeMX中启用USART1 TX DMA
// 发送函数改为
HAL_UART_Transmit_DMA(&huart1, (uint8_t *)buffer, length);
7.2 格式化输出增强
实现更丰富的输出格式:
c复制printf("Temperature: %.1f°C\r\n", temp);
printf("Address: 0x%08lX\r\n", addr);
7.3 多串口管理
当需要同时使用多个串口时:
- 为每个串口创建独立的句柄
- 使用不同的回调函数
- 注意中断优先级配置
8. 性能优化建议
-
减小printf开销:
- 避免频繁调用小量printf
- 使用sprintf先格式化,再一次性输出
-
合理设置中断优先级:
- USART中断不应阻塞关键任务
- DMA传输中断优先级可设低些
-
电源管理:
- 不使用时关闭串口时钟
- 利用低功耗模式特性
我在实际项目中发现,STM32L5的串口稳定性相当不错,即使在110MHz全速运行下,长时间传输也不会出现数据丢失。唯一需要注意的是TrustZone环境下需要对串口外设进行安全区配置,否则会出现访问违例。