4. STM32硬件基础
好,咱们正式开始动手了。
这一章的目标很明确——用STM32CubeMX生成一个干净的基础工程。时钟、GPIO、串口,这三样配好了,后面移植FreeRTOS才有根。
我见过不少新手一上来就急着写代码,结果时钟没配对,串口打印乱码,查了半天才发现是HSE倍频算错了。嗯,咱们先把地基打牢。
4.1 为什么选择CubeMX?
说白了,CubeMX就是ST官方给的图形化配置工具。你点点鼠标,它帮你生成初始化代码。
我个人习惯是:时钟树手动配,外设按需开,中间件后面再加。这样生成的工程干净,没有冗余代码。
核心原则:CubeMX只负责生成初始化代码,业务逻辑你自己写。别指望它帮你搞定任务调度。
4.2 新建工程与芯片选择
打开CubeMX,点击“New Project”。
在Board Selector里,我一般直接搜芯片型号。咱们课程用的是STM32F103C8T6,也就是大家常说的“蓝 pill”核心板。
- Series: STM32F1
- Line: STM32F103
- Package: LQFP48
- MCU: STM32F103C8Tx
双击选中,工程就创建好了。
小技巧:如果你用的是开发板,可以直接在Board Selector里选板子型号,CubeMX会自动配好板载外设的引脚。但咱们为了学透,还是从芯片级别开始。
4.3 配置时钟树——核心中的核心
时钟是MCU的心脏。配错了,整个系统跑起来都是歪的。
我曾经在一个项目里,因为PLL分频系数设错,导致USB时钟不准,PC死活不识别设备。查了两天才找到原因……从那以后,我每次配时钟都会对着数据手册核对一遍。
进入Clock Configuration选项卡,咱们按以下步骤来:
- 选择时钟源: HSE(高速外部晶振)——咱们板子上一般焊的是8MHz晶振。
- 配置PLL: HSE 8MHz → PLLMUL x9 → SYSCLK 72MHz。
- APB1分频: /2 → 36MHz(注意,APB1最高只能到36MHz)。
- APB2分频: /1 → 72MHz。
注意:STM32F103的最高主频是72MHz。别贪心设到128MHz,芯片会直接死给你看。我见过有人把PLL倍频设到16,结果芯片发热严重,程序跑飞。
配置完成后,时钟树应该长这样:
HSE (8MHz) → PLLSRC (HSE) → PLLMUL (x9) → SYSCLK (72MHz)
→ AHB Prescaler (/1) → HCLK (72MHz)
→ APB1 Prescaler (/2) → PCLK1 (36MHz)
→ APB2 Prescaler (/1) → PCLK2 (72MHz)
你可以在CubeMX里看到所有时钟频率都变成了蓝色——蓝色表示合法配置。
4.4 配置GPIO——点亮第一盏灯
GPIO配置其实很简单,但有个坑我得提醒你:默认引脚状态。
我刚开始做项目时,配了一个推挽输出的引脚,结果上电瞬间它输出了一小段高电平,把后面的电路给烧了。后来我才知道,CubeMX生成的代码里,GPIO初始化是在系统时钟配置之后才执行的。也就是说,在初始化之前,引脚是默认浮空输入状态。
咱们这次配一个LED控制引脚:
- 引脚: PC13(板载LED)
- 输出模式: Push-Pull
- 上拉/下拉: No pull-up, no pull-down
- 初始电平: High(LED灭)
- 速度: Low(控制LED不需要高速)
在Pinout & Configuration选项卡里,找到PC13,左键点击,选择GPIO_Output。然后在右侧的GPIO设置里,把Maximum output speed改成Low。
为什么选Low? 高速输出会增加功耗和EMI。控制LED这种低频信号,Low完全够用。省电又干净。
4.5 配置串口——调试的命脉
做嵌入式开发,串口就是你的眼睛。没有串口打印,你连程序跑到哪了都不知道。
咱们用USART1,挂在PA9(TX)和PA10(RX)上。
配置步骤:
- 在Pinout里找到USART1,模式选Asynchronous。
- CubeMX会自动把PA9和PA10配成USART1的TX和RX。
- 进入Parameter Settings:
- Baud Rate: 115200
- Word Length: 8 Bits
- Parity: None
- Stop Bits: 1
这里有个细节:NVIC选项卡里,记得使能USART1全局中断。虽然咱们这次用轮询方式打印,但后面移植FreeRTOS时,串口中断是少不了的。
波特率陷阱: 115200在8MHz HSE下是准确的。但如果你换了晶振频率,比如用12MHz,115200可能产生较大误差。我建议你配完后点一下CubeMX里的“Calculate”按钮,看看实际波特率误差是否在2%以内。超过2%,通信就可能丢数据。
4.6 生成工程代码
配置完了,该生成代码了。
点击Project → Generate Code,在弹窗里设置:
- Project Name: stm32f103_freertos_base
- Project Location: 自己选个目录
- Toolchain / IDE: MDK-ARM V5
- Firmware Package: 选你安装的版本,我用的1.8.5
然后勾选Generate peripheral initialization as a pair of .c/.h files per peripheral——这样每个外设单独一个文件,结构清晰。
点击GENERATE CODE,几秒钟后工程就生成了。
4.7 验证工程——写个简单的测试
打开生成的MDK工程,在main.c的main()函数里,咱们加几行测试代码:
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
// 串口打印测试
char msg[] = "STM32 FreeRTOS Base Project OK!\r\n";
HAL_UART_Transmit(&huart1, (uint8_t *)msg, strlen(msg), HAL_MAX_DELAY);
while (1)
{
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
HAL_Delay(500);
}
}
编译下载,打开串口助手(115200, 8N1),你应该能看到:
STM32 FreeRTOS Base Project OK!
同时板载LED以500ms间隔闪烁。
验证通过的标准: 串口打印不乱码,LED闪烁稳定。这两样对了,说明时钟、GPIO、串口都配好了。
4.8 本章知识结构图
下面这张图帮你理清整个基础工程的配置流程:
4.9 避坑总结
最后,我把这些年踩过的坑列出来,你配工程时对照着检查:
| 配置项 | 常见错误 | 正确做法 |
|---|---|---|
| 时钟源 | 选了HSI,精度不够 | 用HSE外部晶振 |
| PLL倍频 | 倍频后超过72MHz | 8MHz x9 = 72MHz |
| APB1分频 | 忘了分频,导致外设超频 | APB1必须 ≤36MHz |
| GPIO速度 | 全设成High,功耗高 | 按需选择,LED用Low |
| 串口波特率 | 晶振频率与波特率不匹配 | 用CubeMX计算实际误差 |
| NVIC使能 | 忘了开中断 | USART1中断必须使能 |