你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32选择SPL库,还是HAL库开发?

[复制链接]
flyingstar 发布时间:2025-10-16 16:33
从寄存器操作到硬件抽象层:STM32开发库的演进。
演进历程
STM32微控制器自2007年推出以来,STMicroelectronics为其提供了多套软件开发库,经历了从直接寄存器操作到高度抽象化的演进过程:
发展时间线
  • 2007-2010: 标准外设库(SPL)时代
  • 2013-2015: HAL库引入,SPL逐步淘汰
  • 2016-至今: HAL + LL双轨制,CubeMX工具链完善
当前状态
  • SPL: 已停止维护,支持F0/F1/F2/F3/F4系列
  • HAL: ST官方主推,持续更新维护
  • LL: 作为HAL的补充,提供更接近硬件的接口
三大库架构对比特性标准外设库(SPL)HAL库LL库
抽象层次中等高低
代码体积中等大小
执行效率高中等高
学习难度中等低高
可移植性低高中等
维护状态已停止活跃活跃
工具支持无CubeMXCubeMX标准外设库(SPL)设计理念
SPL采用"一个外设一个文件"的设计理念,每个外设都有对应的.c和.h文件,提供中等层次的抽象。
核心特点// SPL典型用法示例
void GPIO_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
   
    // 使能GPIO时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
   
    // 配置GPIO
    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);
}优势
  • 1. 性能优异: 直接操作寄存器,执行效率高
  • 2. 代码紧凑: 相比HAL库,代码体积更小
  • 3. 逻辑清晰: 一个函数完成一个功能,易于理解
  • 4. 调试友好: 可以直接查看寄存器状态
劣势
  • 1. 维护停止: 不再支持新系列MCU
  • 2. 移植困难: 不同系列间API差异较大
  • 3. 工具支持差: 无现代IDE集成支持
  • 4. 文档过时: 缺乏最新的技术文档
HAL库设计理念
HAL库采用"硬件抽象层"设计,旨在提供跨系列的统一API接口,隐藏硬件细节。
核心特点// HAL库典型用法示例
void GPIO_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
   
    // 使能GPIO时钟
    __HAL_RCC_GPIOA_CLK_ENABLE();
   
    // 配置GPIO
    GPIO_InitStruct.Pin = GPIO_PIN_5;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}架构优势
  • 1. 统一接口: 跨系列API一致性
  • 2. 工具集成: 与CubeMX深度集成
  • 3. 功能丰富: 支持复杂外设如USB、以太网
  • 4. 持续维护: 定期更新和bug修复
劣势
  • 1. 代码膨胀: 大量抽象层导致代码体积大
  • 2. 执行开销: 多层函数调用影响性能
  • 3. 内存消耗: 需要更多RAM存储状态信息
  • 4. 调试复杂: 抽象层增加调试难度
LL库(低层库)设计理念
LL库是HAL库的补充,提供更接近硬件的接口,同时保持一定的可移植性。
核心特点// LL库典型用法示例
void GPIO_Config(void)
{
    // 使能GPIO时钟
    LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
   
    // 配置GPIO
    LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_5, LL_GPIO_MODE_OUTPUT);
    LL_GPIO_SetPinOutputType(GPIOA, LL_GPIO_PIN_5, LL_GPIO_OUTPUT_PUSHPULL);
    LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_5, LL_GPIO_SPEED_FREQ_HIGH);
}优势
  • 1. 性能接近寄存器: 大部分函数被内联优化
  • 2. 代码体积小: 相比HAL库显著减少
  • 3. 可读性好: 函数名自解释,代码更清晰
  • 4. 工具支持: 与CubeMX集成
适用场景
  • • 对性能有较高要求的应用
  • • 资源受限的MCU
  • • 需要精确控制时序的场景
  • • 从SPL迁移的项目
实际代码示例对比UART配置与使用对比SPL方式void UART_Config(void)
{
    USART_InitTypeDef USART_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
   
    // 使能时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
   
    // 配置GPIO
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;  // TX
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
   
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // RX
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
   
    // 配置UART
    USART_InitStructure.USART_BaudRate = 115200;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(USART1, &USART_InitStructure);
   
    USART_Cmd(USART1, ENABLE);
}

voidUART_SendString(char* str)
{
    while(*str) {
        while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
        USART_SendData(USART1, *str++);
    }
}HAL方式void UART_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
   
    // 使能时钟
    __HAL_RCC_USART1_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();
   
    // 配置GPIO
    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
   
    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
   
    // 配置UART
    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;
    HAL_UART_Init(&huart1);
}

voidUART_SendString(char* str)
{
    HAL_UART_Transmit(&huart1, (uint8_t*)str, strlen(str), HAL_MAX_DELAY);
}LL方式void UART_Config(void)
{
    // 使能时钟
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1);
    LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
   
    // 配置GPIO
    LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_9, LL_GPIO_MODE_ALTERNATE);
    LL_GPIO_SetAFPin_0_7(GPIOA, LL_GPIO_PIN_9, LL_GPIO_AF_7);
    LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_9, LL_GPIO_SPEED_FREQ_HIGH);
   
    LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_10, LL_GPIO_MODE_ALTERNATE);
    LL_GPIO_SetAFPin_8_15(GPIOA, LL_GPIO_PIN_10, LL_GPIO_AF_7);
   
    // 配置UART
    LL_USART_SetBaudRate(USART1, 115200);
    LL_USART_SetDataWidth(USART1, LL_USART_DATAWIDTH_8B);
    LL_USART_SetStopBitsLength(USART1, LL_USART_STOPBITS_1);
    LL_USART_SetParity(USART1, LL_USART_PARITY_NONE);
    LL_USART_SetTransferDirection(USART1, LL_USART_DIRECTION_TX_RX);
    LL_USART_Enable(USART1);
}

voidUART_SendString(char* str)
{
    while(*str) {
        while(!LL_USART_IsActiveFlag_TXE(USART1));
        LL_USART_TransmitData8(USART1, *str++);
    }
}


收藏 评论0 发布时间:2025-10-16 16:33

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版