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

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

[复制链接]
flyingstar 发布时间:2025-10-16 16:33
从寄存器操作到硬件抽象层:STM32开发库的演进。
演进历程
STM32微控制器自2007年推出以来,STMicroelectronics为其提供了多套软件开发库,经历了从直接寄存器操作到高度抽象化的演进过程:
发展时间线
  • • 2007-2010: 标准外设库(SPL)时代
  • • 2013-2015: HAL库引入,SPL逐步淘汰
  • • 2016-至今: HAL + LL双轨制,CubeMX工具链完善7 S& r  G; q+ @9 t
当前状态
  • • SPL: 已停止维护,支持F0/F1/F2/F3/F4系列
  • • HAL: ST官方主推,持续更新维护
  • • LL: 作为HAL的补充,提供更接近硬件的接口
    7 y4 V6 C1 t7 ^8 w% U
三大库架构对比特性标准外设库(SPL)HAL库LL库: P; }* e/ p0 m" V& b& T( O
抽象层次中等高低8 \/ ~$ _" m' U0 @
代码体积中等大小3 z5 u9 r6 K" A
执行效率高中等高  I" y4 E! G! ~( h, c
学习难度中等低高
  X8 r3 ^6 k* ~# T5 q7 A1 c可移植性低高中等0 W$ L0 v- @9 q( F0 T% f
维护状态已停止活跃活跃6 @# ^7 S' o7 G: r+ ~
工具支持无CubeMXCubeMX标准外设库(SPL)设计理念
SPL采用"一个外设一个文件"的设计理念,每个外设都有对应的.c和.h文件,提供中等层次的抽象。
核心特点// SPL典型用法示例. F* h+ _& Z  f0 ?4 x
void GPIO_Config(void)7 E) J' _! v  G: F% g
{
6 s# v+ L" J5 k1 `3 B    GPIO_InitTypeDef GPIO_InitStructure;8 q0 E1 d% X/ G
   
; H6 K$ M+ ]7 e9 g) w6 R    // 使能GPIO时钟
6 t, L3 D5 _5 r0 }- K    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);3 ?: f. @7 |! \
    . R3 G% E7 M$ }
    // 配置GPIO
# i% e6 e! W$ l1 @- F8 e5 W    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;: b  n: V" [+ R. a
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;+ B1 C2 X* y* c# @
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;4 _, ~; A( s6 m
    GPIO_Init(GPIOA, &GPIO_InitStructure);& N* l- h& `  v0 C- J
}优势
  • 1. 性能优异: 直接操作寄存器,执行效率高
  • 2. 代码紧凑: 相比HAL库,代码体积更小
  • 3. 逻辑清晰: 一个函数完成一个功能,易于理解
  • 4. 调试友好: 可以直接查看寄存器状态# k# M8 b  v) Z& t
劣势
  • 1. 维护停止: 不再支持新系列MCU
  • 2. 移植困难: 不同系列间API差异较大
  • 3. 工具支持差: 无现代IDE集成支持
  • 4. 文档过时: 缺乏最新的技术文档$ e* H+ F, i" E, k* e0 t  @
HAL库设计理念
HAL库采用"硬件抽象层"设计,旨在提供跨系列的统一API接口,隐藏硬件细节。
核心特点// HAL库典型用法示例7 I4 _& N! A: H% t0 N$ ]
void GPIO_Config(void). R, W) e& L# Q5 ]# A
{
+ u% [" a# [! a& F- w    GPIO_InitTypeDef GPIO_InitStruct = {0};
4 m2 |0 u5 t) `, `& D4 c5 K$ E6 y   
4 ]( D$ I/ |8 Y  s' v    // 使能GPIO时钟* O0 T8 A- h2 _7 r6 w; A8 S
    __HAL_RCC_GPIOA_CLK_ENABLE();/ C" l6 q" \* Z8 }
   
# p9 Q! F5 q$ c4 ?7 p* @4 K, a    // 配置GPIO
" I# g! X. \6 V8 m6 o" E' [    GPIO_InitStruct.Pin = GPIO_PIN_5;* g( |/ T: l9 B/ h! f2 Y
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;" l9 u  d3 }1 _0 K+ ^
    GPIO_InitStruct.Pull = GPIO_NOPULL;' X) z9 X0 Q% C2 h6 d3 z& H
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;  L9 H8 z8 j7 ?: x; m8 B/ ~
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);- Q$ Z$ [/ ~+ ~$ Y6 L
}架构优势
  • 1. 统一接口: 跨系列API一致性
  • 2. 工具集成: 与CubeMX深度集成
  • 3. 功能丰富: 支持复杂外设如USB、以太网
  • 4. 持续维护: 定期更新和bug修复
    * ^3 ^1 x" k5 f1 U; f0 X9 e7 a
劣势
  • 1. 代码膨胀: 大量抽象层导致代码体积大
  • 2. 执行开销: 多层函数调用影响性能
  • 3. 内存消耗: 需要更多RAM存储状态信息
  • 4. 调试复杂: 抽象层增加调试难度- a, y5 a- T+ A# }( G
LL库(低层库)设计理念
LL库是HAL库的补充,提供更接近硬件的接口,同时保持一定的可移植性。
核心特点// LL库典型用法示例/ F8 M$ X9 x2 f! @
void GPIO_Config(void)
, v; @4 E! h3 _3 G9 ]{7 ]9 |$ S$ ^. k, ^& }7 ?4 t
    // 使能GPIO时钟1 H* h& M* V( B4 ?9 o  y7 C+ F+ e& }
    LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);" _. y7 A5 C9 U
   
9 i4 }) n( C$ `+ w7 i0 I    // 配置GPIO
- I4 n7 |1 J8 M1 c1 Q* E9 _    LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_5, LL_GPIO_MODE_OUTPUT);
1 \; ]- s3 x4 U  `" l    LL_GPIO_SetPinOutputType(GPIOA, LL_GPIO_PIN_5, LL_GPIO_OUTPUT_PUSHPULL);
+ R- x+ J( a0 ^1 ?    LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_5, LL_GPIO_SPEED_FREQ_HIGH);
" y* v; b  Y# _# |8 i}优势
  • 1. 性能接近寄存器: 大部分函数被内联优化
  • 2. 代码体积小: 相比HAL库显著减少
  • 3. 可读性好: 函数名自解释,代码更清晰
  • 4. 工具支持: 与CubeMX集成3 R6 g3 Z  b7 t5 X
适用场景
  • • 对性能有较高要求的应用
  • • 资源受限的MCU
  • • 需要精确控制时序的场景
  • • 从SPL迁移的项目
    2 h, r* m' U. `8 O
实际代码示例对比UART配置与使用对比SPL方式void UART_Config(void)
) K3 a. ^" z/ r2 U  G. z{( k, U1 q' e% ^  ~' Q( u8 U% Y& ~
    USART_InitTypeDef USART_InitStructure;
) z& E# \. A8 m" A0 f    GPIO_InitTypeDef GPIO_InitStructure;
" x; l5 y5 k: a" V& `* z, t1 }/ C3 M   
4 f4 p: ^0 y1 k/ D2 l3 P: h* _  U) Y1 Y% U    // 使能时钟
2 m2 `! U7 ]" c3 R9 w/ s    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
  Q6 [! e: c% |$ u) c9 D/ `    , ^8 D  O! V0 n0 L7 h/ ^" r+ a( d
    // 配置GPIO
5 f% z9 ~* Y: }; E( k( f    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;  // TX
3 d1 f2 s% o/ a5 T    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
3 m3 d' }; ~, `1 l; F. M    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
1 B& L" f# ?( `3 I; u, M7 l    GPIO_Init(GPIOA, &GPIO_InitStructure);
% ^5 [& J" |: Q( R! B    3 O8 t# o3 l6 n# u3 F
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // RX3 t) T, w+ }  k6 X, F
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
4 X' y+ p  H0 k. Z% \    GPIO_Init(GPIOA, &GPIO_InitStructure);9 p1 P+ C  F, y% c# n
    . S2 D; }" s# D, ^9 v0 L& w* T
    // 配置UART
! a: U; c2 l( T1 [2 C  \    USART_InitStructure.USART_BaudRate = 115200;
. I# h3 K, M% G* k6 |7 [& v    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
# r# P" `. _: z5 W; ?    USART_InitStructure.USART_StopBits = USART_StopBits_1;3 x- L) |$ S# P
    USART_InitStructure.USART_Parity = USART_Parity_No;- r  ^% G( E; e# q5 b
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;: w1 u! Q: A; o5 o2 W
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
. N' E% k" K6 w4 C1 ?" J: k    USART_Init(USART1, &USART_InitStructure);" I# X$ W6 s, `0 S1 U7 u$ S
   
8 G: |- S8 K5 I6 b. |, C5 N    USART_Cmd(USART1, ENABLE);
8 ]4 J/ P, L( I- d- f}
6 S$ J. b) p/ `; M) a3 c/ x7 ?, [2 U- L9 i0 y
voidUART_SendString(char* str)
: u+ m$ S/ F- _, d/ X& y{* ]/ b" K2 W: ?7 Q
    while(*str) {3 ^3 f0 S! \) t* E5 q0 g$ E
        while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);4 T' v& z4 r7 o# P7 j3 C
        USART_SendData(USART1, *str++);8 V: ~* I' n% x' E; ?# Q
    }. n1 U. Q" _2 A- S0 c0 _7 W# w
}HAL方式void UART_Config(void)
9 m/ Y* t5 r+ e  Q) r{
' a1 [. W+ _/ H7 J2 F/ w+ U    GPIO_InitTypeDef GPIO_InitStruct = {0};
, Q6 j# W* p) d- X( W& y    " \* `, K# h( G6 g( J3 ?; [- N+ R
    // 使能时钟. N/ _, V7 V4 \2 ^
    __HAL_RCC_USART1_CLK_ENABLE();8 q' }/ |$ g* C# a0 j8 P
    __HAL_RCC_GPIOA_CLK_ENABLE();. Y& q. L  V; }' q: D( d7 `
   
6 p5 G% {! @1 C6 H+ g: p    // 配置GPIO
- U4 D9 b2 G$ `! ]$ \  [    GPIO_InitStruct.Pin = GPIO_PIN_9;
8 r6 W( ^7 n) n6 _% P0 G; w6 [    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;! F4 U; e2 R9 Y- c  ^9 n" R
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
' G2 S3 V7 x8 Z    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);7 A5 F/ |4 M, H3 |- R: r, I* R4 A
    & R2 {5 s! u4 n; y- m- z
    GPIO_InitStruct.Pin = GPIO_PIN_10;% n" K) t5 g" Y2 B
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;. p1 n+ F) N4 N* q) ]8 c3 Z
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);' j; |8 n3 G) ^1 V* a
    : z: N0 M' z/ ?/ n) N" ~  Y
    // 配置UART% Y3 J* T, R0 H& m% Q
    huart1.Instance = USART1;
2 ], ?! y& f7 X- K: ]  Y$ O    huart1.Init.BaudRate = 115200;& y6 l( @+ ~1 c. {$ m
    huart1.Init.WordLength = UART_WORDLENGTH_8B;6 s: H, A- ]  h
    huart1.Init.StopBits = UART_STOPBITS_1;
: S' Q1 J# E  h/ d3 d/ d/ j& o    huart1.Init.Parity = UART_PARITY_NONE;% I6 ]% L2 ^- ^  K, V* ^
    huart1.Init.Mode = UART_MODE_TX_RX;
# }& P2 K% v4 k1 a3 `: @    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;: j1 K$ I: ~( {8 Q
    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
, e6 [$ r: m, d! l+ W, Q0 }    HAL_UART_Init(&huart1);% [1 w9 {9 w6 K8 w. V9 `
}
& y5 F! o) v; C" P3 I. m. M1 @6 X2 e, h/ y  Z- ?% k9 J
voidUART_SendString(char* str)2 x+ h; l3 d5 e, R% |
{7 |1 [) N/ w4 J6 Q. F4 |. f
    HAL_UART_Transmit(&huart1, (uint8_t*)str, strlen(str), HAL_MAX_DELAY);
, j' ~! p* I6 o3 N* U% S}LL方式void UART_Config(void)7 A5 _* k3 R9 w$ p* x/ M
{
7 H  O7 x# z2 ]    // 使能时钟0 g/ M, b; D/ i+ C6 @1 P- ]( A3 r
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1);
6 `. Q% E9 r# @  u6 V; W' [    LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);- u# I+ B+ ^! m. k) Z
    7 z; h* B. k0 ^! D# c& g9 q
    // 配置GPIO
$ W) j. P* e' d# X/ `( [. G    LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_9, LL_GPIO_MODE_ALTERNATE);
8 Z* ]% L7 V9 M0 x+ j) n6 T1 Y8 N8 ?    LL_GPIO_SetAFPin_0_7(GPIOA, LL_GPIO_PIN_9, LL_GPIO_AF_7);
7 p% S) j. d, n; l    LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_9, LL_GPIO_SPEED_FREQ_HIGH);3 d( m* z/ J: d
      w$ f# `" ~$ I* y
    LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_10, LL_GPIO_MODE_ALTERNATE);
/ z, i9 p3 p- P: u. X$ j+ ]( D% E    LL_GPIO_SetAFPin_8_15(GPIOA, LL_GPIO_PIN_10, LL_GPIO_AF_7);/ S7 s0 j$ t" X2 h0 @2 v
   
2 O0 H6 a/ q8 T: r    // 配置UART
% P+ y! X) z8 J% k; ^) t3 a    LL_USART_SetBaudRate(USART1, 115200);. q" q5 k! _  e( R
    LL_USART_SetDataWidth(USART1, LL_USART_DATAWIDTH_8B);
! s4 S. E. k  O2 c& G. H    LL_USART_SetStopBitsLength(USART1, LL_USART_STOPBITS_1);9 Z6 k7 j/ @( _1 \
    LL_USART_SetParity(USART1, LL_USART_PARITY_NONE);0 \& N& U# _( }  ^9 y) C$ U+ }
    LL_USART_SetTransferDirection(USART1, LL_USART_DIRECTION_TX_RX);
' N6 a; Q! B5 P    LL_USART_Enable(USART1);5 I4 E; a. C: ~6 h6 t7 O% H$ i) K1 w
}
6 I- C6 h- b( w7 N0 ]- O6 H+ f2 a# |8 P  K+ Z1 Q3 k# O# W
voidUART_SendString(char* str)
6 m; Z( C, ^, Z# j, M{2 s7 T( C9 c1 c
    while(*str) {
  Y7 w6 H% }7 D. Y; ?; U        while(!LL_USART_IsActiveFlag_TXE(USART1));- X6 X: q. O& x# c$ F; j! @% T% J
        LL_USART_TransmitData8(USART1, *str++);. o, e" `: a$ I* |4 d  e8 k
    }
# Z% o' @7 \6 I$ L7 x}

5 E6 |+ h2 O4 h+ {4 [) \5 w# U5 G( @
赞 收藏 评论0 发布时间:2025-10-16 16:33

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版