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

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

[复制链接]
flyingstar 发布时间:2025-10-16 16:33
从寄存器操作到硬件抽象层:STM32开发库的演进。
演进历程
STM32微控制器自2007年推出以来,STMicroelectronics为其提供了多套软件开发库,经历了从直接寄存器操作到高度抽象化的演进过程:
发展时间线
  • • 2007-2010: 标准外设库(SPL)时代
  • • 2013-2015: HAL库引入,SPL逐步淘汰
  • • 2016-至今: HAL + LL双轨制,CubeMX工具链完善
    4 n: M% k& `3 A; e* e; O) m
当前状态
  • • SPL: 已停止维护,支持F0/F1/F2/F3/F4系列
  • • HAL: ST官方主推,持续更新维护
  • • LL: 作为HAL的补充,提供更接近硬件的接口
    8 Z! t( u1 U4 H
三大库架构对比特性标准外设库(SPL)HAL库LL库
9 X! T) V' \) W' l2 \. J( m抽象层次中等高低
: w! H6 u# X9 W2 C代码体积中等大小
0 q( Y/ |7 \0 w% L& y2 a7 `执行效率高中等高
( d7 y0 A0 S1 W+ Z( f. ^学习难度中等低高
! N- f- d1 U3 {. E+ W6 ]可移植性低高中等/ Q, R+ _! ?9 p
维护状态已停止活跃活跃
4 H! F. @! r( ?5 Q  L工具支持无CubeMXCubeMX标准外设库(SPL)设计理念
SPL采用"一个外设一个文件"的设计理念,每个外设都有对应的.c和.h文件,提供中等层次的抽象。
核心特点// SPL典型用法示例$ v5 H/ `) H3 h" }- a# x
void GPIO_Config(void)9 Q- H# G" r7 h, p
{
3 Z( @0 R1 q" Q% Z; C; n    GPIO_InitTypeDef GPIO_InitStructure;
/ K# Z/ Q; r+ d+ S5 T   
6 ]7 d% y4 [2 @9 o1 I6 J8 X5 f    // 使能GPIO时钟. V& _5 f+ J$ @9 ~. `6 j  X* s7 D, D
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);+ {9 X2 A3 T' u0 X, m* W
   
! @: B9 B- g" l# K; Q    // 配置GPIO/ E/ E' ]8 i( j' O# s
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
- _5 q/ `6 ^, i4 p    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;0 {2 k% w1 G* J2 D" W; _2 p
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;) S) {, o0 \9 t9 Q% m) x
    GPIO_Init(GPIOA, &GPIO_InitStructure);
( ?4 p1 s, {, ~! `+ }. d}优势
  • 1. 性能优异: 直接操作寄存器,执行效率高
  • 2. 代码紧凑: 相比HAL库,代码体积更小
  • 3. 逻辑清晰: 一个函数完成一个功能,易于理解
  • 4. 调试友好: 可以直接查看寄存器状态! J9 @, R0 A, L2 Y% ?6 y
劣势
  • 1. 维护停止: 不再支持新系列MCU
  • 2. 移植困难: 不同系列间API差异较大
  • 3. 工具支持差: 无现代IDE集成支持
  • 4. 文档过时: 缺乏最新的技术文档% W( O6 R- G5 v0 k' r3 @5 O- k
HAL库设计理念
HAL库采用"硬件抽象层"设计,旨在提供跨系列的统一API接口,隐藏硬件细节。
核心特点// HAL库典型用法示例
9 U1 q0 O7 B" }- i0 o& S0 N# }void GPIO_Config(void)
+ o* @* e1 W5 q2 t# \9 K{# i5 S- H- k! \* f; f
    GPIO_InitTypeDef GPIO_InitStruct = {0};
7 b" ]% C9 \* o* G( Z  H/ c9 i    ! Y- a5 |# T3 w5 }, W# g% w
    // 使能GPIO时钟
9 D8 P% b) m% u! F    __HAL_RCC_GPIOA_CLK_ENABLE();" b: h$ ?+ D: i1 ~! t
    & D# B, E7 `* e' z* F3 S
    // 配置GPIO
4 e3 Q1 K8 e+ x! m8 M, o; Y    GPIO_InitStruct.Pin = GPIO_PIN_5;
7 d& _$ a8 Y2 y% l    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;7 {3 q! O8 z* `# U5 Q& H
    GPIO_InitStruct.Pull = GPIO_NOPULL;: V" H3 b- n. X8 |/ S8 x
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
3 L. @& D. K7 O# y9 Q" N    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);0 H: ^' a9 X, p& z; p* B/ g2 U
}架构优势
  • 1. 统一接口: 跨系列API一致性
  • 2. 工具集成: 与CubeMX深度集成
  • 3. 功能丰富: 支持复杂外设如USB、以太网
  • 4. 持续维护: 定期更新和bug修复: f- {/ f4 K4 j1 _( P$ k
劣势
  • 1. 代码膨胀: 大量抽象层导致代码体积大
  • 2. 执行开销: 多层函数调用影响性能
  • 3. 内存消耗: 需要更多RAM存储状态信息
  • 4. 调试复杂: 抽象层增加调试难度" f% B' t9 ~6 c3 H6 r+ O
LL库(低层库)设计理念
LL库是HAL库的补充,提供更接近硬件的接口,同时保持一定的可移植性。
核心特点// LL库典型用法示例
+ O3 F5 m) |0 U' L" t/ tvoid GPIO_Config(void)8 R( [* U; m" B( r8 u( f3 J
{
: L  Z0 j2 j% m+ i    // 使能GPIO时钟9 Q1 f# f" @0 A
    LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);+ p# ~/ t; |4 f4 o
    + {* P  L; c% C
    // 配置GPIO* Z# A7 ~  G! C4 R
    LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_5, LL_GPIO_MODE_OUTPUT);
) r8 }3 S- q( q) }9 T    LL_GPIO_SetPinOutputType(GPIOA, LL_GPIO_PIN_5, LL_GPIO_OUTPUT_PUSHPULL);. j8 {5 E2 D  ?8 z5 y
    LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_5, LL_GPIO_SPEED_FREQ_HIGH);
& W8 ^9 i$ ]0 G. M1 c}优势
  • 1. 性能接近寄存器: 大部分函数被内联优化
  • 2. 代码体积小: 相比HAL库显著减少
  • 3. 可读性好: 函数名自解释,代码更清晰
  • 4. 工具支持: 与CubeMX集成
    , s$ p* L7 g" w3 z2 ^8 `
适用场景
  • • 对性能有较高要求的应用
  • • 资源受限的MCU
  • • 需要精确控制时序的场景
  • • 从SPL迁移的项目
    8 q3 U# [! [3 q- j
实际代码示例对比UART配置与使用对比SPL方式void UART_Config(void)$ x% w* h% c+ X
{
5 c/ ~) E9 J/ h" Q    USART_InitTypeDef USART_InitStructure;) k, q6 }. C& M# W
    GPIO_InitTypeDef GPIO_InitStructure;$ R! z$ {& M, |( [8 C( ?; u
    # t- D! O" Q( @
    // 使能时钟
4 s0 a' r7 }$ H  D5 u5 g7 a! t4 H& D    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);7 O* w" s$ l0 D/ j% ^
    " A$ \+ i' b! R( E- P! W  V( ?
    // 配置GPIO
6 g6 Z. R% \7 h2 b# V% F    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;  // TX
1 w* c2 w9 t& Z8 _; L  A/ B    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;' R  ?2 w: _- i) e) K3 O
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
# E: u+ ]! n* X( V) \+ [    GPIO_Init(GPIOA, &GPIO_InitStructure);
, G7 p* v- j' C& j) A* Z   
  E9 O8 P$ B/ q    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // RX* ]' L: D4 `( }* |3 a* g
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
' Q/ Q2 F3 S, h4 `* _; x. k; q    GPIO_Init(GPIOA, &GPIO_InitStructure);/ [( H8 Y9 G0 f& q5 O
    $ b" [7 S8 T7 o2 ?0 ?  {
    // 配置UART
; g% w; c9 w3 G8 \4 b  F# x    USART_InitStructure.USART_BaudRate = 115200;7 t: O# H6 }4 ?3 J8 l- H% Z( Z
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;0 e, m- ~& M& \* o- f3 R
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
" T5 a. v6 J* j9 }0 l/ }    USART_InitStructure.USART_Parity = USART_Parity_No;3 X5 L, R( n1 _% O0 @
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;9 w2 P% x+ Z' u
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;- M. k/ t7 x' r" X2 A% M
    USART_Init(USART1, &USART_InitStructure);
, R, @- J0 A2 I& g' t/ ^   
8 d9 C. i' h7 c7 W( ~    USART_Cmd(USART1, ENABLE);+ y- s1 {6 \  q) x! _# O: w2 ^6 J
}& f9 n1 c% p! d! ?7 O" G

  y" V" h# _+ ~' b+ C: x+ gvoidUART_SendString(char* str)
- m* X6 l" f/ T8 c# F- w( y2 N3 y{
$ S1 _( `0 j5 {: I' F5 q6 H    while(*str) {
4 i$ O9 z! s3 x: F; b        while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
9 g: W# s4 t2 Z: s% |/ {- _5 c3 \        USART_SendData(USART1, *str++);4 s( ]/ Z; F% I) ^$ [( Z  j
    }5 r' R, ~9 i$ b6 T8 z+ M( t; S" h
}HAL方式void UART_Config(void)
- f+ }- O$ \7 y0 V# p$ c% k9 t" u{
$ G; ~) ?3 Z1 F4 T# t3 p  ^# \    GPIO_InitTypeDef GPIO_InitStruct = {0};/ N& }: ~( ?& q8 q/ p- B% }- W, N
    ) J. u& T1 u& B6 R
    // 使能时钟
8 B) d0 r! f( a4 U8 _0 A" k8 D    __HAL_RCC_USART1_CLK_ENABLE();
! B( y/ n# w7 F* a! S    __HAL_RCC_GPIOA_CLK_ENABLE();
4 `" I& c3 a3 {$ a/ U* W   
  s) j9 C4 c- Q1 R( W4 m% n' f: u    // 配置GPIO3 q8 a$ k) T2 Z! G* R8 [2 E
    GPIO_InitStruct.Pin = GPIO_PIN_9;4 T9 g0 I& q# w' v! O% X2 \. D' g
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
) }6 ?5 M$ L8 M( v/ ?. T! B    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
- A7 i0 ]/ \9 L0 h# j, E+ ?    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);7 X! z4 ~- r- u/ U7 T( N
    # O, ^' _3 P) R6 z) I8 A" N
    GPIO_InitStruct.Pin = GPIO_PIN_10;8 ]! d2 S& p7 r  K5 K0 G, A' g
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
* ]4 k5 P5 g9 D3 G) n/ p2 f+ M* j    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);$ u+ q9 N0 y) M* i$ k4 d
   
* @( L, h0 z8 s' D% e8 Y    // 配置UART+ `- b: J4 t: T. E4 @- ]; G" O. W
    huart1.Instance = USART1;
3 h0 S8 W7 K1 N6 c* ^; ]  r    huart1.Init.BaudRate = 115200;, ?5 W9 F% f4 A6 Z2 U( _1 ]4 N
    huart1.Init.WordLength = UART_WORDLENGTH_8B;" B; M+ H' M7 f5 [. f
    huart1.Init.StopBits = UART_STOPBITS_1;. `! J( @6 c8 Z$ D; i1 V# k
    huart1.Init.Parity = UART_PARITY_NONE;
( F3 j# J! A& d1 h# E! M4 D    huart1.Init.Mode = UART_MODE_TX_RX;' w& Z/ v/ D- q9 I
    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
1 k# S7 R. ?5 L    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
, C6 N! C: ?$ u/ O9 Z2 @7 C: T    HAL_UART_Init(&huart1);
- p+ f3 n8 _2 \1 `) \: M( s3 |- `+ V}
+ I; D9 e  [, T2 h4 j3 M. G
& U+ o5 `# |& g: ^voidUART_SendString(char* str)
8 W* c0 ^" M$ R8 l1 ?- L{" B* s( P$ R: b
    HAL_UART_Transmit(&huart1, (uint8_t*)str, strlen(str), HAL_MAX_DELAY);
8 @4 x3 t7 \# {$ |, d1 f}LL方式void UART_Config(void)
! ^+ D$ Q' A6 I$ f% Q2 E{/ S- K+ r5 S8 [  X8 }; A/ w3 T  j
    // 使能时钟& F( V: d/ V+ M: r7 \6 A
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1);) k1 B+ y. p$ g
    LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);# c8 e9 W% c8 Q: y* U$ i1 x. c) f
   
4 }6 @7 L8 J% q% B( |, t7 j    // 配置GPIO1 p) U* H- t. C! r
    LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_9, LL_GPIO_MODE_ALTERNATE);! R( B/ M/ q6 {4 w3 n8 }, |3 c
    LL_GPIO_SetAFPin_0_7(GPIOA, LL_GPIO_PIN_9, LL_GPIO_AF_7);
) W! t' w- O. b) ^6 f7 W/ }0 X6 z    LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_9, LL_GPIO_SPEED_FREQ_HIGH);; ?. I' F! E  J8 |
   
$ J+ w3 g- x* p1 `5 J" J  z4 g- p    LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_10, LL_GPIO_MODE_ALTERNATE);' {/ Y% b! }+ g5 a# X9 o1 K7 t
    LL_GPIO_SetAFPin_8_15(GPIOA, LL_GPIO_PIN_10, LL_GPIO_AF_7);+ r/ `, h2 j/ ~; K
   
, g- Z, w2 ^8 L& b7 j& D" _* S# z    // 配置UART
# h- q! t2 `  ~4 r' @' c    LL_USART_SetBaudRate(USART1, 115200);9 [# g8 `( w6 p& _, r8 s
    LL_USART_SetDataWidth(USART1, LL_USART_DATAWIDTH_8B);
2 g+ b  d5 G! S5 p% h5 h+ p    LL_USART_SetStopBitsLength(USART1, LL_USART_STOPBITS_1);, d% G1 v% ]3 t( y/ h9 C: K' n7 l
    LL_USART_SetParity(USART1, LL_USART_PARITY_NONE);! N7 m, C! h, l
    LL_USART_SetTransferDirection(USART1, LL_USART_DIRECTION_TX_RX);
: Y* h1 `, {3 T1 S9 ]    LL_USART_Enable(USART1);
: i+ o6 e; T% M; p: |}2 ~9 ~! A. `6 ~5 x: t- g

2 O% ?+ v5 D. E1 p  D) f  ^/ FvoidUART_SendString(char* str)0 T- ^. j0 J6 z
{9 n, W2 E/ o+ e- M9 C  `
    while(*str) {5 E+ q3 }6 W' Y- O5 V' r
        while(!LL_USART_IsActiveFlag_TXE(USART1));
( k! x* C" ^5 y' R% C4 L  A        LL_USART_TransmitData8(USART1, *str++);
  n& y' l/ |' D5 M  n3 E' J    }! e- s. F. Q% y4 d6 g
}
& K! |+ `  q1 ^: K- r' i1 J
7 p: o3 C) t- N: C
赞 收藏 评论0 发布时间:2025-10-16 16:33

举报

0个回答

所属标签

相似技术帖

官网相关资源

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