STM32中HAL库接口函数的共性以及架构思想

最近,我在使用STM32CUBEMX这个软件生成HAL库的模板,并学习STM32单片机的USB Device外设功能以及相关协议栈,发现了HAL的一些特点,现在记录下来。

(1)"函数的本质是一个数据处理器"这句话的理解。

首先理解一下寄存器的作用,首先要明白操作那个寄存器就是操作硬件,也就是读写寄存器就是实现了STM32单片机功能的控制。

首先看一下以下代码:

cpp 复制代码
typedef struct
{
  __IO uint32_t GOTGCTL;              /*!<  USB_OTG Control and Status Register       Address offset: 000h */
  __IO uint32_t GOTGINT;              /*!<  USB_OTG Interrupt Register                Address offset: 004h */
  __IO uint32_t GAHBCFG;              /*!<  Core AHB Configuration Register           Address offset: 008h */
  __IO uint32_t GUSBCFG;              /*!<  Core USB Configuration Register           Address offset: 00Ch */
  __IO uint32_t GRSTCTL;              /*!<  Core Reset Register                       Address offset: 010h */
  __IO uint32_t GINTSTS;              /*!<  Core Interrupt Register                   Address offset: 014h */
  __IO uint32_t GINTMSK;              /*!<  Core Interrupt Mask Register              Address offset: 018h */
  __IO uint32_t GRXSTSR;              /*!<  Receive Sts Q Read Register               Address offset: 01Ch */
  __IO uint32_t GRXSTSP;              /*!<  Receive Sts Q Read & POP Register         Address offset: 020h */
  __IO uint32_t GRXFSIZ;              /*!< Receive FIFO Size Register                 Address offset: 024h */
  __IO uint32_t DIEPTXF0_HNPTXFSIZ;   /*!<  EP0 / Non Periodic Tx FIFO Size Register  Address offset: 028h */
  __IO uint32_t HNPTXSTS;             /*!<  Non Periodic Tx FIFO/Queue Sts reg        Address offset: 02Ch */
  uint32_t Reserved30[2];             /*!< Reserved 030h*/
  __IO uint32_t GCCFG;                /*!< General Purpose IO Register                Address offset: 038h */
  __IO uint32_t CID;                  /*!< User ID Register                           Address offset: 03Ch */
  uint32_t  Reserved40[48];           /*!< Reserved 040h-0FFh */
  __IO uint32_t HPTXFSIZ;             /*!< Host Periodic Tx FIFO Size Reg             Address offset: 100h */
  __IO uint32_t DIEPTXF[0x0F];        /*!< dev Periodic Transmit FIFO                 Address offset: 0x104 */
} USB_OTG_GlobalTypeDef;
cpp 复制代码
#define USB_OTG_FS_PERIPH_BASE               0x50000000U
cpp 复制代码
#define USB_OTG_FS          ((USB_OTG_GlobalTypeDef *)USB_OTG_FS_PERIPH_BASE)

其中第一个类型表示USB_OTG的寄存器组数据,第二个宏表示寄存器组首地址值,最终定义了一个宏"USB_OTG_FS"代表整个寄存器组的地址。到这里数据已经有了,而在HAL库的源文件"stm32f1xx_ll_usb.c"中定义的API函数的参数列表中都有USB_OTG_GlobalTypeDef *类型的参数。这样调用这些API函数的时候就实现了参数的传递,也就在函数内部实现了对寄存器组的控制。

cpp 复制代码
HAL_StatusTypeDef USB_CoreInit(USB_OTG_GlobalTypeDef *USBx, USB_OTG_CfgTypeDef cfg);
HAL_StatusTypeDef USB_EnableGlobalInt(USB_OTG_GlobalTypeDef *USBx);
HAL_StatusTypeDef USB_DisableGlobalInt(USB_OTG_GlobalTypeDef *USBx);
...
static HAL_StatusTypeDef USB_CoreReset(USB_OTG_GlobalTypeDef *USBx);

真正验证了"函数其实是一个数据处理器"这句话,而且更进一步"HAL库中API函数组其实是指针变间接处理同一个自定义结构体类型数据的数据处理器"。

在其他HAL库中也有相似的用法,所以我们需要做的就是定义这个结构体类型的数据(寄存器组已经定义了,无需定义,硬件上自然存在),然后在需要的时候,调用这些API函数完成参数传参。函数内部就自动完成对这些结构体类型数据的访问了,只不过是以指针间接访问的方式实现的。

真的很难想象,HAL库每一个源文件中少则十几个,多册几十个函数居然都是操作寄存器组,那可想而知,寄存器虽然没那么多,但是操作它的花样还是很多的,主要原因是每一个寄存器都有32bit,寄存器内部各个bit位代表不同硬件操作。

当然了,其他类似的自定义结构体类型是内存变量的情况,函数参数为自定义结构体类型指针变量,函数内部实现对自定义结构体变量内部成员的读写访问,一般不会涉及到位操作,只是简单内存变量的读写访问。

(2)关于架构的思想。

我现在有一个感受就是:我已经看了好多linux源码程序了,c语言的各种用法也都遇到过,熟悉了,为什么切换到STM32单片机的程序就感觉无从下手,不知道从哪里看呢?

我现在的答案是:缺乏架构思想,也就是那些源文件是在顶层,哪些顶层源文件中的函数调用底层源文件中的函数。

首先,最顶层的是唯一的main.c,因为其他函数都是从main.c中的main()开始调用的。

然后是adc.c、can.c、tim.c等STM32CUBEMX软件自动生成的外设源文件,每一个源文件中定义了第一条论述中的自定义结构体类型变量实体。然后调用API函数实现简单的初始化、去初始化等操作,让外设处于准备工作状态。这一层如果是复杂的外设例如USB、以太网等,可能需要调用一些协议栈,这就是我接下来要说的了

然后是协议栈,中间层、RTOS操作系统等这些纯软件的操作。这一层一般不涉及到硬件操作,具有一定可移植性。

最后,HAL库层(硬件抽象层),这一层是软件的最底层,主要就是操作寄存器组实现各个功能控制,主要用到了位运算。

再往下,就是硬件层了,属于纯数字电路、模拟电路等就不论述了。

注意:以上只是简单的说明,并不固定死的,也并不规定不能跨层访问,只是大致的分层等。到这里可能有人要问了,那业务功能层在那一层呢?我们都知道业务功能层是实现具体的客户需求,属于应用层的范畴,他应该在高于第二层或者与第二层平行的关系。因为应用层主要是实现客户需求功能会调用到中间层(去操纵内存变量,内存变量代表业务逻辑)、或者HAL库层(去操作寄存器)。

相关推荐
隔窗听雨眠1 天前
STM32/ESP32实战驱动的达林顿阵列高效复用指南
stm32·单片机·嵌入式硬件
XiYang-DING1 天前
【Java EE】TCP(Transmission Control Protocol)
单片机·tcp/ip·java-ee
北京盟通科技官方账号1 天前
工业 PC 平台 EtherCAT 主站协议栈选型探讨:开源方案与商业级实时架构的工程落地对比
架构·机器人·开源·工控·ethercat·盟通科技·ec-master
无心水1 天前
【分布式利器:金融级】金融级分布式架构开源框架全景解读
人工智能·分布式·金融·架构·开源·wpf·金融级框架
__log1 天前
NestJS vs Spring Boot:从架构哲学到实战选择的技术全景解析
spring boot·后端·架构·typescript
搬砖的小码农_Sky1 天前
AMD Ryzen AI Strix Halo架构处理器:如何在笔记本上跑通原本属于服务器的模型?
人工智能·架构·gpu算力
千匠网络1 天前
千匠网络制造行业渠道分销B2B解决方案:AI驱动,重构产业分销模式
网络·云原生·架构·制造业·b2b·电商解决方案
小短腿的代码世界1 天前
Qt属性系统揭秘:从Q_PROPERTY宏到动态元对象系统的完整架构解析
开发语言·qt·架构
bubiyoushang8881 天前
STM32L051 的 串口升级
stm32·单片机·嵌入式硬件
我叫张小白。1 天前
MySQL架构与SQL执行完全解析
sql·mysql·架构