一、前言
之前在搭建STM32的标准库环境时就告诉过大家,开发STM32的方式主要有三种。一种是最原始但是效率最高的寄存器开发,另一种是效率仅次于寄存器难度相对较低的标准库开发,最后一种是最为简单但是程序效率最低的HAL库开发。如果对于初学者而言,你使用HAL库你可以快速的配置STM32的外设并将STM32使用起来,但是你会少很多接触STM32底层代码的机会,这不会让你的代码能力有所提升。所以,对于初学者,我并不建议一开始就学习HAL库,而是从标准库学起,由下而上的学习。在企业开发中,为了开发效率和程序员之间的开发环境统一,会更倾向于使用HAL库进行开发。提到HAL库的环境配置与效率问题,我们不得不提到一款软件了---------cubeMX,这是由ST公司开发的用于简化STM32的初始化配置的一款软件,它能省去我们对函数库的配置与对外设的初始化,我们只需使用简单的几个步骤就能配置好STM32的HAL库开发环境并且初始化外设。那么,本次的教程,就会教大家如何安装cubeMX以及安装相关的固件库并且配置STM32的基本环境。
二、在开始之前
在开始配置HAL库之前,大家需要先配置好keil的环境,因为HAL库始终只是一个函数库,概念和标准库是一样的,然而cubeMX只是用来生成HAL库的软件而已。所以尽管HAL库简单,我们仍然需要keil来进行编译。这里需要大家准备好keil的环境并且已经安装好了STM32对应的芯片包。具体教程请看下面的文章:
keil的安装以及芯片包安装:[STM32]如何正确的安装和配置keil?(详细)-CSDN博客
在安装好keil以后,这里还需要下载我给的资料包,资料包中包含了cubeMX的安装包以及部分芯片在cubeMX的固件包。这里cubeMX安装包的下载方式较为苛刻,所以不推荐大家自己下载。
资料下载:https://pan.baidu.com/s/1IL9IQzxCNC95UWupvSFsug?pwd=clxm
提取码:clxm
在下载完资料以后,就可以继续下面的步骤了。
三、cubeMX的安装
既然我们要使用HAL库,第一步当然是配置一个HAL库的环境。上面我也提到了,HAL库的环境我们可以使用cubeMX直接配置。所以这里我们需要安装cubeMX。
打开我给的资料包文件夹下的cubeMX的文件夹就可以看到cubeMX的安装包了:

我们双击安装包启动安装引导程序:

首先就是这里可以选择是只为我安装还是为所有用户安装,这里我们选择"只为我安装"即可,我们选择上面的选项:

这里我们直接点击"Next":

这里我们需要同意协议,并且点击"Next":

这里我们再将"已阅读ST条款"打上勾,然后点击"Next":

下面需要选择一下cubeMX的安装路径,这里需要注意的是cubeMX对中文非常敏感,路径中不能有一点中文或者其它特殊字符。选择好路径以后,我们直接点击"Next":

这里点击了"Next"以后,可能会弹出下面的提示:

这里的提示表示这个目录已经存在,问我们要不要覆盖,如果点击了"yes"这个目录中原本文件夹就没有了。
如果收到了下面这样的提示就表示cubeMX安装的目录不为空,我们需要将目录清空或者新建一个目录:

来到下一步以后,这里有两个选项是关于快捷方式的需要我们选择要不要在桌面或者开始菜单添加快捷方式,这里我都打勾表示都要添加。随后点击"Next"即可:

随后就进入了安装,大家这里耐心等待:


进度条走完以后,我们直接点击"Next":

最后点击"Done":

至此,我们的cubeMX就已经安装完成了:

四、cubeMX的更新以及芯片包的安装
cubeMX和别的一些IDE或者语言不同,它的版本并不是固定在低版本,相反,cubeMX版本最好保持在一个比较高的版本。新版本会对旧版本生成的工程进行向下兼容,但是旧版本是没办法兼容新版本的。所以,现在就来教大家如何更新cubeMX吧。首先我们启动cubeMX:

这里我们点击上方菜单的"Help":

在"Help"的下拉菜单中,我们点击"Check for Updates":

这里会列出我们可以更新的cubeMX版本和固件包的版本,如果这里是空的,就表示你的cubeMX和固件包不需要更新:

这里我们需要勾选要更新的cubeMX和相关的固件包,最后点击"Install":

随后就进入了更新得状态,但是这里可能会因为网络更新失败,这里目前没有解决办法,大家只能尝试使用一些正向代理手段来解决:

当然,如果实在没办法更新的话,不更新也没关系,我给的cubeMX的安装包版本是比较新的。
下面我们来教大家如何安装固件包,这里先说一下固件包的概念。固件包是为了让cubeMX支持相关的STM32芯片,假如我这里的想要生成STM32F1的HAL库工程,我就需要安装一个F1的固件包。所以,为了让我们的cubeMX能够支持到我们芯片,首先就需要安装相关的固件包。这里固件包可以分为在线安装和离线安装。这里两种方法我们都会介绍。首先是在线安装:
我们这里同样要点击菜单中的"Help":

然后点击下拉菜单中的"Manage embedded software packages":

随后就能看到下面的窗口了:
这里有STM32几乎所有单片机的型号,大家选择自己型号的单片机下载即可,这里我就用F1举例。我们点击STM32F1:

这里的下拉菜单中我们可以选择固件包的版本,这里建议大家选择最新版,我们直接在固件包前面打上勾然后点击"Install"即可:

随后就会开始安装了:

这里在安装固件包时,仍然可能因为网络出现错误。当然这里如果你因为网络问题一直无法下载固件包的话,可以看下面的离线固件包安装教程。
这里如果固件包安装好了固件包对应的前面的框的颜色会发生改变:

至此,我们的在线安装固件包就已经完成了。
现在你可能已经完成了在线安装,或者说你想进行下面的离线安装,但是我们现在有一件必须做的事,那就是确定自己的用户名中没有中文。怎么看用户名中有没有中文呢,我们需要到C盘中的"用户"文件夹下:

这里可以看到,我的计算机中拥有两个用户,这两个用户的用户名都没有中文和别的特殊字符,这里的两个文件夹就代表了这两个用户的用户文件夹:

如果你发现你的用户名中有中文,那可能就需要修改用户名或者是重新创建一个用户,重新创建用户相对简单一些。不管是哪种方法,在网络上都有对应的教程,大家跟着操作就行。这里保证用户名中没有中文的一步是绝对要做的,不然后面的cubeMX在生成的时候是一定会报错的。大家可能会有疑问,我们这里C盘下的用户文件夹,这个文件夹不就是中文吗,为什么这个中文没关系,其实这里的中文只是单纯的被显示为了中文,其实本质还是英文路径,不信吗?假如我们随便查看一个用户文件夹的属性:

我们可以看到这个文件夹位于C盘下的Users文件夹下,是的这里"用户"两个字被替换为了"Users"。
这里我们解决了用户名的问题就可以开始准备离线安装固件包了。首先我们这里需要了解一个路径"C:\Users\85884\STM32Cube\Repository",即用户目录下的"STM32Cube"目录下的"Repository"目录:

这个目录包含了我们下载的固件包,以文件夹的形式存放在这里,这里的每一个文件夹就是一个固件包上面有单片机的型号和固件包的版本。所以,如果我们想离线安装的话,只需要将对应的固件包的文件夹复制到此处即可,打开我给的资料中的固件包文件夹,这里我提供了大多数常用系列的固件包:

大家使用时只需要将这些固件包复制到我刚才说的文件夹中即可。
复制进去以后,我们重启cubeMX就可以看到对应的固件包已经安装成功了:

如果我给的固件包中没有你想要的,可以去下方ST的github的开源主页:
cubeMX固件包开源主页:

在主页中往下滑,就可以看到所有系列的固件包了:

这里我们以F7的固件包举例,我们点击"STM32CubeF7"就可以进入F7固件包相关的主页:

随后我们点击页面中的"Code":

在下拉菜单中点击"Download ZIP":

随后浏览器就会弹出下载了:

我们将这个压缩包下载到我们能找到的地方:

解压得到以下文件夹:

我们将这个文件夹复制到对应的路径中:

这个时候我们再启动cubeMX,再次来到固件包的管理页面,可以看到我们的固件包已经被添加进来了:

至此,我们离线安装固件包就已经完成了。
五、cubeMX新建一个STM32 HAL库工程
前面的步骤都算是为新建工程做的准备,从现在开始,我们才正式的开始创建cubeMX的工程并且生成STM32的工程,这里我会使用STM32F103C8T6来举例。我们首先还是启动cubeMX:

随后点击中间的"ACCESS TO MCU SELECTOR":

在点击了以后这里可能会弹出更新框,也可能会更新失败,不过不用担心,只要固件包配置正确了,这里更新与否都无所谓:

随后会弹出这个芯片选择页面,这里要我们选择我们要使用的芯片:

直接在左上角的搜索框输入要使用的芯片型号即可:

我们在搜索结果中,双击就可以选择这个芯片了:

随后就来到一个这样的页面,这也表示我们的工程被创建了:

现在我们开始一些简单的配置使STM32能够正常工作,这些配置放在别的系列的单片机中也是必须的,我们首先来配置STM32的时钟,这里点击"System Core",在下拉菜单中点击"RCC":

这里我们需要将外部高速时钟使能(HSE):

配置完成以后就是这样的:

随后我们来对时钟进行详细的配置,这里点击顶部的"Clock Configuration"进入时钟的配置界面:

在cubeMX中,我们配置时钟输入或者是主频亦或是每个外设的时钟是非常简单的,我们只需要能看懂时钟树即可,现在我来带大家看看时钟树,我们先看最左边的部分:

这里有四种时钟,即外部高速,外部低速,内部高速,内部低速时钟。这些时钟被输入到了芯片内部,我们可以使用"锁相环源选择多路复用器"来选择那一路时钟进入锁相环。
我们继续往后面看,这里有"x"或者"/"符号的地方就是锁相环,它可以使时钟分频或者倍频,这也是为什么我们的外部时钟输入只有8M,而STM32的主频却有几十上百M,这些频率都是通过锁相环分频或者倍频之后得到的:

随后就是"锁相环源选择多路复用器",我们看到在时钟树中能够选择时钟源的地方就使用的是"锁相环源选择多路复用器":

在STM32F103单片机中的多路复用器只有三个,随着系列的增加,这里的多路复用器和锁相环都会变多。
我们现在来调整多路复用器,使STM32的系统时钟直接接到我们的外部高速时钟,具体的我们需要调整多路复用器,如图:

这里大家可能会问,16M的频率是不是太低了。这里我们当然可以改,我们直接改"HCLK"这里:

可以直接输入72回车,cubeMX会自动配置锁相环:

如上图就算是配置好了。这里最高频率不要超过芯片能工作的最高频率,否则可能会是芯片无法工作甚至烧毁。
配置完时钟,我们点击"Pinout & Configuration"回到刚才的配置界面:

随后点击"SYS"我们需要配置一下调试接口:

这里配置为"Serial Wire":

设置以后,我们可以发现PA13和PA14被占用了,这也刚好是我们使用STLink下载程序的接口。如果不配置的话,下次烧录可能会存在烧录不进去的情况,如果你已经烧录不进去了,可以考虑使用串口将程序擦除再烧录。
配置完上面的模块以后,STM32已经可以基本的工作了,但是我们还需要配置一些GPIO来查看一点现象,比如,我们现在就来配置一下STM32最小板上LED对应的引脚,来点一个灯试试看。我们这里可以直接点击右边单片机上的PC13:

这里因为我们需要点灯,所以把GPIO配置为输出模式。配置完成以后,对应的GPIO会亮起:

然后我们再点击左边菜单中的GPIO进行详细配置:

点击选中我们要配置的GPIO口:

下面我们来详细的看看这些参数:

首先是"GPIO output level"表示GPIO一开始输出的电平,有"High"和"Low"两种选项,即一开始GPIO默认高或者低。
然后是"GPIO mode",表示GPIO的输出模式,有开漏输出和推挽输出两种,这里因为要驱动LED,所以选择推挽输出。
然后是"GPIO Pull-up/Pull-down"表示GPIO的上下拉状态,这里可以上拉,也可以下拉或者说不上拉也不下拉。
最后是"Maximum output speed"表示GPIO的输出速度,这里我们可以直接选择高。
经过了上面的配置,我们的GPIO就已经配置好了。下面可以准备生成keil工程了,我们这里点击"Project Manager"进入项目配置界面:

首先是"Project Name"即项目的名字,大家可以根据用途给项目命名,我这里的项目是点灯,所以这里直接就写"LED",注意,这里的项目名不能有中文和特殊字符:

然后是"Project Location",我们需要选择一下项目的路径,注意这里路径中的每一个文件夹都不能有中文:

随后在"Toolchain /IDE"这里我们要选择"MDK-ARM":

版本直接默认即可:

随后我们点击"Code Generator"配置一下代码的生成:

这里在第一个框中我们要选择"Copy all used libraries into the project folder"表示复制所有的库文件:

在第二个框中,我们将"Generate peripheral initialization as a pair of '.c/.h' files per peripheral"打上勾,表示将为每一个外设都生成一个单独的.c .h:

至此,我们所有的配置都已经完成了,我们直接点击"GENERATE CODE"生成工程:

在生成完成以后,可以看到这样一个弹窗,如果你在生成时报错了,就去检查对应的固件包有没有安装好,或者路径中有没有中文,cubeMX大部分的错误都是这两种:

这里我们直接点击"Open Project"这可以直接启动Keil:

点击了以后可以看到我们的keil了已经启动:

这里可以先不动,我们直接点击编译,编译一般都是没有错误和警告的,这也意味着HAL库的环境已经搭建完成了:

我们这里进入main.c:

往下滑就能找到我们的主函数了:

主函数的while也在这下面:

我们的一些初始化函数也被写在了主函数中:

既然我们一开始已经配置了GPIO,那么现在的GPIO已经被"MX_GPIO_Init"这个函数初始化为了我们想要的状态。我们不用再对GPIO有多余的配置,下面我们就来点个灯吧,我们可以直接使用HAL库中的引脚电平翻转函数和延时函数:

这里我们在主函数的循环中,每500ms翻转一次电平。大家注意,在cubeMX生成的工程中,一定要将代码写在"BEGIN"和"END"中,比如"/* USER CODE BEGIN WHILE */"和/* USER CODE END WHILE */""这两个就是配对的,代码要写在这两个注释之间,不然下次使用cubeMX生成代码时,以前写的代码就会被覆盖。
我们再次将代码编译并且下载:

程序下载以后,可以看到LED正常闪烁。如果你的LED没有闪烁可能就需要检查一下是不是哪里没有配置好,或者使用调试模式看看问题。至此,我们的STM32 HAL库工程就已经生成完成了。
六、结语
在cubeMX中,我们可以配置STM32的所有外设,极大的简化了我们搭建环境和外设初始化的过程,但是问题也随之而来,HAL库将函数封装得太上层了,我们需要修改底层代码会变的非常不便。至于选择什么库进行开发,就看大家自己吧。最后,感谢大家的观看!