ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Keil5新建STM32工程:Pack、标准库、CubeMX与Options配置

Keil5新建STM32工程:Pack、标准库、CubeMX与Options配置 很多人第一次打开Keil5点开File菜单里的New uVision Project填了个名字然后在Select Device那个对话框前面就愣住了——左边厂商树展开是空的或者好不容易选了个STM32F103点OK之后Project窗口依然一片空白编译按钮是灰的连个main函数都没有。这不是你操作错了而是Keil5从MDK5开始换了一套器件管理逻辑把原本内置的器件库拆成了独立的Pack包同时它也不再帮你生成任何源码。它只负责建一个空壳索引剩下的库文件、启动文件、宏定义、头文件路径全都要你自己摆进去。所以keil5新建工程这件事本质上是理解一套工程组织逻辑而不是死记几个按钮。这篇内容我会把标准库新建工程、CubeMX生成工程、C51工程的差异、以及Options for Target里那些必须改和千万别乱动的选项一次讲透顺便把新建不了工程芯片列表空下载失败编译很慢这些高频问题按排查顺序串起来。无论你手里是F103C8T6这种最小系统板还是拿来跑触摸屏Modbus通讯的板卡这套流程都通用。1. 先把新建工程这件事的本质说透1.1 .uvprojx只是个索引文件你的代码不在里面新手最容易误解的一点是以为Keil工程像一个压缩包代码都装在里面。实际不是。当你保存工程后目录里会多出一个后缀为.uvprojx的文件老版本是.uvproj它本质上是一份XML文本记录的内容只有几类选用了哪颗芯片、工程里挂了哪些源文件、每个文件在磁盘上的相对路径、每个编译分组的配置、C/C的宏和头文件搜索路径、以及调试器和下载器的参数。真正的.c和.h文件永远躺在你自己创建的文件夹里Keil只是引用它们的位置。这个认知非常关键因为它直接解释了两个常见现象。第一你把工程文件单独拷给别人对方打开全是红叉——因为被引用的库文件没跟着走。第二你重命名或移动了工程外层的文件夹工程里所有文件路径瞬间失效编译报cannot open source input file。所以我一直建议新建工程的第一步不是打开Keil而是在资源管理器里先把目录骨架搭好之后再让Keil往里面挂文件。顺序反了后面要花几倍时间擦屁股。1.2 Pack机制决定了你在Select Device里能看见什么MDK5把器件支持拆成了Device Family Pack简称DFP。你装完Keil本体里面只有ARM自家的通用内核模板比如ARMCM3、ARMCM4所有ST、GD、NXP、Nordic的具体芯片都要额外下载对应的Pack。这就完美解释了那个经典问题为什么我打开Select DeviceSTMicroelectronics下面什么都没有因为STM32F1系列的Pack没装。解决办法有两个方向一是在Keil里点Pack Installer那个彩色小方块图标联网后从列表里找到STM32F1 Series并Install二是去芯片厂商官网下载离线Pack包双击安装。前者方便但受网络影响后者适合内网或网络不稳的环境。装完之后不需要重启KeilSelect Device列表会立刻刷新出来。顺便说一句Pack不只塞器件描述还带了各家官方例程、CMSIS组件、中间件这也是为什么一个Pack动辄几百兆。你不需要全部拥抱它但至少要知道列表为空Pack缺失这条因果链。1.3 目录结构必须在动手之前想清楚Keil不会帮你组织文件它只记录你放文件的位置。所以一个可维护的工程目录规划应该在新建之前定下来。我常年用的骨架大致是这样工程根目录下分Doc放原理图、数据手册、笔记、Libraries放CMSIS内核文件和标准外设驱动、User放main.c和用户自己的模块、Project放.uvprojx和输出中间文件、Output放最终hex和bin。这样做的好处是Libraries和User这两块内容替换或升级时互不干扰Output随时可以整个删掉重新编译不会误删源码。很多人图省事所有文件全塞在根目录一开始确实快十几个文件还能忍。等工程长到几十个.c找文件靠翻合并冲突靠猜那时候再回头整理路径改动会牵一发动全身。所以我的经验是宁可前期多花五分钟建文件夹也别后期花两小时改路径。这条规律和你用哪颗芯片、跑什么业务都无关属于放之四海皆准的工程习惯。2. 三种新建工程场景先分清你属于哪一种2.1 标准库手动搭建控制力最强也最练基本功STM32标准外设库StdPeriph Library虽然官方已经不再主推但在教学、老项目维护、以及对底层寄存器理解要求高的场合依然是主流选择。它的新建流程是纯手工的建目录、拷库、加启动文件、配宏、加路径一步步来。好处是整个过程你完全清楚每个文件在干什么出了问题能定位到具体环节坏处是初次操作确实繁琐任何一个步骤漏了都会编译失败。判断你是否该走这条路可以看两个信号一是你要不要读寄存器级别的代码二是你在不在乎为什么这样配。如果你只是想快速点灯、跑通一个外设那CubeMX那条路更省事。但如果你之后要做底层驱动、要改时钟树、要抠中断向量表标准库这条手工路径练出来的手感是绕不过去的。2.2 CubeMX生成再导入快但要知道它替你做了什么CubeMX的路子是图形化配置→生成工程。你选芯片、配时钟、勾外设、设引脚点生成它会直接输出一个带main.c、带HAL库、带初始化代码的完整工程甚至能直接选工具链为MDK-ARM并自动生成.uvprojx。这种方式对新手极其友好点灯、串口、定时器基本开箱即用。但要注意CubeMX生成的是HAL库工程和你手动搭的标准库工程是两套东西别混着用。另外CubeMX生成的代码里有大量USER CODE BEGIN/END注释块你写的代码必须放在这些块里否则下次重新生成配置时会被覆盖。我见过有人把业务逻辑写在块外改了个引脚重新生成代码全没了。所以走CubeMX路线第一条纪律就是尊重它的代码分区标记。2.3 C51与MDK共存它们其实是两个IDE很多做单片机的人同时用51和STM32于是想让一个Keil5同时干两件事。这里要澄清C51和MDK-ARM是Keil家族里两套独立的工具链虽然界面长得几乎一样但编译器、器件库、工程格式都不通用。官方确实提供了C51和MDK可以安装到同一台机器的方案但它们是分目录安装的独立程序不是一个软件切换模式。实践中更稳妥的做法是把C51和MDK装在不同路径下各自用各自的图标启动工程也分开放。混合安装偶尔会因为共享组件版本冲突出现奇怪现象比如打开A工程提示缺少组件、Pack列表显示异常之类。如果你只是偶尔用51建议直接分开两台环境或者干脆用各自的独立版本省掉排查麻烦。记住一条新建工程时先确认你打开的是哪个IDEC51工程用MDK是打不开的反之也一样。3. 手把手搭一个STM32标准库工程3.1 建目录和拷库这一步偷懒后面全要还回来先在你选定的磁盘位置建一个工程根目录名字用英文加下划线绝对不要用中文和空格。原因很现实Keil的编译器和某些命令行工具对中文路径支持很差报错信息往往含糊你根本想不到是路径惹的祸。我吃过一次亏工程放在我的文档\单片机项目\温度采集下面编译一直报找不到头文件排查半天才发现是路径里的中文字符。目录建好后从标准库压缩包里把CMSIS和STM32F10x_StdPeriph_Driver两个文件夹拷进Libraries。CMSIS里重点要core_cm3.c/h、system_stm32f10x.c/h、以及stm32f10x.hStdPeriph_Driver里是src和inc两个子目录src放.cinc放.h。启动文件startup_stm32f10x_hd.s在CMSIS的device目录下它会根据你的芯片容量选型号小容量用ld中容量用md大容量用hd互联型用cl。选错启动文件会导致中断向量表对不上程序跑飞。启动文件后缀对应容量典型型号_ld小容量 16-32K FlashSTM32F103C4/C6_md中容量 64-128KSTM32F103C8/CB_hd大容量 256-512KSTM32F103ZE/VC_cl互联型STM32F105/107这张表建议收藏初学者最常犯的错就是F103C8T6配了个_hd启动文件编译能过但中断行为诡异。3.2 New uVision Project与芯片选择的动作细节打开KeilProject菜单里选New uVision Project弹出的对话框先让你选保存位置和工程名。这里有个细节工程文件建议放进Project子文件夹而不是根目录这样输出文件会和源码天然隔离。名字我习惯和项目一致比如TempMonitor。紧接着就是Select Device对话框。展开STMicroelectronics找到STM32F1 Series再往下选STM32F103右边会列出具体型号。这里要特别注意型号的Flash和封装后缀比如STM32F103C8和STM32F103CB前者64K后者128K选错会影响后续宏定义和链接脚本的判断。选好后点OKKeil会弹出一个Manage Run-Time Environment对话框。3.3 Manage Run-Time Environment标准库工程该不该用它这个RTE对话框是MDK5的新东西允许你勾选CMSIS的组件比如CMSIS Core、Device Startup、以及各家提供的中间件。对于CubeMX的HAL工程很多依赖可以在这里一键勾选。但对于标准库手动工程我的建议是直接点Cancel关掉不要在这里勾任何东西。原因在于RTE勾选的组件走的是Pack里的文件和你手动拷进Libraries的标准库是两套来源混用极易出现重复定义、版本不一致、头文件互相覆盖的问题。标准库工程讲究的是我清楚每个文件从哪来那就老老实实手动添加。Cancel之后Keil会生成一个空的工程骨架此时Project窗口里只有一个Target 1里面什么都没有别慌这是正常的。3.4 添加启动文件、库文件和main接下来是新建分组。右键Target 1选Manage Components或者直接用工具栏那个带小方块的图标进入Files分组管理界面。我一般建四个组Startup、CMSIS、StdPeriph_Driver、User。分组本身不影响编译但影响你看工程的清晰度文件一多分组就是救命稻草。Startup组里加startup_stm32f10x_hd.sCMSIS组里加core_cm3.c和system_stm32f10x.cStdPeriph_Driver组里按需加外设驱动比如gpio、rcc、usart、tim的.c文件不用全加用到哪个加哪个能显著加快编译User组里加你自己写的main.c。添加文件时用Add Files按钮路径一定要指向你实际拷贝的位置。这里有个高频坑添加完后编译报undefined symbol八成是某个用到的外设驱动.c没加进来或者启动文件没加。还有一种是multiply defined通常是把同一个文件加了两次或者既用了RTE又手动加了库。遇到先检查分组列表有没有重复项。3.5 头文件路径与宏定义编译能过的隐形前提文件加完不代表能编译。Keil需要通过路径找到.h需要宏定义来告诉标准库我用的是哪个芯片。这两项都在Options for Target的C/C选项卡里配。Include Paths要把Libraries\CMSIS、Libraries\STM32F10x_StdPeriph_Driver\inc、User这几个目录都加进去。Define栏里至少写两个宏USE_STDPERIPH_DRIVER和STM32F10X_HD。前者让stm32f10x.h去包含标准库的配置头后者让库知道你的芯片属于大容量系列决定寄存器映射和一些条件编译分支。这两个宏写错或漏写症状很典型报一堆寄存器未定义、或者编译出来的程序功能不全。我一般会对照启动文件的容量后缀来写宏_hd启动文件配STM32F10X_HD_md配STM32F10X_MD保持严格一致避免埋雷。路径和宏都配好点Rebuild如果前面步骤没错这时候应该能整齐地编译通过了。4. Options for Target里哪些必须改哪些别乱动4.1 Target选项卡与Xtal变灰的真正原因Options for Target的Target选项卡里第一项是晶振频率Xtal。有些人发现这一栏是灰的改不了就以为软件坏了。其实它变灰只说明一件事当前选中的器件没有提供外部晶振参数或者你选的是ARMCMx这种通用内核模板而不是具体芯片。等你正确装了STM32的Pack、在Select Device里选了真实型号Xtal就能正常填写了F103一般填8.0单位MHz。这个值Keil自己不会去设置芯片它主要供调试时的一些时序估算和仿真参考真实时钟还是靠你代码里的时钟配置。但填对有个好处用软件仿真跑延时函数时时间基准是对的。所以别嫌它没用顺手填上也算给自己留个校准点。4.2 Output与Listinghex文件和浏览信息Output选项卡里最重要的勾是Create HEX File没有它你编译出来只有axf没有hex很多烧录工具只认hex就会出现编译成功但下载工具找不到文件。另外Browse Information建议勾上它生成浏览信息配合Listing里的选项你才能右键函数跳转定义、查看调用关系。代价是编译稍慢但换来的是代码可读性值得。Output目录建议设成单独文件夹别和源码混在一堆。Keil默认把中间文件、axf、map、hex都扔在工程目录时间久了乱成一团找hex都费劲。我在Target选项卡里把输出目录指到Output源码区就永远干净。4.3 C/C选项卡宏、路径、优化等级的取舍除了前面说的宏和路径C/C选项卡里还有优化等级Optimization。新手建议先用Level 0也就是不优化。为什么因为开优化后单步调试经常出现变量被优化掉断点跳来跳去某行代码看着没执行的现象这些不是bug是编译器为了效率重排了指令。先在Level 0下把逻辑调通功能稳定后再逐步提高优化等级压缩体积或提速。还有个容易忽略的是C99 Mode。标准库里有些代码用了C99语法如果你手动写的代码里用了for循环内声明变量这种写法不开C99就报错。勾上C99 Mode基本能解决一大类语法在别处能用这里不行的疑惑。至于Warnings别一上来就全关警告里藏着未初始化、隐式声明这类真bug建议至少保留默认等级。4.4 Debug与Utilities下载器怎么配才不白折腾Debug选项卡左边选调试器用ST-Link就选ST-Link Debugger用J-Link选J-Link/J-Trace。选完点右边的Settings在Debug页里把Port选成SW正常情况下SW Device区域能识别到芯片ID。如果这里显示一片空白或者cannot access target说明硬件连接或供电有问题先别急着重装软件。Utilities选项卡里Use Target Driver for Flash Programming要勾上并选同一个调试器这样点下载按钮才能把hex写进芯片。很多人Debug配好了、能进调试但一按下载就失败往往就是Utilities这里没配对或者没勾Update Target before Debugging。调试和下载看着是两件事其实都要在Options里各配一处漏一处就有一半功能用不了。4.5 编译很慢的几个真实原因keil5编译很慢是个高频抱怨但慢通常有具体来源。第一Browse Information开着第一次全编译会生成大量浏览数据慢是正常的增量编译就快了。第二标准库把不需要的外设.c全加进来每个源文件都要单独编译文件越多越慢按需添加能立竿见影。第三输出目录里堆积了大量历史中间文件或者被杀毒软件实时扫描拖累把工程目录加进杀软白名单常有奇效。第四机械硬盘大量小文件确实会慢换SSD提升明显。我自己的做法是开发阶段开Browse Information方便跳转做最终发布版本时临时关掉它全编译一次又快又能看体积。另外Rebuild All只在动了库或宏定义时才用平时用Build就够了增量编译只编改动的文件速度快一个数量级。5. 新建工程后最常见的故障按这个顺序排查5.1 芯片列表为空或新建不了工程有人在Find a Device里搜半天搜不到自己的芯片或者在Select Device里厂商树是空的。这说明对应Pack没装。打开Pack Installer联网后在Devices页找到对应系列点Install或者下离线包双击安装。装完列表立刻出现不用重启。另一种新建不了工程的表现是点New uVision Project后没反应或者保存失败。先检查工程保存路径有没有中文、有没有写权限再检查是不是打开着同名工程导致了占用冲突。还有一种极隐蔽的情况软件许可未正确激活MDK会限制工程大小超过一定代码量会报链接错误。这种报错信息通常是*** ERROR L250之类遇到时留意一下许可状态用正规授权即可别去折腾来路不明的激活工具轻则报毒重则源码被篡改。5.2 编译通过但下载失败这是最让人抓狂的一类因为代码明明没问题。排查顺序我固定这样走先看Utilities里下载器配对没有再看硬件连线SWDIO、SWCLK、GND、3V3四根线要接牢尤其是GND别忘然后确认目标板有没有独立供电有些板子靠调试器供电电流不够一接大负载就复位接着看芯片是不是被读保护了新买的芯片或跑过带保护程序的可能处于保护状态需要用工具解除最后考虑BOOT0的接法正常从Flash启动时BOOT0要接地。排完这五步九成下载问题能定位。剩下的可能是复位引脚被外部电路拉死、调试口被代码复用成了普通IO。后者特别常见你在程序里把PA13、PA14配成了GPIO下载后调试口就锁了下次连不上。解决办法是用复位瞬间连接的方式擦除或者改代码别占用这两个脚。5.3 左侧Project窗口文件树不见了有人手滑把Project窗口关了或者拖走了工程里空空如也以为文件丢了。其实是视图问题。去View菜单里找到Project Window重新勾上或者双击一下浮动窗口的标题栏让它停靠回来。如果窗口在但里面工程树没展开点一下Target 1前面的加号。文件是真丢还是假丢看磁盘目录就知道只要.uvprojx还在、源文件还在重新挂进去就好。这个算不上故障但吓人程度不低。5.4 C51与MDK工程互相打不开前面提过这两套是独立工具链。如果你试图用MDK打开C51工程会提示无法识别的工程格式反之亦然。还有一种情况是同一个工程在不同版本Keil间打开高版本创建的工程低版本打不开会提示版本过高。团队协作时统一Keil版本这点很重要否则会出现在我这能编译在你那报错的扯皮。我吃过亏后来在README里强制写明版本号和Pack版本才消停。6. 让工程能被反复复用的几个习惯6.1 全部使用相对路径Keil默认记录的文件路径有两种形式绝对和相对。绝对路径写死了盘符一旦工程换电脑就全失效相对路径则以工程文件为基准整个文件夹挪到哪都还能用。在Manage Components添加文件时Keil通常会自动转成相对路径但如果你手动改过配置或用过绝对路径就要留意了。迁移工程前我习惯用文本编辑器打开.uvprojx搜一下盘符比如D:或C:\Users搜到就说明有绝对路径残留得改掉。这条习惯的价值在团队里尤其明显。别人clone你的仓库直接双击工程就能编译中间不需要手动改任何路径这才是合格的工程交付。6.2 攒一个自己的模板工程新建工程的动作重复度很高聪明的做法是攒一个骨架模板目录结构、启动文件、常用外设驱动、宏定义、头文件路径、下载器配置全都配好并验证过编译和下载。以后开新项目直接复制这个模板改个名、换掉芯片相关配置即可五分钟进入写代码状态而不是半小时在配环境。我现在的模板里连串口printf重定向、延时函数、常用GPIO初始化都带了省下大量重复劳动。模板也要定期维护比如Pack升级、库文件微调后把模板同步更新一次避免它随着时间变成腐坏的老代码。6.3 写一份能自救的README每个工程根目录放一个README写清楚五件事用的Keil版本、Pack版本、芯片型号、依赖的库、以及编译下载的注意事项。别看它简单一年后你自己回来看都会感谢当初写下它的自己更别说交接给同事了。遇到编译报错时第一件事就是对照README核版本很多玄学问题其实是版本对不上。顺带说一句Output目录和中间文件不进版本管理用.gitignore忽略掉仓库里只留源码、库和工程文件。这样仓库干净clone快也避免别人拿到你本机的编译产物产生困惑。把这些习惯做扎实新建工程这件事就从每次都要重新摸索变成一套流程无脑执行这才是一个从业者该有的效率状态。
返回列表