
在嵌入式圈子里有一个组合到今天依然是“入门必选、量产常见”的经典搭配Keil MDK-ARM 配 STM32F103。尤其 v5.43a 这个版本在 2024 年到 2025 年这段时间里几乎成了芯片资料、开源项目、旧工程维护的默认基准。不少人回头去装 5.43a不是因为追新而是因为新版本搞不定老工程、旧库、第三方插件反而是这个版本兼容性最稳。这篇文章就围绕“MDK-ARM v5.43a STM32F103 开发环境”这条主线把从软件安装、器件支持包部署、License 授权、工程创建、编译烧录到常见问题排查的完整流程过一遍。文章里的每一步都来自我实际搭建和教学过程中反复确认过的做法照着走基本不会被卡住。适合刚开始学 STM32 的同学也适合从其他 IDE比如 IAR、Eclipse转过来的工程师。1. 为什么是 v5.43a选这个版本的三个理由很多人在选 Keil 版本时会纠结到底用 MDK v4、v5 还是最新的 v6我的建议很直接——如果你搞 STM32F103直接固定在 v5.43a 或者差不多时期的 v5 版本即可不需要追新。1.1 版本谱系和工程生态的匹配关系Keil 的 MDK-ARM 从 v4 跳到 v5 之后最核心的变化是编译器和器件支持包Device Family Pack简称 DFP彻底分离。v4 时代芯片型号直接内嵌在安装包里到了 v5你需要单独装一个对应厂商和芯片系列的 Pack比如 STM32F1 系列就需要安装 Keil.STM32F1xx_DFP。MDK v5.43a 这个版本的特殊之处在于它处在 AC5 编译器仍被大量使用、AC6 编译器开始普及的过渡期。ARM Compiler v5AC5在 STM32F103 这种 Cortex-M3 内核上编译出来的代码稳定、成熟很多老工程师习惯用 AC5 编译正式项目。而 v5.43a 默认同时支持 AC5 和 AC6你既可以在 Option 里切换编译器版本也不会因为版本太高导致某些旧版 DFP 加载不了。1.2 STM32F103 和 MDK v5.43a 的兼容性为什么好STM32F103 是基于 Cortex-M3 内核的经典芯片ARM 官方对这颗内核的编译器支持非常成熟。MDK v5.43a 自带的调试器驱动、FLASH 下载算法、CMSIS 组件基本是围绕 F1 系这种老芯片做过大量优化的。我在实际比对过 v5.36、v5.38、v5.43a 之后发现针对 STM32F103 而言5.43a 在编译速度、烧录稳定性上和三方调试器ST-Link、J-Link、CMSIS-DAP的适配都是最稳的一档。另一个很现实的原因是网上大量现成工程、正点原子、野火等开发板的配套例程很多直接标注“Keil MDK v5.43a 打开”如果你版本不一致打开工程时轻则警告、重则变量定义冲突或者语法错误。1.3 电脑环境的基本要求MDK-ARM v5.43a 对电脑的要求不高实测在 4GB 内存的旧笔记本上跑 STM32F103 工程都没问题。操作系统建议 Windows 10 或 Windows 11 64 位Windows 7 虽然也能装但调试器驱动方面偶尔会有兼容性问题。需要注意的是MDK 这个 IDE 对中文用户名或者中文路径比较敏感安装路径和工程路径里最好全用英文字符。1.4 哪些情况可以考虑其他版本如果你要搞的是 STM32H7、STM32MP1 这类高端芯片或者需要 Cortex-M7 内核的深度优化那建议用更新的 MDK v5.40 以上版本如果你要兼容 2009 年左右的老工程那可以考虑 MDK v4.74 配合旧库。但如果你就是老老实实搞 STM32F103v5.43a 几乎是一个不需要思考的选择。2. 第一步获取、安装 MDK-ARM v5.43a2.1 软件获取的正规渠道获取 MDK-ARM 的唯一正规渠道是 ARM 官网keil.arm.com 或者 www.keil.com。下载页面里选择 MDK-ARM 的 Downloads 区域找到 5.43a 版本的安装包即可。这里要特别提醒一句下载和授权走官方渠道是最省心的做法。网上很多“破解工具”、“注册机”不仅违反软件授权协议而且常会携带恶意程序。MDK 本身提供功能完整的评估版对学习来说基本够用后续如果做商业项目购买正版授权也是成本可控的正路。评估版Evaluation Version的限制主要是代码编译量不超过 32KB对于 STM32F103 的基础入门、外设驱动学习、Modbus 通信、小型 RTOS 移植这些场景来说32KB 其实相当宽裕一个精简的 FreeRTOS 点灯工程编出来也就 10~20KB。先评估、后购买是非常合理的学习路径。2.2 安装流程中的关键选项安装过程不算复杂但有三个细节直接影响后面的使用体验。第一个是安装路径。默认路径一般是 C:\Keil_v5建议保持默认不要改到带有空格或中文的目录否则部分编译器和调试脚本在寻找绝对路径时可能出错。第二个是组件选择。安装向导会让你勾选要安装的组件默认全选即可但如果电脑空间紧张可以去掉 32 位支持、不需要的 License Management 文档之类的项目。核心组件是 MDK Core 和 ARM Compiler。第三个是器件支持包的处理。官方安装包在最后一步会询问是否立即运行 Pack Installer这里可以先跳过等到后面单独装 DFP。2.3 安装目录结构看一眼装完之后建议打开安装目录扫一眼理解它的布局ARM/ARMCC这里存放的是 AC5 编译器也就是 armcc 那套工具链。ARM/ARMCLANG这是 AC6 编译器基于 Clangv5.43a 会自带。ARM/PACK这个文件夹是器件支持包的大本营DFP 装好之后会出现在这里。UV4Uvision 主程序目录启动入口是 UV4.exe。TOOLS.INIIDE 的配置文件记录安装路径、PACK 路径等信息。以后如果遇到“无法打开某个 Pack”的报错大概率是 ARM/PACK 路径不对或者 Pack 损坏。2.4 License 授权的配置方式安装完成后打开 uVision在菜单 File - License Management 里能看到当前的授权状态。如果显示 Evaluation则代表评估版。激活方式有两种第一种如果你有正版激活码直接在 License Management 界面填入 License ID CodeLIC即可这种方式最方便。第二种如果只有激活文件.lic需要点击 Licenses 选项卡然后通过 Browse 加载对应的 .lic 文件。针对 STM32F103 学习场景建议先不急着激活直接用评估版跑通全流程等确认开发环境没问题再考虑正式授权。这样你在排查问题时也不会把“授权异常”这个变量混进来。3. 第二步部署 STM32F103 器件支持包DFP3.1 Pack Installer 到底在干什么MDK v5 之后芯片型号、启动文件、Flash 下载算法、SVD 调试描述文件全部打包在 DFP 里。如果没有对应的 DFP你在 uVision 的 Device 列表里根本找不到 STM32F103C8T6 这个型号更别提建立工程了。所以装完 MDK 之后第一件事就是装 Pack。3.2 在线安装最省事的方式打开 uVision点击工具栏上的 Pack Installer 图标在 Devices 选项卡里展开 STMicroelectronics - STM32F1 Series可以看到不同子系列的 Pack 版本。直接点击 Install 按钮即可。在线安装会自动匹配 MDK 版本一般不会出现兼容性问题。需要提醒的是Pack Installer 有时候会卡在 Checking for new packs 的界面这通常是因为网络连接官方服务器不稳定。此时可以关掉重试或者直接改用离线安装。3.3 离线安装网络受限时的备用方案在 ARM 官网的 PACK 下载页面找到 Keil.STM32F1xx_DFP.2.4.1.pack 这样的文件版本号可能更新下载后直接双击或者用 Pack Installer 的 File - Import 菜单导入。离线 Pack 的好处是一次下载之后可以反复安装适合内网开发环境。安装完成后可以在 Pack 区域看到 STM32F1 系列的组件列表包括CMSISDevice:StartupDevice:STM32F103 系列的外设定义Flash 编程算法这里要注意 DFP 版本并不是越新越好。有些过于新的 DFP 会默认启用一些新的 CMSIS 头文件规范对老工程不友好。STM32F1 系列的话2.3.0 到 2.4.x 这个区间都适合。3.4 确认 Pack 安装成功最简单的方法在 uVision 中点击 Project - New uVision Project在弹出的芯片选择对话框中直接输入 STM32F103C8如果能看到对应型号并支持点选说明 Pack 已经生效。如果没有回到 Pack Installer 里再确认一遍安装状态。4. 第三步创建一个可编译、可烧录的 STM32F103 工程4.1 工程结构选型标准库、HAL 库还是 LL 库STM32F103 的软件开发方式通常有三种标准外设库StdPeriph、HAL 库、LL 库。在 MDK v5.43a 下这三种都能用但取舍差别不小。如果你看的是 ST 官方或较老的教程大概率用的标准外设库如果是从 STM32CubeMX 起步用的是 HAL 库。我的观点是新学的人建议直接上 HAL 库因为 CubeMX 生成的代码可以直接在 MDK 中打开省去手写初始化配置的大量时间比如 SPI 通过 DMA 读取传感器数据这种外设组合CubeMX 图形化配置完再导入 MDK 编译效率高很多。如果你在维护老项目、或者需要对寄存器级别的操作有绝对掌控力标准库依然能打。无论选哪种MDK 工程的文件组织逻辑是一样的都要包含启动文件、系统时钟文件、外设驱动、用户主程序。4.2 用 uVision 创建一个空白工程在菜单 Project - New uVision Project输入工程名比如 STM32F103_Demo选择保存路径。这时会弹出 Device 选择窗口按芯片具体型号选择比如STM32F103C8T6选择 STMicroelectronics - STM32F1 Series - STM32F103 - STM32F103C8。STM32F103ZET6对应 STM32F103ZE。选好型号后会弹出 Manage Run-Time Environment 窗口。在这里可以勾选需要的软件组件比如 CMSIS:CORE、Device:Startup这两个是必须的。其他外设组件可以按需勾选如果不想用 MDK 自带的组件也可以后面手动添加库文件。4.3 芯片选型与启动文件的关系选完芯片后uVision 会自动为工程添加对应的启动文件比如 startup_stm32f103xb.s和系统文件system_stm32f1xx.c这是初学者最容易忽略的部分。很多人编译报错原因就是工程里少了这两个基础文件。启动文件的作用是定义中断向量表、初始化堆栈、调用 SystemInit、跳转到 main 函数。system_stm32f1xx.c 则负责把系统时钟配置到目标主频比如 72MHz。如果不小心删了启动文件整个工程必然编译失败。4.4 配置编译输出与调试器选项建立工程后在 Project - Options for Target 里有几个选项必须确认Output 选项卡勾选 Create HEX File这样编译后能生成用于烧录的 .hex 文件。Debug 选项卡右侧 Use 下拉框里选择调试器类型常用的是 ST-Link Debugger 或 J-LINK。如果用的是开发板自带的 CMSIS-DAP这里选 CMSIS-DAP Debugger。Utilities 选项卡勾选 Use Debug Driver 或选择 ST-Link这一步负责烧录时调用下载算法。C/C 选项卡如果用了 HAL 库或者标准库需要在这里添加 Include Paths也就是头文件路径。4.5 一个最小可运行的工程源文件要准备多少以标准库为例一个最小点灯工程源文件大概需要这些main.c主循环控制 GPIO。stm32f10x_gpio.c / stm32f10x_rcc.c外设驱动源文件按需从标准库拷贝。stm32f10x_it.c中断服务函数文件。system_stm32f10x.c时钟初始化。startup_stm32f10x_hd.s启动文件。用 HAL 库的话CubeMX 生成工程后会把这些都替你组织好你只需要在 MDK 里打开 .uvprojx 工程文件。4.6 从 CubeMX 生成的工程导入 MDK 的注意事项用 CubeMX 生成工程时Toolchain 选择 MDK-ARM V5生成的 .uvprojx 直接双击就能用 MDK 打开。这里有一个常见坑如果 CubeMX 版本较新生成的工程可能默认使用 AC6 编译器。虽然 v5.43a 能编译 AC6 代码但如果你想把工程切回 AC5需要在 Options - Target - ARM Compiler 里切换为 Version 5并且把相应的启动文件、宏定义重新检查一遍。我个人的习惯是新工程用 AC5因为很多开源代码、老驱动都基于 AC5 的语法习惯切换到 AC5 后省去一堆编译告警。5. 第四步编译、烧录、调试的完整闭环5.1 第一个程序建议从点灯开始硬件上最简单的方式是一块 STM32F103 最小系统板外接 ST-Link然后板载一个 LED 接在 PC13比如常见的 STM32F103C8T6 蓝色 pill 板。程序逻辑很简单开启 GPIOC 时钟配置 PC13 为推挽输出然后延时翻转电平。用库函数写法大致如下#include stm32f10x.h void Delay(void) { for (volatile int i 0; i 800000; i); } int main(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitStructure.GPIO_Pin GPIO_Pin_13; GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_2MHz; GPIO_Init(GPIOC, GPIO_InitStructure); while (1) { GPIO_ResetBits(GPIOC, GPIO_Pin_13); Delay(); GPIO_SetBits(GPIOC, GPIO_Pin_13); Delay(); } }这段代码在 MDK 里直接编译正常情况下 0 Error 0 Warning生成的 .hex 大小只有几 KB。5.2 Flash 下载算法配置与烧录流程在开始烧录之前打开 Options for Target - Utilities - Settings这里会列出当前调试器的信息。核心要确认的是 Flash Download 列表里是否自动识别了 STM32F10x Med-density Flash 这种编程算法。如果列表为空需要手动 Add 对应的算法。对于 STM32F103C8T6 这种中容量产品64KB Flash算法是 STM32F10x Med-density Flash对于 ZET6512KB Flash算法是 STM32F10x High-density Flash。选错算法轻则烧录失败重则把整个 Flash 内容擦掉但写不进去。实际烧录操作有两种方式方式一进入 Debug 模式点击菜单 Flash - Download或者直接按 F8 快捷键MDK 会通过调试器把程序写入 Flash然后自动复位运行。方式二把工程编出来的 .hex 文件用 ST-Link Utility、STM32CubeProgrammer 或第三方 Flash 烧录工具单独烧录。在调试阶段直接按 F8 最方便程序下载完成即可进入硬件调试。这里有一个实际体会初次烧录时一定确认接线ST-Link 的 SWDIO、SWCLK、GND、3V3 对应好接反了大概率识别不到目标芯片甚至可能烧坏调试器。5.3 Debug 调试模式下的几个实用操作进入在线调试后经常用到的窗口有Register 窗口观察 R0-R15、PSP、MSP 等寄存器值做异常分析时非常有用。Memory 窗口直接查看指定地址的内存内容比如检查 SPI DMA 接收缓冲区的原始数据。Watch 窗口右键变量名 Add to Watch实时观察变量的变化。Peripherals 窗口可以直接查看 GPIO、USART、SPI 外设寄存器的当前值很多外设问题在这里一眼就能看出来。关于调试模式下的一个技巧性内容热搜词里有人问“keil调试助手里面的 debug 模式如何显示结构体变量”这里顺带讲一下在 Watch 窗口添加结构体变量时先展开结构体然后在成员变量的后面输入要监视的表达式比如输入数组名加 [0] 可以逐项查看数组元素如果结构体含有指针成员直接展开指针指向的内存即可查看具体数值。另外在 Call Stack Locals 窗口可以自动显示当前函数内的局部变量包括结构体。调试中还经常遇到的问题就是程序跑飞。当单步执行时如果程序跳到了一个全是 0xFFFFFFFF 的地址通常说明芯片进入了 HardFault_Handler。这时打开 Processor Fault Status 窗口查看 CFSR、HFSR 寄存器大概能看出是总线错误还是栈溢出如果栈溢出优先检查启动文件中 Stack Size 是否太小或者主程序里是否有超大的局部数组。6. 常见问题与排查技巧实录6.1 编译报错“cannot open source input file ... 或 No such file”这种报错八成是 Include Paths 路径没有配置对。检查 C/C 选项卡里 Include Paths 是否包含所有头文件所在目录尤其用 HAL 库时至少需要包含固件包根目录下的 Drivers/CMSIS/IncludeDrivers/CMSIS/Device/ST/STM32F1xx/IncludeDrivers/STM32F1xx_HAL_Driver/Inc标准库同理需要把每个外设驱动的头文件目录都加进去。出现这类问题不要慌把路径逐条捋一遍基本能解决。6.2 下载失败No Target Connected 或 RDDI-DAP Error这个问题的高频原因是接线、驱动、供电三选一。先检查 ST-Link 与板子的接线是否牢靠再用电脑的设备管理器查看驱动是否被正确识别。如果设备管理器里 ST-Link 显示黄色感叹号重新安装驱动。另一个常见原因是开发板供电不足。某些小系统板依靠 ST-Link 供电但 ST-Link 输出的 3.3V 电流有限如果板上有传感器、OLED、WiFi 模块同时取电一进入烧录过程电压被拉低调试器就掉线了。解决方法是给开发板单独接 USB 供电同时共地。6.3 编译通过、烧录成功但程序不运行先检查 Boot0 引脚的启动模式。STM32F103 的 BOOT0 接低电平时从主 Flash 启动接高电平时进入系统引导或串口下载模式。如果你之前用串口下载过程序把 BOOT0 跳线跳回 0 再看。再一个常见原因是看门狗或者时钟配置问题。比如初始化时把独立看门狗IWDG使能了但主程序里没有及时喂狗导致芯片一直复位。排查方法是先注释掉所有看门狗相关代码确认程序能跑起来再说。6.4 中文乱码问题MDK 默认编辑器对中文的支持并不好。如果你在代码注释里写中文或者用 OLED 显示屏显示中文经常遇到乱码。建议在 Edit - Configuration - Editor - Encoding 里把默认编码改为 UTF-8。但这里有个坑改编码后之前用 GB2312 编码保存的旧文件可能直接变成乱码注意切换编码时的备份。如果只是串口打印乱码排查方向是代码里的字符串编码、串口波特率、目标板晶振是否与你程序设置的时钟一致。6.5 关于 License、授权和版本的一些提醒每次打开 MDK 时如果日志里出现 FLEXlm Error 或 License 到期提示说明授权异常。评估版不需要额外激活但会有代码量限制和弹窗提醒不影响学习使用。再次强调市面上流传的注册机类工具无论从合规性还是安全性上都不值得碰而是建议直接通过 ARM 官网购买 Node-Locked License。除非你只是用评估版做学习32KB 限制对 STM32F103 常用外设实验完全够用。6.6 其他高频问题速查表现象常见原因处理建议编译时 AC6 报错老代码依赖 AC5 语法切换编译器到 Version 5下载算法不匹配DFP 缺失或选错 Flash 算法更新 DFP在 Flash Download 里重新选调试时无法设置断点编译优化等级太高将 Optimization 改为 -O0 或调试等级编译变量未定义头文件包含不全使用 Go To Definition 追踪定位程序复位后时钟不对外部晶振失效改用内部时钟确认问题是否在晶振电路打开老工程报错缺少旧版 DFP安装对应的器件支持包7. 一些值得一提的典型应用场景7.1 串口控制与 Modbus 通信STM32F103 配上 MDK 开发环境最常见的工业应用就是串口控制和 Modbus 通信。很多传感器、电表、PLC 都支持 Modbus-RTU而 ModbusPoll 这类上位机软件可以直接与 STM32 下位机联调。在 MDK 工程里串口接收最好配合中断或 DMA否则高速率通信丢包会非常严重。拿 SPI 通过 DMA 方式读取芯片数据为例用 CubeMX 配置 SPI 外设和 DMA 通道后生成的代码里既有初始化流程也有 DMA 中断回调之后用 MDK 编译烧录读取 sensor 数据时效率比轮询方式高几个量级。类似的配置比如 AD7190 这种高精度 ADC 通过 SPI 读取也可以用同一个套路。7.2 在 STM32F103 上移植 FreeRTOS很多人在 MDK 环境下把 FreeRTOS 移植到 STM32F103C8T6。核心步骤是在工程里加入 FreeRTOS 源码中的 kernel 相关文件tasks.c、queue.c、list.c、portable 里的 GCC/ARM_CM3 移植文件然后配置 FreeRTOSConfig.h 里的宏定义。v5.43a 的编译环境对 FreeRTOS 非常友好只要把时钟节拍源选好普通点灯演示基本一次成功。注意一点用 AC5 编译 FreeRTOS 时栈对齐方式要符合 ARM AAPCS 标准开发头文件里的 configTOTAL_HEAP_SIZE 不要开得太大C8T6 只有 20KB RAM给系统留足空间。7.3 音频解码和第三方库移植热搜词里还有像“stm32f103移植minimp3解码库”这种需求。在 MDK 中移植第三方库的思路几乎一致将源码文件加入工程把头文件路径和宏定义配置好然后处理与硬件相关的数据输入输出接口。minimp3 的特点是单文件、依赖少在 MDK 中移植时重点在于内存分配解码 MP3 至少需要几十 KB 的 RAM 缓冲区所以不建议在 C8T6 这种小内存芯片上解码高码率文件ZET6 这类大内存型号会更合适。7.4 跨厂商芯片的工程移植有的项目要求把 STM32F103 的 HAL 库工程移植到其他厂商同内核芯片上比如 APM32。在 MDK 环境中做这件事大体思路是保留用户应用层代码替换 CMSIS 设备头和启动文件编译链接层面则切换对应的 DFP。这需要你对工程的每一个外设初始化代码都做一次筛查因为不同厂商的寄存器和外设布局不是全部兼容。8. 关于环境搭建这件事的一些真心话从零搭一套 MDK-ARM v5.43a STM32F103 开发环境对老手来说也就十分钟的事但对新手来说中间可能踩的坑确实不少。我在帮同事和学员排错时见过太多人卡在安装路径中文、DFP 版本不匹配、调试器驱动这些并非不可逾越的问题上。我的实际体会是搭建开发环境这件事最重要的是“固定”和“最小化”。固定指的是选定一个版本组合之后不要再频繁升级尤其不要在生产项目做到一半时去换编译器或 DFP 版本。最小化指的是出了问题不要一下子怀疑编译器、怀疑库、怀疑电脑先用最小工程验证硬件通路再逐步添加代码。如果你刚开始接触 STM32F103建议从一块最小系统板加一个 ST-Link 开始不要去碰那些功能复杂的大板子先把点灯跑通再逐步加串口、SPI、DMA、FreeRTOS。环境稳定之后你会发现 MDK v5.43a 这个“老版本”反而是让你最安心能出活的工具。