
1. 准备工作先把开发板和工具认清楚做嵌入式开发这几年我最大的感受是许多新手倒在起跑线上不是因为代码写不出来而是因为开发环境没搭好或者板子都没认清就开始写代码最后连程序烧不进去都不知道问题出在哪。STM32F103 是意法半导体推出的经典 Cortex-M3 内核芯片主频最高 72MHzFlash 从 16KB 到 512KB 不等内存从 6KB 到 64KB因其性价比高、资料丰富至今仍被高校和企业大量使用。如果你是刚接触嵌入式的学生或者想从 Arduino 转型到更专业的开发平台这门课就是为你准备的。整条学习路线其实可以浓缩成四个环节认识板子、搭建环境、编译烧录、调试运行。只要把这四步走顺了后面的 GPIO、定时器、串口、中断都是一马平川。在动手之前先想清楚一个问题你到底需要什么样的开发板这取决于你想学什么、预算多少、手头有什么工具。市面上的 STM32F103 开发板大致分三类最小系统板比如蓝药丸 C8T6、完整型开发板比如正点原子 Mini 板、野火指南者、自制核心板。我的建议是新手从最小系统板起步原因很简单它电路简单、引脚全部引出、价格便宜而且能逼着你理解时钟、复位、启动模式这些底层细节。注意这里说的“认识开发板”不是让你看一遍图文介绍就完事而是要求你能指着一块板子说出上面每一个芯片、每一个插座、每一个跳线帽是干什么用的。这块基础打牢了后面调试程序时会省下大量时间。另外除了开发板本身你需要准备的工具如下表所示。虽然有些工具不是必须的但我建议一步到位因为它们在后续课程和实际项目中都会反复用到。工具用途优先级开发板STM32F103C8T6 最小系统板学习主战场必需ST-Link V2 调试器下载程序、在线调试强烈建议USB-TTL 串口模块如 CH340串口通信、ISP 下载建议杜邦线若干连接电路必需面包板搭建外围电路建议万用表排查硬件故障强烈建议示波器或逻辑分析仪观测波形调试高级功能选配这里我想分享一下选型逻辑不要一上来就买八九十块钱的完整开发板。虽然带液晶屏、按键、LED 的板子看着很炫但它们替你做了太多事情导致你对底层原理的理解会打折扣。我第一次带学生实训时有同学用完整开发板做了点灯实验却连 LED 为什么亮都说不清楚换用最小系统板后自己动手接线路、查数据手册反而很快入了门。2. 开发环境搭建KEIL MDK 安装与芯片支持包配置2.1 为什么选择 KEIL MDK 而不是其它 IDESTM32F103 的开发环境选择有好几种KEIL MDK、IAR EWARM、STM32CubeIDE、PlatformIO VSCode甚至 GCC 命令行工具链。对于新手和大多数企业工程师来说KEIL MDK 依然是最主流的选择原因有三第一KEIL MDK 的操作界面、编译流程和调试功能非常贴近嵌入式工程师的实际习惯代码编辑、编译、下载、在线调试全部在一个窗口里完成学习成本低。第二几乎所有 STM32 教程、例程、网课都以 KEIL MDK 为默认环境你用它能少碰到很多“版本不兼容”的坑。第三KEIL MDK 的工程管理逻辑清晰从固件库到中间件到用户代码分层填写能帮助你建立标准的工程组织观念。有人说 KEIL 界面老旧不如 VSCode 好看。我不否认但我要说的是工具的“好看”是次要的工程的“可复现”和“可维护”才是关键。尤其在企业里老项目用 KEIL 是常态你换个 IDE 可能连编译都过不了。提示KEIL MDK 官方并不免费但商业评估版MDK-Community对代码体积 32KB 以内的工程免费。STM32F103C8T6 的 Flash 是 64KB不过一般学习工程仅用十几KB评估版够用。2.2 安装步骤详解KEIL MDK 的安装过程不复杂但有几个细节值得注意。我按步骤拆开讲去 KEIL 官网下载 MDK-ARM 安装包区分版本目前常见的是 5.36 或 5.37 等双击运行依次点击 Next。需要提醒的是安装路径最好不要有中文和空格这主要是为了避免某些编译插件报路径错误。在安装类型界面选择 Core 即可这样会默认安装到 C 盘 KEIL_v5 目录。如果你希望装到别的盘可以自定义路径但后续芯片支持包的路径也会跟着变要注意一致性。安装完成后先别急着打开 IDE。接下来最关键的一个步骤是安装芯片支持包Pack。你可能在建立工程时发现 Device 列表里找不到 STM32F103C8原因就是 Pack 没装。Pack 是一种封装了芯片型号、寄存器定义、启动文件、Flash 算法的插件包没有它KEIL 根本不认识你的芯片。打开 KEIL 后在 Pack Installer 窗口里点右上角的 Pack 图标从列表里找到Keil::STM32F1xx_DFP点击 Install 即可。如果你网络不好也可以去 Keil 官网下载离线包手动双击安装效果一样。安装完 Pack 后需要注意 KEIL 的Options for Target窗口中Device一栏应能正常显示 STM32F103 系列芯片型号。很多新手在建立工程时看到 Device 下拉框空白就是 Pack 没弄好回头重新装一遍基本上能解决。2.3 串口驱动的坑与解决经验如果你用的是 USB-TTL 串口模块比如 CH340G在 Windows 上往往需要手动安装驱动。正常情况下把模块插入 USB 口设备管理器里会出现 COM 口。但问题来了很多新系统默认不识别 CH340会在设备管理器里显示黄色感叹号。遇到这种情况我的处理顺序是固定的检查线材和 USB 口换一根数据线试试很多“驱动有问题”其实是线材本身不通电。去官网下载最新版 CH340 驱动右键以管理员身份运行安装。装完后拔插设备观察设备管理器变化。这三个步骤能解决我遇到的 90% 串口识别问题。还有一个进阶建议装完驱动后在设备管理器里右键 COM 口、打开“属性 → 端口设置”将波特率设为 115200数据位 8、停止位 1、无校验这是串口调试时的标准配置。3. 工程模板搭建从固件库到 GPIO 点灯全流程3.1 标准外设库还是 CubeMX 生成的 HAL 库在 2024 年的今天摆在你面前的有两条路老派的标准外设库StdPeriph Library和新派的 STM32CubeMX HAL 库。很多 2020 年之前的教程都在教标准外设库但近两年 HAL 库已经成为主流尤其在企业项目中CubeMX 建工程已经成了默认流程。我自己两种都用过可以给出客观的对比标准外设库代码可以直接操作寄存器逻辑更透明适合深度理解底层HAL 库抽象层更高开发效率高代码移植方便CubeMX 里鼠标点一点就能生成初始化代码。对于实训目的我的建议是以 HAL 库入门同时把标准库的例程当参考。因为你初次学习追求的是“快速点亮一盏灯”的正反馈而不是被一堆寄存器配置困住。当然你如果未来想走嵌入式底层驱动方向标准库和寄存器操作那一套还得回头补课。至少现阶段先用 HAL 把流程跑通。3.2 用 CubeMX 生成 MDK 工程CubeMX 是一款图形化初始化工具它的核心价值在于把引脚分配、时钟树、外设参数这些极容易出错的工作自动化。我们以下面的 C8T6 点灯实验为例走一遍打开 STM32CubeMX选择Access to MCU Selector在搜索框输入 STM32F103C8双击选中。在System Core里配置RCC将 HSE 设置为 Crystal/Ceramic Resonator。这是为了使用外部晶振保证系统时钟稳定。在Clock Configuration页面配置时钟树HSE 8MHz 经 PLL 倍频到 72MHz。关键操作是输入 8在 PLL Source 选择 HSEPLL Mul设为 9此时系统时钟 SYSCLK 会显示 72MHz符合芯片最高主频。配置 GPIO在芯片引脚图上点击想要控制的引脚PC13 或 PA1选择GPIO_Output同时可在 GPIO 设置里调节初始电平、推挽/开漏等参数。在Project Manager里填写工程名、路径、选择 MDK-ARM V5 工具链并勾选生成外设初始化代码。点击 GENERATE CODECubeMX 会生成一个完整的 MDK 工程。这里我需要提醒一个新手常犯的错在 CubeMX 里定义引脚为输出后如果电路是高电平点亮 LED记得把 GPIO 的初始电平设为低电平否则程序一上电 LED 就会亮容易误以为是程序跑飞了。生成工程后用 KEIL 打开.uvprojx文件即可进入主程序编写。一个最简单的点灯代码是在while(1)循环里写while (1) { HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET); // LED 亮 HAL_Delay(500); // 延时 500ms HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); // LED 灭 HAL_Delay(500); }这段代码的作用是让 PC13 引脚交替输出高低电平LED 以 1Hz 频率闪烁。注意 CubeMX 生成的项目里SystemClock_Config()函数已经被自动调用你不需要手动初始化时钟这对新手来说非常友好。3.3 KEIL 工程关键配置检查清单用 CubeMX 生成的 KEIL 工程已经配置好绝大多数参数但你依然要在 KEIL 的Options for Target里确认几项内容否则可能踩到烧录和调试的坑Device 选择确认当前选择的芯片型号是 STM32F103C8。Debug 选项在下拉框中选择 ST-Link Debugger并点击 Settings 确认能够识别到设备 ID。如果这里识别不到后面烧录肯定失败。Utilities 设置勾选Use Debug Driver并在 Flash Download 里勾选Reset and Run这是让程序烧录完成后自动复位的选项不勾选的话程序不会自动启动。代码生成选项如果是用标准库需要把 C 语言标准设置为 C99否则一些语法会报错。我见过太多人在 GPIO 代码完全正确的情况下程序就是跑不起来到最后发现是 Debug 设置里选错了调试器或者 Reset and Run 没有勾选。这种低级错误其实很好排查花十分钟检查一遍配置能省掉后面一个小时的烦恼。4. 烧录与调试ST-Link 接线、Flash 算法与串口通信4.1 ST-Link 与开发板的硬件连接ST-Link V2 是 STM32 开发中最常用的调试下载器它支持 SWD 和 JTAG 两种接口对新手来说我强烈建议用 SWD 四线方式占用引脚少稳定可靠。接线颜色标准如下ST-Link V2 引脚开发板对应引脚说明3.3V3.3V 电源引脚注意别接 5VSWDIOPA13数据线SWCLKPA14时钟线GNDGND地在接线前先确认开发板供电方式。最小系统板一般可以通过 USB 口或 ST-Link 供电我建议如果你的 ST-Link 是带电源输出的版本直接由 ST-Link 供电即可但前提是总电流不大。如果外接了传感器模块最好用 USB 独立供电避免 ST-Link 供电不足导致复位不稳定。注意很多 ST-Link 的排针定义并不统一不同厂商的线序可能截然不同。接线前务必对照 ST-Link 外壳上的丝印和开发板引脚图逐一确认这是我带实训时发现最容易被忽略的地方也是最容易烧板子的地方。4.2 KEIL 里配置 ST-Link 并下载程序硬件接好后打开 KEIL 的Options for Target进入 Debug 设置设置 Debug 下拉框为ST-Link Debugger并点击右侧 Settings。在 Debug 子页里确认 Port 为 SWMax Clock 可以设为 4MHz 或 2MHz。如果连接不稳定把时钟降下来反而更可靠。点击Flash Download选项卡勾选Reset and Run并在 Programming Algorithm 中确认已经加载了 STM32F10x Med-density Flash 算法。设置完成后点击编译F7确保无错误然后点击 DownloadF8烧录程序。如果一切顺利状态栏会显示Flash Load finished程序随即开始运行。这里我在实践中遇到过一种情况程序烧录进去后 LED 不工作板子完全没有反应。经过排查发现是 BOOT0 引脚的电平状态问题。STM32F103 支持三种启动方式由 BOOT0 和 BOOT1 的电平决定。正常运行时 BOOT0 必须接低电平GND如果在高电平状态芯片会从系统存储器启动正常运行的程序当然不会执行。BOOT0BOOT1启动模式0XFlash 启动正常模式10系统存储器启动ISP 下载11SRAM 启动调试用4.3 串口通信printf 重定向和监控程序烧进去之后如果只能看 LED 闪烁未免太单调。实际开发中最常用的调试手段是串口打印。STM32F103 的 USART1 引脚是 PA9TX和 PA10RX你需要用 USB-TTL 模块连接STM32 PA9TX → USB-TTL 的 RXSTM32 PA10RX → USB-TTL 的 TX共地两块板子的 GND 必须相连要注意的是USB-TTL 模块上如果标明 3.3V/5V 跳线务必调到 3.3V否则可能烧毁 STM32 的引脚。串口初始化和 printf 重定向是新手比较容易卡住的点。在 HAL 库工程中可以用以下方式重定向 printf 到串口int fputc(int ch, FILE *f) { HAL_UART_Transmit(huart1, (uint8_t *)ch, 1, 0xFFFF); return ch; }同时在 KEIL 的 Options 里勾选Use MicroLIB这个操作让编译器用精简的 C 库从而支持 printf 重定向。很多人的 printf 不出数据其实就是没有勾选这个选项。串口的收发看起来简单但实际调试中有三个高频问题一是波特率匹配不上双方波特率必须完全一致常见是 115200二是地没共好导致信号参考点不对出现乱码三是 TX/RX 接反了。排查顺序按照这三个来基本能解决绝大多数串口问题。5. 开发板深度认识最小系统电路与引脚资源解析5.1 STM32F103C8T6 最小系统剖析认识开发板不能停留在“会用”的层面至少要弄清楚一块最小系统板由哪些部分组成。以常见的 C8T6 蓝药丸板为例它的最小系统包括电源电路、晶振电路、复位电路、启动模式配置电路以及必要的去耦电容。我在给学员讲解时会把这块板子拆解成如下几个模块逐一过一遍电源电路方面C8T6 工作电压是 2.0V 到 3.6V典型值是 3.3V。开发板通常提供一个 USB 5V 输入然后经过 AMS1117-3.3 稳压芯片降为 3.3V 供芯片使用。这里有个重要知识点如果你想自己设计板子必须考虑 5V 转 3.3V 电路也就是把 5V 输入经过稳压芯片转换为 3.3V 输出同时输入输出端各放置一个 10uF 和一个 100nF 的去耦电容。这个电路我在很多学员的自制板里都见过大部分问题出在电容漏焊或极性焊反导致电压纹波大芯片工作不稳定。晶振电路方面HSE高速外部时钟采用 8MHz 晶振负载电容通常选 22pF 左右。HSE 是系统时钟的重要组成部分如果焊接不良CubeMX 生成的工程会在 HAL_RCC_ClockConfig 阶段卡住死循环。我的排查建议是程序卡死在Error_Handler()时优先考虑晶振是否起振。复位电路方面NRST 引脚接一个外部复位按键和 RC 复位电路。按键按下把 NRST 拉低芯片复位。如果你发现程序运行中频繁自动复位检查复位引脚是否有干扰或去耦电容是否有问题。启动配置电路方面BOOT0 引脚通常接一个下拉电阻到 GND通过跳线帽或拨码开关可切换启动模式。BOOT1 引脚在 C8T6 上一般悬空即可。5.2 读懂 STM32F103 的引脚资源STM32F103C8T6 是 LQFP48 封装共有 36 个 GPIO 引脚分布在 PA0-PA15、PB0-PB15、PC13-PC15、PD0-PD1 等端口。每个端口都支持多种复用功能包括 USART、SPI、I2C、定时器、ADC 等。理解引脚资源的关键是学会查数据手册里的引脚定义表。我给新手的一个建议是拿到一块新板子别急着接线先做一份“引脚资源速查表”。把每个引脚可能用到的功能列出来这样在设计电路时选引脚就不会出现“冲突”的情况。比如你用了 PA9 做串口 TX同时又想让它做普通 GPIO 输出高电平那就可能有冲突因为它的复用功能占用会影响外部电路。对于 C8T6 来说最常用的资源可以粗略概括如下USART1 固定接 PA9、PA10I2C1 接 PB6SCL、PB7SDASPI1 接 PA5SCK、PA6MISO、PA7MOSIADC1 的通道大部分分布在 PA0-PA7高级定时器 TIM1 的 PWM 输出在 PA8、PA11 等引脚。你可能不需要把所有功能都背下来但每次用到某个外设前先查一遍引脚定义形成习惯是很重要的。5.3 最小系统板的常见连接陷阱认识了开发板资源之后还要多看几个容易犯的硬件问题。我在带实训时经常看到学员出现以下几种连接错误第一种是供电引脚接反。很多最小系统板的 3.3V 和 5V 引脚挨得很近杜邦线插反后芯片直接冒烟。虽然芯片一般内置保护电路但反复反接会缩短寿命。第二种是外部模块电平不匹配。有些 5V 传感器模块输出高电平 5V直接接 STM32 引脚可能造成损坏。正确的做法是使用电平转换电路或选用 3.3V 供电的模块版本。这里可以用一个简单的分压电阻或电平转换模块来解决具体电路网上资料很多我不再赘述。第三种是引脚复用冲突。比如你想同时使用 SWD 调试PA13、PA14和定时器 PWM 输出而 PA14 恰好是某个定时器的复用引脚就有可能冲突。此时需要改用其它 GPIO 作为调试口或者把 PWM 输出迁到其它引脚。CubeMX 的引脚分配图能直观看出哪个引脚被占用用起来很方便。6. 常见问题与排查技巧实录6.1 编译报错与工程配置问题速查现象可能原因解决方案Device 下拉框无芯片可选Pack 未安装或安装失败重装 Keil.STM32F1xx_DFP编译报错缺stm32f1xx_hal.h工程头文件路径缺失Options → C/C → Include Paths 添加 HAL 库路径编译报Error: L6218E: Undefined symbol缺少外设源文件或 HAL 库模块未启用检查工程添加的 .c 文件是否完整程序烧录后没反应BOOT0 处于高电平将 BOOT0 接到 GND点击 Download 提示无法连接ST-Link 接线错误或驱动问题检查 SWDIO、SWCLK、GND 接线并重装调试器驱动串口输出乱码波特率不匹配或公共地未连接统一波特率、连接 GND这张表是我在实训中最常拿出来对照的。很多问题看起来千奇百怪归根到底是几个固定原因按照“工程配置 → 硬件接线 → 驱动安装”的顺序去排查效率最高。6.2 芯片锁死与 Flash 保护问题还有一个必须提到的问题是芯片被锁死。这种情况一般发生在你用调试器连接芯片时误操作了读保护或者程序里不小心设置了 Flash 的写保护选项字节。此时 KEIL 下载程序会报类似Error: Flash Download failed - Cortex-M3的错误。我的处理办法是用 ST-Link Utility官方工具连接芯片在 Option Bytes 里将读保护等级调整为 Level 0执行擦除后重新上电即可恢复。如果没有 ST-Link Utility也可以在 KEIL 里进入 Debug 模式在 Flash 菜单里执行 Erase 操作但成功率稍低。这个问题的本质是 STM32 的 Flash 保护机制在工作。对新手来说操作时不要随便动 Option Bytes 设置如果不小心动了也不要慌按上面的方法恢复即可。6.3 调试器连接失败的高级排查思路有一个场景是ST-Link 驱动装了、接线也对但 KEIL 的 Settings 里始终识别不到设备。我遇到这种问题时会按以下顺序排查检查 ST-Link 是否为山寨版。市面上很多十几块钱的 ST-Link V2 用的是国产芯片方案固件版本老经常出现识别不稳定。如果是这种情况升级固件到最新版本或者换用正版。检查驱动加载情况。右键“此电脑” → 管理 → 设备管理器看是否有ST-Link相关设备。如果没有很可能驱动被安全软件拦截了手动安装驱动即可。降低 SWD 通信速率。在 KEIL 的 Debug Settings 里把 Max Clock 从 4MHz 降到 1MHz很多时候能解决连接不稳定的问题。检查杜邦线长度和质量。超过 20cm 的高阻抗杜邦线在高速通信时信号会衰减换短线或改用线夹更稳妥。这种基础问题如果卡住了不要急着怀疑芯片坏了先检查环境和工具。7. 实训后的进阶路径建议写完点灯实验、跑通串口打印、理解了最小系统板之后你已经算踏进嵌入式开发的大门了。后续怎么走我给你几条建议第一条建议是吃透 CubeMX 生成的初始化代码。很多人用 CubeMX 生成了工程就直接写用户代码从不看初始化函数。我建议你花一个晚上把SystemClock_Config()、MX_GPIO_Init()这类函数一行一行读一遍再对照参考手册比如 RM0008理解寄存器配置。你会惊讶地发现图形化工具背后其实是一套严格的寄存器操作逻辑。第二条建议是多做小项目刻意训练“读电路图 写驱动”的组合能力。比如外接一个 OLED 显示屏、写一个 I2C 扫描程序、用定时器做精确延时、用外部中断读取按键。这些项目单个看起来不难但组合在一起就能覆盖 STM32 的绝大部分常用外设。第三条建议是尽早接触版本管理工具。我知道很多嵌入式新手觉得 Keil 项目加不进 Git 里其实是因为没有忽略生成文件。建议在工程目录下加入.gitignore忽略*.o、*.axf、*.hex等编译产物只跟踪源码和 CubeMX 的.ioc文件。这样你的工程才具备可追溯性也为后续多人协作打好基础。最后说一下我个人的体会嵌入式开发的学习曲线确实比较陡但它的“正反馈”也来得很快。只要环境搭好、板子点亮、串口能打印你就有了一整套可以复用的基础工具后面再学 RTOS、学嵌入式 Linux甚至转型做嵌入式 AI 开发都不会觉得突兀。这个第 00 课看起来只是搭环境实际上是为你整个嵌入式的学习路线打下最底层的地基。把地基打牢别赶进度是一个我见过太多人忽略、但无比重要的建议。