热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

STM32从固件库到HAL库

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



让坚持成为一种热爱,极致成为一种精神。历时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芯片),只能更换系统时钟频率(降频)。
在这里插入图片描述



结语

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







推荐阅读
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • 本文详细介绍如何使用Python进行配置文件的读写操作,涵盖常见的配置文件格式(如INI、JSON、TOML和YAML),并提供具体的代码示例。 ... [详细]
  • 本文详细介绍了 Dockerfile 的编写方法及其在网络配置中的应用,涵盖基础指令、镜像构建与发布流程,并深入探讨了 Docker 的默认网络、容器互联及自定义网络的实现。 ... [详细]
  • 扫描线三巨头 hdu1928hdu 1255  hdu 1542 [POJ 1151]
    学习链接:http:blog.csdn.netlwt36articledetails48908031学习扫描线主要学习的是一种扫描的思想,后期可以求解很 ... [详细]
  • Java 中 Writer flush()方法,示例 ... [详细]
  • 本文介绍了如何使用 Spring Boot DevTools 实现应用程序在开发过程中自动重启。这一特性显著提高了开发效率,特别是在集成开发环境(IDE)中工作时,能够提供快速的反馈循环。默认情况下,DevTools 会监控类路径上的文件变化,并根据需要触发应用重启。 ... [详细]
  • Java 中的 BigDecimal pow()方法,示例 ... [详细]
  • Java 类成员初始化顺序与数组创建
    本文探讨了Java中类成员的初始化顺序、静态引入、可变参数以及finalize方法的应用。通过具体的代码示例,详细解释了这些概念及其在实际编程中的使用。 ... [详细]
  • 本文介绍了Java并发库中的阻塞队列(BlockingQueue)及其典型应用场景。通过具体实例,展示了如何利用LinkedBlockingQueue实现线程间高效、安全的数据传递,并结合线程池和原子类优化性能。 ... [详细]
  • 主要用了2个类来实现的,话不多说,直接看运行结果,然后在奉上源代码1.Index.javaimportjava.awt.Color;im ... [详细]
  • 题目描述:给定n个半开区间[a, b),要求使用两个互不重叠的记录器,求最多可以记录多少个区间。解决方案采用贪心算法,通过排序和遍历实现最优解。 ... [详细]
  • 深入解析Spring Cloud Ribbon负载均衡机制
    本文详细介绍了Spring Cloud中的Ribbon组件如何实现服务调用的负载均衡。通过分析其工作原理、源码结构及配置方式,帮助读者理解Ribbon在分布式系统中的重要作用。 ... [详细]
  • DNN Community 和 Professional 版本的主要差异
    本文详细解析了 DotNetNuke (DNN) 的两种主要版本:Community 和 Professional。通过对比两者的功能和附加组件,帮助用户选择最适合其需求的版本。 ... [详细]
  • UNP 第9章:主机名与地址转换
    本章探讨了用于在主机名和数值地址之间进行转换的函数,如gethostbyname和gethostbyaddr。此外,还介绍了getservbyname和getservbyport函数,用于在服务器名和端口号之间进行转换。 ... [详细]
  • ImmutableX Poised to Pioneer Web3 Gaming Revolution
    ImmutableX is set to spearhead the evolution of Web3 gaming, with its innovative technologies and strategic partnerships driving significant advancements in the industry. ... [详细]
author-avatar
刘小飘168585
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有