标准外设库与HAL库有什么区别?都怎样去使用?如何区分?

一、核心区别

先通过核心特征对比,帮你建立 "一眼识别" 的基础,这也是区分两者的核心依据:

核心维度 标准外设库 (SPL) HAL 库 (Hardware Abstraction Layer)
命名风格 函数名短,无统一前缀(如GPIO_SetBitsUSART_SendData 所有函数以HAL_开头,命名冗长且格式统一(如HAL_GPIO_WritePinHAL_UART_Transmit
芯片支持 仅支持 F1/F4 等老系列,无官方更新 支持全系列 STM32(F0/F1/F4/L4/H7 等),持续更新
核心设计 寄存器级封装,直接操作寄存器 抽象层封装,屏蔽寄存器差异,跨系列兼容
配套工具 无官方图形化工具,纯手动写代码 配套 STM32CubeMX 图形化配置,自动生成代码
状态 / 返回值 函数无统一返回值(多为 void) 几乎所有函数返回HAL_StatusTypeDef枚举(如HAL_OKHAL_ERROR
中断处理 手动编写中断服务函数,无回调机制 内置回调函数(如HAL_UART_RxCpltCallback),中断逻辑更规范

二、使用方法(极简实操版)

1. 标准外设库 (SPL) 的使用(仅老项目 / 学习底层)

SPL 已被 ST 废弃,仅适合理解寄存器原理,核心是 "手动配置寄存器 + 调用外设函数":

核心步骤:
  1. 下载对应芯片的 SPL 包(如 F103 的STM32F10x_StdPeriph_Lib_V3.5.0);
  2. 引入核心头文件(stm32f10x.h)和外设文件(如stm32f10x_gpio.c);
  3. 手动配置时钟→初始化外设→调用外设函数。
极简示例(GPIO 翻转):
复制代码
#include "stm32f10x.h"
void GPIO_Init_PA0(void) {
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能时钟
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
}
int main(void) {
    GPIO_Init_PA0();
    while(1) {
        GPIO_SetBits(GPIOA, GPIO_Pin_0);   // 无HAL前缀,短函数名
        for(int i=0; i<1000000; i++);
        GPIO_ResetBits(GPIOA, GPIO_Pin_0);
        for(int i=0; i<1000000; i++);
    }
}
2. HAL 库的使用(当前主流)

HAL 库的核心是 "图形化配置 + 自动生成代码 + 调用 HAL 前缀函数",效率远高于 SPL:

核心步骤:
  1. 安装 STM32CubeMX(图形化工具),选择对应芯片;
  2. 图形化配置外设(如 GPIO、UART),设置时钟、引脚功能;
  3. 生成工程代码(支持 Keil/STM32CubeIDE 等);
  4. 在生成的代码中调用HAL_前缀函数。
极简示例(同功能 GPIO 翻转):
复制代码
#include "main.h"
GPIO_InitTypeDef GPIO_InitStruct;

int main(void) {
    // 自动生成的初始化代码(CubeMX生成)
    HAL_Init();                     // HAL库初始化
    SystemClock_Config();           // 时钟配置(CubeMX生成)
    __HAL_RCC_GPIOA_CLK_ENABLE();   // 使能GPIOA时钟(HAL封装)
    
    // GPIO初始化
    GPIO_InitStruct.Pin = GPIO_PIN_0;          // 注意:PIN大写,带下划线
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);    // HAL前缀函数
    
    while(1) {
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);  // HAL前缀
        HAL_Delay(500);                                      // HAL自带延时
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);
        HAL_Delay(500);
    }
}

三、如何快速区分两者?(实操技巧)

拿到一段 STM32 代码,按以下步骤 10 秒内就能区分:

  1. 看函数前缀 :有HAL_(如HAL_GPIO_WritePin)→ HAL 库;无统一前缀(如GPIO_SetBits)→ SPL;
  2. 看引脚定义 :用GPIO_PIN_0(大写 + 下划线)→ HAL 库;用GPIO_Pin_0(小写 Pin)→ SPL;
  3. 看返回值 / 状态 :函数返回HAL_StatusTypeDef(如HAL_OK)→ HAL 库;函数多为 void→ SPL;
  4. 看工程文件 :包含stm32xxx_hal.c/h(如stm32f1xx_hal_gpio.c)→ HAL 库;包含stm32xxx_stdperiph.c/h→ SPL;
  5. 看配套工具痕迹 :工程中有CubeMX生成的注释(如/* USER CODE BEGIN */)→ HAL 库;纯手动编写无此类注释→ SPL。

四、总结

  1. 核心区分点 :HAL 库所有函数带HAL_前缀,SPL 无统一前缀;HAL 库用GPIO_PIN_0,SPL 用GPIO_Pin_0
  2. 使用选择:新项目优先用 HAL 库(CubeMX + 自动生成代码,效率高),仅学习底层时用 SPL;
  3. 关键特征:HAL 库跨系列兼容、有回调函数、配套图形化工具;SPL 轻量高效但仅支持老芯片、无官方更新。
相关推荐
czhaii9 小时前
8051U深度入门到32位51大型实战
单片机
Hans_Rudle9 小时前
在香橙派(昇腾NPU)(kunpengpro/aipro)上部署自己的模型 -以Unet为例
嵌入式硬件·香橙派
boneStudent9 小时前
Day28:I2C 配置与使用
stm32·单片机·嵌入式硬件
法号:行颠10 小时前
Chaos-nano协作式异步操作系统(六):`Chaos-nano` 在手持式 `VOC` 检测设备上的应用
c语言·单片机·嵌入式硬件·mcu·系统架构
XINVRY-FPGA11 小时前
XC7Z030-2SBG485I Xilinx Zynq-7000 系列 SoC FPGA
嵌入式硬件·fpga开发·硬件工程·fpga
xiaohai@Linux12 小时前
LVGL显示gif动图导致MCU进入HardFault_Handler问题(已解决!)
单片机·lvgl
czhaii12 小时前
并口LCD1602用DMA刷屏
单片机·嵌入式硬件·硬件工程
离凌寒13 小时前
二、在freertos中对应esp01s模块的ap模式下的通信测试。
单片机·freertos·esp01s
CFZPL13 小时前
esp32,stm32编译的不同
单片机·esp32