1. STM32入门:从内核到第一个工程模板
各位同学,欢迎来到《STM32嵌入式系统开发实战》的第一章。我叫老张,在嵌入式这行摸爬滚打了十几年,踩过的坑比你们吃过的盐还多(开个玩笑)。今天咱们不聊虚的,直接上手把STM32的底裤扒开看看——从ARM Cortex-M内核到底层选型,再到把Keil MDK环境搭好、跑通第一个工程模板。
这一章的目标很明确:让你脑子里有个清晰的地图,手上有个能用的工具。别急着写代码,先把地基打牢。
1.1 ARM Cortex-M内核:到底是个什么玩意儿?
说白了,Cortex-M就是ARM公司设计的一系列32位微控制器内核。它不是一颗完整的芯片,而是一个“大脑”——你需要给它配上Flash、RAM、外设接口,才能变成一颗真正的MCU。
我刚开始接触ARM时,总把Cortex-M和ARM7搞混。后来才明白,Cortex-M是ARMv7-M架构的产物,专门为深度嵌入式、低功耗、实时控制场景设计的。跟老一代ARM7比,它多了硬件除法器、嵌套向量中断控制器(NVIC)、可选的MPU(内存保护单元),还有最重要的——Thumb-2指令集。
核心要点:Cortex-M系列不跑Linux,不跑Android。它跑的是裸机或RTOS(实时操作系统)。你写的代码直接操作寄存器,没有操作系统那一层开销。
目前市面上主流的Cortex-M内核分这么几档:
| 内核 | 架构 | 典型主频 | 特点 | 常见STM32系列 |
|---|---|---|---|---|
| Cortex-M0 | ARMv6-M | 48 MHz | 超低功耗、极小面积、指令集精简 | STM32F0 |
| Cortex-M3 | ARMv7-M | 72 MHz | 性能与功耗平衡、硬件除法、单周期乘法 | STM32F1 |
| Cortex-M4 | ARMv7E-M | 168 MHz | 带FPU(浮点运算单元)、DSP指令 | STM32F4 |
| Cortex-M7 | ARMv7E-M | 400+ MHz | 高性能、双精度FPU、Cache、TCM | STM32F7/H7 |
嗯,这里要注意:M0和M0+是冯·诺依曼结构,M3/M4/M7是哈佛结构。哈佛结构指令总线和数据总线分开,取指令和访存可以同时进行,性能自然更高。我在一个电机控制项目里,就因为没注意这个区别,把M0的代码直接往M4上搬,结果中断响应时序全乱了——教训啊。
1.2 STM32系列选型:别选错了,否则哭都来不及
STM32家族庞大得像个动物园。F0、F1、F2、F3、F4、F7、H7、L0、L1、L4、L5、G0、G4、WB、WL……光看型号就头大。但别慌,选型其实就三个维度:性能、功耗、外设。
我个人习惯把选型分成四类场景:
- 入门学习:STM32F103C8T6(蓝色药丸板)。72MHz、64KB Flash、20KB SRAM,便宜、资料多、社区活跃。我带的实习生都用这个起步。
- 低功耗产品:STM32L4系列。跑在几十微安级别,适合电池供电的传感器节点、穿戴设备。
- 高性能计算:STM32H743。400MHz+、双精度FPU、2MB Flash、1MB SRAM,跑算法、做图形界面、搞音频处理都行。
- 无线连接:STM32WB55。内置蓝牙5.0和802.15.4,做物联网网关很方便。
我的建议:初学者别贪多。先拿F103把GPIO、定时器、中断、串口、ADC这几个基本功练扎实了,再考虑换系列。内核变了,但寄存器操作思路是相通的。
选型时还有几个坑,我帮你列出来:
- Flash和RAM要留余量:实际需求×1.5倍。我见过有人选64KB Flash的芯片,代码编译完62KB,加个功能就爆了。
- 引脚兼容性:同一系列不同型号引脚往往兼容。比如STM32F103C8T6和STM32F103RBT6,前者48脚,后者64脚,PCB设计时可以考虑向上兼容。
- 温度范围:工业级(-40~85℃)和商业级(0~70℃)价格差不少。如果产品要过认证,别省这个钱。
1.3 开发板资源介绍:你的第一块STM32板子
咱们课程用的是STM32F103C8T6最小系统板,也就是俗称的“蓝色药丸”。别小看它,麻雀虽小五脏俱全:
| 资源 | 说明 |
|---|---|
| 主控 | STM32F103C8T6,Cortex-M3 @72MHz |
| Flash | 64KB |
| SRAM | 20KB |
| GPIO | 37个可用IO,大部分支持5V容忍 |
| 调试接口 | SWD(SWCLK + SWDIO),2线搞定下载和调试 |
| 板载外设 | 1个电源LED、1个用户LED(PC13)、1个复位按键 |
| 时钟源 | 8MHz外部晶振(HSE)、32.768kHz RTC晶振 |
这块板子最让我喜欢的是SWD调试接口——只需要一根ST-Link/V2下载器,接4根线(VCC、GND、SWDIO、SWCLK)就能下载和调试。不像早期的JTAG要接一堆线。
注意:PC13这个引脚驱动的LED是低电平点亮的。很多新手上来就写GPIO_SetBits(LED_PORT, LED_PIN),结果灯死活不亮——因为你要写GPIO_ResetBits才对。我当年也犯过这个错,查了半小时。
1.4 开发环境搭建:Keil MDK安装与工程模板建立
好,理论说完了,咱们动手。环境搭建分三步走:
1.4.1 安装Keil MDK
- 去Keil官网下载MDK-ARM(当前最新是5.38a版本)。注意区分MDK-ARM和MDK-Professional,咱们用前者就够了。
- 安装时一路默认路径,但建议不要有中文和空格。我习惯装到 D:\Keil_v5。
- 安装完成后,打开Pack Installer,找到STM32F1系列的支持包(Keil.STM32F1xx_DFP),下载安装。这一步是让Keil认识STM32F103的寄存器定义和启动文件。
- 破解(懂的都懂)。用注册机生成License,填进去。
小技巧:安装完成后,在Keil里点 Project → Manage → Component Environment,检查一下STM32F1xx_DFP的版本。我建议用2.4.0以上版本,启动文件更完善。
1.4.2 建立工程模板
我习惯自己建模板,不用STM32CubeMX自动生成——因为我想知道每一行代码在干什么。模板结构如下:
Project_Template/
├── User/ # 用户代码
│ ├── main.c
│ ├── stm32f10x_it.c # 中断服务函数
│ └── stm32f10x_conf.h
├── CMSIS/ # 内核抽象层
│ ├── core_cm3.h
│ ├── core_cm3.c
│ └── system_stm32f10x.c
├── FWLIB/ # 标准外设库
│ ├── inc/ # 头文件
│ └── src/ # 源文件
├── Startup/ # 启动文件
│ └── startup_stm32f10x_md.s
└── Project.uvprojx # Keil工程文件
新建工程的步骤:
- 打开Keil,Project → New μVision Project,选好芯片型号(STM32F103C8)。
- 在弹出的Manage Run-Time Environment里,不要勾任何东西。我们手动添加文件。
- 在工程里新建5个Group:User、CMSIS、FWLIB、Startup、Doc。
- 把对应文件拖进去。启动文件选 startup_stm32f10x_md.s(md代表Medium Density,中等容量)。
- 配置魔术棒(Options for Target):
- Target标签:Xtal选8.0MHz,勾上Use MicroLIB(精简版C库,省RAM)。
- Output标签:勾上Create HEX File,方便烧录。
- C/C++标签:Define里填
STM32F10X_MD, USE_STDPERIPH_DRIVER。 - Debug标签:选ST-Link Debugger,点Settings,确认SWD模式,速度选1.8MHz(别选太高,容易不稳定)。
1.4.3 写一个点灯程序验证
模板建好后,写个最简单的程序验证环境是否正常:
#include "stm32f10x.h"
void Delay(uint32_t count) {
while(count--);
}
int main(void) {
// 使能GPIOC时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
// 配置PC13为推挽输出
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
while(1) {
GPIO_ResetBits(GPIOC, GPIO_Pin_13); // 低电平点亮
Delay(0xFFFFF);
GPIO_SetBits(GPIOC, GPIO_Pin_13); // 高电平熄灭
Delay(0xFFFFF);
}
}
编译通过后,用ST-Link连接板子,点Download。如果蓝色药丸板上的LED开始闪烁——恭喜你,环境搭建成功了!
我曾经遇到一个坑:下载时Keil报错“No ST-Link detected”。检查了驱动、USB线、接线都没问题。最后发现是ST-Link的固件版本太老,用STM32 ST-LINK Utility升级了一下就好了。如果你也遇到类似问题,先升级固件试试。
1.5 本章知识体系总览
下面这张图帮你把本章的知识点串起来:
这张图把本章的五个核心知识点串成了一条线。你跟着这个路径走,就不会迷路。
好了,第一章就到这里。环境搭好了,灯也亮了,接下来咱们就可以开始真正写代码了。记住:嵌入式开发没有捷径,但一定有方法。我踩过的坑,你尽量别踩;我总结的经验,你直接拿去用。这样学起来,效率至少翻一倍。