草庐IT

STM32的HAL库及其使用

路溪非溪 2024-02-11 原文

随着时代的逐步发展,联网、USB、文件系统、加密算法、RTOS、GUI等第三方组件变得越来越重要,简陋的标准库已经很难满足当代单片机开发需求了。

事实上,单片机开发在走PC、手机等以CPU为核心的产品的老路:底层和细节越来越成熟,ARM提供CPU的库、单片机厂商提供外设库,单片机软件工程师直接基于这些库来构建自己的应用。现在更倾向于提供一整套开发生态而不只是一个SDK包,于是HAL库应运而生,提供HAL抽象层驱动来加速产品移植和选型,增加客户粘度。

STM32软件开发的各种模式
第1代:寄存器开发
第2代:标准库开发
第3代:HAL/LL库 + STM32CubeMX工具开发

  • HAL(hardware abstract layer)、LL(lowerlevel layer)
  • HAL库的优势是便于在不同型号的STM32芯片之间移植,劣势是代码效率低。标准外设库可以很简单直接跟踪到底层寄存器,而HAL库里面的代码想要跟踪并理解底层很难。
  • LL库几乎等同于直接操作寄存器
  • CubeMX工具是ST的一站式开发包,层级高于SDK包,包含了STM32芯片开发的所有官方资源,提供了友好的使用方法;CubeMX是一个windows上的IDE软件;CubeMX是一个工具包加芯片容器,各系列芯片资料以插件补丁形式安装;
  • HAL/LL库和CubeMX本质上是独立的东西,只是使用上纠缠在一起了而已。
  • CubeMX和Keil MDK是不同作用的东西,要搞清楚。

那到底什么是HAL库呢?

STM32 HAL固件库是Hardware Abstraction Layer的缩写,中文名称是:硬件抽象层。HAL库是ST公司为STM32的MCU最新推出的抽象层嵌入式软件,为更方便的实现跨STM32产品的最大可移植性。HAL库的推出,可以说ST也慢慢的抛弃了原来的标准固件库,这也使得很多老用户不满。但是HAL库推出的同时,也加入了很多第三方的中间件,有RTOS,USB,TCP / IP和图形等等。

和标准库对比起来,STM32的HAL库更加的抽象,ST最终的目的是要实现在STM32系列MCU之间无缝移植,甚至在其他MCU也能实现快速移植。

并且从16年开始,ST公司就逐渐停止了对标准固件库的更新,转而倾向于HAL固件库和 Low-layer底层库的更新,停止标准库更新,也就表示了以后使用STM32CubeMX配置HAL/LL库是主流配置环境。

HAL库目录结构

STM32Cube_FW_F1_V1.8.4

HAL库的目录内容如下所示:

在第二个Documentation中有个文档,里面有目录结构说明:

相对标准库,重点多了个BSP,这里面放的是板级支持包,针对的是ST官方出的几款特定开发板。

另外,中间件也需要重点关注下。

其他和标准库的很类似,此处不赘述。



HAL项目解读

HAL工程创建后的文件目录如下:

其中.ioc就是mx项目文件。可双击后打开进行修改。用记事本打开,可以看到其内容,比如以下是该文件开头部分的几行:

注意:不同的MX版本、不同的固件版本、不同的芯片,其项目目录都可能有所差别。

所以,需要掌握本质的东西,才能举一反三。

重点关注各文件,以及文件的作用。

Core目录

这一块不要死记硬背,关键是要学会阅读源码。

Core目录应该是和内核相关的程序代码。

 

main文件

在main文件中,主要实现了如下功能:

在MX中配置的引脚的宏定义;

系统时钟配置;

引脚初始化;

stm32f1xx_hal_conf.h

这里面主要是一些配置信息。

模块使能的宏定义

定义各时钟源默认的时钟值

关于回调函数等的一些配置

 网络相关的配置

SPI_CRC配置

指定模块的头文件包含

断言定义

stm32f1xx_it

定义了系统异常处理函数

需要处理中断直接在里面指示的位置写,调用和管理等都会交由 HAL 库完成。

头文件

c文件中基本都是空的,需要自己去定义如何处理这些异常

stm32f1xx_hal_msp.c

MSP即MCU Specific Package,也就是和具体的单片机相关的一些配置。例如在普通的 Init 函数中设置的是与具体 MCU 无关的参数,MspInit 中就会有些关于具体引脚的配置。举例来说,用 CubeMX 自动生成 USART 和 DMA 的配置,那么 MX_USART1_UART_Init 函数里面就会配置 USART 的一些约定参数例如波特率等,而在 HAL_UART_MspInit 函数中就会配置例如 USART 占用具体哪个脚,配置 DMA 占用哪个通道和其他参数等。

system_stm32f1xx.c

文件里面已经讲到了,重点如下:

SystemInit()初始化系统时钟;

SystemInit()在启动文件中被调用,且在复位之后,跳转到main之前被执行;

另外就是一个内核时钟HCLK变量以及和时钟更新函数。

MDK-ARM目录

这个目录里主要是生成的Keil工程。

除了.uvprojx之外,还有一个比较重要的文件,那就是startup_stm32f103xe.s

这就是程序的启动文件,主要是进行底层的初始化。

比如:

内存空间的相关设置

中断向量表定义

异常的系统化处理

比如在复位异常中,就能看到先执行的SystemInit函数,然后再执行main函数。

再就是堆栈的初始化

Drivers目录

STM32F1xx_HAL_Driver

这里面就是各个外设的驱动程序。

里面包含了HAL和LL的库文件,我们重点关注HAL库文件。

另外,对于有的外设,除了有常规的文件,还有一个ex扩展文件。

常规文件中是一些常用的功能,ex中是一些相对复杂不太常用的功能。 

另外,在该目录中,还有一个不是特定外设的文件

stm32f1xx_hal

这个文件里放的是跟系统相关的一些内容

比如Tick时钟频率

 各外设Debug模式的宏定义;

初始化/去初始化

Tick相关函数/省电模式相关函数/获取版本/获取ID号等函数

CMSIS目录

这里面内容比较多。

几个比较重要的文件提一下。

Device\ST\STM32F1xx\Include

stm32f1xx.h

这里面主要是选择设备、版本号、一些标志位状态位、头文件包含、带参宏等等。

具体查看源码。

stm32f103xe.h

另外,CMSIS\Device\ST\STM32F1xx\Source\Templates\arm

这里面有arm单片机的一些启动文件。

 

 其他目录暂时不管,有需要再去看看。

打开MDK-ARM下的工程文件:

工程目录如下:

不赘述。

注意:

自动生成的project目录结构和名称等都是既定的,最好不要改;
由CubeMX工程到MDK工程是单向的,不能逆向同步;
STM32CubeMX工具只是生成工程和外设初始化代码,大量开发工作还是靠自己的;
HAL库是一套体系,有自己的架构,必须理解透彻,否则会有无处下手的感觉;
因为HAL库很庞大,整个编译一次很久,所以建议要点build而不是rebuild;

源码简读

自行阅读源码。

做好必要的记录。

有关STM32的HAL库及其使用的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  5. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  6. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  7. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  8. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  9. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  10. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

    我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

随机推荐