大家好,欢迎来到IT知识分享网。
这是方便协会同学们找到本文章而创作的。
本文针对的是想学习HAL库的同学的入门教程。
图 1 CUBEMX图标
这是CUBEMX的图标,是ST公司为统合自己公司旗下的32位MCU芯片的驱动库而设置的生成式软件。现在也有不少国产32位MCU也有自己的类似CUBEMX的生成代码软件。
图 2CUBEMX主页
这是CUBEMX主页,左边是你之前打开的工程文件。而我们想要新建工程文件,就选择:在中间蓝色大框的New Project下的最上面的“Start My project from MCU”选项;其余两项分别是ST自己生产的用于测试的测试板“…from ST Board”选项和例程选项”…from example”,本系列要是没有你们需要解决的问题的处理方法,可以去这里看看ST官方怎么做。
- 芯片选型
点击” ACCESS TO MCU SELECTOR ”,进入单片机选型界面:
图 3MCU选型界面
这里分几个大部分:
图 4MCU外部属性
- 外部属性:
这部分里,主要包含封装,内核,产线等等,比如STM32F1是CORTEX-M3内核系列的,而STM32F4和STM32G4都属于CORTEX-M4F内核系列
图 5MCU内在参数
- MCU内在参数:
在外在参数下面,就是MCU的内在参数,比如内核Flash的大小,有无自带的EEPROM(标准库阶段学习的I2C控制的AT24C02就是EEPROM),RAM内存大小(不严谨地说,Flash是STM32的外存部分,属于ROM,负责存储代码,全局变量之类的,而RAM是STM32的运行内存,一般需要计算的变量都在这里进行,即便是全局变量,也需要从ROM取值到RAM里才能参与计算。而说这里不严谨是因为STM32系列比较庞杂,RAM和ROM并不一定是严格证明细分的,有时候RAM并不作为运行内存),外设的多少(比如定时器数量、模数转换器的数量等等),有无保密系统等等。
图 6芯片选型表
图 7芯片介绍
- 芯片选型:
而窗口占比较大的区域就是芯片选型表,有时候你可能知道你要选哪个系列的,但对具体哪个型号并不清楚,那么这时就可以点击选型表上的芯片,再在芯片介绍里查看芯片的具体信息,比如外设参数,封装尺寸等等。
虽然整个界面比较复杂,但是我们可以直接在左上角的Commercial Part Number里直接输入你想要的芯片的型号,比如STM32F103RCT6,再在芯片选型表里选中它就行。
图 8选中RCT6
双击选型表中的选型栏,等待CUBEMX生成界面,我们就在新窗口里进入配置界面了。
图 9配置界面
- 配置单片机(以RCT6为例)
在配置界面里,分为左右两个部分,右边是可视化配置界面,我们可以从这里看到我们未配置的引脚和已经完成配置的引脚状态。
左边的项目栏里,将包含这款芯片支持的所有外设和中间库。
现在,我们来看一下如何配置:
- 所有芯片配置的必须步骤
- 烧录引脚的配置:无论你是使用STLink或者使用JLink,都需要将SDIO和SCLK接入到单片机上,其对应的单片机引脚就是PA13、PA14,所以如果你在标准库中配置过PA13或者PA14,就会导致你的MCU在下一次烧录的时候出现问题,因为处于上电状态的MCU此时烧录引脚已经被配置到其他功能中去了。
而使用JLink烧录的同学知道,STM32常见烧录方式是SWD模式,即Serial Wire。
我们点击左侧项目栏的”System Core”,选中SYS,在Debug下拉菜单里找到Serial Wire。此时右侧可视化图标里PA13、PA14引脚变绿,并显示其对应功能。
图 10配置烧录引脚
-
- 晶振配置:在标准库里,我们并不经常提起晶振配置这个概念,以至于有些同学并不清楚其举足轻重的地位。
学习过模数电,甚至只学过电分的同学知道,MCU本质是一种时序电路,是有时间敏感性的,它不像非时序电路一样,其输出无时无刻都按照某一数学规律变化或保持恒值,而是依据它当前所执行到的程序指令决定。
而程序何时执行到某一位置,除了代码的结构以外,硬件上的,就是由单条指令执行的速度决定,而这一速度归根溯源就是由晶振速度决定。STM32拥有四条晶振通道,分别是LSE、LSI、HSE、HSI。
其中,LSI和HIS是STM32自带的内部晶振,但由于STM32F1并不是对小型化和低功耗化的特异化后的产品,因此其LSI和HIS晶振频率并不精准,这会严重影响STM32的稳定性,因此市面上几乎所有STM32F1核心板上都会有主频晶振存在,而主频晶振一般接入在HSE通道上(至于HSE是什么,我们会在下面的内容中讲到)。
此时,我们选中System Core 下的另一个项目:RCC,在RCC中,点击HSE下拉菜单,选择Crystal/Ceramic Resonator,这时右侧可视化图标里PD0、PD1就会变绿,并显示其作为晶振输入的作用。
图 11配置晶振
-
- RCC时钟树配置:在学习标准库的时候,同学们或多或少都知晓时钟树的概念,但是大多数学长学姐都在教学时避而不谈。但是在HAL库里,你可以通过配置环节来理解STM32的时钟树,这对未来其他主控芯片的学习会有所帮助。
图 12RCC时钟树界面
选择上方四个选项栏的Clock Configuration,进入RCC时钟树界面,就能看到图12的场景,乍一看非常复杂。
首先,图12被一条竖线分割成1 9开的两个部分,其中占比为1成的部分里有一个蓝色的框和一个灰色的框,这两个框分别代表为HSE和LSE的晶振频率,比如协会自用板子是8M的HSE主频晶振,那么就在框里写入8M,如果你们需要RTC等,要使用到LSE,那么在晶振配置里将LSE作为主频晶振(就是选择Crystal/Ceramic Resonator),再回到CC里就会看到LSE框也会变蓝。
HSE的全名是High Speed External clock即“高速外部时钟”,同理,LSE就是低速外部时钟;HSI的全名是High Speed Internal clock 即“高速内部时钟”,同理,LSI就是低速内部时钟。低速时钟往往只有几十K Hz的频率,而高速时钟往往都是不小于4M Hz,有些先进芯片甚至直接从25M Hz起步。
对于STM32G0、STM32C0、STM32L系列等等,这些芯片往往用于低功耗、小型化的环境里,占用电路版面较小,芯片引脚数量偏少,使得没有足够的引脚用于接入外部晶振,那么此时就只能使用内部晶振作为MCU的时钟源,因此,内部时钟并不是完全不能使用,但是对于不同型号的单片机,内部时钟的效果是不一样的,STM32F1的内部时钟的上下浮动相比只有几块的还只有±10ppm误差的晶振来说还是过高了。所以并不推荐使用。
这里的1成部分就是STM32的外围时钟部分,而剩下的9成部分,就是STM32的内部时钟结构,而想要看懂时钟树,我们就要顺着时钟树的箭头走向一步步看。
图 13PLL锁频环
首先,我们跟着HSE的输入箭头指向了一个选择器PLL Source Mux。
这是一个数据选择器,它就像铁轨的换轨闸刀一样,选择某一通道后,数据流就只会从某一通道流出或者流向某一通道,锁频环就是典型的流入通道选择器,而锁频环的两种流入来源(一般称作时钟源)分别是HSI和HSE,而在他们之前的选项框里的“/x”就是分频器。
分频器,是对频率信号的频率作除法的器件,一个10K Hz的信号进入“/10”分频器后,再输出就是1K Hz信号了,所以,HSE信号在进入时,就已经被预先分频1倍,那么就是8/1=8M Hz。
但是,当前选择器依旧选择的是HSI,所以我们点击HSE的复选框,将PLL时钟源接到HSE上。
我们在数据选择器后的框中,可以看到PLL框和一个“*PLLMul”框,这两个框分别表示当前PLL时钟频率(也就是时钟源经过分频后的时钟频率)和倍频器的倍数。
倍频器,是对频率信号的频率作乘法的器件,一个1K Hz的信号进入”*10”倍频器后,就会输出为10K Hz,所以,当前锁频环倍频倍数是2倍,也就是PLL时钟频率*2,就是PLL锁频环输出信号的频率了。
那么,PLL有什么作用呢?PLL的作用相当于巡线小车的巡线PID,刚刚提到,即使是比内部晶振性能更优异的外部时钟晶振,也会有±10ppm到±30ppm的误差,而这一误差是建立在晶振工作在标准工作环境下测量的,也就是说,在面对更恶劣的现实环境中,晶振误差会进一步拉大,而这将导致包括滴答在内的很多时敏指令和总线波特率会出现反复波动,轻则延时不准确,重则MCU无法正常工作。因此,需要有一个器件来专门稳定时钟源信号,这就是锁频环的作用。锁频,顾名思义就是锁定频率,而环是控制上的用语,即是闭环。比如巡线小车的巡线PID就是位置环,电机控速的PID就是速度环。需要注意,锁频环不是简单使用PID来稳定时钟的,PID并不适合用于这种场景。
图 14AHB总线
经过锁频环后,我们就需要进入系统时钟源选择器这里,我们需要将来自锁频环的更稳定的时钟信号接入到整个系统时钟“System Clock”里去,我们可以看到,系统时钟只允许了3种来源,HSI、HSE和PLLCLK,而LSE和LSI并不见踪影,这是因为LSE和LSI是用于RTC等待机任务里的,是为低功耗场景设计的,系统时钟是全功率状态下的MCU使用的时钟。
所以,这里我们选择PLLCLK,点击其的复选框,就可以完成系统时钟的选择。
那么,这里我们要讲一下总线的问题:总线就是一组信号线。比如在协会自用板上,MPU6500和AT24C02的I2C挂载在同一条I2C上,那么就称这两个器件挂载在同一I2C总线上。再比如,如果显示屏的SPI和W25Q16挂载在同一SPI下,那么就称这两个器件挂载在同一SPI总线下。又或者电脑通过USB连接STM32,那么也称这两个部件在同一USB总线上。
而单片机是一个微型计算机,其内部包含CPU,外设,内存等等,而CPU如果想要控制例如串口UART的外设,就需要CPU与串口外设进行通信,告知其命令,然后由外设执行具体任务。在STM32F1系列中,定时器、通信外设等等都分别挂载在APB1和APB2两条总线上(APB,Advanced Peripheral Bus,先进外设接口),而在STM32F4中,还会有AHB这样的比APB更复杂更先进的总线,CPU通过APB总线,寻找外设,然后通知外设,向外设发送命令和访问外设内容,来实现CPU与外设间的通信。需要注意的是,这些通信都是在STM32内部完成的,跟外围电路没有太大关系,CPU通过执行指令来向外设发送命令。
那么,APB时钟频率需要多少呢?
我们看到在HCLK框下,写着72M Hz的字样,说明AHB的通信频率最大就72M Hz。
那么我们只需要按照最大要求,点击HCLK框,直接输入72,回车即可,CUBEMX会自动匹配分频器和倍频器的值。
此处为拓展内容:
1个CPU想要控制某一外设,就需要联系这一外设的控制器,就好像老板要工厂生产某一样东西,就需要联系生产部的部长,由部长来负责具体的决策,不可能事无巨细。而在计算机系统中,联系某一器件就是通信,通信就绕不开三个话题:同步、半单全双工和串并行。
串并行就是当某一组bits的数据,比如一字节8bit的数据,是以1bit为单位的按顺序发送,还是开拓8条信道一次就发送8bit数据的选择,就是串行和并行的区别,并行系统速度要远远比串行系统快,但是需要占用大量信道,就会非常消耗资源,而且对时序要求严格,哪怕1微秒的数据延迟都将导致严重错误(这也是为什么前面一直强调时钟的稳定性),常见并行外设就是GPIB,不过这种外设一般多在FPGA上看到,用于短距传播大量数据。
而AMBA总线是一种并行总线,它的带宽就是32位,这也是将STM32作为32位的单片机的原因之一。
其次就是单双工和半全双工的问题,单工通信就是数据流向只有一个方向,比如只有从机输出线的SSI总线就是典型的单工通信;双工通信就是既可以发也可以收。而在收发的同时性问题上,又衍生出了半双工和全双工,半双工在同一时间内只能发或者只能收,比如UART、I2C和RS485等,而全双工在同一时间内可以完成发与收两个任务,比如SPI。
AMBA就是典型全双工总线,它拥有两条独立的收发信道,每条信道的带宽都是32位。
最后就是同步性,UART就是典型的异步通信,这使得在不同的UART控制器间通信会需要波特率对准的问题,但是不是所有设备都能调节波特率,也不是所有环境都能有稳定的波特率持续存在。因此,一般同步通信总线会出一条时钟线来使所有设备以时钟线的频率作为波特率的基准,并以此采集数据。
举个例子,SPI通信中,存在SCK信号线,称作串行时钟线,当SPI模式处于模式0时,SPI时钟线第一次从低电平转高电平(即上升沿)时,就会采集一次MOSI或者MISO的上的电平,为高就记为1,为低就记为0。如此一来,单位时间内,能采集多少数据(即波特率)就只由上升沿在单位时间内出现的频率来决定,而这个频率就是SPI的“波特率”。同理,对于同步半双工I2C总线来说,通信速率也是由SCL的频率来决定的。这一分析过程叫时序分析。在同步通信中,主机是时钟线的高优先级仲裁者。大部分时间,由主机来控制时钟线。
在AMBA总线当中,AMBA有一根专门的总线时钟线,所有并行信号都是依据AMBA的总线时钟线来决定其他信号线的时序。
综上,ABMA是一种全双工同步并行通信总线。
但是,这还不够,我们知道,摩托罗拉电气标准的SPI想要在众多设备中选择其中之一,就需要将对应CS片选线拉低。而I2C想要在众多设备中选择其中之一,就需要在SDA上先广播地址寻找对应的设备,等待设备的回应再进行通信。
ABMA则是专门留出一条带宽为32位的并行地址总线,在需要呼叫对应外设的寄存器时,就会在地址总线上输入对应地址,等待对应外设寄存器回应,所以你们可以通过查询寄存器手册,看到几乎所有外设寄存器都是32位地址。
总之,不要把RCC时钟树想得太难,虽然其具体技术细节是非常复杂的,但是去像SPI和I2C那样出于应用的考虑去理解ABMA就会简单很多。
图 15AMBA总线
- 配置一个GPIO
完成必要配置后,我们就可以开始一些简单的引脚配置了。点击任意未使用的引脚。
图 16点击引脚
其中就包含这个引脚上的外设和GPIO输入输出模式。
点击GPIO_Output后,PB15就被设置为输出模式,再在进入System Core,点击GPIO,进入之后可以看到GPIO引脚的配置状态。
图 17GPIO项目表
点击GPIO后,就可以选择GPIO mode,默认输出电平、上下拉等等。
这里重点是可以利用User Label,命名这个引脚。
图 18PB15命名CCS
完成之后PB15的输出模式就配置好了。
然后进入Project Manager里,在Project里,对Project Name命名,在Project Location 里选择工程位置,在Toolchain里选择MDK-ARM,版本选择5.0以上,在Coder Generator里,勾选上Generate peripheral initialization as a pair of’.c/.h’files per peripheral选项即可
最后点击右上角GENERATE CODE生成代码即可。
点击Open Project,就会打开工程文件。
如果后面你想直接打开工程,就到你Project Location设置的工程路径下找到MDK-ARM的文件夹,在里面就有KEIL5的文件。
图 19KEIL5界面
打开KEIL5之后,会发现有这么几个组别分类,Driver是HAL的底层库,不需要去管,主函数在User/Core里。
图 20Main文件界面
在主函数文件里,只有USER CODE XXX BEGIN XXXX到USER CODE XXX END XXX部分内是可以写自己的代码的,否则在CUBEMX的工程IOC改动后重新生成工程就会复写你写过的代码。
在HAL库里,所有MCU的外设驱动函数都被统一,例如GPIO的操作函数就是HAL_GPIO_XXX()。假如我们要拉高PB15。那么就写:
图 21注意代码所处位置是在BEGIN与END之间
拉低电平就写:
图 22拉低电平
至于其他的,比如翻转电平函数等等,可以在CSDN或其他地方中上查HAL库函数的大全。
编写于2024/6/4
CSDN:https://blog.csdn.net/m0_?spm=1000.2115.3001.5343
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/126750.html