ARTICLE DETAIL

资讯详情

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

Keil5新建STM32标准库工程:从零配置到编译下载避坑指南

Keil5新建STM32标准库工程:从零配置到编译下载避坑指南 写这篇教程之前我犹豫了一下要不要写。网上搜Keil5新建工程确实有铺天盖地的图文教程但大多数都停留在点Next、点Finish的层面完全没讲清楚为什么要这样配置。结果就是很多新手照着教程建好工程一编译几十个报错也不知道去哪里排查回头又得重新搜一遍。之所以还要再写这篇是因为我在带新人、逛论坛的过程里发现真正把Keil5 MDK新建工程这件事讲透的内容并不多尤其是标准外设库Standard Peripheral Library工程的完整搭建流程、编译下载时那些看起来莫名其妙的问题该怎么定位很少有教程系统地讲。这篇教程以STM32F103C8T6为基础使用Keil MDK 5.37版本配合标准外设库V3.5.0从准备工作开始到新建工程、配置魔术棒Options for Target、添加启动文件、编译下载全程手把手。你不需要有任何Keil的使用经验但需要已经装好了Keil MDK和对应的器件支持包Device Family Pack简称DFP。如果连Keil都还没装建议先去ST官网把STM32F1系列的DFP下载好再搜一篇安装教程按照步骤装完再回来看这篇否则下一步会卡住。1. 新建工程前先搞清楚几个为什么新手最容易犯的错误是上来就开始点点点建到一半才突然发现自己连到底要用标准库还是HAL库都没想明白工程建好了代码结构却乱成一锅粥。这里花几分钟把几件影响后面所有操作的事说清楚。1.1 标准库和HAL库的区别你的选择决定了工程结构STM32的开发库目前主流就两个标准外设库Standard Peripheral Library简称标准库和HAL库。标准库偏向寄存器操作代码直接、简洁执行效率高但需要手动处理的细节多适合学习原理、做小型项目。HAL库封装层次更高代码量更大但跨芯片平台的移植性更好配合STM32CubeMX图形化配置工具开发速度更快适合做产品原型和项目交付。对于学STM32的新手或者只是想在Keil里跑通一个简单的点灯、串口实验我非常推荐标准库。原因很简单标准库里每个外设的初始化过程、寄存器配置逻辑都是显式暴露的你在阅读代码的过程里能清晰地看到这个寄存器写这个值有什么作用对理解芯片工作方式帮助极大。HAL库虽然也能完成同样的功能但一层套一层的封装会让初学者很难建立底层概念。这篇文章以标准库V3.5.0为例如果你用的是HAL库工程搭建流程大方向一致只是文件添加、宏定义、启动文件这些地方略有区别后面我会专门提一句HAL库版本有哪些不同。1.2 STM32F103C8T6的启动文件该选哪个HD还是MDSTM32启动文件startup_stm32f10x_hd.s等是根据芯片Flash容量来区分的。STM32F103C8T6的Flash容量是64KB按官方分类属于中等容量Medium-density应该用 start_stm32f10x_md.s。这是新手最容易踩的坑之一很多人都听说过要选hd但那是针对STM32F103RCT6256KB Flash这类高容量芯片的。如果你选错启动文件工程也能编译通过但下载到板子上大概率跑不起来或者调试时发现在启动阶段就异常跳飞了。这个坑在后面的避坑章节我会再展开一次。1.3 Keil5 MDK、Keil uVision、MDK-ARM到底什么关系很多新手下载软件的时候会被这几个词搞晕Keil5、MDK、MDK-ARM、uVision5。这里统一解释一下Keil是公司名字MDKMicrocontroller Development Kit是Keil针对ARM系列芯片推出的开发套件uVision是它的集成开发环境界面程序MDK5.37里自带的版本是uVision5。所以你打开软件看到窗口标题写着uVision5这跟Keil5 MDK就是一回事不存在什么Keil5和Keil5 uVision5是两款软件的区分。有一个点需要特别注意MDK-ARM只支持ARM架构的芯片不支持8051等51单片机。如果你同时玩51和STM32需要在电脑上分别安装Keil C51和MDK-ARM两个版本并且安装路径要分开界面看起来一样但底层编译工具链完全不同。这也是热词里有keil5mdk和keil5uvision有什么区别这个问题的原因。2. 动手新建工程的完整过程前面的理论问题梳理清楚了现在正式进入实际操作。整个过程我按顺序拆成六个步骤每一步都写得比较细照着做基本不会漏东西。2.1 第1步规划你的工程目录结构建工程之前先在你的工作目录下建一个用来放工程的文件夹名字随你喜欢但建议不要带中文和空格否则Keil在编译时可能因为路径解析问题报奇怪错误。我习惯用类似STM32_Project这样的目录规划一级目录工程名如LED_Demo二级目录下面按照功能拆分子文件Doc存放文档说明Libraries核心库文件Project存放Keil工程文件User存放main.c等用户代码Hardware存放自己写的外设驱动代码Libraries里面再分CMSIS和STM32F10x_StdPeriph_Driver两个文件夹。CMSIS放内核相关的头文件、系统初始化文件标准外设驱动库的inc和src则放在STM32F10x_StdPeriph_Driver里。用户自己写的程序放在User和Hardware里。2.2 第2步准备标准库里那堆文件如果你下载的是标准外设库V3.5.0的压缩包解压之后可以找到Libraries和Project两个文件夹。打开Libraries里面有CMSIS和STM32F10x_StdPeriph_Driver这两个文件夹直接复制到你刚才规划的工程目录的Libraries里即可。你需要的核心启动文件在Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\arm路径下。标准库的启动文件只分了ld/ md/ hd/ xl这几档按芯片容量选就行。我用STM32F103C8T6就选startup_stm32f10x_md.s。还需要在CMSIS里找到两个核心文件core_cm3.c和core_cm3.hARM Cortex-M3内核相关定义system_stm32f10x.c和system_stm32f10x.h系统时钟初始化2.3 第3步打开Keil新建空白工程启动MDK5后在菜单栏选择Project | New uVision Project然后选到你规划的Project文件夹里输入工程名字点保存。此时弹出一个对话框让你选择设备型号。如果你之前已经装好了STM32F1系列的DFP包在这个界面左侧的搜索栏直接输入STM32F103C8下方会列出对应芯片选中后点OK。如果这个对话框里什么都搜不到说明DFP包没装或者装错了版本。解决办法是在Keil里打开Pack Installer找到STMicroelectronics目录展开后找到STM32F1系列DFP点Install等待下载完成再重新新建工程。选完芯片后会弹出一个问你是否要复制启动文件到工程文件夹的对话框建议直接选No后面手动控制启动文件。因为自动复制的启动文件不一定会根据你的芯片容量正确选型而且文件位置可能和你自己的工程目录结构冲突不如自己管理来得清晰。2.4 第4步添加文件到工程在工程管理界面左侧的Project栏右键点击Target 1选择Manage Project Items。在这里可以自由组织工程分组。我习惯这样建User放main.c、stm32f10x_it.c中断服务函数文件等CMSIS放core_cm3.c、system_stm32f10x.cStartup放启动文件startup_stm32f10x_md.sFWLIB放标准库的src目录下的所有外设驱动源文件Hardware放自己写的外设驱动添加完第一层分组后还需要把物理路径和分组对应起来。先关闭Manage Project Items对话框回到主界面。选中一个分组右键点击Manage Project Items在每个分组下点Add Files把对应文件加进来。注意文件类型过滤器启动文件、源文件、头文件的扩展名不同需要在文件类型下拉框里切换。标准库src下有很多外设驱动源文件不需要全加进来用哪个外设加哪个。比如只用GPIO和RCC就加stm32f10x_gpio.c和stm32f10x_rcc.c。懒一点的全加进去也行就是编译时间长一些工程冗余一些。新手建议即使暂时用不到也把常用外设加上省得后面反复操作。2.5 第5步指定头文件路径Include Path添加源文件只是第一步编译时Keil要能找到对应的.h头文件否则会报fatal error: stm32f10x.h: No such file or directory。解决办法是进入魔术棒Options for Target在C/C选项卡里把Include Paths那栏填上所有头文件所在的路径。需要填的路径至少包括工程目录里的User文件夹Libraries\CMSIS\CM3\CoreSupportLibraries\CMSIS\CM3\DeviceSupport\ST\STM32F10xLibraries\STM32F10x_StdPeriph_Driver\inc你新建的Hardware文件夹路径用分号分隔。在输入框右侧有三个点的按钮点开可以像资源管理器一样逐层选择文件夹逐个加进去比手输路径更不容易出错。2.6 第6步配置宏定义Define在C/C选项卡里还有一个Define输入框标准库工程里通常要填USE_STDPERIPH_DEVICE有些教程还会加上STM32F10X_MD。前者是标准库编译时用来使能外设驱动的宏后者是配合条件编译区分芯片容量的宏。STM32F103C8T6就填STM32F10X_MD符合中等容量芯片的定位。有些HAL库工程还会填USE_HAL_DRIVER但标准库不需要。这些宏定义看起来简单少了任何一项编译时都会报一堆莫名其妙的未定义错误。新手经常在这里看漏看到几千行报错直接懵了。3. 魔术棒Options for Target少配一项都会翻车工程文件添加完毕头文件路径和宏定义也填好了但还有几个关键配置没过。很多人东拼西凑建的工程之所以下载不了程序、调试失败绝大多数情况都是这节内容出了问题。3.1 Target选项卡芯片型号和浮点单元魔术棒的第一个Tab是Device显示当前选的芯片型号一般不需要动。第二个Tab是Target这里有几个注意事项ARM Compiler版本选择在新版MDK5里默认用的编译器是Arm Compiler 6AC6老教程大多是针对AC5写的。标准库的代码是以AC5的语法风格写的直接拿到AC6下编译偶尔会遇到语法警告甚至报错。解决办法是在这个界面把编译器版本切换成AC5如果安装了对应版本或者保留AC6把有兼容性问题的代码改用__STATIC_INLINE等新写法。新手建议直接用AC5比较稳妥。不要勾选Use MicroLIB这个勾选选项只在你使用标准库的printf重定向到串口时需要用。它会把标准C库精简掉一部分减小Flash占用代价是部分C库函数行为不一样。刚建工程用不上可以先不勾。Floating Point HardwareSTM32F103没有FPU就选Not Used不用管。3.2 Output选项卡生成Hex文件点Output选项卡勾选Create HEX File。这一步很多人漏掉结果程序编译通过、下载也没问题但量产烧录的时候发现根本没有.hex文件能用。它的作用是在编译完成后额外生成一个HEX格式的机器码文件这个文件可以直接用ST-LINK的烧录工具或串口ISP方式烧进芯片不需要依赖Keil环境。日常学习点灯可以不在意但如果你后面要做离线烧录、给板卡批量写程序这个文件是刚需。3.3 Debug选项卡ST-Link还是J-LinkDebug选项卡用于选择调试器和下载器。左边Use那栏默认可能是Use Simulator要改成你实际使用的调试器。我用的是ST-Link就在下拉框里选ST-Link Debugger。选完右边还有一行Settings按钮点进去可以看到调试器是否识别到目标板芯片信息如果这里读不到芯片程序下载基本不可能成功。我用的ST-Link在调试打印机被识别成CMSIS-DAP或ST-Link V2新版Keil都能兼容。J-Link用户就选J-LINK / J-TRACE Cortex。3.4 Utilities选项卡Flash Download设置必看Utilities选项卡对于新手来说最容易被忽略但下载失败大多集中在两个地方一是Flash Download里的编程算法Programming Algorithm没有添加二是Reset and Run没有勾选。点Utilities选项卡在Flash Download那一栏点右边的Settings弹出来的对话框里查看Programming Algorithm列表是否为空。为空的话点Add选择对应芯片的烧写算法。STM32F103C8T6是512KB Flash的型号算法文件选择STM32F10x Med-density Flash不要选成Low-density或High-density否则下载时地址空间对不上会报错。对话框下方有个Reset and Run复选框勾选后程序下载完自动复位运行不然每次下载完你都要手动按一下板子上的复位键才能跑程序。这个小细节对调试体验影响很大建议一开始就勾上。3.5 C/C选项卡的其他小项C/C选项卡里除了前面提到的Include Paths和Define还有个Optimization选项。新手调试阶段建议选Level0-O0也就是关闭优化。优化级别越高调试时看到的变量实时值越可能不真实断点也可能因为代码被重排而跳来跳去增加定位问题的难度。运行稳定后再切换成Level2或Level3来减小代码体积和提升运行速度。4. 编译、下载和第一个点灯程序所有配置都完成之后现在写一段最基础的程序验证整个工程是否构建成功。4.1 编写main.c和系统初始化在User分组下的main.c中写入最精简的模板。标准库的应用代码需要包含stm32f10x.h头文件并在main函数里调用SystemInit如果是标准库新版本的启动文件中已经调用过则可以省略再初始化外设。用GPIO点亮PC13上的LED完整代码如下#include stm32f10x.h void delay(void) { unsigned int i; for (i 0; i 500000; 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_50MHz; GPIO_Init(GPIOC, GPIO_InitStructure); while (1) { GPIO_SetBits(GPIOC, GPIO_Pin_13); delay(); GPIO_ResetBits(GPIOC, GPIO_Pin_13); delay(); } }同时建议在User分组中添加stm32f10x_it.c这个文件负责存放中断服务函数。标准库模板里会有一个空实现的版本你可以从标准库的Project例程中复制过来避免后面要用中断时出现硬错误。4.2 编译时遇到的那些报错写完代码点Build按钮或者按F7正常情况下底部编译输出栏会显示0 Error(s)0 Warning(s)。如果出现两个Warnings通常来自标准库里的某些宏未被使用不影响运行暂可忽略。如果编译直接报错常见的有error: #5: cannot open source input file core_cm3.hInclude Paths没配对回去把CMSIS那两个路径加上error: #20: identifier GPIO_Pin_13 is undefined头文件没包含或者宏定义STM32F10X_MD没填Error: L6218E: Undefined symbol SystemInit (referred from startup_stm32f10x_md.o)system_stm32f10x.c文件没有添加到工程或者分组文件里只有启动文件缺失源文件这些报错看起来吓人但把每个报错的信息和文件路径逐行翻译成中文基本上就是找不到XX文件或者XX符号没定义两类顺着上面配置项排查就能解决。最忌讳的是看到报错就重新建工程反而找不到真正的问题。4.3 下载和运行编译通过后接好ST-Link点击Download按钮下载。下载成功的标志是底部信息栏出现Flash Load finished at ...同时板子上的LED开始按照你写的延时节奏闪烁。如果这一步出问题留意以下三种情况Error: Flash Download failed - Cortex-M3通常是因为芯片进入休眠或者没有正确复位可以把板子断电重插或者按住复位键再点下载下载瞬间松开复位键Error: No ST-LINK detected驱动或接线问题去设备管理器查看ST-Link是否被正确识别识别不到就重新安装ST-Link驱动下载成功但程序不运行检查Utilities里的Reset and Run有没有勾选没勾就手动按一下板子上的复位键5. 我实际使用中一定要再重复的几件事工程搭建的流程走完一遍之后最后再分享几次实操下来比较痛的经验每一条都是我自己踩过并花时间排查过的希望对你有帮助。5.1 路径中永远不要带中文这一点老生常谈但年年有人踩。Keil5的编译器对中文路径的支持一直不太好就算当前版本能编译通过后面换台电脑、换个编译器版本就可能崩。工程文件夹和安装路径统一使用英文或拼音别在新建文件夹3里建工程。我见过一个朋友把工程放在桌面上一个叫毕业设计最终版的文件夹里结果AC6编译器直接报无法打开中间文件换AC5倒是编译过了但每次构建都要三十秒以上极其难受。5.2 启动文件和芯片容量不匹配时现象会很诡异如果你选错了启动文件程序编译正常下载正常但芯片运行起来完全不符合预期点灯不亮、串口乱码、调试时PC指针跑飞。排查这种问题非常耗费时间。遇到此类现象务必回来检查startup文件是否是与你芯片Flash容量对应的版本。STM32F103C8T6是64KB Flash用md版本不要用hd版本。5.3 标准库和HAL库的工程不能混用很多人在中途从标准库迁移到HAL库或者反过来把两个库的源文件都加进同一个工程。两个库对寄存器操作、时钟配置的实现完全不同混在一起编译十有八九会出现重复定义、头文件冲突甚至编译直接崩溃。实际项目中确定了一种库就坚持用到项目结束不要中途切换否则改代码的成本远大于你的预期。5.4 用CubeMX生成工程也需要做同样的事热词里有cubemx新建工程如果你用STM32CubeMX生成工程那么恭喜你前面提到的启动文件、芯片选型、头文件路径这些事CubeMX都会自动生成好不用手动配置。但CubeMX默认生成的是HAL库工程而且生成时选择的IDE要选MDK-ARM V5生成后用Keil打开还是建议在魔术棒里把Include Paths和Define检查一遍。CubeMX不是万能药生成后的工程依然可能因为编译器版本不匹配AC5/AC6出现标准库风格的报错。5.5 最后补充一个调试效率小技巧如果你用的是ST-Link并且Keil版本比较新可以在Debug选项卡里把ST-Link的SWO跟踪使能打开配合ITM_SendChar函数实现printf调试输出。串口调试要接线、要配置波特率SWD调试只要一根线查看变量、打印日志都方便很多。具体操作是在main.c中包含stdio.h然后用fputc重定向ITM端口在DebugprintfViewer窗口就能看到打印信息。这一段细节偏进阶但学会了能明显提升调试效率。建工程这件事本质上就是一个模板化的流程。第一次跟着教程完整走一遍后面再建新项目就是十分钟的事。我自己的习惯是在本地保留一份建好的标准库工程模板新建项目时直接复制一份改改名字就开工比每次从头配置省事很多。如果你也打算长期用Keil开发STM32建议花点时间整理自己的模板库把常用外设的裸机驱动都封装好放进去后续项目开发效率会有质的提升。
返回列表