第一章:课程导论与开发环境搭建
各位同学好,我是你们的嵌入式讲师。说实话,做了十几年嵌入式开发,串口通信是我打交道最多的外设,没有之一。从最早的51单片机到现在的STM32,串口调试就像工程师的“听诊器”——项目跑不起来,第一件事就是看串口打印。
这一章我们不急着写代码。先把路铺好,后面才能跑得快。我个人习惯是:环境搭建阶段多花半小时,调试阶段就能省下半天。
1.1 课程目标与学习路径
这门课的核心目标只有一个:让你真正掌握STM32 HAL库下的串口不定长数据接收与DMA传输。不是停留在“能跑例程”的程度,而是遇到问题能自己定位、自己修。
课程三大能力目标:
- 能写:独立完成串口+DMA的工程配置与代码编写
- 能调:使用调试器、逻辑分析仪、串口助手定位故障
- 能修:解决实际项目中遇到的丢帧、死机、DMA卡死等问题
学习路径我建议这样走:
- 基础夯实(第1-5章):环境搭建、HAL库串口基础、DMA原理
- 核心实战(第6-15章):不定长接收的多种实现方案
- 调试进阶(第16-25章):故障定位方法论、常见坑点解析
- 项目整合(第26-30章):综合案例与性能优化
你想想看,如果连printf都打不出来,后面谈DMA传输就是空中楼阁。所以我们先从最基础的串口打印开始。
1.2 STM32CubeMX与HAL库概述
STM32CubeMX是ST官方推出的图形化配置工具。说白了,就是帮你自动生成初始化代码的。我刚开始用的时候还不太信任它,总觉得手写寄存器更“可控”。直到有一次项目赶工期,CubeMX帮我省了整整两天的配置时间——嗯,从那以后我就真香了。
| 对比项 | 标准库 | HAL库 | LL库 |
|---|---|---|---|
| 抽象层次 | 中等 | 高 | 低 |
| 代码量 | 较多 | 少(自动生成) | 较少 |
| 移植性 | 差 | 好 | 中等 |
| 学习曲线 | 陡峭 | 平缓 | 中等 |
| 适合场景 | 老项目维护 | 快速开发/原型 | 性能敏感场景 |
这门课我们全程使用HAL库。原因很简单:串口+DMA的配置逻辑在HAL库中封装得相当完善,我们能把精力集中在业务逻辑和调试方法上,而不是跟寄存器位定义死磕。
我的建议:如果你之前用过标准库,别急着排斥HAL。先跟着做两个项目,你会发现HAL的中断回调机制其实很优雅。当然,LL库也有它的用武之地——我们在第28章讲性能优化时会提到。
1.3 硬件平台介绍
课程选用的是STM32F103C8T6,也就是大家常说的“蓝 pills”核心板。为什么选它?
- 性价比高:十几块钱一块板,坏了不心疼
- 资料丰富:网上随便一搜都是案例
- 外设齐全:3路USART、1路DMA1(7通道)、1路DMA2(5通道)
- 市场占有率高:很多工业产品还在用这个型号
核心参数一览:
| 参数 | 值 |
|---|---|
| 内核 | ARM Cortex-M3 @ 72MHz |
| Flash | 64KB |
| SRAM | 20KB |
| USART | 3路(USART1/2/3) |
| DMA | DMA1(7通道)+ DMA2(5通道) |
| 调试接口 | SWD(4线)/ JTAG(5线) |
我在项目中遇到过用F103做串口服务器的情况,挂4个串口同时收发,DMA全开,跑了两年没出过问题。这颗芯片的稳定性是经过市场验证的。
注意:F103的USART2和USART3挂载在APB1总线上,时钟最高36MHz。如果你要用高波特率(如921600),建议优先使用挂载在APB2上的USART1。我曾经在这个坑上浪费了半天——USART2在2M波特率下死活收不到数据,换到USART1就好了。
1.4 开发环境安装与配置
我个人习惯用Keil MDK,但IAR也完全没问题。这里以Keil为例,步骤很简洁:
- 安装Keil MDK:建议5.27及以上版本,对HAL库支持更好
- 安装器件包:Keil→Pack Installer→搜索STM32F1xx→安装最新版
- 安装STM32CubeMX:从ST官网下载,建议6.x版本
- 安装驱动:CH340串口驱动(板载USB转串口用)
- 验证安装:打开CubeMX,能识别到STM32F103C8Tx即可
环境配置中最容易出问题的就是器件包版本不匹配。我记得有一次帮学生远程调试,折腾了半小时发现他装的是F4的包,工程却是F1的——编译不报错,下载就死机。
避坑指南:安装完成后,建议先跑一个官方的Blinky例程。如果LED能闪,说明环境基本没问题。不要一上来就搞串口——先确认MCU能跑起来,再谈外设。
1.5 第一个串口打印工程
好,现在我们来动手。用CubeMX创建一个最简单的串口打印工程。
CubeMX配置步骤:
- 新建工程,选择STM32F103C8Tx
- 在Pinout视图找到USART1,Mode选Asynchronous
- Parameter Settings:Baud Rate=115200,Word Length=8,Parity=None,Stop Bits=1
- NVIC Settings:使能USART1全局中断
- Clock Configuration:HSE=8MHz,SYSCLK=72MHz
- Project Manager:Project Name=uart_print,Toolchain=MDK-ARM
- 点击GENERATE CODE
生成代码后,在main.c的main()函数中添加:
#include "stdio.h"
// 重定向printf到串口
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 100);
return ch;
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
while (1)
{
printf("Hello from STM32F103! System running at %d MHz\r\n", HAL_RCC_GetSysClockFreq() / 1000000);
HAL_Delay(1000);
}
}
编译下载,打开串口助手(波特率115200),你应该能看到每秒打印一次的信息。
常见问题:如果串口助手收不到数据,先检查三件事:
- 板子的USB转串口驱动装了吗?(CH340最常见)
- TX/RX接反了吗?(STM32的TX接串口助手的RX)
- 波特率一致吗?(CubeMX配的115200,串口助手也得是115200)
我曾经遇到过一个很隐蔽的问题:某品牌的USB转串口模块在115200下不稳定,降到9600就好了。后来换了FT232的模块才解决。所以如果你死活调不通,不妨换个串口模块试试。
1.6 本章知识体系
下面这张图帮你梳理本章的核心脉络:
这张图把本章的四个模块串起来了。你会发现,所有工作最终都指向一个目标:让串口能打印出东西。这是后面所有DMA传输、不定长接收实验的基础设施。