STM32的四种开发方式

2023-05-16

STM32的四种开发方式

首先看下ST官方给出的四种开发方式的比较

在这里插入图片描述

寄存器开发

寄存器编程对于从51等等芯片过渡过来的小伙伴并不陌生,不管你是什么库,最终操作的还是寄存器,所以对于标准库、HAL库、LL库都是在寄存器上的编程,所以可以直接在各种库中直接操作寄存器。

但寄存器开发方法到了STM32就变得不太容易行得通了,因为STM32的寄存器数量是51单片机的十数倍,如此多的寄存器根本无法全部记忆,开发时需要经常的翻查芯片的数据手册,此时直接操作寄存器就变得非常的费力了。但还是会有很小一部分人,喜欢去直接操作寄存器,因为这样更接近原理,知其然也知其所以然。

寄存器开发优缺点:

  1. 比其他库,直接操作寄存器来得更为直接、高效,省略了繁琐的调用和封装过程,但可移植性相对会降低一些。
  2. 同时对于芯片的熟练程度也是提出了要求,对于一款相对外设比较丰富的芯片需要花一定的时间阅读文档的等等,对开发人员有一定的门槛。
  3. 虽然开发起来相对来说比较慢一些,比较繁琐一些,但是接触的都是真正的底层内容,出了问题,我们也能从源头来快速分析解决问题,而且写的代码中省去了一些不必要的判断过程,执行效率会相对高一些,代码看起来也会清爽一些。

标准库开发

标准库全名叫标准外设库(Standard Peripheral Library),其实标准库所做的事情就是对寄存器进行了封装,形成了一套API函数供用户使用

因为STM32有非常多的寄存器,而导致了开发困难,所以为此ST公司就为每款芯片都编写了一份库文件,也就是工程文件里stm32F1xx…之类的。在这些 .c .h文件中,包括一些常用量的宏定义,把一些外设也通过结构体变量封装起来,如GPIO口时钟等。所以我们只需要配置结构体变量成员就可以修改外设的配置寄存器,从而选择不同的功能。用户不用去管寄存器到底是如何操作的,直接调用接口函数进行开发即可。

标准库在早期版本也叫固件函数库或简称固件库,不同人有不同的说法,知道这是同一个东西就行了

HAL库开发

HAL库是ST公司目前主力推的开发方式,全称就是Hardware Abstraction Layer(硬件抽象层)。

它的出现比标准库要晚,但其实和标准库一样,都是为了节省程序开发的时期,而且HAL库尤其的有效,如果说标准库把实现功能需要配置的寄存器集成了,那么HAL库的一些函数甚至可以做到某些特定功能的集成。也就是说,同样的功能,标准库可能要用几句话,HAL库只需用一句话就够了。

并且HAL库也很好的解决了程序移植的问题,不同型号的stm32芯片它的标准库是不一样的,例如在F4上开发的程序移植到F3上是不能通用的,而使用HAL库,只要使用的是相通的外设,程序基本可以完全复制粘贴,注意是相通外设,意思也就是不能无中生有,例如F7比F3要多几个定时器,不能明明没有这个定时器却非要配置,但其实这种情况不多,绝大多数都可以直接复制粘贴。

而且使用ST公司研发的 STM32CubeMx 软件,可以通过图形化的配置功能,直接生成整个使用HAL库的工程文件,可以说是方便至极,但是方便的同时也造成了它执行效率的低下。

HAL库与标准库的区别:https://www.elecfans.com/d/1814945.html(文章同时也介绍了1.句柄 2.MSP函数 3.Callback函数;对HAL库结构和移植使用都有介绍)

在前面的标准库中提到过,所有的API接口都是围绕着外设寄存器基地址,而对于HAL其围绕的是Handle,即一个外设句柄。

在这里插入图片描述

UART_HandleTypeDef 结构体内容


/**
  * @brief  UART handle Structure definition
  */
typedef struct __UART_HandleTypeDef
{
  USART_TypeDef                 *Instance;        /*!< UART registers base address        */
  UART_InitTypeDef              Init;             /*!< UART communication parameters      */
  uint8_t                       *pTxBuffPtr;      /*!< Pointer to UART Tx transfer Buffer */
  uint16_t                      TxXferSize;       /*!< UART Tx Transfer size              */
  __IO uint16_t                 TxXferCount;      /*!< UART Tx Transfer Counter           */
  uint8_t                       *pRxBuffPtr;      /*!< Pointer to UART Rx transfer Buffer */
  uint16_t                      RxXferSize;       /*!< UART Rx Transfer size              */
  __IO uint16_t                 RxXferCount;      /*!< UART Rx Transfer Counter           */
  DMA_HandleTypeDef             *hdmatx;          /*!< UART Tx DMA Handle parameters      */
  DMA_HandleTypeDef             *hdmarx;          /*!< UART Rx DMA Handle parameters      */
  HAL_LockTypeDef               Lock;             /*!< Locking object                     */
 
  __IO HAL_UART_StateTypeDef    gState;           /*!< UART state information related to global Handle management
                                                       and also related to Tx operations.
                                                       This parameter can be a value of @ref HAL_UART_StateTypeDef */
 
  __IO HAL_UART_StateTypeDef    RxState;          /*!< UART state information related to Rx operations.
                                                       This parameter can be a value of @ref HAL_UART_StateTypeDef */
 
  __IO uint32_t                 ErrorCode;        /*!< UART Error code                    */
 
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
  void (* TxHalfCpltCallback)(struct __UART_HandleTypeDef *huart);        /*!< UART Tx Half Complete Callback        */
  void (* TxCpltCallback)(struct __UART_HandleTypeDef *huart);            /*!< UART Tx Complete Callback             */
  void (* RxHalfCpltCallback)(struct __UART_HandleTypeDef *huart);        /*!< UART Rx Half Complete Callback        */
  void (* RxCpltCallback)(struct __UART_HandleTypeDef *huart);            /*!< UART Rx Complete Callback             */
  void (* ErrorCallback)(struct __UART_HandleTypeDef *huart);             /*!< UART Error Callback                   */
  void (* AbortCpltCallback)(struct __UART_HandleTypeDef *huart);         /*!< UART Abort Complete Callback          */
  void (* AbortTransmitCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Abort Transmit Complete Callback */
  void (* AbortReceiveCpltCallback)(struct __UART_HandleTypeDef *huart);  /*!< UART Abort Receive Complete Callback  */
  void (* WakeupCallback)(struct __UART_HandleTypeDef *huart);            /*!< UART Wakeup Callback                  */
 
  void (* MspInitCallback)(struct __UART_HandleTypeDef *huart);           /*!< UART Msp Init callback                */
  void (* MspDeInitCallback)(struct __UART_HandleTypeDef *huart);         /*!< UART Msp DeInit callback              */
#endif  /* USE_HAL_UART_REGISTER_CALLBACKS */

} UART_HandleTypeDef;
  • 从UART_HandleTypedef结构体里面的内容来看,其中不仅仅包括了UART_Typedef寄存器基地址数据结构,同时还包含通信过程的数据结构,比如缓存区指针及大小等,以及各种初始化和中断回调函数等等用户型数据。

  • 那么HAL库所实现的API不再是简单的像标准库那样封装寄存器了,而是实现了一个外设对象的数据结构封装,这样对于所有的处理只需要传入这个handle对象句柄即可对该对象进行所有操作。

HAL库每个handle句柄结构体中都会存在MSP两个回调函数指针 xxCallback

在这里插入图片描述

这算是HAL库设计不错的地方,MSP(MCU Specific Package)表示单片机的具体方案,是MCU相关的初始化处理。

在早期使用标准库学习stm32的过程中,很多小伙伴都会有这样的体会,经常性的忘记初始化引脚、初始化时钟、处理中断优先级等等错误,那么现在HAL库通过这两个回调函数在初始化过程中用来处理与当前外设功能相关性并不大的硬件配置,这样一方面起到了提醒的目的,另一方面也增强了可移植性。

  • 当然HAL库缺点也非常明显,较多的函数嵌套以及结构体索引,会导致占用更多的程序空间,并且效率上大打折扣。

  • 对于函数指针的大量使用,虽然可以带来代码的更好的扩展和复用,但是其对于MCU的RAM占用也是一笔资源。

  • 然而HAL库性能上的损失,从而让更多的项目趋向于使用高性能MCU

STM32 HAL库结构

在这里插入图片描述

LL库开发

LL库是与HAL库打包发布的一部分库文件,其也叫底层库(Low-Layer),它也是对寄存器进行了封装,与标准库其实差别并不是很大。

在这里插入图片描述

上图是LL库中的UART的相关实现,似乎函数声明部分该库中提供的API并没有标准库那么多,其实LL库中大部分API都是以static inline这样的内联函数形式进行定义的。

内联函数的优势在于不会像函数调用需要跳转到定义处等额外处理,而有点像宏定义一样直接展开并copy代码到执行位置,相对效率会提高很多,当然如果代码特别大,运行时间长,也就没有内联的必要了,所以其内联函数内部代码都相对比较短小。

如何进行选择

ST公司并没有强制要求一定要使用哪一种库来进行开发,所以对于库的选择还是要看个人需求,通过上面的这些描述,大家应该对这些库有了一个清晰的认识。

1、寄存器库算是所有库的根基,对于技术研发非常规范的公司会直接去封装寄存库,根据自己本公司的编码规范从而实现自身的一套API,这样一方面兼容已开发算法等应用库,同时有利于代码风格统一。虽然开发起来相对来说比较慢一些,比较繁琐一些,但是接触的都是真正的底层内容,出了问题,我们也能从源头来快速分析解决问题,而且写的代码中省去了一些不必要的判断过程,执行效率会相对高一些,代码看起来也会清爽一些。

2、标准库的话,用户可以直接使用,使用起来方便,快捷,开发速度快,相对起来也容易上手一点,但是对底层的寄存器操作原理了解不深,只知其一,不知其二,出了问题,解决起来比较麻烦。且官方的驱动库为了容错性高一些等原因,会引入一些判断机制,相对复杂一些,但是实际上有的东西是我们用不到的,这就会造成代码执行效率会相对低一些。

对于一些已使用标准库的老项目,如果技术到位的话,可以直接根据HAL或者LL库,进行版本上的升级和优化,从而降低产品开发风险和成本。

3、对于性能要求不高,且追求开发时效性,可以使用HAL与CubeMX工具结合开发,HAL 的结构更加容易整合 STM32CubeMx,而 STM32CubeMX 是 ST 这几年极力推荐的程序生成开发工具,bug再多应该也会得以修复。

使用 STM32CubeMx 开发,这个相比较来讲入门是最快的,不用接触那些库函数接口,也不用去理会那些寄存器操作,只要在图形化的界面上勾选一些选项就可以了,这简直是懒人必备神器,但是话说回来,这种开发方式,基本上接触单片机底层内容为0%,只要写应用程序就可以了,出了问题更难解决。如果换了个平台,没有这种方便的图形化配置工具,就有点不知所措了。

参考:

https://www.elecfans.com/d/1814945.html

https://www.freesion.com/article/11981446782/

https://zhuanlan.zhihu.com/p/385063476

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32的四种开发方式 的相关文章

  • KEIL添加新的.C文件

    KEIL添加新的 C文件 问题描述 之前在网上看了很多方法添加 C文件 xff0c 结果经常报重复定义的错误 xff0c 记录一下自己的方法吧 解决方案 xff1a 右键 add exiting 点击魔法棒 34 C C 43 43 inc
  • 汇总:使用keil5所遇见的一些常见问题以及解决方法

    一 新建keil5工程时出现这个警告 解决方法 xff1a 右键单击Keil STM32F1xx DFP pdsc xff0c 然后点开属性界面 xff0c 由于Keil STM32F1xx DFP pdsc文件是只读文件 xff0c 将只
  • 自定义串口协议

    文章目录 前言一 有限状态机有限状态机代码接收数据缓冲缓冲要求循环队列 一 循环队列代码实现循环队列头文件 xff1a 源文件 xff1a 二 有限状态机与解码有限状态机核心实现代码有限状态机与解码头文件源文件 三 使用小例子总结 前言 此
  • stm32f1串口发送与接收

    目录 串口配置 串口发送 1使用SendString函数发送 2使用printf函数发送 串口接收 串口配置 首先对串口进行初始化 包括使能串口时钟 xff0c 这里我使用的是usart2 xff0c 使能GPIO时钟 xff0c 这里我用
  • 串口通讯详解

    这篇文章包含了串口通讯里面的大部分概念问题 目录 串口通讯线 同步串行 xff08 ISP xff09 异步串行 xff08 UART xff09 波特率 数据帧 串口通讯线 串口通信线最少需要2根 xff08 GND和信号线 xff09
  • 包罗万象!V3Det:1.3W类全新目标检测数据集(港中文&上海AI Lab)

    作者 CV君 编辑 我爱计算机视觉 点击下方卡片 xff0c 关注 自动驾驶之心 公众号 ADAS巨卷干货 xff0c 即可获取 点击进入 自动驾驶之心 目标检测 技术交流群 后台回复 2D检测综述 获取鱼眼检测 实时检测 通用2D检测等近
  • stm32f4串口接收与发送

    之前有写一篇stm32f1串口接收与发送的文章 xff0c stm32f4与f1只有配置上的一点不同 xff0c 今天把f4的串口接收与发送代码分享一下 详细解释推荐大家看f1那篇 xff0c 都是一样的 xff0c stm32f1串口发送
  • -> 在c语言中是什么意思?

    gt 是一个整体 xff0c 它是用于指向结构体子数据的指针 xff0c 用来取子数据 换种说法 xff0c 如果我们在C语言中定义了一个结构体 xff0c 然后申明一个指针指向这个结构体 xff0c 那么我们要用指针取出结构体中的数据 x
  • C++中 i<<=1是什么意思

    左移赋值运算 变量i 左移1位 xff0c 结果仍然保存到变量i 举个栗子 xff1a i 61 101001 执行 xff1a i span class token operator lt lt 61 span span class to
  • 详解KITTI数据集

    详解KITTI数据集 一 KITTI数据集发布方 2011年 xff0c Andreas Geiger xff08 KIT xff09 Philip Lenz xff08 KIT xff09 Raquel Urtasun xff08 TTI
  • OpenCV各版本差异

    Opencv2标志着opencv革命性的改变 xff0c Opencv2带来了全新的C 43 43 接口 xff0c 将Opencv的能力无限放大 在2 0时代 xff0c opencv增加了新的平台支持 xff0c 包括iOS和Andro
  • realsense D435 D435i D415深度相机在ros下获得RGB图、左右红外摄像图、深度图、IMU数据

    首先你要你确保你的相机驱动已经安装好 xff0c 环境配置可以看我的另一篇文章 xff1a https blog csdn net weixin 46195203 article details 119205851 第一步 xff1a 新建
  • LaTex学习之算法如何写以及常用语句IF、FOR、WHILE

    首先是在头文件中加上 usepackage span class token punctuation span algorithm span class token punctuation span algorithmic span cla
  • latex报错:Missing delimiter (. inserted). ... {\xi \left( {p,{p_q}} \right)} \right|}}

    理想中的公式 xff0c begin span class token punctuation span equation span class token punctuation span span class token punctua
  • sort函数第三个参数cmp必须声明为static

    span class token keyword bool span span class token keyword static span span class token function comp span span class t
  • linux下Tinyhttpd安装运行

    tinyhttpd 超轻量型 Http Server tinyhttpd 全部代码在500 行左右 xff0c 是一个超轻量型 Http Server xff0c 这是是学习C C 43 43 入门非常棒的一个开源项目 xff0c 可以帮助
  • CVPR 2023|DropKey:两行代码高效缓解ViT过拟合(美图&国科大)

    编辑 CV技术指南 点击下方卡片 xff0c 关注 自动驾驶之心 公众号 ADAS巨卷干货 xff0c 即可获取 点击进入 自动驾驶之心 全栈算法 技术交流群 前言 美图影像研究院 xff08 MT Lab xff09 与中国科学院大学突破
  • C++并发与多线程学习笔记--线程启动、结束,创建线程多法

    一 范例演示线程运行的开始 程序运行起来 xff0c 生成一个进程 xff0c 该进程所属的主线程开始自动运行 xff1b 当主线程从main xff08 xff09 函数返回 xff0c 则整个进程执行完毕 主线程从main xff08
  • 顶层const和底层const

    概念解释 表示声明常量的const都是顶层const 用于声明引用的const都是底层const 顶层const是 xff1a 指针本身是常量 底层const是 xff1a 指针所指的对象是常量 即是顶层const又是底层const xff
  • c++中从出年月日的字符串提取整形int

    在C 43 43 中字符串有两种 xff0c 不过提取方式类似 xff0c 具体如下 xff1a 一 以 0 结束的字符数组 对于以 0 结束的字符数组 xff0c 可以有如下两种方式 xff1a 1 通过自定义函数提取 由于格式固定 xf

随机推荐

  • STM32与4脚光敏电阻的简单使用——初学

    这是我第一次写CSDN xff0c 排版可能有许多问题 xff0c 描述的可能也有不清楚的地方 xff0c 有问题的小伙伴可以私聊我 xff0c 一起学习共同进步 今天发现了一个很有意思的传感器 光敏传感器 xff0c 它可以判断光线的亮暗
  • STM32与人体红外感应模块的简单使用——入门级

    工作原理 人体有恒定的温度 xff0c 可以发出10UM的红外波 xff0c 而人体红外感应模块就可以探测出这些红外波 xff0c 从而产生电平转换 由此人们可以使用人体红外检测模块来检测是否有人 模块工作环境 工作电压 xff1a 5V至
  • 光敏,红外,人体红外检测模块的模拟输出(ADC)实验——入门

    前面给大家介绍了传感器的开关输出的使用 xff0c 今天给大家介绍一下常见传感器的模拟输出的用法 xff0c 用到了STM32的ADC xff08 模数转换 xff09 模块和USART串口通信模块 代码就是正点原子的ADC实验的代码 今天
  • 直流电机+L298N电机驱动模块

    本次来写一下关于驱动直流电机的知识 xff0c 今天目的是驱动它 xff0c 下次写使用PWM精准的对直流电机进行控速 下面是我使用的直流电机图 xff1a 由于STM32单片机不能直接的输出较大电压和电流 xff0c 所以得借助驱动模块来
  • 操作系统的内存管理——页式、段式管理、段页式管理

    操作系统的内存管理中段式管理与页式管理并不是对立的 xff0c 他们结合起来内存的使用效率会更高 他们都属于离散分配内存的管理方式 xff0c 当然还有连续型内存分配的管理方式 xff0c 连续分配是指为一个用户程序分配连续的内存空间 连续
  • linux内存机制原理---分页、分段底层原理

    自我总结 xff1a 分段 43 分页 43 虚拟内存 61 现代操作系统的内存管理机制 一 linux的内存分布 内核与高速缓冲区占用了前1MB内存 xff0c 后面15MB属于主存 xff0c 可以由用户自由分配 四种地址 xff1a
  • linux进程的内存与ELF文件

    一 linux为每个进程分配的虚拟内存 提到进程的内存就是虚拟内存 1G的内核区域 3G的用户区域 xff0c 提到进程的内存就是下面这个图 xff0c 都可以用它进行分析 虚拟内存是为了实现多任务 xff0c 所以操作系统才引入了它 二
  • YOLO终结者?RT-DETR一探究竟!

    作者 迪迦奥特曼 编辑 极市平台 点击下方卡片 xff0c 关注 自动驾驶之心 公众号 ADAS巨卷干货 xff0c 即可获取 点击进入 自动驾驶之心 目标检测 技术交流群 导读 实时目标检测中击败YOLO家族 xff1f 来看看百度飞桨的
  • C语言中的位段操作—嵌入式学习(实习篇)

    记录实习期间学到的新的知识 malloc申请内存 xff1a 当申请小内存的时 xff0c malloc使用sbrk分配内存 xff1b 当申请大内存时 xff0c 使用mmap函数申请内存 xff1b 但是这只是分配了虚拟内存 xff0c
  • 运行excel时报错“由于找不到vcruntime140_1.dll,无法继续执行代码”--已解决

    问题描述 xff1a 清除文件时误删microsoft visual c 43 43 2015 microsoft visual c 43 43 2018等文件 xff0c 导致运行excel时报错 由于找不到vcruntime140 1
  • Jetson TX2新手上路全记录(2)

    xff08 2 xff09 查看ubuntub版本 cat proc version 判断ubuntu网络是否连通 xff1a ping www baidu com 数据刷新无异常即连通 破防了 xff0c 前天刷机看来没成功 原因 xff
  • TX2查看cudnn版本 `cat /usr/include/cudnn.h | grep CUDNN_MAJOR -A 2无反应

    之前cat usr include cudnn h grep CUDNN MAJOR A 2命令可以查看cudnn版本 xff0c 但是之后新版本的版本信息放在了cudnn version h xff0c 我的环境为ubuntu18 04
  • yolo实现交通信号灯视频流识别代码搬运及调试

    yolo实现交通信号灯视频流识别调试过程 所用代码 xff1a 基于YOLOv3的红绿灯检测识别 xff08 Python源码可直接运行 xff09 原作者是tensorflow1 xff0c 我的环境是tensorflow2 xff0c
  • TX2通过yolov4实现交通信号灯视频检测

    所用代码以后上传 环境部署 Jetson TX2刷机及安装的软件包版本如下 xff1a 整个过程中遇到最多的就是不同tf keras版本之间导致的问题 xff0c 所以部署环境的时候千万注意各种包的依赖关系 xff0c 我因为兼容性问题走了
  • TX2 查看内存使用情况

    TX2 查看内存使用情况 不知道为什么无法使用sudo xff5e tegrastats xff0c 报错 command not found 参考NVIDIA TX2 目标检测 查看显卡使用状况 jtop jtop使用指南 NVIDIA
  • Modelsim解决中文注释乱码

    Modelsim中文注释出现乱码 xff0c 解决过程如下 1 菜单栏 Tools Preferences xff0c 点击By name 2 找到source选项 xff0c 下拉选项中双击encoding 3 弹出的对话框中将encod
  • 【资料分享】IMAX-B6AC充电器使用方法

    因为说明书都是英文的嘛 xff0c 所以 xff0c 还是写个充电方法吧 刚打开的时候 xff0c 界面应该是这个样子的 如果很不幸 xff0c 你的不是 xff0c 那么 xff0c 多按几次Stop键 xff0c 直到它是这个界面 菜单
  • GPIO简介

    1 什么是GPIO xff1f GPIO是General Purpose Input Output xff0c 即通用输入输出端口 xff0c 简称GPIO 作用 xff1a 负责采集外部器件的信息或者控制外部器件工作 xff0c 即输入输
  • 多目标跟踪入门:从SORT到FairMOT

    点击下方卡片 xff0c 关注 自动驾驶与AI 公众号 ADAS巨卷干货 xff0c 即可获取 点击进入 自动驾驶之心 目标跟踪 技术交流群 后台回复 目标跟踪综述 获取单目标 多目标 基于学习方法的领域综述 xff01 目标跟踪分为单目标
  • STM32的四种开发方式

    STM32的四种开发方式 首先看下ST官方给出的四种开发方式的比较 寄存器开发 寄存器编程对于从51等等芯片过渡过来的小伙伴并不陌生 xff0c 不管你是什么库 xff0c 最终操作的还是寄存器 xff0c 所以对于标准库 HAL库 LL库