三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

HAL库、标准库、LL库和寄存器开发有什么区别?STM32四种开发方式一次讲透

HAL库、标准库、LL库和寄存器开发有什么区别?STM32四种开发方式一次讲透

HAL库、标准库、LL库和寄存器开发有什么区别?STM32四种开发方式一次讲透

前言

学习 STM32 时,经常会看到完全不同风格的代码。

有的项目这样控制 GPIO:

HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);

有的项目却是:

GPIO_SetBits(GPIOA,GPIO_Pin_5);

还有一些代码写成:

LL_GPIO_SetOutputPin(GPIOA,LL_GPIO_PIN_5);

甚至还能看到:

GPIOA->BSRR=(1U<<5);

它们明明都是让 PA5 输出高电平,为什么写法完全不同?

实际上,这四种代码分别对应 STM32 常见的四种开发方式:

开发方式常见名称
STM32 HALHAL库
Standard Peripheral Library标准外设库 / 标准库 / SPL
Low-LayerLL库
Register Programming寄存器开发

这四种方式并不是四套完全不同的硬件。

它们最终操作的都是同一个 STM32 外设寄存器。

区别主要在于:

程序员与硬件寄存器之间隔了多少层封装。

可以把它们理解为:

应用程序 ↓ HAL库 ↓ LL库 / 标准库 ↓ CMSIS + 芯片寄存器定义 ↓ STM32硬件寄存器 ↓ GPIO / UART / SPI / ADC / TIM ...

当然,实际库之间并不是严格的逐级调用关系,例如 HAL 并不是所有函数都会调用 LL。

这张图更重要的是表达:

从 HAL 到寄存器开发,抽象程度逐渐降低,对硬件细节的控制能力逐渐提高。

本文就详细讲清楚:

  • HAL库是什么;
  • 标准库是什么;
  • LL库是什么;
  • 寄存器开发是什么;
  • 四种方式代码有什么区别;
  • 性能差距到底有多大;
  • 新项目应该选择哪一种;
  • HAL和LL能不能混合使用;
  • 为什么仍然要学习寄存器。

一、先理解:什么叫“库”

STM32的GPIO、UART、ADC、SPI等外设最终都是通过寄存器控制的。

例如 GPIO 外设中可能包含:

MODER OTYPER OSPEEDR PUPDR IDR ODR BSRR AFR

如果完全不用任何库,我们就需要自己写:

GPIOA->MODER&=~(3U<<(5U*2U));GPIOA->MODER|=(1U<<(5U*2U));GPIOA->BSRR=(1U<<5U);

这种方式最直接。

但是对于初学者来说,会立即遇到很多问题:

MODER为什么这样配置? 为什么左移10位? 为什么BSRR可以设置GPIO? GPIOA地址在哪里定义? GPIO时钟打开了吗? 不同型号寄存器是否一样?

为了降低开发难度,ST在寄存器之上封装了一系列函数。

于是我们就可以写:

HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);

而不需要每次自己计算寄存器位。

这就是库最重要的作用:

把复杂的底层寄存器操作封装成更加容易理解、复用和维护的接口。


二、HAL库是什么

HAL 的全称是:

Hardware Abstraction Layer

中文通常叫:

硬件抽象层

目前学习 STM32CubeMX、STM32CubeIDE 时,最常接触的就是 HAL。

例如:

HAL_GPIO_WritePin();HAL_UART_Transmit();HAL_UART_Receive();HAL_I2C_Master_Transmit();HAL_SPI_Transmit();HAL_ADC_Start();HAL_TIM_PWM_Start();

可以看到,HAL函数的命名方式比较统一。

基本形式类似:

HAL_外设_功能()

例如:

HAL_UART_Transmit();

看到名字基本就能猜出来:

使用UART发送数据

三、HAL库最大的特点是什么

HAL最核心的特点就是:

封装程度高。

例如发送串口数据:

uint8_tmessage[]="Hello STM32\r\n";HAL_UART_Transmit(&huart1,message,sizeof(message)-1U,100U);

程序员只需要关心:

用哪个UART? 发送哪个数组? 发送多少字节? 超时时间是多少?

而很多底层细节由HAL处理。

例如:

  • 检查外设状态;
  • 判断发送寄存器;
  • 等待标志位;
  • 管理UART句柄;
  • 更新HAL状态;
  • 处理超时;
  • 返回错误状态。

因此 HAL 非常适合快速开发。


四、HAL为什么经常和CubeMX一起使用

STM32CubeMX 可以自动生成大量HAL初始化代码。

例如配置 USART1 后,可能自动生成:

UART_HandleTypeDef huart1;staticvoidMX_USART1_UART_Init(void){huart1.Instance=USART1;huart1.Init.BaudRate=115200;huart1.Init.WordLength=UART_WORDLENGTH_8B;huart1.Init.StopBits=UART_STOPBITS_1;huart1.Init.Parity=UART_PARITY_NONE;huart1.Init.Mode=UART_MODE_TX_RX;huart1.Init.HwFlowCtl=UART_HWCONTROL_NONE;huart1.Init.OverSampling=UART_OVERSAMPLING_16;if(HAL_UART_Init(&huart1)!=HAL_OK){Error_Handler();}}

这也是 HAL 在现代 STM32 开发中非常常见的原因。

很多初始化工作不需要完全手写。

流程变成:

CubeMX配置图形界面 ↓ 生成HAL初始化代码 ↓ 编写自己的业务代码

对于项目开发效率提升非常明显。


五、HAL库的优点

HAL最明显的优势是开发效率。

例如操作GPIO:

HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);

很直观。

HAL的另一个优势是接口风格比较统一。

例如不同STM32系列中,经常仍然可以看到类似接口:

HAL_GPIO_WritePin();HAL_UART_Transmit();HAL_ADC_Start();

虽然不同系列的外设能力和 HAL 细节仍可能不同,但相对于直接操作寄存器,迁移工作通常更加容易。

因此HAL特别适合:

场景是否推荐
STM32初学非常推荐
快速做功能验证非常推荐
一般工业控制推荐
团队协作推荐
快速产品开发推荐
极限性能代码需要具体分析

六、HAL库有什么缺点

HAL的主要代价就是封装。

例如:

HAL_GPIO_WritePin();

内部不只是简单的一条寄存器赋值。

HAL通常还需要进行:

  • 参数判断;
  • 状态管理;
  • 函数调用;
  • 结构体访问;
  • 错误处理。

而直接寄存器操作可能只是:

GPIOA->BSRR=GPIO_PIN_5;

所以对于某些极高频率执行的代码,HAL的函数调用和抽象可能增加额外开销。

但这里有一个很常见的误区:

不能简单理解成“HAL性能差,所以实际项目不能用”。

实际系统性能瓶颈可能来自:

  • 外设本身的速度;
  • Flash等待;
  • 总线竞争;
  • DMA配置;
  • 中断设计;
  • 算法复杂度;
  • RTOS调度;
  • 缓冲区设计。

而不是HAL函数本身。

比如:

HAL_UART_Transmit(...);

如果串口只有115200 bit/s,真正占时间最多的是物理串口发送,而不是函数封装。

因此,是否需要从HAL优化到LL或寄存器,需要通过实际测量判断。


七、什么是标准库

标准库经常简称:

SPL

全称:

Standard Peripheral Library

中文通常叫:

STM32标准外设库

很多较早的STM32项目,特别是STM32F1项目,大量使用标准库。

例如GPIO操作:

GPIO_SetBits(GPIOA,GPIO_Pin_5);

GPIO复位:

GPIO_ResetBits(GPIOA,GPIO_Pin_5);

初始化:

GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);

这就是非常典型的STM32标准库风格。


八、标准库为什么很多老教程都在用

如果你搜索:

STM32F103教程 STM32标准库 STM32 GPIO STM32 USART

会发现很多早期教程都是这种代码:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

然后:

GPIO_Init(GPIOA,&GPIO_InitStructure);

这是因为在STM32早期开发生态中,SPL曾经非常流行。

它相比寄存器开发已经提供了较好的抽象,同时代码结构又比较贴近外设本身。

所以很多开发者觉得SPL有一种:

“没有HAL那么厚,又没有寄存器那么底层”

的感觉。


九、标准库的优点

标准库的特点可以概括为:

结构清晰 接口直接 比较贴近外设 历史资料丰富

例如:

USART_SendData(USART1,0x41);

含义很直接:

向USART1发送0x41

等待发送完成:

while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET){}

学习时也比较容易对应:

USART ↓ 数据寄存器 ↓ 状态标志

所以SPL对于理解STM32外设结构很有帮助。


十、标准库目前最大的限制

标准库最大的现实问题是:

它属于较早期的STM32软件生态,目前新系列开发通常以STM32Cube HAL/LL为主。

所以新项目如果使用较新的STM32系列,一般不会优先考虑SPL。

标准库现在更常见的场景是:

维护旧项目 学习STM32F1 阅读历史源码 接手以前的产品代码

因此不能简单说:

HAL一定比标准库好

而应该说:

新项目生态:HAL / LL更主流 旧项目维护:标准库仍然非常重要

十一、什么是LL库

LL全称:

Low-Layer

即:

底层库

LL属于STM32Cube软件生态的一部分。

它的定位可以简单理解为:

HAL ↓ 封装较高 LL ↓ 更接近寄存器 寄存器 ↓ 直接控制硬件

例如GPIO输出高电平:

LL_GPIO_SetOutputPin(GPIOA,LL_GPIO_PIN_5);

UART发送一个字节可能会使用类似:

LL_USART_TransmitData8(USART1,0x41);

然后判断标志:

while(LL_USART_IsActiveFlag_TC(USART1)==0){}

相比HAL:

HAL_UART_Transmit();

LL明显更加接近外设硬件逻辑。


十二、LL为什么比HAL更接近底层

例如HAL操作GPIO:

HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);

而LL:

LL_GPIO_SetOutputPin(GPIOA,LL_GPIO_PIN_5);

LL函数通常非常轻量,很多实现甚至可以直接映射到底层寄存器访问。

例如概念上可能类似:

GPIOA->BSRR=LL_GPIO_PIN_5;

因此它的函数调用链更短,也更容易看出:

这个函数最终操作哪个寄存器

十三、LL库的优点

LL主要优势是:

代码轻量 执行路径短 更接近寄存器 方便进行底层优化 同时保留ST官方支持

这使得LL特别适合:

  • 电机控制;
  • 高频定时器控制;
  • 高频GPIO操作;
  • 对中断延迟敏感的程序;
  • 对Flash和RAM敏感的项目;
  • 需要理解底层行为的开发。

十四、LL库的缺点

LL并没有HAL那么“省心”。

例如HAL可能直接给你:

HAL_UART_Transmit(&huart1,data,length,timeout);

而LL更可能需要自己组织:

判断TXE 写数据寄存器 更新发送下标 继续发送 等待TC

因此需要开发者更清楚:

  • USART状态机;
  • 标志位意义;
  • 中断工作流程;
  • 外设寄存器;
  • 时序要求。

所以LL的学习门槛通常高于HAL。


十五、什么是寄存器开发

寄存器开发是最直接的一种方式。

不使用高级封装函数,而是直接修改硬件寄存器。

例如让GPIOA Pin5输出高电平:

GPIOA->BSRR=(1U<<5U);

配置GPIO模式可能是:

GPIOA->MODER&=~(3U<<(5U*2U));GPIOA->MODER|=(1U<<(5U*2U));

此时你必须真正知道:

MODER是什么? GPIO5对应哪两位? 01表示什么模式? BSRR为什么可以置位?

也就是说:

寄存器开发没有高级库帮你隐藏硬件细节。


十六、寄存器开发到底有多底层

实际上即使写:

GPIOA->BSRR=(1U<<5U);

也并不是完全脱离软件库。

GPIOA和寄存器结构体通常来自芯片设备头文件,例如CMSIS Device部分。

概念上可能有:

typedefstruct{volatileuint32_tMODER;volatileuint32_tOTYPER;volatileuint32_tOSPEEDR;volatileuint32_tPUPDR;volatileuint32_tIDR;volatileuint32_tODR;volatileuint32_tBSRR;}GPIO_TypeDef;

然后:

#defineGPIOA((GPIO_TypeDef*)GPIOA_BASE)

所以所谓寄存器开发通常是:

使用芯片官方头文件提供的寄存器结构定义,直接访问外设寄存器。


十七、寄存器开发的优势

最大的优势就是:

控制非常直接

你明确知道每一条语句修改哪个寄存器。

例如:

GPIOA->BSRR=(1U<<5U);

就是直接操作BSRR。

执行效率高

没有复杂的软件层。

方便学习硬件本质

你会真正理解:

RCC如何开时钟 GPIO模式怎么配置 UART波特率寄存器怎么计算 ADC为什么需要采样时间 TIM为什么需要PSC和ARR

方便极限优化

在性能敏感场景中,可以直接按照硬件能力组织代码。


十八、寄存器开发的缺点

寄存器开发最大的问题不是“难写”,而是:

整个工程的软件复杂度会快速上升。

例如一个GPIO还比较简单。

但如果你直接用寄存器完成:

USB Ethernet SDMMC 复杂DMA 高级定时器 FDCAN LTDC

代码量和调试难度会迅速增加。

另外不同STM32系列之间寄存器结构可能差异明显。

比如:

STM32F1 GPIO

和:

STM32F4 GPIO

寄存器配置方式就存在明显不同。

因此直接寄存器开发的移植成本通常更高。


十九、用同一个GPIO例子比较四种写法

假设目标:

将PA5置为高电平。

HAL

HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);

特点:

最容易理解

标准库

GPIO_SetBits(GPIOA,GPIO_Pin_5);

特点:

接口清晰 比HAL更加直接

LL

LL_GPIO_SetOutputPin(GPIOA,LL_GPIO_PIN_5);

特点:

轻量 接近寄存器

寄存器

GPIOA->BSRR=(1U<<5U);

特点:

最直接

从代码风格可以明显看到:

HAL ↓ SPL ↓ LL ↓ 寄存器

硬件抽象逐渐减少。


二十、再比较一个UART发送

假设要发送字符:

'A'

ASCII:

0x41

HAL写法

uint8_tdata='A';HAL_UART_Transmit(&huart1,&data,1U,100U);

开发者几乎不需要关心UART内部寄存器。


标准库写法

USART_SendData(USART1,0x41);while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET){}

已经能明显看到:

发送数据 ↓ 检查TC

LL写法

不同系列接口会有所差异,概念上类似:

LL_USART_TransmitData8(USART1,0x41);while(LL_USART_IsActiveFlag_TC(USART1)==0){}

寄存器写法

不同STM32系列UART寄存器名称可能不同。

某些较老系列的概念代码类似:

USART1->DR=0x41;while((USART1->SR&USART_SR_TC)==0U){}

而较新的系列可能使用:

TDR ISR

等寄存器。

这正好体现了:

寄存器开发与具体芯片绑定得最紧。


二十一、四种方式的核心区别

可以用下面这张表快速理解:

项目HAL标准库LL寄存器
抽象程度最高较高较低最低
上手难度最低中等较高最高
开发速度较快中等
代码量通常较多中等较少可很少
底层控制较弱中等最强
可读性较高中等看开发者水平
移植便利性较好一般一般较差
官方现代生态老项目为主始终可用
适合初学很适合可以进阶深入学习

二十二、HAL是不是一定比LL慢

这是一个需要谨慎理解的问题。

不能简单地说:

HAL一定慢 LL一定快

更准确的说法是:

LL和寄存器通常具有更短、更直接的执行路径,因此更容易进行极限性能优化。

例如GPIO快速翻转:

GPIOA->BSRR=GPIO_PIN_5;

确实可能比:

HAL_GPIO_WritePin(...);

更轻量。

但是如果发送一个UART数据包:

UART物理传输耗时 = 几毫秒

而HAL函数多花:

几十或几百个CPU周期

整个系统未必有明显区别。

所以工程优化不能靠感觉。

应该:

先测试 ↓ 找到瓶颈 ↓ 只优化真正耗时的地方

二十三、HAL占用Flash一定很大吗

HAL通常会引入比直接寄存器更多的代码。

但实际最终固件大小还受到:

编译优化等级 链接器垃圾回收 实际调用函数 Debug / Release 库配置 芯片系列

影响。

现代编译器会删除大量没有被引用的函数。

因此不能看到完整HAL源码很多,就直接认为:

整个HAL都会被编译进最终固件。

真正应该看的是:

最终.map文件 Flash Usage RAM Usage

二十四、HAL和LL可以同时用吗

可以,而且这是非常实用的工程方式。

例如:

系统初始化 → HAL UART协议 → HAL + DMA 普通GPIO → HAL 高速GPIO → LL 高频中断 → LL/寄存器 复杂USB → HAL

也就是说,不一定要:

整个项目全部HAL

或者:

整个项目全部寄存器

完全可以采用:

大部分使用HAL,提高开发效率;性能敏感区域使用LL或寄存器优化。

这是非常典型的工程思路。


二十五、HAL和LL混用需要注意什么

虽然可以混用,但不能毫无规则。

例如HAL内部会维护:

Handle状态 Lock状态 ErrorCode DMA状态

如果你绕开HAL,直接修改HAL正在管理的外设寄存器,有可能让:

HAL的软件状态

和:

真实硬件状态

不一致。

例如HAL认为:

UART正在Busy

但你直接修改寄存器关闭了UART。

后续HAL调用就可能出现异常。

因此建议:

可以混用,但必须明确每个外设由谁负责管理。


二十六、为什么学习HAL之后仍然建议看寄存器

即使实际项目一直使用HAL,也非常建议学习寄存器。

因为HAL只是:

实现方法

寄存器和Reference Manual才能告诉你:

硬件为什么这样工作

例如I2C一直BUSY。

如果只会HAL,可能只看到:

HAL_BUSY

但如果理解寄存器,就会继续检查:

BUSY STOPF TXIS RXNE NACKF

同样,UART出现错误,可以继续检查:

ORE FE NE PE

ADC异常可以检查:

EOC OVR ADRDY

所以:

HAL帮助你快速完成项目,寄存器知识帮助你真正解决难问题。


二十七、为什么标准库仍然值得学习

虽然新STM32项目通常不再以SPL作为首选,但它仍然有学习价值。

因为很多经典项目和教程都是标准库。

例如你接手一个老项目,看到:

GPIO_Init();USART_Init();TIM_TimeBaseInit();NVIC_Init();

如果完全不了解标准库,就很难阅读。

所以SPL现在更像:

STM32历史生态必须读懂的一种语言

特别是在:

STM32F103 经典工业产品 早期开源项目 旧版Keil工程

中仍然非常常见。


二十八、四种方式分别适合什么人

HAL

适合:

STM32初学者 应用开发工程师 快速产品开发 复杂项目团队

重点是:

先把功能做出来

标准库

适合:

维护STM32老项目 学习经典F1教程 阅读历史源码

LL

适合:

已经掌握HAL 对性能有要求 希望深入理解底层 需要优化中断或外设操作

寄存器

适合:

深入理解MCU 底层驱动开发 极限性能优化 特殊时序 Bootloader 面试底层能力提升

二十九、不同项目应该怎么选

可以按需求判断。

项目推荐方式
STM32入门学习HAL
普通工业控制HAL
RS485/ModbusHAL或HAL+LL
普通传感器采集HAL
快速产品原型HAL
维护STM32F1旧项目SPL
高频GPIOLL/寄存器
电机控制HAL+LL或LL
高频定时中断LL/寄存器
BootloaderHAL/LL/寄存器均可能
极小Flash项目LL/寄存器
学习底层原理寄存器
大型团队项目通常优先HAL及规范化封装

三十、初学者最容易犯的错误

一个常见问题是:

刚开始学STM32,就觉得“HAL太低级,我必须直接学寄存器”。

实际上这通常会严重降低学习效率。

因为初学STM32需要同时理解:

C语言 GPIO 时钟 中断 UART 定时器 ADC I2C SPI DMA

如果每一项还要同时研究全部寄存器位,很容易把注意力全部耗在配置细节上。

更推荐:

先HAL完成功能 ↓ 理解外设工作流程 ↓ 查看HAL底层实现 ↓ 学习LL ↓ 阅读Reference Manual ↓ 自己写寄存器

这样学习曲线更加平滑。


三十一、推荐学习路线

第一阶段,使用HAL。

目标是:

会使用GPIO 会UART 会ADC 会定时器 会PWM 会I2C 会SPI 会DMA

第二阶段,开始看标准库老代码。

重点不是专门重新学习一遍所有SPL API,而是做到:

看到SPL代码能读懂

第三阶段,学习LL。

例如把:

HAL_GPIO_WritePin();

改成:

LL_GPIO_SetOutputPin();

然后逐渐学习:

UART LL TIM LL DMA LL ADC LL

第四阶段,打开Reference Manual。

真正理解:

RCC GPIO USART TIM ADC DMA

对应寄存器。

第五阶段,尝试自己写底层驱动。

例如:

寄存器点灯 寄存器UART发送 寄存器定时器 寄存器PWM 寄存器ADC

这时候你会发现:

HAL、LL和寄存器其实并不是三套完全不同的知识,它们只是在不同抽象层描述同一个硬件。


三十二、真正优秀的工程师应该会哪一种

并不是“只会寄存器”才叫高手。

真正重要的是:

能根据项目需要选择合适的抽象层。

例如一个复杂项目包含:

USB 以太网 ADC PWM UART GPIO FreeRTOS

完全寄存器开发可能带来巨大的维护成本。

更加合理的方案可能是:

USB → HAL Ethernet → HAL UART → HAL + DMA 普通GPIO → HAL 高速PWM控制 → LL 关键中断 → 寄存器

这就是工程上的权衡。


三十三、不要为了“底层”而底层

嵌入式开发中经常出现一种误区:

寄存器最底层 ↓ 所以寄存器一定最好

实际上完全不成立。

如果项目目标是:

3个月内完成产品 多人协作 后续维护5年

那么开发效率和可维护性可能远比节省几十条指令重要。

反过来,如果项目是:

20kHz电机控制环 亚微秒级GPIO时序 极小Flash MCU 高频中断

那么LL或者寄存器就非常有价值。

所以开发方式的选择,本质上是一个工程权衡问题。


三十四、一句话理解四种开发方式

可以这样记忆:

HAL 像使用完整工具箱。 工具已经准备好,拿来就用。 标准库 像模块化零件盒。 结构清晰,需要自己组合。 LL 像轻量工具。 保留便利,同时更加接近底层。 寄存器 像自己拿扳手直接拧螺丝。 最灵活,但最考验经验。

三十五、最终对比

从抽象程度看:

HAL ↓ 标准库 ↓ LL ↓ 寄存器 越来越接近硬件

从开发效率看,通常可以粗略理解为:

HAL > 标准库 > LL > 寄存器

从底层控制能力看:

寄存器 > LL > 标准库 > HAL

从学习难度看:

HAL < 标准库 < LL < 寄存器

但这些只是一般趋势。

实际情况还与:

芯片系列 外设类型 编译器优化 代码设计 开发人员能力

有关。


三十六、面试中怎么回答

如果面试官问:

HAL、LL和寄存器开发有什么区别?

可以回答:

它们最终都是控制STM32硬件外设, 区别主要在于软件抽象层级。 HAL是ST提供的高层硬件抽象库, 封装程度较高,接口统一,开发速度快, 适合快速开发和大多数应用项目。 LL是STM32Cube中的Low Layer底层库, 相比HAL更加接近寄存器, 函数更加轻量,执行路径更直接, 适合性能敏感或者需要更多底层控制的场景。 寄存器开发则直接操作外设寄存器, 控制最灵活,也最有利于理解硬件工作原理, 但是开发和维护成本较高,可移植性也较差。 实际工程中并不是必须三选一, 可以使用HAL完成大部分功能, 在性能关键部分使用LL或寄存器优化。

如果继续问:

标准库呢?

可以回答:

标准库也就是SPL,是STM32早期非常常用的 Standard Peripheral Library。 它的抽象程度通常介于HAL和寄存器之间, 接口比较清晰,在STM32F1等老项目中很常见。 但现在新的STM32系列主要使用STM32Cube生态, 因此新项目通常优先考虑HAL和LL, 标准库更多用于维护和阅读历史项目。

三十七、总结

HAL、标准库、LL和寄存器开发,并不是四种完全不同的STM32。

它们控制的是同一个硬件。

真正区别是:

程序员距离硬件有多远。

HAL:

抽象高 开发快 容易维护 适合绝大多数应用开发

标准库:

结构清晰 贴近传统STM32外设开发 适合旧项目和历史代码

LL:

代码轻量 性能较好 更加接近底层 适合性能敏感场景

寄存器:

控制最直接 灵活性最高 最能理解硬件 但开发和维护成本最高

对于大多数刚学习STM32的人,推荐路线是:

HAL ↓ 理解外设 ↓ 阅读LL和HAL源码 ↓ Reference Manual ↓ 寄存器开发

而不是一开始就追求全部寄存器。

最后用一句话总结:

HAL让你快速把项目做出来,LL让你更接近硬件并提高控制效率,而寄存器知识则让你真正理解STM32为什么这样工作。标准库则是理解大量经典STM32老项目的重要桥梁。

没有绝对最好的开发方式。

只有:

最适合当前项目性能、开发周期、团队能力和维护需求的开发方式。

← 返回列表