第3章 软件环境配置与使用入门 本章要点 STM32开发方式; 软件资源安装与配置; 基于CubeMX的HAL库开发模式; CMSISDAP调试器使用; 编译器优化与Volatile关键字。 基于STM32CubeMX的HAL库的嵌入式系统开发之所以高效、快捷、可移植性强,在一定程度上得益于软件开发平台的高效配置。相比于传统的寄存器或是标准库开发,HAL库开发的软件环境配置更为复杂,涉及软件众多,甚至成为嵌入式学习的拦路虎。为帮助读者顺利搭建适合自己的嵌入式软件平台,本章将详细介绍各相关软件的安装、配置和使用方法。 微课视频 3.1STM32开发方式 嵌入式系统软件设计的编程语言分为汇编语言和高级语言两种,目前广泛使用C语言进行嵌入式系统应用开发,而依据开发库的不同,STM32开发方式又可以划分为STM32Snippets库、标准外设库(Standard Peripheral Library)、STM32Cube HAL库、STM32Cube LL库4种。 3.1.1STM32Snippets库 图31STM32Snippets库 STM32Snippets可翻译为“代码片段”,其实就是常说的“寄存器”开发STM32的底层驱动代码。STM32Snippets库是高度优化的示例代码集合,使用符合CMSIS的直接寄存器访问来减少代码开销,从而在各种应用程序中最优化STM32微控制器的性能。 早期的51单片机、AVR单片机和PIC单片机均采用的是寄存器开发方式。尤其是我们十分熟悉的51单片机,开发一个51单片机程序,一般是采用汇编语言或是C语言编写控制程序,操作相应寄存器(例如P1、IE、IP、TMOD、T1等),实现相应控制功能。 ST官方仅提供STM32F0和STM32L0两个系列的STM32Snippets库,如图31所示,但寄存器开发方式适用所有的STM32微控制器。对于没有提供STM32Snippets库的微控制器开发时只需包含该系列芯片的寄存器定义头文件便可使用寄存器开发方式,而这一步操作往往是在工程模板创建时已经完成。 虽然寄存器开发方式直接、高效,但是STM32片上资源十分丰富,要记住每个寄存器名称和操作方式是十分困难的,且编写出来的程序可读性、可维护性和可移植性都比较差。因此,除对速度要求较高和需要反复执行的代码外,一般不使用寄存器开发方式。值得注意的是,寄存器开发方式是其他一切开发方式的基础,所有开发模式本质上操作的是寄存器,有时在其他开发模式中直接操作寄存器会起到事半功倍的效果。 3.1.2标准外设库 为帮助嵌入式工程师从查找、记忆芯片手册中解脱出来,ST公司于2007年推出标准外设库(Standard Peripheral Libraries,SPL),也称标准库,STM32标准库是根据ARM Cortex微控制器软件接口标准(Cortex Microcontroller Software Interface Standard,CMSIS)而设计的。CMSIS标准由ARM和芯片生产商共同提出,让不同的芯片公司生产的ARM CortexM微控制器能在软件上基本兼容。 STM32标准库是一个或一个以上的完整的软件包(称为固件包),包括所有的标准外设的设备驱动程序,其本质是一个固件函数包(库),由程序、数据结构和各种宏组成,包括了微控制器所有外设的性能特征。该库还包括每一个外设的驱动描述和应用实例,为开发者访问底层硬件提供了一个中间API(Application Programming Interface,应用编程接口)。通过使用标准库,开发者无须深入掌握底层硬件细节,就可以轻松应用每一个外设,就像在标准C语言编程中调用printf()一样。每个外设驱动都由一组函数组成,这组函数覆盖了该外设的所有功能。每个器件的开发都由一个通用API驱动,API对该驱动程序的结构、函数和参数名称都进行了标准化。 标准外设库如图32所示,目前,其支持STM32F0、STM32F1、STM32F2、STM32F3、STM32F4、STM32L1系列, 不支持STM32F7、STM32H7、STM32MP1、STM32L0、STM32L4、STM32L5、STM32G0、STM32G4等后面推出的系列。 图32标准外设库 3.1.3STM32CubeMX HAL库 标准外设库不仅明显降低了开发门槛和难度,缩短了开发周期,降低开发成本,而且提高了程序的可读性和可维护性,给STM32微控制器开发带来极大的便利。但是不同系列微控制器的标准库是不通用的,差别较大,给代码复用和程序移植带来挑战,进而影响项目开发效率。 2014年ST公司推出硬件抽象层(Hardware Abstraction Layer,HAL)库,HAL库比标准库抽象性更好,所有API具有统一的接口。STM32Cube HAL库如图33所示,基于HAL库的程序可以在STM32全系列微控制器内迁移,可移植性好; 借助图形化配置工具STM32CubeMX可以自动生成初始化代码和工程模板,高效便捷,是ST公司主推的一种开发方式。 图33STM32Cube HAL库 3.1.4STM32CubeMX LL库 基于STM32CubeMX的HAL库开发高效、快捷,支持STM32全系列产品,但是其抽象层次高,多层函数嵌套,代码冗余度相对较高,对芯片容量小,性价比要求高的应用场合有时难以胜任。所以,ST公司对于部分产品在推出其HAL库时,同步推出底层(LowLayer,LL)库,LL库中大部分代码直接操作寄存器,更接近硬件,代码量少,但应用方法和HAL库并无区别。 3.1.5开发方式比较与选择 ST公司提供的4种嵌入式开发方式各有所长,为帮助初学者选择合适的开发方式,下面对4种开发方式进行比较,并给出作者的选择建议。 1. 开发方式比较 表31分别列出了4种开发方式在可移植性(Portability)、优化程度(Optimization Memory&Mips)、易用性(Usability)、意愿性(Readiness)和硬件覆盖(Hardware Coverage)程度方面的对比结果。 表31开发方式对比 开发库可 移 植 性优 化 程 度易用性意愿性硬件覆盖程度 STM32Snippets库++++ 标准库++++++++++ HAL库++++++++++++ LL库+++++++++ 由表31可知,STM32Snippets库(寄存器)开发方式除优化性能方面表现较好,其他性能均较差,所以目前已较少为嵌入式工程师使用。标准库各方面性能均处于中间位置,有着不错的性能表现,另外由于标准库推出较早,在STM32嵌入式开发中获得了广泛的应用。HAL库除优化程度表现欠佳外,其他方面均具有最优性能,综合性能最好,是未来嵌入式开发的发展方向。LL库除优化程度这一性能指标和HAL库的表现相反外,其他性能表现的趋势二者是一致的,但LL库的表现稍弱于HAL库。 2. 开发方式选择 各种开发方式的性能表现决定了其应用场合,嵌入式开发者应根据应用场合和自身技术背景选择适合自己和项目的嵌入式开发方式。选择没有固定规则,且带有一定的主观性,此处只给出一些选择建议,仅供参考。 (1) 如果开发者使用的是小容量、少引脚的微控制器,并且想利用好存储器中的每一位,追求最高性价比,因为硬件抽象是需要成本的,那么寄存器开发或者STM32Cube LL库开发将是最佳选择。 (2) 作为有过8位单片机开发经验的开发者,如果习惯直接寄存器操作,那么寄存器开发或STM32Cube LL库开发将是一个很好的起点。如果更喜欢C语言编程,那么建议使用STM32Cube HAL库开发或标准库开发。 (3) 有过标准库开发经验的嵌入式工程师,且将来可能仅使用同一系列的微控制器(如STM32F1系列),可以继续使用标准库进行开发。如果开发者计划在未来使用不同的STM32系列,那么作者建议考虑使用STM32Cube库开发,因为这更容易在系列之间移植。 (4) 如果设计者希望代码具有好的可移植性同时保持较高的优化性能,则开发者可以使用STM32Cube HAL库开发方式,并用特定的优化替换一些冗余度高的调用,从而保持最大的可移植性和隔离不可移植但经过优化的区域。也可以使用STM32Cube HAL库和STM32Cube LL库混合编程的方法来达到上述相同的效果。但需要注意的是,对于同一外设,不可同时使用HAL进程和LL进程。 对于一个控制系统来说,稳定可靠是最重要的,标准库在同一系列芯片之间代码可直接复用,所以其依然是很多STM32开发者难以割舍的情怀。近年来,随着微控制器存储容量成倍增长,主频持续提高,淡化了人们对性能的考量,开发人员更关心软件开发效率和产品迁移,基于STM32CubeMX的HAL库开发方式逐渐流行起来。本书也是以此开发方式讲解嵌入式系统开发的,有时为了快捷访问和优化性能,也会在部分模块内直接操作寄存器。 微课视频 3.2软件资源安装与配置 基于STM32CubeMX的HAL库开发主要需要图形化配置软件STM32CubeMX、Java开发环境、MDKARM集成开发环境(Integrated Development Environment,IDE)、芯片器件包、HAL固件包。上述5个软件资源的安装又可划分为两个主要部分。第一部分的重点是安装STM32CubeMX开发工具,安装之前需要先安装Java运行环境(Java Runtime Environment,JRE),安装之后还需要在STM32CubeMX中添加芯片的HAL固件包。第二部分重点是MDKARM集成开发环境的安装,同样安装完成之后需要添加芯片的器件包。 3.2.1JRE安装 1. 下载JRE文件 在浏览器地址栏输入网址: https://www.java.com/en/download/manual.jsp,打开如图34所示的JRE下载界面,单击“Windows Offline(64bit)”链接开始下载64位Windows操作系统离线JRE安装文件。 图34JRE下载界面 下载完成的JRE安装文件,名称为jre8u341windowsx64.exe,大小为83.4 MB,版本号为8.0.3410.10。 2. 安装JRE程序 双击JRE安装文件,开始安装Java运行环境,JRE安装界面如图35所示。一般无须更改任何设置,直接单击“安装”按钮开始安装,待出现“您已成功安装Java”对话框,单击“关闭”按钮完成安装。 图35JRE安装界面 3.2.2STM32CubeMX安装 STM32CubeMX软件是意法半导体公司推出的一款具有划时代意义的软件开发工具,它是ST公司STM32Cube计划中的一部分。该软件是一个图形化开发工具,用于配置和初始化其旗下全系列基于ARM Cortex内核的32位微控制器,并可以根据不同的集成开发环境,如IAR、KEIL和GCC等,生成相应的软件开发项目和C代码。简单地说,STM32CubeMX软件是一款图形化的初始化C代码生成器,在本书的后续表述中也会将其简称为CubeMX或Cube。 1. STM32CubeMX下载 在ST官网(www.st.com)首页搜索栏输入STM32CubeMX,在搜索结果页面单击STM32CubeMX链接,进入产品介绍页面,继续单击Get Software进入图36所示STM32CubeMX下载页面。上述操作也可以通过在地址栏输入如下网址完成: https://www.st.com/en/developmenttools/stm32cubemx.html#getsoftware 在图36中,需要根据具体操作系统选择相应的软件进行下载,大多数读者使用的是Windows操作系统,需要下载STM32CubeMXWin安装包,同时软件要不断升级,也可以通过Select version下载列表框选择不同的软件版本,如果是下载最新的版本则可以单击Get latest进入下载链接。 图36STM32CubeMX下载页面 选择好类别和版本之后,还需要接受许可协议,注册和登录账号才能完成下载。作者下载的安装包文件名为en.stm32cubemxwin_v661.zip,版本号为V6.6.1,大小为454MB。 2. STM32CubeMX软件安装 双击安装包中的可执行文件SetupSTM32CubeMX6.6.1Win.exe,启动安装程序,安装界面如图37所示。 图37安装界面 依次单击Next按钮,接受许可协议,同意隐私条款,自定义安装路径,然后开始程序安装,经过短暂的等待,STM32CubeMX程序就已经成功安装。 3.2.3HAL固件包安装 STM32CubeMX支持全系列STM32芯片的开发,而芯片初始化代码和资源管理是基于HAL/LL固件包的,但CubeMX没有必要也不可能将所有芯片的固件包都集成到开发环境当中,因此还需要添加可能用到芯片系列的HAL/LL的固件包。因为本书是基于HAL库的开发,所以此处仅添加HAL固件包。 固件包有两种安装方式,一种是在线安装,另一种是将固件包下载后本地安装。本节采用在线安装方式安装STM32F4固件包,采用本地安装方式安装STM32F1固件包,但在实际安装时均推荐在线安装。 1. 固件包文件夹设置 STM32CubeMX软件安装完之后会在桌面和开始菜单生成一个快捷方式,还可以将其添加到开始屏幕或任务栏。双击其快捷方式即可运行STM32CubeMX软件,启动界面如图38所示。 图38STM32CubeMX启动界面 图39软件库文件夹设置 在安装固件包之前需要对软件环境和库文件夹进行设置,以便后续使用过程中更加得心应手。由于C盘容量经常告急,作者一般将嵌入式学习的软件安装在计算机最后一个分区G盘,所以还需要将软件库文件夹也设置在G盘。 启动界面最上方共有三个菜单项即File,Window、Help,依次选择Help→Updater Settings菜单项,打开图39所示软件库文件夹设置对话框。其中Repository Folder选项就是需要设置的软件库文件夹,所有的MCU固件包和扩展包均安装到此目录下,这个文件夹一经设置并且安装一个固件包之后就不能再更改,此处只需将盘符由C修改为G即可。如果使用默认路径或是浏览选择其他路径也是可以的,但需要注意路径名中尽量不要带有中文或空格。在图39中还可以对软件更新和数据更新选项进行设置。 2. 固件包在线安装 如果个人计算机已成功连接至网络,固件包安装一般采用在线安装方式,该方式方便快捷,还可以在线更新。在图38启动界面依次单击Help→Manage embedded software packages菜单项,打开如图310所示的嵌入式软件包管理对话框。这里将STM32Cube MCU固件包和STM32Cube 扩展包统称为嵌入式软件包。 图310嵌入式软件包管理对话框 在图310对话框中找到所用芯片系列,如STM32F4,单击左侧的下三角按钮后会展开不同版本,最前面的一般是最新版本,选择一个版本,将复选框选中,单击对话框下面的Install按钮开始安装,等待一段时间,当复选框变成绿色填充时表示固件包已成功安装。 3. 固件包本地安装 如果个人计算机不具备联网条件,且已获取固件包安装文件,可以采用本地安装方式。下面以安装STM32F1系列固件包为例,讲解本地安装方式。 在ST公司官网(www.st.com)首页搜索栏输入关键字STM32CubeF1,进入STM32CubeF1 Active页面,单击Get Software按钮进入HAL库下载页面,如图311所示。在下载资源列表中有两个软件包可以下载,其中STM32CubeF1为基础包,Patch_CubeF1为补丁包,所以这两个文件都需要下载,且均选择最新版本。下载完成的基础包文件为en.stm32cubef1.zip,版本为v1.8.0,大小为109MB,补丁包文件为en.patch_cubef1_v184.zip,版本为v1.8.4,大小为51.4MB。 图311HAL库下载页面 在图38启动界面依次单击Help→Manage embedded software packages菜单项,打开嵌入式软件包管理对话框,单击左下角的From Local按钮,浏览选择STM32CubeF1基础包,如图312所示,单击“打开”按钮开始安装,安装完成之后,软件包管理对话框固件包列表中STM32Cube MCU Package for STM32F1 Series列表项前的复选框绿色填充,并出现了版本号1.8.0,表示基础包安装完成。 图312基础包离线安装 如果采用相同方法安装补丁包,则会出现依赖错误(Missing dependency for this package),表示不可以在软件包管理对话框中同时安装基础包和补丁包。 解决上述问题的方法是将下载好的基础包和补丁包复制到库文件夹,默认路径为C: /Users/86139/STM32Cube/Repository/,若已修改请将其替换为新的目标路径,并对这两个文件进行重新命名。如果在重新命名时记不清命名规则,可以从已安装的固件包名称得到相应启示。 基础包: en.stm32cubef1.zip→STM32Cube_FW_F1_V180.zip。 补丁包: en.patch_cubef1_v184.zip→STM32Cube_FW_F1_V184.zip。 再次打开如图313所示的补丁包离线安装对话框,选中固件包1.8.4版本前面的复选框,单击Install按钮开始安装(操作方法同在线安装),此时STM32CubeMX会检测到补丁包已存在,跳过软件下载程序,直接进行解压步骤,安装完成之后,1.8.4版本的固件包前面复选框同样进行了绿色填充。至此STM32CubeF1固件包基础包和补丁包全部安装完成。 图313补丁包离线安装 由上述操作可知,STM32Cube固件包离线安装是对基础包和补丁包分别进行下载和安装的,过程较为复杂,所以除非存在无法联网等特殊情况,推荐使用在线安装。 3.2.4MDKARM安装 1. MDKARM简介 MDKARM源自德国的KEIL公司,也称KEIL MDKARM、KEIL ARM、KEIL MDK、Realview MDK、IMDK、μVision5(μVision4)等,全球超过10万的嵌入式开发工程师使用MDKARM。目前最新版本为MDK 5.37,该版本使用μVision5集成开发环境,是目前针对ARM处理器,尤其是ARM CortexM内核处理器的最佳开发工具。 MDK5向后兼容MDK4和MDK3等,以前的项目同样可以在MDK5上进行开发(需安装兼容包),MDK5同时加强了针对ARM CortexM微控制器开发的支持,并且对传统的开发模式和界面进行升级,如图314所示,MDK5由两个部分组成: MDK Tools(MDK工具)和Software Packs(软件包)。其中,MDK Tools包含MDKCore和Arm C/C++Compiler两部分; Software Packs可以独立于工具链进行新芯片支持和中间库的升级。 图314MDK5组成 2. MDKARM下载 在KEIL官网(www.keil.com)首页,单击顶端Download链接,首先出现一个Overview页面,继续单击Product Downloads选项,进入如图315所示的产品下载列表页面。 图315产品下载列表 在图中有4个下载选项,第1个选项为MDKARM,适用于ARM内核开发工具,最新版本为5.37,其他选项用于相应型号单片机的开发。单击MDKARM软件图标进入下载页面,填写并提交用户信息之后,软件便开始下载。 在最新的MDK 5.37版本中仅内置Compiler 6.18,没有预装Compiler 5,这将会导致在早期的MDK5或MDK4创建的文件无法编译。虽然用户也可以手动添加Compiler 5,但这个操作比较麻烦,也会进一步增加安装文件占用空间,因此,如果读者不需要打开以前创建的工程,可以直接安装最新版本,否则可以和作者一样选用上一个版本的安装文件MDK535.EXE,文件大小为890MB。 3. MDK软件安装 双击下载完成的MDK535.EXE可执行文件启动安装程序,单击Next按钮,同意许可协议,进入安装路径设置,默认安装于C盘,此处将其修改为G盘,MDK安装界面如图316所示,继续单击Next按钮,填写用户信息开始软件安装,当安装界面出现Finish按钮,表示软件已安装完成,单击此按钮退出安装程序。 图316MDK安装界面 3.2.5器件包安装 随着芯片系列、种类越来越多,MDKARM软件越来越难以将所有组件都集成到一个安装包中,所以和MDK4版本不同,从MDK5开始,MDKCore是一个独立的安装包,基于μVision,对ARM CortexM设备提供支持,提供安装程序用于下载、安装和管理软件包,可随时将软件包添加到MDKCore,使新的设备支持和中间件更新独立于工具链。 在MDK 5.35安装完成后,要让MDK5支持STM32F4和STM32F1系列芯片开发,还要安装STM32F4的器件包(Keil.STM32F4xx_DFP.2.16.0.pack)和STM32F1的器件包(Keil.STM32F1xx_DFP.2.4.0.pack),安装方式依然分为在线安装和离线安装,实际安装时推荐使用离线安装。 1. 器件包在线安装 MDKARM软件安装成功之后,会在桌面和开始菜单栏创建快捷方式,双击或单击快捷方式启动Keil μVision5,单击调试工具栏最右边Pack Installer图标,打开如图317所示器件包在线安装对话框。 图317器件包在线安装 在图317器件包安装管理器中,在Device栏,先选择芯片厂家STMicroelectronics,再选择STM32F4系列,Summary栏显示该系列器件的数量,在Pack栏选择安装文件STM32F4xx_DFP,单击Action栏的Install按钮开始安装,此时按钮转变为灰色不可用状态,对话框的最下面显示器件包安装进度和安装方式。当器件包安装完成,Install按钮前面绿色图标会被点亮。 2. 器件包离线安装 如果已经获取器件包文件,则也可以采用离线安装的方式进行。 首先需要前往官方下载地址(https://www.keil.com/dd2/pack/)下载最新的器件包,在资源浏览页面中,首先找到芯片厂家STMicroelectronics,然后找到要下载的产品系列名称STM32F1 Series Device Support,Drivers and Examples,单击后面的下载按钮开始资源下载。以STM32F1为例,下载完成后文件名称为Keil.STM32F1xx_DFP.2.4.0.pack,版本号为2.4.0,大小为47.9MB。 双击下载文件开始器件包安装,器件包离线安装页面如图318所示,安装文件会自动识别MDKARM的安装路径,无须任何更改,单击Next按钮开始安装,出现Finish按钮提示安装完成。当器件包安装完成,打开图317所示器件包安装管理器,和在线安装方式一样,Install按钮前面绿色图标也将被点亮。 图318器件包离线安装 作者在安装的过程中发现,无论是在线安装还是离线安装方式,器件包的下载速度均十分缓慢,如果可以通过共享获得器件包,采用离线安装方式更简单、快捷,是推荐安装方式。 3.2.6MDKARM注册 MDKARM作为ARM CortexM内核微控制器最全面的解决方案,提供了丰富的产品线,其支持能力和产品特性如图319所示。MDKLite是免费评估版,默认即是安装此版本,要想获得开发环境全面支持和更好使用性能,还需要将其注册为MDKProfessional版本。 图319MDKARM支持能力和产品特性 在桌面或开始菜单找到Keil μVision5快捷方式,右击选择以管理员身份运行。单击File→License Management菜单项,打开授权管理对话框,如图320所示,将图中Computer ID填写到注册软件CID文本框,注册目标选择ARM,版本选择Professional,复制软件生成的License ID,并填写到图中License ID Code(LIC)编辑框,单击Add LIC按钮完成注册。注册成功会在授权管理对话框显示使用期限和“***LIC Added Successfully***”提示信息。 图320MDK授权管理对话框 3.2.7软件安装总结 软件平台配置主要包括两方面工作。一方面是软件资源下载,一般是从官方网站直接下载,除因兼容性问题选择了MDKARM的上一个版本MDK 5.35,其余软件和资源包均为最新版本。另一方面是软件安装,本书围绕着两个软件展开: 第一个软件是图形化配置工具STM32CubeMX的安装,安装之前需要先安装JRE,安装完后还需要安装芯片的固件包(HAL/LL),在固件包安装过程中,推荐使用在线安装方式; 第二个软件是32位MCU集成开发环境MDK 5.35,安装完成之后还需要安装芯片器件包,器件包推荐离线安装。 微课视频 3.3基于STM32CubeMX的HAL开发方式 基于STM32CubeMX的HAL开发涉及软件众多,对于初学者有时可能不知从何开始。为此,作者设计了本书第一个也是最简单的项目实例,即配置开发板LED指示灯L1引脚为输出模式(默认输出低电平),编写LED周期闪烁应用程序,连接调试器,下载程序并复位运行。 3.3.1STM32CubeMX生成初始化代码 使用标准库进行嵌入式开发的第一步就是建立适合自己的工程模板,并编译通过,此外,在使用外设之前需要花较多精力对其初始化,然后才是应用程序的编写。而借助STM32CubeMX可以轻松完成前面两步,显著减少了代码量,可靠性也得到进一步的提高。 1. 选择MCU芯片 运行STM32CubeMX软件,其初始界面如图321所示,各部分功能如图中标注所示,可以在该界面打开或新建工程。其中新建工程又分为3种方式,第1种是Start My project from MCU(选择一款MCU)新建工程,这是最常用的方式,其他2种方式分别是Start My project from ST Board(选择ST评估板)和Start My project from Example(参考例程)新建工程。 图321STM32CubeMX初始界面 选择第1种方式新建工程,单击ACCESS TO MCU SELECTOR选项打开如图322所示MCU/MPU芯片选择对话框。 图322MCU/MPU芯片选择 为方便查找芯片,该对话框中设置了各种筛选条件,比方按产品信息、存储器、定时器、模数转换器等,每一个筛选类别又细分为多个子项目。最快捷简单的方法是在Commercial Part Number列表组合框中输入芯片名称(如STM32F407ZET6),MCUs/MPUs List列表将会列出相应的芯片,其上部也会给出芯片主要性能介绍,单击列表前面的星形符号,可以收藏此芯片,双击芯片名称,完成MCU选择,跳转至工程创建对话框,如图323所示。配套步骤是按照工程创建流程组织的,在完成芯片选择之后,还需要经过Pinout & Configuration(引脚及资源配置)、Clock Configuration(时钟配置)、Project Manager(工程管理)等步骤才能初始化外设和生成项目工程。 图323工程创建对话框 2. 配置GPIO引脚 下面以PF0引脚配置为例,讲解GPIO(通用目的输入输出)引脚的配置。PF0引脚配置如图324所示,首先在工程创建对话框中的引脚视图上找到PF0引脚,也可以使用右下方的查找工具输入引脚名称进行快速查找。在PF0引脚上用鼠标左键选择引脚功能为GPIO_Output。然后展开左侧最上面的System Core(系统内核)配置组别,选择GPIO子项,此刻在配置类别和引脚视图中间增加了GPIO Mode and Configuration配置区域,这一区域划分为Mode和Configuration两个子区,但是对本项目来说,GPIO引脚无须配置工作模式,仅需配置Configuration选项即可。 图324PF0引脚配置 根据项目设计要求,需要将PF0引脚配置为输出模式,默认输出电平为低电平,没有上拉或下拉,最大输出速度为低,其实上述设置均为GPIO_Output模式的默认设置,此处无须修改。 3. 配置时钟源(RCC) 完成引脚配置之后,还需要配置System Core下面的RCC子项,时针源配置过程及结果如图325所示,此处实际上是配置系统的时钟源。其中High Speed Clock(HSE)和Low Speed Clock(LSE)均有3个选项: Disable(禁用外部时钟)、BYPASS Clock Source(外部有源时钟)、Crystal/Ceramic Resonator(外部无源陶瓷晶振)三个选项。由第2章开发板硬件电路可知,开发板的外部高速时钟(HSE)和外部低速时钟(LSE)引脚均外接石英晶体振荡器,所以HSE和LSE均应选择Crystal/Ceramic Resonator。 图325时钟源配置过程及结果 4. 配置调试方式 调试方式配置如图326所示,选择System Core类别下的SYS子项对调试方式进行配置,由第2章硬件电路可知,开发板设计板载CMSISDAP调试器采用Serial Wire Debug(SWD,串行线调试)方式,所以在SYS模式配置中Debug应当选择Serial Wire调试方式。此时引脚视图中SWD调试用到的PA13和PA14变为绿色,并对其调试功能进行了标注。调试方式一定要设置,否则可能导致工程无法调试下载。在图326中的Timebase Source(时基时钟)需要保持默认值SysTick定时器,不要修改。 图326调试方式配置 5. 配置系统时钟 如图327所示,单击工程创建对话框流程控制按钮Clock Configuration进入系统时钟配置界面,此处只需要配置系统时钟,配置步骤根据图327中序号依次开展。 图327系统时钟配置 时钟配置第①步选择HSE作为系统的时钟源,并在Input frequency频率输入框中输入数字8,表示频率为8MHz。第②步设置分频系数“/M”为“/4”,外部8MHz经4分频后频率为2MHz。第③步将“*N”倍频系数设置为“×168”,2MHz经168倍频后频率为336MHz。第④步将“/P”分频系数设置为“/2”,336MHz再经2分频后频率为168MHz。第⑤步将System Clock Mux设置为PLLCLK,AHB分频系数保持默认值1,此时SYSCLK和HCLK时钟频率均为STM32F407最高频率168MHz。第⑥步将APB1分频系数设为4,PCLK1工作于最高允许频率42MHz,APB2分频系数设为2, PCLK2工作于最高允许频率84MHz。 工程创建时可以将系统时钟配置在一个很广的范围内,但是为了最大限度发挥CPU潜能,一般将其配置在最高工作频率168MHz,这一频率也是标准库例程的默认工作频率。即使将系统时钟配置在168MHz主频上,也有很多种组合,上述配置选项只是一个参考实例。 6. 工程选项配置 在完成引脚及资源配置和时钟配置之后,下一步就是工程管理配置,单击主界面的Project Manager标签进入工程管理配置,如图328所示,在左侧配置类别列表中有3个子项,分别为Project(工程)、Code Generator(代码生成)、Advanced Settings(高级选项),一般只需要配置前两项。 图328工程管理配置 Project选项配置界面一般只需设置图中框线标出的地方,即设置工程文件名称、工程路径、工具链文件夹路径。其实只需输入工程名称和工程路径,工具链文件夹路径是二者的合成。STM32CubeMX在工程文件路径创建一个以工程名称命名的文件夹,工具链文件夹及其他文件均存放在这一文件夹内。 为便于交流和学习,本书工程名称采用统一命名格式,即章节(2位)+序号(2位)+空格+项目主题。例如本章的项目名称为0301 Template,表示第3章第1个项目,重点讲解工程开发的模板结构,为便于后续章节共用模板,本章创建工程名称为Template,项目备份时再将名称更改为0301 Template。 工具链/集成开发环境(Toolchain/IDE)这一选项也十分重要,由组合框下拉列表选项可知,STM32CubeMX支持的工具链有EWARM、MDKARM、STM32CubeIDE、Makefile 4种。本书使用的集成开发环境是MDK 5.35,所以Toolchain/IDE选项选择MDKARM,Min Version选项是用来选择开发工具的版本号的,但是列表中并没有V5.35这一选项,只需要选择STM32CubeMX所支持的最新版本V5.32就可以,或者直接选择V5。 配置完Project选项之后,还需要配置Code Generator选项,这部分配置实际取决于开发者的使用习惯,本书的代码生成选项配置情况如图329所示,其中重要部分使用框线标出,具体步骤如下。 图329Code Generator选项配置 第1步,STM32Cube MCU packages and embedded software packs(器件包和软件包)复制方式选择,建议选择Copy only the necessary library files(仅复制必需的文件),否则全盘复制会使文件很大。 第2步,Generated files(生成文件)方式选择,该选项组列出了4个选项,各选项相互之间并没有联系,可以选中(打钩)或取消,其中第1项和第2项默认为未选中,第3项和第4项默认为选中。 其中第1项Generate peripheral initialization as a pair of ‘.c/.h’ files per peripheral询问是否为每个外设生成一对“.c/.h”文件。假设初始化了GPIO外设,选中该选项则会生成gpio.c和gpio.h两个文件,否则将所有外设的初始化函数全部放于main.c中。这一选项是否选中不会对代码生成和程序执行产生任何影响,仅会影响文件组织结构。为了程序开发的条理性,建议选中此选项。第2~4项采用默认选项,无须更改。 至此,基于STM32CubeMX的HAL库初始化代码生成的全部配置工作已经完成,单击配置界面右上方的GENERATE CODE按钮,即可生成包含外设初始化代码的MDKARM工程文件。 微课视频 3.3.2MDKARM集成开发 使用STM32CubeMX初始化外设时,还生成一个采用该芯片开发的工程模板,用户可以直接在此模板上进行应用程序开发,减少了工作量,提升了效率,而代码编辑、编译、下载、调试是在MDKARM集成开发环境中完成的。 1. 工程模板结构 STM32CubeMX软件在生成代码时会在指定路径创建以工程名命名的工程文件夹,其目录结构如图330所示,工程模板文件夹根目录下有3个文件夹和2个文件。 图330工程模板目录结构 1) Core文件夹 Core文件夹存放的是用户文件,包含两个子文件夹: 一个是Inc文件夹,用于存放头文件; 另一个是Src文件夹,用于存放源文件。 2) Drivers文件夹 Drivers文件夹是固件库驱动程序,也包含两个子文件夹,其中CMSIS存放内核驱动程序,STM32F4xx_HAL_Driver存放STM32F4的HAL库的驱动程序。STM32F4的HAL库驱动程序驱动的每一个外设都有一个源文件和一个头文件,分别存放于Src子文件夹和Inc子文件夹。 3) MDKARM文件夹 MDKARM文件夹存放MDKARM工程相关文件,Template.uvprojx是MDK5工程文件。Template子文件夹用于存放编译输出文件,数量较多,占用空间较大,备份时可以仅保留.axf和.hex两个文件。 4) .mxproject文件 .mxproject是STM32CubeMX的配置文件。 5) .ioc文件 Template.ioc文件是STM32CubeMX的项目文件,如果需要更改外设配置信息,可双击打开该项目文件,更改相关配置重新生成工程文件即可。 2. MDKARM软件使用 双击打开MDKARM文件夹中的工程文件Template.uvprojx,软件主界面如图331所示。 图331MDKARM软件主界面 1) 标题栏 标题栏位于软件界面最上方,左边显示打开工程的路径,右边是最小化、还原、最大化三个按钮。 2) 菜单栏 菜单栏位于标题栏下方,包含软件的全部操作,有File、Edit、View、Project、Flash、Debug、Peripherals、Tools、SVCS、Window、Help共11个菜单命令。 3) 工具栏 工具栏位于菜单栏下方,包含软件常见操作命令。在软件使用过程,虽然所有的命令都可以通过菜单栏查找到,但使用工具栏更便捷一些。 4) 工程管理区 工程管理区位于界面中部左侧,和8位单片机简单的文件结构不一样,STM32项目开发文件必须以工程方式进行组织,且在一个工程中需要对文件按类别进行分组。单击工程管理区分组名称前面的“+/-”号可以展开或收起分组的文件目录。 选择Project→Manage→Project items菜单,或工具栏中的图标即可以打开Manage Project Items对话框,如图332所示,在此对话框中,可对工程文件、分组名称、包含文件进行更改和配置,修改结果会同步更新到工程管理区。 图332项目分组管理对话框 在后续嵌入式开发中,涉及新建文件或项目移植时需要更改项目分组结构也可以在工程管理区分组文件夹上双击添加文件,或者选中分组文件单击鼠标右键,选择“删除”命令进行删除。 5) 代码编辑区 代码编辑区位于界面中部右侧,双击工程管理区项目分组下的任一文件,即可将此文件在代码编辑区打开,此文件处于编辑状态,编辑器支持同时打开多个文件。 编辑器的字体、颜色、缩进等个性化选项都是可以设置的。单击Edit→Configuration菜单打开编辑器设置对话框,其中有很多选项卡,第一个选项卡是Editor,为了更好地支持中文注释,可以将Encoding选项设为Chinese GB2312(Simplified),也可以更改编辑制表位缩进字符Tab size等内容。第二个选项卡是Colors and Fonts,用于设置编辑器的字体和颜色,一般只修改编辑器的字体,操作方式如图333所示。在Windows列表框选择一类文件,如C/C++Editor files,保持Element列表框中的默认选项Text,在Font面板中选择相应的字体、字号和颜色完成设置即可。 图333编辑器字体设置 6) 信息输出区 信息输出区位于主界面下端,多数情况输出的是编译信息,下面就介绍如何设置编译选项,并对工程进行编译。 单击Project→Options for Target菜单项,或单击工具栏中的图标,或按下Alt+F7快捷键均可以打开工程选项对话框,如图334所示。工程文件有很多重要设置均在这一对话框进行设置,此处仅讲解编译相关设置。 图334“工程选项”对话框——编译选项设置 该对话框中Target选项卡的Code Generation区域的ARM Compiler列表框有4个可选项,用于指定工程所使用的编译器。4个选项实际上对应两个编译器,Use default compiler version 6和V6.16是一个编译器,即编译器6; Use default compiler version 5和V5.06 update 7(build 960)是一个编译器,即编译器5。 编译器选择原则是: 如果使用早期的工程只能选择编译器5,如果是最近创建的工程,编译器5和编译器6都可以。编译器5的编译速度较慢,但可以生成文件跟踪链接,有利于快速组织代码,且为STM32CubeMX创建工程模板默认选项。此处推荐选择编译器5。 如果选择编译器6编译项目,工程选项对话框中原C/C++选项卡就会更改为C/C++(AC6),读者可以通过此处快速地了解工程所采用的编译器版本。 在图331MDKARM软件主界面工具栏中最下面一行为Build工具栏,其命令图解如图335所示。Build工具栏总共有5个编译命令。第1个命令仅编译当前活动文件,不进行链接和生成目标文件。第2个命令是编译修改过的目标文件,即所谓的增量编译(Build)。第3个命令是重新编译(Rebuild)所有目标文件,不管文件是否有改动。如果工程是首次编译,增量编译和重新编译效果是一样的,都是将所有文件全部编译,如果工程已经编译过了,且工程较大,选择增量编译要比重新编译快得多!第4个命令是批量编译。第5个命令是停止编译。 图335Build工具栏命令图解 作者在实际使用过程中发现,如果选择编译器5,则使用增量编译比较快; 如果使用编译器6,因为编译器本身编译速度比较快,就无所谓哪一种编译方式; 工作空间若只有一个工程,则无须使用批量编译。 选择编译器5,单击Rebuild按钮,开始项目编译,信息输出区输出编译结果,如图336所示,“0 Error(s),0 Warning(s)”表示工程模板创建正确,可以在此基础上进行应用程序开发。 图336编译信息输出窗口 3. 代码分析及组织方式 基于STM32CubeMX的HAL库开发,需要对程序框架和代码结构进行分析,然后进行应用程序代码快速组织。 1) 代码分析 STM32CubeMX创建的MDK工程包含文件及其分组,具体情况如表32所示。 表32工程包含文件及其分组 文 件 分 组文 件 名 称文 件 功 能 Application/MDKARMstartup_stm32f407xx.s芯片启动文件 Application/User/Core main.c用户主文件 gpio.cGPIO函数文件 stm32f4xx_it.c中断服务程序文件 stm32f4xx_hal_msp.cMCU支持文件 Drivers/STM32F4xx_HAL_Driver stm32f4xx_hal_rcc.c时钟HAL库驱动文件 stm32f4xx_hal_rcc_ex.c扩展RCC驱动文件 stm32f4xx_hal_gpio.cGPIO的HAL库驱动文件 ………… Drivers/CMSISsystem_stm32f4xx.cSTM32F4系统文件 芯片启动文件和系统文件只需要包含进工程,用户在编程的时候一般无须关心。C语言有且仅有一个main()函数,用户程序是从main()函数开始执行的,main()函数是编写在main.c文件中的,其部分代码如下: #include "main.h" #include "gpio.h" void SystemClock_Config(void); int main(void) { /* USER CODE BEGIN 1 */ //用户程序沙箱开始 /* 用户程序代码 */ /* USER CODE END 1 */ //用户程序沙箱结束 /* 复位所有外设,初始化闪存接口和SysTick定时器 */ HAL_Init(); /* 配置系统时钟 */ SystemClock_Config(); /* 初始化所有配置的外设 */ MX_GPIO_Init(); /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } void SystemClock_Config(void) { //代码省略 } void Error_Handler(void) { //代码省略 } 对main.c文件进一步分析,文件首先包含main.h和gpio.h两个文件,在包含语句中的文件名上右击,选择Open document ‘main.h’命令,操作方法如图337所示,打开main.h头文件。由源代码可知main.h主要工作是包含stm32f4xx_hal.h头文件,并对main.c中定义的函数进行声明。用同样的方法打开gpio.h文件,可知其主要工作是对gpio.c定义的函数进行声明。 用户程序设计从main()函数开始,芯片启动完成之后自动转入主函数执行。在main()函数中,调用HAL_Init()初始化HAL库,其功能是复位所有外设、初始化Flash接口、配置系统定时器SysTick周期为1ms。调用SystemClock_Config()函数进行系统时钟配置,其代码是由STM32CubeMX根据用户设定参数生成的。调用MX_GPIO_Init()函数对用户配置的GPIO引脚进行初始化,初始化代码由STM32CubeMX根据用户设定生成。 图337在包含语句中的文件名上右击打开main.h头文件 函数SystemClock_Config()是直接定义在main.c文件中,另外还有一个异常处理函数Error_Handler()也存放在main.c中,而GPIO初始化函数MX_GPIO_Init()存放在gpio.c文件中。 如果想查看MX_GPIO_Init()函数源码,可以将光标置于函数名称上右击,选择Go To Definition of ‘MX_GPIO_Init’菜单,即可打开函数所在文件gpio.c,并定位到函数所在位置,如图338所示。 图338右击函数并选择命令进行跳转 由函数的MX_GPIO_Init()源代码可知,其主要工作包括开端口时钟,设置PF0初始化电平,为GPIO初始化结构体的成员依次赋值和调用HAL_GPIO_Init完成引脚初始化。 上述所有代码均由STM32CubeMX生成,仅为初始化代码和程序框架,要实现运算、控制功能,还需在此基础上进一步开发。由于在系统设计过程中可能需要更改系统方案,对外设再次进行配置,为了保证用户编写程序不受重新配置影响,STM32CubeMX在生成工程时特意提供一个个程序沙箱,用于放置用户代码。 每一个程序沙箱均为一对程序注释,以USER CODE BEGIN开始,至USER CODE END结束,如main.c程序代码中的加粗部分。用户必须将程序写在这两个注释的中间,否则重新生成工程时用户代码将丢失。 2) 代码组织 通过上述初始化之后,PF0输出电平为低电平,经编译、下载到微控制器Flash存储器中,L1指示灯是一直亮的。下面对该项目进行一点改动,通过编写程序让L1以一定周期闪烁,也通过此实例介绍MDKARM的代码组织技巧。 第1步,将GPIO写输出端口电平函数HAL_GPIO_WritePin()复制到main.c,右击打开函数定义,查看其功能。 第2步,在函数调用变量处依次右击查看其定义,由此可知函数最后一个参数是用来设置端口电平的,可以取GPIO_PIN_RESET和GPIO_PIN_SET两者之一。 第3步,改写HAL_GPIO_WritePin()函数,使PF0也可以输出高电平,即L1指示灯可以熄灭。 第4步,修改程序,实现L1指示灯周期闪烁,所有增加程序均应写在程序沙箱里。参考程序代码如下,为便于读者查看,将程序沙箱的注释语句作加粗显示。 int main(void) { /* USER CODE BEGIN 1 */ //用户程序沙箱 uint32_t i; /* USER CODE END 1 */ //用户程序沙箱 HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); /* USER CODE BEGIN WHILE */ //用户程序沙箱 while (1) { HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, GPIO_PIN_RESET); for(i=0;i<12000000;i++) ; HAL_GPIO_WritePin(GPIOF, GPIO_PIN_0, GPIO_PIN_SET); for(i=0;i<12000000;i++) ; /* USER CODE END WHILE */ //用户程序沙箱 } } 3.4CMSISDAP调试器使用 作者所设计的嵌入式开发板板载CMSISDAP调试器,可以将其添加到MDK集成开发环境中,就像以前使用STLink、ULINK等调试器一样。 3.4.1调试器连接与驱动安装 使用一端是A型口,另一端是B型口的USB数据线分别连接开发板和PC,如果计算机安装Windows 10以上操作系统,计算机会自动安装好驱动程序,调试器是开源、免驱动的。如果是Windows 7操作系统,还需要手动安装驱动,在设备管理器更新驱动程序,浏览找到驱动文件即可完成安装。 3.4.2调试选项设置与程序下载 打开MDKARM工程,单击Project→Options for Target菜单项,或单击工具栏中的图标,或按下Alt+F7快捷键均可以打开“工程选项”对话框,如图339所示。 图339“工程选项”对话框——调试器选择 选择Debug选项卡,选中右侧Use单选按钮,在右边的下拉列表中选择CMSISDAP Debugger,单击Settings按钮,打开调试选项设置对话框,如图340所示。 图340“调试选项设置”对话框 首先设置Debug选项卡,在CMSISDAPJTAG/SW Adapter选项区域,选择具体调试设备CMSISDAP_XH,调试器名称在调试器驱动程序中定义,默认为CMSISDAP。Port是调试方式选择,调试器与开发板主控芯片只有SWD方式连接,没有JTAG方式连接,所以只能选择SW,时钟频率Max Clock选择10MHz。完成上述设置在SW Device选项区域会显示调试器序列号和名称,表示识别成功。 其次设置Flash Download选项卡,如图341所示,在Download Function选项区域,有3个关于擦除的单选按钮,分别是Erase Full Chip(全芯片擦除)、Erase Sectors(只擦除扇区)、Do not Erase(不进行擦除),此处保留默认设置Erase Sectors即可。右侧的Program(编程)和Verify(校验)两个复选框默认是选中的,还需要将Reset and Run(复位并运行)选项选中,以使调试器下载完程序复位MCU并运行。MDKARM会根据芯片类型自动填充SRAM和Flash存储器的大小和地址范围,无须设置。 图341Flash Download选项卡 完成上述选项设置,单击工具栏Rebuild按钮,再单击Flash→Download菜单或者工具栏中的Load按钮,或按F8快捷键,程序开始下载,完成之后复位MCU并运行,如图342所示。观察程序运行效果,检查是否满足系统设计要求,不满足则修改程序直至达到预期目标。 图342程序下载运行 3.5开发经验小结——编译器优化与volatile关键字 3.5.1编译器优化 MDK ARM编译器会对程序代码进行编译优化,以获得更好的空间和时间性能。 例如,如下代码: a=2; a=3; b=4; b=5; c=a+b; 可以优化为如下代码: a=3; b=5; c=a+b; 如此一来,代码长度和运行时间均得到优化,提升了代码性能。上述例程仅用于说明编译器优化原理,实际优化要远比其复杂得多,对此不作进一步的探讨。 编译器优化减小了代码空间,提升了程序运行速度,但也使得程序运行时间变得不确定,而且有些场合是不允许优化的。那有没有办法不让编译器对变量进行优化呢?答案当然是肯定的。 3.5.2volatile关键字 1. volatile的基本概念 volatile意为易变的、不稳定的。简单地说,就是不让编译器进行优化,即每次读取或者修改volatile变量的值时,都必须重新从内存或者寄存器中读取或者修改。在嵌入式开发中,volatile关键字主要用于以下场合: (1) 中断服务程序中修改的供其他程序检测的变量。 (2) 多任务环境下各任务间共享的标志。 (3) 存储器映射的硬件寄存器。 2. volatile应用实例 对于本章实践的L1周期闪烁项目,在同一硬件平台和相同的控制程序下,由于编译优化选项设置的不同,闪烁的快慢是有差异的!如果想要软件延时时间确定,只需要使用volatile关键字修饰循环变量的定义即可,此时编译器将不再对其进行优化,具体语句如下: volatile uint32_t i; 为便于记忆和使用,在HAL库中给出了volatile关键字的宏定义,具体代码如下,读者使用关键字和宏定义的效果一样。 #define __IO volatile 本章小结 本章重点讲解了3部分内容,第1部分内容是嵌入式开发方式的选择,本书详细介绍了4种开发模式,并从可移植性、优化性能、易用性、意愿性、硬件支持面等多方面进行对比,最终选择综合表现优异的基于STM32CubeMX的HAL库开发方式,该方式也是目前主流的开发方式。第2部分内容是软件资源安装与配置,详细讲解了JRE、STM32CubeMX、固件包、MDKARM和器件包的安装,讲解较为详细,读者自行配置软件平台时,根据实际情况可以省略部分步骤。第3部分内容是通过一个简单项目实例,讲解了如何运用STM32CubeMX生成初始化代码,并在MDKARM进行代码组织,编译成功之后再下载运行,项目十分简单,但包含嵌入式开发的完整过程,具有很好的参考意义。 思考拓展 (1) STM32开发方式中执行速度最快,占用空间最小的是哪一种? (2) STM32开发方式中可移植性最好、开发效率最高的是哪一种? (3) STM32产品线中哪些系列既有标准库又有HAL库? (4) 根据本书介绍的方法下载软件,完成软件平台的搭建。 (5) 参照本书的示例程序,创建一个工程项目,并验证其正确性。 (6) 选择不同编译器对项目进行编译,体会编译器性能差异。 (7) 将CMSISDAP调试器添加进MDKARM,并下载程序验证。 (8) 打开工程进行代码分析,并列举一些常见的快速组织代码技巧。