STM32从固件库到HAL库

news2024/11/20 1:34:02

让坚持成为一种热爱,极致成为一种精神。历时10个月,目前我又重新回到了程序员的身份,2023想玩不一样的嵌入式。🚀

目录

  • 前言
  • 一、安装STM32CubeMX
  • 二、配置自己的HAL库MDK工程
  • 三、HAL库与固件库的区别
    • 1.句柄
    • 2.回调函数
    • 3.时钟配置
    • 4.HAL_Init()
    • 5.其他
  • 结语


前言

我学STM32是基于固件库的,之后的一年都是用固件库开发STM32。其实固件库还是挺好用的,很稳定,即使ST已经放弃很多年了。
为什么改用HAL库?
1)CubeMX+HAL库是大势所趋。
2)CubeMX可以直接生成驱动代码,而且CubeMX是很好的工具,即使不用HAL库,里面的一些工具对开发也很有帮助。
3)HAL库效率不如固件库,一些关键代码可以改为寄存器操作,比如串口、DMA、ADC。
4)现在很多优秀的开源项目都是基于HAL库开发,看不懂代码怎么CV[doge]
一些个人做法
直接用CubeMX生成的MDK工程开发我认为是不可取的。开发过程中随时会修改驱动参数,而CubeMX每次修改都会覆盖原工程,只能在固定区域编程,极其不优雅。因此我的做法是用自己配置的工程开发,然后把CubeMX生成的驱动代码复制到自己工程里。本文基于这种做法展开。

开发环境
操作系统:Windows 11
JAVA 1.8.0_351
STM32CubeMX 6.5
STM32Cube_FW_F1_V 1.8.4
STM32Cube_FW_F4_V 1.26.1
keil MDK 5.36

一、安装STM32CubeMX

CubeMX需要JAVA环境,首先需要安装JAVA。适用于 Windows 的 64位 Java
然后安装CubeMX,直接在ST官网搜即可。ST官网
安装完配置仓库地址,然后下载对应的芯片包即可。
第一次打开设置时会报错,等几分钟再打开
在这里插入图片描述
在这里插入图片描述
下载芯片包
在这里插入图片描述
在这里插入图片描述
开启工程后第一步应该先设置RCC时钟源和SYS调试接口,根据我的做法这部分可以直接跳过,因为只需要驱动代码,所以直接配置IO口生成即可。

二、配置自己的HAL库MDK工程

这部分跟配置固件库工程步骤相同,只是把对应文件改为HAL库,这里我直接在正点原子的例程代码基础上进行修改,HAL库版本的原子例程依旧带有system文件夹。然后建立BSP文件,把CubeMX生成的驱动代码复制过来即可。下面讲下HAL库跟固件库的一些区别。

三、HAL库与固件库的区别

这里简单说下除命名外的一些区别。

1.句柄

所谓句柄,在HAL库里就是一个外设的结构体。
在固件库中我们是这样初始化外设的:先定义一个函数,在函数里定义一个结构体,开启时钟,然后操作这个结构体成员,最后利用这个结构体初始化外设。
在HAL库中,需要定义一个全局变量结构体,也就是句柄,为什么是全局变量?因为不只是初始化外设要用到,后面对外设的一系列操作都需要用到,比如说ADC的校正、读取,串口的接发。

2.回调函数

在固件库初始化外设中,一般都是先打开时钟,配置GPIO,配置复用功能。而在HAL库中时钟、GPIO和中断的配置都放到了回调函数中(带有MspInit结尾),因为HAL库在Init外设后会自动调用回调函数,回调函数是weak(弱定义)函数,默认为空,也就是ST让用户重新定义的函数。既然回调函数中放入了时钟和GPIO配置,那么初始化函数中就只剩下外设的复用配置。
还有一个问题,例如串口只有一个回调函数HAL_UART_MspInit,在配置USART1时会调用函数HAL_UART_MspInit,配置USART2时也会调用函数HAL_UART_MspInit,所以HAL_UART_MspInit中必须判断目前在配置哪个串口,这样才不会出错。
另外,回调函数默认是一个空函数,不一定要按照ST的思路来编程,我们也可以把回调函数中的代码放回到初始化函数中,也就是像用固件库编程那样。下面是串口的回调函数代码。

void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
    GPIO_InitTypeDef gpio_init_struct;
    if(huart->Instance == USART_UX)                             /* 如果是串口1,进行串口1 MSP初始化 */
    {
        USART_UX_CLK_ENABLE();                                  /* USART1 时钟使能 */
        USART_TX_GPIO_CLK_ENABLE();                             /* 发送引脚时钟使能 */
        USART_RX_GPIO_CLK_ENABLE();                             /* 接收引脚时钟使能 */

        gpio_init_struct.Pin = USART_TX_GPIO_PIN;               /* TX引脚 */
        gpio_init_struct.Mode = GPIO_MODE_AF_PP;                /* 复用推挽输出 */
        gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉 */
        gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;          /* 高速 */
        gpio_init_struct.Alternate = USART_TX_GPIO_AF;          /* 复用为USART1 */
        HAL_GPIO_Init(USART_TX_GPIO_PORT, &gpio_init_struct);   /* 初始化发送引脚 */

        gpio_init_struct.Pin = USART_RX_GPIO_PIN;               /* RX引脚 */
        gpio_init_struct.Alternate = USART_RX_GPIO_AF;          /* 复用为USART1 */
        HAL_GPIO_Init(USART_RX_GPIO_PORT, &gpio_init_struct);   /* 初始化接收引脚 */

#if USART_EN_RX
        HAL_NVIC_EnableIRQ(USART_UX_IRQn);                      /* 使能USART1中断通道 */
        HAL_NVIC_SetPriority(USART_UX_IRQn, 3, 3);              /* 抢占优先级3,子优先级3 */
#endif
    }

3.时钟配置

在固件库中,根据外设对应的AHB、APB1、APB2时钟用对应的RCC函数打开时钟。如

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE );

在HAL库中把每个外设和GPIO的时钟都单独分开为一个宏。如

ADC_ADCX_CHY_CLK_ENABLE();      /* 使能ADCx时钟 */
ADC_ADCX_CHY_GPIO_CLK_ENABLE(); /* 开启GPIO时钟 */

4.HAL_Init()

main函数中需要加入HAL_Init()函数进行系统初始化。
HAL_Init()的功能是配置Flash,设置中断分组、系统时钟。默认的中断分组是4(如果后面不进行修改)

HAL_StatusTypeDef HAL_Init(void)
{
  /* Configure Flash prefetch, Instruction cache, Data cache */ 
#if (INSTRUCTION_CACHE_ENABLE != 0U)
  __HAL_FLASH_INSTRUCTION_CACHE_ENABLE();
#endif /* INSTRUCTION_CACHE_ENABLE */

#if (DATA_CACHE_ENABLE != 0U)
  __HAL_FLASH_DATA_CACHE_ENABLE();
#endif /* DATA_CACHE_ENABLE */

#if (PREFETCH_ENABLE != 0U)
  __HAL_FLASH_PREFETCH_BUFFER_ENABLE();
#endif /* PREFETCH_ENABLE */

  /* Set Interrupt Group Priority */
  HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);

  /* Use systick as time base source and configure 1ms tick (default clock after Reset is HSI) */
  HAL_InitTick(TICK_INT_PRIORITY);

  /* Init the low level hardware */
  HAL_MspInit();

  /* Return function status */
  return HAL_OK;
}

不难发现,里面也有一个回调函数,这里也是一个空函数。

5.其他

以上四个是重要区别,其他基本都是命名区别,可以结合例程代码进行配置,在熟悉固件库的基础上花几个小时就可以快速入门HAL库。

另外我在配置时钟,发现我之前一直忽视了32的ADC时钟,以F1为例,官方给出的ADC最高采样率是1M,时钟频率最高为14MHz。
采样率 = 1 / ( 用户配置时钟周期 + 12.5(固定转换时钟周期)×(1/14MHz))
用户配置周期最小1.5,在这种情况下可以达到1M采样率。
但是当系统为72M时ADC并不能达到14MHz,如下图所示,ADC时钟最高只能达到12MHz
此时最高率为1 / ( 1.5 + 12.5(固定转换时钟周期)×(1/12MHz))≈ 857KHz
也就是说如果要ADC跑到1M(F1芯片),只能更换系统时钟频率(降频)。
在这里插入图片描述

结语

以上是本篇文章的所有内容。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/147639.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Bulma - 免费开源的纯 CSS 前端 UI 框架,专注于构建移动优先的响应式 web 界面

简单易用的 CSS 框架,虽然只有一个 CSS 文件,但功能很强大,在国外很受开发者欢迎,推荐给大家。 关于 Bulma CSS 框架 Bulma 是一个简单、很容易自定义的 CSS UI 框架,提供了众多预定义好的样式,开发者可以…

宠物吸毛器控制板开发,构建理想人宠共居空间

目前养宠物的人越来越多,猫狗等宠物一直存在着严重的掉毛情况,宠物毛发可能会引起过敏等疾病反应,日常生活中清理工作是一大难题,市面上关于宠物的吸毛产品非常的少,为此沐渥开发了一款宠物吸毛器控制板,适…

奇怪,郭德纲小儿子八岁生日,现场照片发布不久却被删除了

2022年1月5日,对于北京德云社来说,是一个双喜临门好日子,首先德云社相声春晚开始录制,其次郭德纲的儿子郭汾阳,也要过八岁生日了。郭汾阳作为德云社的少班主,是郭德纲老师和董事长王惠所生,老来…

与ChatGPT的聊天:如何使用Python连接Neo4j并创建无向图?

0. 前言 尝试请ChatGPT帮写代码: 但发现ChatGPT可以给出逻辑上正确的程序,一旦具体深入询问,有可能会产生错误。 当然,也可能因为提问的人比较少🤣 不管怎么说,这篇可以当成是对ChatGPT茶余饭后的谈资&am…

数据库,计算机网络、操作系统刷题笔记28

数据库,计算机网络、操作系统刷题笔记28 2022找工作是学历、能力和运气的超强结合体,遇到寒冬,大厂不招人,可能很多算法学生都得去找开发,测开 测开的话,你就得学数据库,sql,oracle…

产品重要更新: GcExcel Java Edition 6.0.2 Crack

重要产品更新: JDK 6 和 7 已经走到了生命的尽头。自此, GcExcel Java Edition将不再支持它们,现在将从最新的v6 版本及更高版本开始以JDK 8为目标。GcExcel Java Edition 6.0.2 Crack by Ω578867473 GcExcel高速 Java Excel 电子表格 API …

Zookeeper简介

引言 在分布式环境下,如果舍弃SpringCloud,使用其他的分布式框架,那么注册心中,配置集中管理,集群管理,分布式锁,分布式任务,队列的管理想单独实现怎么办。 Zookeeper介绍 Zookeeper…

Flink 运行架构

1 Flink 运行时的组件 Flink 运行时架构主要包括四个不同的组件,它们会在运行流处理应用程序时协同工作:作业管理器(JobManager)、资源管理器(ResourceManager)、任务管理器(TaskManager&#…

一篇文章让你掌握HTML(下)

目录 1. 列表标签 1.1 无序列表 1.2 有序列表 1.3 自定义列表 2. 表格标签 2.1 表格的基本标签 2.2 表格相关属性 2.3 表格标题和表头单元格标签 2.4 表格的结构标签 2.5 合并单元格 3. 表单标签 3.1 input系列标签 3.1.1 input系列标签-文本框 3.1.…

MATLAB-非线性方程(组)求解

求非线性方程或方程组解的问题也就是求函数零点的问题。对于任意函数,在求解范围内可能有零点,也可能没有;可能只有一个零点,也可能有多个甚至无数个零点。MATLAB没有可以求解所有函数零点的通用命令,下面将分别讨论一元函数和多元…

Nginx入门知识

一、什么是NginxNginx (engine x) 是一个高性能的HTTP和反向代理web服务器,Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,在BSD-like 协议下发行。其特点是占有内存少,并发能力强&am…

JavaScript 字符串

文章目录JavaScript 字符串JavaScript 字符串字符串长度特殊字符字符串可以是对象字符串属性和方法字符串属性字符串方法JavaScript 字符串 JavaScript 字符串用于存储和处理文本。 JavaScript 字符串 字符串可以存储一系列字符,如 “John Doe”。 字符串可以是插…

如何连接远程mysql数据库(原创)

一、连接远程数据库:(前提本地也有mysql的客户端) 1、显示密码 如:MySQL 连接远程数据库(192.168.5.116),端口“3306”,用户名为“rfid_hh”,密码“123456” C:/>mysq…

20230107报警器的测试

20230107报警器的测试 2023/1/7 13:01 新款夹子户外报警器防盗报警器果园自动打电话无线距离防水报警器 拼多多的货。不到30¥,也就那么回事了,没有太高期望。 需要在微信公众号注册。 拿掉强磁铁之后,GSM模块通电了!…

英国学校遭遇机密数据大规模泄露

在 2022 年发生攻击事件后,来自 14 所英国学校的机密数据已被黑客在线泄露。 泄露的文件包括孩子的 SEN 信息、学生护照扫描件、员工工资表和合同细节。在受影响的学校拒绝支付攻击者的赎金要求后,信息被泄露。 据报道,攻击和泄密是由威胁行…

前端开发--JavaScript高级

JavaScript高级这一篇就够了JavaScript高级1、基础总结深入1.1 数据类型的分类和判断1.2 数据,变量, 内存的理解1.3 对象的理解和使用1.4 函数的理解和使用2、函数高级2.1 原型与原型链2.2 执行上下文与执行上下文栈2.3 作用域与作用域链2.4 闭包2.5 内存溢出与内存泄露3、对象…

DC-1靶场实操

靶场部署 下载网址:Vulnerable By Design - Search: DC- ~ VulnHub tips:强烈建议各位师傅们使用迅雷或idm要不然下载靶场将是一个十分痛苦的环节 之后环境搭建操作步骤一致故此处搭建环境以DC-1为例 将下好的压缩包解压,你就会看到一个.…

2023春招面试专题:高并发解决方案

如何理解高并发? 高并发意味着大流量,需要运用技术手段抵抗流量的冲击,这些手段好比操作流量,能让流量更平稳地被系统所处理,带给用户更好的体验。 我们常见的高并发场景有:淘宝的双11、春运时的抢票、微…

kaggle平台学习复习笔记 | 计算机视觉

目录1.The Convolutional Classifier2.Convolution and ReLU3.Maximum Pooling4.The Sliding Window5.Custom Convnets6.Data Augmentation1.The Convolutional Classifier 使用Keras创建第一个计算机视觉模型。 用于图像分类的网络由两部分组成:卷积层和密集层 卷…

华为云服务器无法正常访问端口

出错场景: 2023年1月7日22:05:32 在新服务器上运行自己服务端软件,其他客户端无法访问端口 进行连接。 服务端的程序启动了,客户端无法交互,连接失败。 首先检查能不能ping通 ping IP地址–发现是可以ping通的,再测…