首页 / 资讯中心 / 文章详情

Keil5 配置 STM32F103:器件支持包与标准外设库导入

Keil5 配置 STM32F103:器件支持包与标准外设库导入 ★ FEATURED ARTICLE
1. 别急着新建工程先把 Keil5 里三层库的关系捋直我见过太多人在这一步折戟Keil5 装好了破解也做了右键 New uVision Project弹出器件选择框在搜索栏里敲STM32F103结果列表空空如也。于是开始怀疑是不是装了个假 Keil或者以为要去某个论坛下个Keil5 全器件包。其实绝大多数情况下问题不在 Keil 本身而是器件支持包没有安装和芯片库文件没有导入这两件事被混成了一件事。这两个动作在流程上一前一后缺一不可但它们的职责范围完全不同先把这一点掰开揉碎后面所有操作都会顺。STM32F103 这颗芯片在嵌入式入门领域的地位不用多说零售几十块的核心板、教程里翻来覆去的流水灯、串口打印、PWM 调光几乎都绕不开它。围绕它的一套开发环境无非是Keil MDK5 作为 IDE 和编译器芯片的器件支持包告诉 IDE 这颗芯片有多少 Flash、多少 RAM、外设寄存器地址在哪、启动文件长什么样而固件库则是厂商用 C 语言把寄存器操作封装成函数让你写GPIO_SetBits()而不是直接往0x40010C0C里写位。前者是 IDE 的认知后者是代码的血肉。把这两个概念搞混就会出现器件列表里有芯片但一编译就提示stm32f10x.h找不到这种典型症状。这篇内容会从零开始把器件支持包的安装、标准外设库的文件筛选、Keil 工程的分组配置、头文件路径与全局宏的对应关系、启动文件与芯片容量的匹配规则以及编译下载阶段最高频的十几条报错逐个拆开讲。适合三类人第一次接触 STM32 的学生、从别的平台转过来的工程师、以及带新人时想找一份能直接抄的配置清单的老手。全文的操作路径基于 Keil MDK5 的常规版本具体菜单文字可能随版本略有差异但逻辑通用。1.1 为什么 Keil5 装完还是搜不到 STM32F103Keil MDK5 从第五代开始做了一件很现代的事把器件信息从 IDE 安装包里剥离出去做成独立的Device Family Pack简称 DFP器件家族支持包。安装包本体只带 ARM 编译器、调试器驱动、以及少量通用中间件芯片相关的 ALG 烧录算法、SFR 寄存器定义、启动文件、示例工程全部放在 Pack 里按需下载。这样做的初衷是减小主安装包体积、让芯片厂商能自己维护更新代价就是新人第一次用会觉得装了个寂寞。所以当你在器件框里搜不到 STM32F103正确的判断顺序是先看 Pack Installer 里Keil::STM32F1xx_DFP这一项装了没有再看装的是不是过老的版本老版本的 Pack 里器件命名和现在略有差异最后才怀疑安装路径或权限问题。反过来如果器件列表里能选到STM32F103C8但新建工程后编译报一堆头文件找不到那就跟 Pack 无关了问题出在固件库文件没加进工程、或者头文件搜索路径没配。这两类问题的分界线就是器件选择框里有没有东西记住这一条排查效率能翻倍。还有一个隐藏细节MDK5 允许同时安装多个版本的 Pack工程属性里可以指定用哪个版本。团队协作时如果一个人用 Pack 2.3.0、另一个人用 2.4.0理论上寄存器定义是一致的但如果涉及启动文件差异偶发编译警告不一致的情况。稳妥做法是在模板工程里把 Pack 版本固定下来或者在版本变更时统一更新别各写各的。1.2 器件支持包、CMSIS、外设库三者各管什么把这三层用生活化的比喻讲清楚器件支持包像是一本房产证说明这块地芯片的面积、边界、门牌号Flash 大小、RAM 大小、外设基地址CMSIS 像是水电煤标准接口由 ARM 主导定义规定内核相关的访问方式比如NVIC_EnableIRQ()、SysTick_Config()这类函数和core_cm3.h里的内核寄存器结构体外设库则是装修公司厂商基于前两者把 GPIO、USART、TIM 这些外设的操作封装成函数。实际工程里这三层的物理位置是这样的core_cm3.c/h来自 CMSIS管的是 Cortex-M3 内核system_stm32f10x.c/h和stm32f10x.h来自器件支持层管的是芯片级时钟和寄存器映射stm32f10x_gpio.c、stm32f10x_usart.c这些来自外设驱动层管的是具体外设。stm32f10x.h是整个体系的总入口它内部会根据你定义的宏去决定包含哪颗芯片的头文件、要不要把stm32f10x_conf.h拉进来。理解了这一层你就明白为什么工程里必须同时加core_cm3.c和system_stm32f10x.c缺一个都会在链接阶段报未定义符号。也明白了为什么全局宏里必须同时写USE_STDPERIPH_DRIVER和STM32F10X_HD——前者控制stm32f10x.h是否包含外设库的配置文件后者告诉编译器这颗芯片属于大容量系列决定了寄存器结构体里某些成员的偏移量。少写一个不报错才怪。1.3 标准外设库和 HAL 库这个项目该选哪个打开任何一份 STM32F103 的教程你都会看到两种流派一种用STM32F10x_StdPeriph_Lib_V3.5.0另一种用STM32CubeF1里的 HAL 库。这两者在导入方式上有本质区别选错了会白白折腾半天。标准外设库是老派做法文件是手动拷贝进工程的需要自己建目录、加分组、配路径过程稍繁琐但每一个文件在干什么都清清楚楚非常适合打基础。它的代码风格是直接操作寄存器封装函数名短执行效率高缺点是厂商早已停止更新新芯片不支持。HAL 库是新派做法通常配合 STM32CubeMX 图形化工具生成工程骨架代码由工具自动生成导入过程被大幅简化跨系列移植性好缺点是代码层级多、体积大、初学者容易只知其然。对于手上这颗 STM32F103我的建议很直接如果你是为了搞懂底层、做课程设计或小批量产品用标准外设库它逼着你去理解时钟树、理解寄存器后期排查硬件问题时有底气如果你要快速出原型、或者后续可能换到 F4/G0 系列用 CubeMX 加 HAL别在手动拷贝文件上耗时间。这篇文章的主线走标准库路线因为导入库文件这个动作在标准库场景下才有完整的操作链条HAL 路线会在后面单独说明差异点。2. 器件支持包的两种安装方式与验证方法2.1 在线装Pack Installer 的正确打开姿势Keil 主界面工具栏上有一个带绿色小方块的图标或者走菜单Project → Manage → Pack Installer都能打开 Pack 管理窗口。窗口左侧是器件厂商树展开Keil节点能看到STM32F1 Series再往下就是STM32F1xx_DFP。右侧会列出该 Pack 的所有版本、发布日期、以及当前状态。点Install按钮就开始下载安装安装完成后按钮会变成Remove或Up to date。在线安装最常遇到的问题有两个。第一是网络卡顿导致下载中断表现为进度条走一半停住或者提示下载失败。这不是 Keil 的问题换一个网络时段重试往往就好了。第二是权限问题如果 Keil 安装在C:\Keil_v5这类需要管理员权限的目录Pack 写入时可能失败表现是显示安装完成但目录里没有文件。解决办法是以管理员身份运行 Keil或者把 Pack 的存储路径改到用户目录下——Pack Installer里可以设置Folder选项指向一个有写权限的路径即可。安装完成后有一个容易忽略的细节别忘了点Packs标签页右上角的刷新。有些版本在安装后器件列表不会立刻刷新导致你以为没装成功。还有一种情况是安装了多个版本的 DFP工程默认用的是旧版本这时需要在Options for Target → Device页面确认一下当前选中的 Pack 版本或者直接在工程里重新选一次芯片型号。2.2 离线装.pack 文件的获取与双击安装带宽紧张、或者目标机器不能联网的时候离线安装是更靠谱的路子。.pack文件本质上是一个改了后缀的压缩包内部包含描述文件、器件定义、启动文件、烧录算法等。获取途径通常有三种从已经装好的同事电脑上到Keil_v5\ARM\PACK\Keil\STM32F1xx_DFP\目录下把整个版本文件夹打包带走从芯片厂商提供的开发资源页下载或者从单位内部的软件仓库获取。拿到.pack文件后操作极其简单直接双击。系统会自动调用 Keil 的 Pack 安装程序弹出确认窗口点 Next 一路到底即可。如果双击没反应说明 Pack 文件没有关联到 Keil可以手动在 Pack Installer 里走File → Import导入。安装路径默认是C:\Keil_v5\ARM\PACK\Keil\STM32F1xx_DFP\版本号\进去之后应该能看到Device、Include、Flash、SVD等子目录这就是后面排查问题的第一手依据。这里提醒一句离线安装时不要图省事把不同版本的文件夹直接覆盖。不同版本的 DFP 目录结构可能有调整覆盖会导致描述文件和实际文件对不上出现器件列表显示但打开就报错的情况。正确做法是让每个版本各占一个文件夹Keil 通过工程配置决定用哪个。2.3 怎么确认装好了三个可检查的位置判断 Pack 是否真的安装成功不要只看安装程序说的完成用下面三个位置交叉验证最稳。第一个位置是新建工程的器件选择框。新建工程在搜索框输入STM32F103如果列表里出现STM32F103C8、STM32F103ZE等型号说明器件描述文件已经被读到这是最直观的信号。第二个位置是文件系统里的 Pack 目录。进入Keil_v5\ARM\PACK\Keil\STM32F1xx_DFP\里面应该有一个以版本号命名的文件夹其下的Device\Include里能找到stm32f10x.h一类文件Device\Source\ARM里能找到startup_stm32f10x_hd.s这类启动文件。如果目录是空的说明安装过程其实失败了。第三个位置是Pack Installer 里的状态标记。找到STM32F1xx_DFP那一行如果按钮显示Remove或者状态是Up to date说明已装如果显示Install说明没装成功。检查位置正常表现异常含义新建工程器件列表能搜到 STM32F103 各型号Pack 未安装或未刷新Pack 安装目录版本文件夹内有 Device/Include/Flash安装中断或权限不足Pack Installer 状态显示 Remove 或 Up to date仍显示 Install 说明没装上3. 标准外设库导入的完整实操3.1 先建目录再动鼠标一套能复用的工程骨架很多人导入库文件的方式是边加边想文件往工程里一拖路径随手一配编译报错了再回头改。这种打法在单个工程上还能凑合一旦要开第二个工程就全乱套。我的习惯是先在磁盘上把目录结构定死再打开 Keil让文件系统的物理结构和 Keil 里的逻辑分组一一对应。推荐的骨架是这样的工程根目录下建CORE、FWLIB、USER、OBJ、HARDWARE五个文件夹。CORE放内核与启动相关文件core_cm3.c/h、system_stm32f10x.c/h、stm32f10x.h、启动文件.sFWLIB下再分inc和src分别放外设库的头文件和源文件USER放main.c、stm32f10x_it.c/h、stm32f10x_conf.hOBJ专门存编译中间文件和 hexHARDWARE留给后续自己写的板级驱动比如led.c、key.c、usart.c。这套结构的好处在于Keil 里的Target分组名和磁盘目录名完全对应任何人拿到你的工程看一眼目录树就知道文件在哪后续要换芯片或者升级库只需要替换CORE和FWLIBUSER和HARDWARE几乎不用动编译产物全在OBJ里清理工程时删这一个文件夹就够不会误删源码。注意路径里绝对不能出现中文字符和空格。这是血泪教训Keil 的编译器和链接器对非 ASCII 路径的处理并不一致轻则生成的.axf路径错乱重则直接报cannot open source input file或者链接阶段找不到.o文件。工程放在D:\Work\STM32\F103_Template这种纯英文路径下最省心。3.2 哪些文件必须拷哪些纯属占地方从标准外设库的原始压缩包里往工程里拷文件时很多人图省事整个Libraries目录连同Project目录一起搬过来结果是工程里塞了几百个文件绝大部分根本用不上还容易因为重复添加导致链接报错。真正需要的其实就那么一批按下面的清单挑就行。CMSIS 内核层core_cm3.c、core_cm3.h。这两个文件是 Cortex-M3 内核的访问接口任何 M3 内核的工程都要用放在CORE目录。器件支持层system_stm32f10x.c、system_stm32f10x.h、stm32f10x.h以及startup目录下对应容量的.s启动文件。system_stm32f10x.c里定义了SystemInit()函数负责在上电时配置时钟默认是把外部 8MHz 晶振倍频到 72MHz这个文件不加链接到SystemInit时会报未定义符号。stm32f10x.h是整颗芯片的寄存器总表几万行必须加。外设驱动层inc目录下所有.hsrc目录下所有.c。这里面包括misc.cNVIC、SysTick 相关、stm32f10x_gpio.c、stm32f10x_rcc.c、stm32f10x_usart.c等等。虽然你可能只用得到其中几个但全加进去最省心链接器会自己剔除没被引用的函数不会让固件变大。如果实在在意编译时间可以先只加misc、rcc、gpio这三个最基础的后续用到哪个补哪个。用户层stm32f10x_conf.h外设库的配置文件控制哪些外设的头文件被包含、stm32f10x_it.c/h中断服务函数模板、main.c。stm32f10x_conf.h这个文件容易被漏掉而它恰恰是stm32f10x.h在USE_STDPERIPH_DRIVER宏打开后要去包含的文件路径配错就会报cannot open source input file stm32f10x_conf.h。目录必加文件作用漏了会怎样COREcore_cm3.c/h内核寄存器与 NVIC 接口NVIC 相关函数未定义COREsystem_stm32f10x.c/h系统时钟初始化SystemInit 未定义COREstm32f10x.h芯片寄存器总定义全工程找不到类型定义COREstartup_stm32f10x_xx.s中断向量表与启动流程链接报复位向量缺失USERstm32f10x_conf.h外设头文件开关提示找不到该文件USERstm32f10x_it.c/h中断服务函数模板可省但中断不好写FWLIBinc/src 全套外设操作函数外设函数未定义3.3 Keil 工程里建组、加文件的具体顺序磁盘结构定好之后打开 Keil 新建工程器件选STM32F103C8以常见的核心板为例弹出Manage Run-Time Environment窗口时直接点Cancel因为走标准库路线不需要通过 RTE 自动加文件手动加更可控。接着点工具栏的三色方块图标打开Manage Project Items。在Groups一栏里依次新建CORE、FWLIB、USER、HARDWARE四个组然后把对应目录下的文件逐个Add进去。加文件时有个细节启动文件要按芯片容量选不是随便挑一个。STM32F103C8 的 Flash 是 64KB属于中容量对应startup_stm32f10x_md.s如果是 ZET6 那种 512KB 的要用startup_stm32f10x_hd.s。选错的后果后面单独说。顺序上建议先加CORE再加FWLIB最后加USER这样在工程树里呈现的位置和依赖关系一致读起来顺。加完之后别忘了把OBJ目录设置成输出目录Options for Target → Output → Select Folder for Objects指向OBJ文件夹同时勾上Create HEX File方便后续用串口或者离线烧录器下载。FWLIB组里加文件时不要一次性全选上百个文件拖进去容易因为鼠标滑脱加重复。可以按住 Ctrl 分批加加完在组里扫一眼看有没有同名的.c出现两次。重复添加是后面链接报重复定义的头号原因。3.4 头文件路径、全局宏、启动文件三件套这三项是编译能否通过的关键缺一不可而且必须相互匹配。打开Options for Target → C/C页面分三步走。第一步配Include Paths。把CORE、FWLIB\inc、USER三个目录加进去。如果你的main.c里还包含了HARDWARE下的头文件那也要加进来。这里的原则是凡是#include xxx.h里用双引号引的头文件所在目录都要在路径列表里。路径顺序有讲究如果两个目录下有同名头文件编译器按顺序取第一个所以把最具体的目录放前面比较安全。第二步配Define。在Preprocessor Symbols的Define框里填USE_STDPERIPH_DRIVER, STM32F10X_MD。这两个宏用逗号分隔注意不要用中文逗号。前一个宏是告诉stm32f10x.h我用了外设库请把stm32f10x_conf.h包含进来后一个宏是告诉它芯片属于哪个容量等级。C8T6 是 64KB Flash属于中容量 MD如果板子是 RCT6256KB或 ZET6512KB要改成STM32F10X_HD如果是 C6T6 那种 32KB 的是STM32F10X_LD。容量宏选错的典型症状是编译能过但中断向量表对不上一进中断就跑飞或者定时器、串口的行为莫名其妙。原因在于stm32f10x.h里会根据这个宏定义不同的中断号枚举和寄存器结构体选错等于拿错了地图。第三步确认编译器版本。Options for Target → Target页面里有ARM Compiler选项标准外设库 3.5.0 那套代码是基于 ARM Compiler 5AC5写的用 AC6 编译会出现大量警告甚至错误比如启动文件里的汇编语法不被识别。如果下拉框里能选Use default compiler version 5选它最稳妥如果 MDK 版本较新、装的时候没勾 AC5需要单独补装编译器组件否则只能硬着头皮用 AC6 加一堆兼容参数不推荐新手走这条路。提示配完这三项之后先别急着写业务代码写一个只有#include stm32f10x.h和空main的测试文件按一次 F7 编译。能过 0 Error 就说明库导入这条链路通了再往里添外设代码。这个习惯能帮你把库配置问题和业务代码问题彻底隔离开。3.5 写个最小 main.c 把编译跑通最小的骨架长这样包含stm32f10x.h写一个main函数函数体里先调用一个延时循环把唯一要做的事放在死循环里。别小看这几行它能验证的事情不少——头文件路径通不通、宏定义对不对、启动文件和SystemInit能不能链接上一次编译全暴露。#include stm32f10x.h static void delay(volatile uint32_t n) { while (n--) { __NOP(); } } int main(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitTypeDef gpio; gpio.GPIO_Pin GPIO_Pin_13; gpio.GPIO_Mode GPIO_Mode_Out_PP; gpio.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOC, gpio); while (1) { GPIO_ResetBits(GPIOC, GPIO_Pin_13); delay(500000); GPIO_SetBits(GPIOC, GPIO_Pin_13); delay(500000); } }这段代码里RCC_APB2PeriphClockCmd来自stm32f10x_rcc.cGPIO_Init和GPIO_SetBits来自stm32f10x_gpio.c。如果编译时提示这几个函数未定义说明FWLIB里的.c没加全或者加进去了但因为路径问题没被编译。如果提示RCC_APB2Periph_GPIOC未定义那多半是宏没配对stm32f10x.h走进了一个不包含该枚举的分支。编译通过后看 Build Output 窗口的提示正常情况下应该是0 Error(s), 0 Warning(s)或者少量无关紧要的警告。如果出现Warning: #1-D: last line of file ends without a newline那只是文件末尾没换行不影响功能但顺手补上更规范。3.6 下载配置与第一次点灯验证编译过了不等于板子能跑下载配置是另一道坎。打开Options for Target → Debug在右上角的下拉框里选你手上的调试器常见的是ST-Link Debugger或者CMSIS-DAP Debugger。选完点旁边的Settings在Debug标签页里把Port设成SW不是 JTAGMax Clock拉到 1.8MHz 或 4MHz太快反而容易连不上。右侧的SW Device区域如果能看到一串 IDCODE说明芯片已经被识别到链路是通的如果显示No target connected先查线序SWDIO、SWCLK、GND 三根线必须接对板子要独立供电或者由调试器供电。接着切到Flash Download标签页勾上Reset and Run这样下载完程序自动复位运行不用手动按复位键。下面的Programming Algorithm列表里应该有STM32F10x Med-density Flash之类的条目如果没有点Add手动添加算法文件就来自前面装的器件支持包。这一步如果加错了容量比如中容量板子选了高容量算法会出现能连上但下载失败的现象报错通常是Flash Download failed - Target DLL has been cancelled。下载成功后板子上的 LED 应该开始闪烁。如果没闪先确认 LED 接的是不是 PC13不同核心板丝印不同再确认晶振有没有焊好——SystemInit()默认会尝试启动外部 8MHz 晶振如果晶振不起振时钟会退回到内部 RC程序跑得慢但一般不致命。真正致命的是BOOT0拉高进了 ISP 模式程序下进去也不运行把BOOT0接 GND 就好。4. 报错现场导入库文件最高频的几类问题4.1 头文件找不到路径和宏的连环套cannot open source input file core_cm3.h和cannot open source input file stm32f10x.h是出现频率最高的两条报错本质上都是头文件搜索路径没覆盖到对应目录。前者的解决方法是把CORE目录加进 Include Paths后者要么是CORE路径没加要么是stm32f10x.h根本没拷进工程。稍微绕一点的是cannot open source input file stm32f10x_conf.h。这个文件的特殊之处在于它并不是被你的main.c直接包含的而是stm32f10x.h在检测到USE_STDPERIPH_DRIVER宏之后主动去包含的。所以即使你压根没在代码里写#include stm32f10x_conf.h它照样会被要求存在。解决思路有两条把stm32f10x_conf.h放到USER目录并加入路径或者干脆在stm32f10x.h里把那段#include注释掉不推荐会失去外设头文件的统一管理。还有一类更隐蔽的报错指向stm32f10x.h内部的某一行提示#error directive: Please select first the target STM32F10x device used in your application (in stm32f10x.h file)。这不是路径问题是容量宏没定义或者拼错了。回到Define框检查STM32F10X_MD是不是漏写、是不是写成了STM32F10x_MD大小写敏感、是不是用了中文逗号分隔。报错信息根因处理动作cannot open core_cm3.hCORE 未入路径添加 CORE 到 Include Pathscannot open stm32f10x.hCORE 未入路径或文件缺失检查文件是否存在并加路径cannot open stm32f10x_conf.hUSER 未入路径拷贝该文件并加路径#error Please select first the target容量宏缺失或拼错补 STM32F10X_MD/HD/LDUndefined symbol SystemInit缺 system_stm32f10x.c加入 CORE 组4.2 链接期的重复定义与未定义符号编译阶段过了链接阶段报L6200E: Symbol xxx multiply defined说明同一个符号在多个.o文件里都有定义。最常见的原因是启动文件被加了两次或者FWLIB里同一个.c在两个组里各加了一遍。Keil 的工程树里同名文件可以重复出现肉眼不容易发现去Manage Project Items里逐个组数一遍最快。另一个高频原因是文件被复制到了两个目录。比如你既把stm32f10x_gpio.c放在FWLIB\src又在HARDWARE里复制了一份改过的版本两个都被加进工程链接器就懵了。这种情况的报错往往会指明具体的符号名对着符号名去找哪个函数被定义了两次一般在stm32f10x_xxx.c里能定位到。反过来L6218E: Undefined symbol xxx是找不到定义。SystemInit未定义说明system_stm32f10x.c没加NVIC_PriorityGroupConfig未定义说明misc.c没加assert_failed未定义说明你在stm32f10x_conf.h里打开了USE_FULL_ASSERT但没实现这个函数。最后这种情况解法很简单要么把USE_FULL_ASSERT注释掉要么在main.c里补一个空的assert_failed实现。4.3 启动文件选错芯片容量的典型症状启动文件的作用是定义中断向量表和复位入口不同容量芯片的中断源数量不一样启动文件自然不同。选错的症状分三档轻症是编译通过、程序能跑但某些中断进不去。比如中容量板子误用了小容量的startup_stm32f10x_ld.s向量表里少了几个中断入口用到 TIM3、TIM4 这类外设中断时就会跳到错误地址或者直接进 HardFault。中症是链接报错提示某个中断处理函数重复定义或者向量表大小不匹配。因为启动文件里对每个中断都写了一个默认的Handler弱符号如果你的stm32f10x_it.c里也定义了同名函数链接器会按强弱符号规则处理但如果启动文件里压根没有这个中断的槽位就会报未定义。重症是程序下载后完全没反应连点灯都不亮。这种情况通常是启动文件里的栈大小、堆大小配置和芯片实际 RAM 不匹配或者向量表首地址被改错了。判断用哪个启动文件看芯片型号里的 Flash 容量代码就够C8、R8是 64KB 属中容量用mdC6、R6是 32KB 属小容量用ldRC、ZC、VE是 256KB 以上属大容量用hdIG、VG是 1MB 属超大容量用xl带互联型字样的如STM32F105/107用cl。拿不准的时候查一下芯片数据手册里的 Flash 一栏比对着容量选别凭型号里的字母猜。4.4 下载与调试阶段的坑库文件导入正确、编译链接全绿仍然可能在下载环节卡住。No target connected除了线序问题还有一个常见原因是调试器驱动没装或者被系统识别成了别的设备。设备管理器里如果看到黄色感叹号重新装一遍驱动就行。Cannot access target或者Error: Flash Download failed多半是芯片被读保护了或者上一次下载中途断电导致 Flash 状态异常。处理方法是用调试器的Connect under Reset模式连接在Debug → Settings里把Connect选项改成under Reset同时按住板子的复位键点下载连上之后再松开。这一招对付砖头状态的核心板特别有效。还有一类问题出在下载算法和芯片容量不匹配。前面提到过Flash Download里的Programming Algorithm必须和实际容量对应。C8T6 用的算法名字里带Med-densityZET6 用High-density选错了会报地址越界或者校验失败。如果你从别人那里拷来的工程模板这一项往往带着原作者板子的配置换板子之后必须重新确认。注意Reset and Run这个勾选项建议一直开着。我遇到过不少人说下载成功但程序不跑最后发现每次下载完都要手动按一下复位键纯粹是忘了勾这一项。5. 把配好的工程固化成模板5.1 模板要删掉什么、保留什么第一次把库导入跑通之后别急着开始写业务代码先花十分钟把它做成模板。具体做法是把当前工程另存一份命名为F103_Template之类然后清理掉与业务相关的东西main.c里只留一个空的死循环、HARDWARE目录清空、OBJ里的编译产物全部删除、工程里针对具体板子的引脚定义全部去掉。保留下来的是CORE、FWLIB、USER三件套加上已经配好的Include Paths、全局宏、启动文件、输出目录、下载器配置。模板要做干净还有一个理由Keil 的工程文件是文本格式的.uvprojx里面记录了每一个文件的绝对路径或者相对路径。如果模板里残留了D:\某次实验\xxx.c这种绝对路径换一台电脑打开就会报找不到文件。稳妥做法是在Manage Project Items里把所有文件路径改成相对于工程根目录的形式然后整个文件夹复制到别处打开测试一次确认路径没有写死。模板里还有一个值得固化的东西默认的时钟配置。system_stm32f10x.c里的SystemInit()默认把系统时钟配到 72MHz如果你板子上的晶振不是 8MHz或者你想跑在 48MHz可以在main开头重新调用RCC相关函数覆盖掉。把这套配置写进模板的main.c注释里下次开新工程直接抄能省不少查手册的时间。5.2 多工程共享一份库目录的相对路径玩法当项目多起来每个工程里都复制一份FWLIB会造成磁盘浪费更麻烦的是库文件升级时得挨个工程替换。解决办法是把库目录提到工程外层用相对路径引用。具体布局是这样的在最外层建一个Lib目录里面放FWLIB和CORE然后每个具体项目一个文件夹里面只有USER、HARDWARE、OBJ。在项目的Include Paths里用..\Lib\CORE、..\Lib\FWLIB\inc这样的相对路径指过去。Keil 里添加文件时也走相对路径加进去之后在工程树里会显示..\Lib\FWLIB\src\stm32f10x_gpio.c这种形式。这种玩法的收益在团队协作时特别明显库出现 bug 或者要统一升级版本只改一处所有工程跟着生效。代价是工程不能单独拷走必须连同外层的Lib一起打包。所以交付给别人的时候要么把Lib一起压缩要么临时把库文件拷进工程内部再打包别让人家打开就一堆红叉。相对路径还有一个隐蔽的坑Keil 在计算相对路径时基准是.uvprojx文件所在目录。如果你把工程文件放在USER子目录里而.uvprojx在项目根目录那..\Lib的层数就要按.uvprojx的位置算不是按main.c的位置算。搞混了就会报路径找不到但用资源管理器看明明文件就在那儿。最后分享一个我自己用了很久的小习惯每次新建工程先不写代码把main.c写成下面这样编译一次下载一次看灯闪不闪。闪了说明从器件包、库文件、路径、宏、启动文件、下载算法到硬件链路整条路都是通的后面写什么都有底气不闪就按前面几节的排查顺序从后往前捋问题一定出在某个具体环节而不是玄学。这个点灯验收的动作花不了两分钟但能挡掉后面百分之八十的莫名其妙。int main(void) { /* 点灯验收能闪说明整条工具链通了 */ while (1) { } }
阅读完成 · 觉得有帮助?
咨询建站