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

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

[复制链接]
flyingstar 发布时间:2025-10-16 16:33
从寄存器操作到硬件抽象层:STM32开发库的演进。
演进历程
STM32微控制器自2007年推出以来,STMicroelectronics为其提供了多套软件开发库,经历了从直接寄存器操作到高度抽象化的演进过程:
发展时间线
  • 2007-2010: 标准外设库(SPL)时代
  • 2013-2015: HAL库引入,SPL逐步淘汰
  • 2016-至今: HAL + LL双轨制,CubeMX工具链完善# t2 r" \/ H" F% [: u- m: W0 {
当前状态
  • SPL: 已停止维护,支持F0/F1/F2/F3/F4系列
  • HAL: ST官方主推,持续更新维护
  • LL: 作为HAL的补充,提供更接近硬件的接口2 g/ D& t0 ^' y# w
三大库架构对比特性标准外设库(SPL)HAL库LL库
, N* P4 X- N) B. U7 S4 y5 X抽象层次中等高低
- s. ^6 T7 `8 u代码体积中等大小/ @9 V- a$ e! L6 O9 L
执行效率高中等高& c" M* Z  G* C' Y/ d5 S
学习难度中等低高8 R' C" e- _7 u' P3 b2 p( z- t  [
可移植性低高中等
8 B" g# i8 ~" e2 k) [; t8 s维护状态已停止活跃活跃# ]0 T  l% ?& x  H8 j- Q
工具支持无CubeMXCubeMX标准外设库(SPL)设计理念
SPL采用"一个外设一个文件"的设计理念,每个外设都有对应的.c和.h文件,提供中等层次的抽象。
核心特点// SPL典型用法示例
" @: i4 v% m7 `8 t  Zvoid GPIO_Config(void)
1 C; V# r+ H; F$ B7 H* D+ \5 ^9 N( n{: M: A2 u! Y' s* h2 R7 z: ?
    GPIO_InitTypeDef GPIO_InitStructure;) m6 Z) N% p+ d! O4 y3 h
   
- ^4 v1 s; s& h7 [7 T    // 使能GPIO时钟+ Y, D+ Z6 u" J
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);6 z5 G  ^" z6 o3 r8 E. W4 o. V$ _( ]
    5 t( [' p, R6 I! ^: m
    // 配置GPIO: X) W" p- s+ N: {; d
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;( s. m# v6 @4 N: h* \$ i1 q
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;* c3 g$ Z$ H/ w3 ?2 a: N
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
7 \! }; k0 [; I9 w    GPIO_Init(GPIOA, &GPIO_InitStructure);
0 `$ x& H7 \! z5 [: K}优势
  • 1. 性能优异: 直接操作寄存器,执行效率高
  • 2. 代码紧凑: 相比HAL库,代码体积更小
  • 3. 逻辑清晰: 一个函数完成一个功能,易于理解
  • 4. 调试友好: 可以直接查看寄存器状态# c8 Q. |* S( d6 [& b  S
劣势
  • 1. 维护停止: 不再支持新系列MCU
  • 2. 移植困难: 不同系列间API差异较大
  • 3. 工具支持差: 无现代IDE集成支持
  • 4. 文档过时: 缺乏最新的技术文档
    : e; O8 {. M( k& d- A
HAL库设计理念
HAL库采用"硬件抽象层"设计,旨在提供跨系列的统一API接口,隐藏硬件细节。
核心特点// HAL库典型用法示例7 H* o- n: O" o
void GPIO_Config(void)" ?/ G; E5 m  Y4 {1 N
{
: @: V) D, q, H# b    GPIO_InitTypeDef GPIO_InitStruct = {0};
) Q5 K) q+ p0 b# j! W% z4 H    0 ^. |1 J. _5 b! z/ i: @
    // 使能GPIO时钟
. u" s9 p: f2 @- ?* n  _  I    __HAL_RCC_GPIOA_CLK_ENABLE();
2 f( V2 ]* n( N    ! {- a0 ?! u0 j8 Y
    // 配置GPIO
3 o3 O$ }2 C- ~* B+ Q    GPIO_InitStruct.Pin = GPIO_PIN_5;
( k/ R6 B, I! h$ I    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;1 v4 h8 j2 D* a/ J& J" K8 }( u
    GPIO_InitStruct.Pull = GPIO_NOPULL;
/ I/ H. f# Q! ~: [    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
( g2 ~+ ]3 e" Y) O# G    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);( W1 f+ D( Z+ E8 O( r4 v4 \
}架构优势
  • 1. 统一接口: 跨系列API一致性
  • 2. 工具集成: 与CubeMX深度集成
  • 3. 功能丰富: 支持复杂外设如USB、以太网
  • 4. 持续维护: 定期更新和bug修复
    % t( p% H2 O% o  C) F6 p7 e
劣势
  • 1. 代码膨胀: 大量抽象层导致代码体积大
  • 2. 执行开销: 多层函数调用影响性能
  • 3. 内存消耗: 需要更多RAM存储状态信息
  • 4. 调试复杂: 抽象层增加调试难度
    ) y& a. P0 ]- K. F6 G+ V2 [
LL库(低层库)设计理念
LL库是HAL库的补充,提供更接近硬件的接口,同时保持一定的可移植性。
核心特点// LL库典型用法示例6 U( P, c3 X2 }# Y5 t: H
void GPIO_Config(void)8 j$ c! G: q/ N3 F. T  N' h
{- L! _  t6 q9 y
    // 使能GPIO时钟! v9 h2 F. K4 e% h/ ]) V% j
    LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
& z- F  _* z% c; q7 V: u7 t& ^    ; p0 s7 z8 i# d  z
    // 配置GPIO/ S( y) X  H% v) g, K/ X7 S
    LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_5, LL_GPIO_MODE_OUTPUT);0 Z& e; q+ ^: ]6 @1 K
    LL_GPIO_SetPinOutputType(GPIOA, LL_GPIO_PIN_5, LL_GPIO_OUTPUT_PUSHPULL);
$ ]: G$ n; H9 v* f- ]    LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_5, LL_GPIO_SPEED_FREQ_HIGH);, x4 y3 y  G8 F/ K+ D
}优势
  • 1. 性能接近寄存器: 大部分函数被内联优化
  • 2. 代码体积小: 相比HAL库显著减少
  • 3. 可读性好: 函数名自解释,代码更清晰
  • 4. 工具支持: 与CubeMX集成& Y( [' C4 O8 \; e1 m* s) g
适用场景
  • • 对性能有较高要求的应用
  • • 资源受限的MCU
  • • 需要精确控制时序的场景
  • • 从SPL迁移的项目
    ) C, t9 G" }* b6 j( |
实际代码示例对比UART配置与使用对比SPL方式void UART_Config(void)# ]8 d/ r" j! _; |: r
{& m" |+ {# @$ T) ]8 z- I; P# F5 O9 t
    USART_InitTypeDef USART_InitStructure;" p$ u) r2 k5 X
    GPIO_InitTypeDef GPIO_InitStructure;. W* N7 P5 U! |$ a. h
    0 o$ O7 E! @3 S! ~) y! x% E
    // 使能时钟# [. f( b, V8 k( @5 e, ?# X5 b
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);8 e' }1 Z  g% X( g4 {+ a
    2 E+ d# U4 h/ t' C* L
    // 配置GPIO- [' J+ A& K$ `3 S
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;  // TX) X( ~9 d& i+ @& X- m
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
2 Q% W( ~% e* a, p# D% z, T1 w; X    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;0 J1 M4 }- U4 y1 |* {
    GPIO_Init(GPIOA, &GPIO_InitStructure);
5 z6 t+ r/ N' Q5 O& w/ H    ) t6 ^) [$ m/ r/ {& T
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // RX
) j) I- \) @% D# @4 P" p% ]8 U    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;- h  I* N2 d: l4 @) Y
    GPIO_Init(GPIOA, &GPIO_InitStructure);
- B3 `: P5 W  }( p6 M    ; d* p1 I# J  G: ^- _
    // 配置UART
6 T$ ?5 Q; [( {7 H* j1 _    USART_InitStructure.USART_BaudRate = 115200;5 s  w. g0 w7 M( Q7 ^
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;, _' l$ I  p$ g$ Z4 M
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
1 Q1 k+ b& b. c* c% S; z, M    USART_InitStructure.USART_Parity = USART_Parity_No;
( V8 w5 \. W3 Y4 G8 M" X    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
1 J6 u+ P1 G: ]; p    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
# x" R8 @; J0 u! ?    USART_Init(USART1, &USART_InitStructure);( k9 r& L+ M+ N2 I, r+ ^9 F
   
' B8 |  D/ Y; a4 n$ q* n    USART_Cmd(USART1, ENABLE);' I8 ^% o" K1 _; ^7 n
}; T/ \7 U' C2 ~% h# _% q- U! t
: O) u5 i  J0 u. i5 A/ q
voidUART_SendString(char* str)& Z3 p) _' {" I6 c8 c( M: C
{0 Z2 w) s% N& T  s
    while(*str) {+ p; L% u& b! R
        while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);! E6 T, k9 i6 `& l- G2 I1 r
        USART_SendData(USART1, *str++);0 m8 d- p: L" s+ v
    }) e, D* ?& H! J4 M
}HAL方式void UART_Config(void)
; d# V( F- o: O: f1 q5 S{
! S/ p3 s9 ]. M. C3 C" _" U! U" d    GPIO_InitTypeDef GPIO_InitStruct = {0};( S# l1 W! n9 m8 W. k2 e
   
. s1 ?7 L, Y: Q8 g9 D4 C, F    // 使能时钟
2 A4 Z1 e7 t$ \  v+ B    __HAL_RCC_USART1_CLK_ENABLE();
( d& h9 B2 i* X( j( N; W    __HAL_RCC_GPIOA_CLK_ENABLE();
! t# a# Q( s6 I6 j# u   
( v# f1 ]5 F/ N    // 配置GPIO
. u1 p: L: ?- H. R. L, R' u    GPIO_InitStruct.Pin = GPIO_PIN_9;0 ]0 B' _' _: P# l
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
8 e( @6 G; y4 T4 z: D$ t    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
8 R2 _' }, ?# T6 K1 G- @" h    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
$ {" u- \( R# M   
) m& a/ `5 y- g# \( l4 P  l$ o    GPIO_InitStruct.Pin = GPIO_PIN_10;$ |( }- C; ^7 G- d3 X0 L/ p
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
. e  G5 o+ \: a- a: w0 D/ f4 a    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
3 u8 c. I. w% p& s$ a, W   
' R- H% _( \$ _: o% i    // 配置UART
6 H6 t3 w' O$ ~6 A: o    huart1.Instance = USART1;6 ]+ C& @, j' f: p% Q
    huart1.Init.BaudRate = 115200;) I( b$ z- o& Y: g
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
/ H$ H' M* g7 F' X0 l7 ^  ~2 c  b$ Q    huart1.Init.StopBits = UART_STOPBITS_1;
, u) g; Y& a3 X( K- F    huart1.Init.Parity = UART_PARITY_NONE;" B- }" ^- i5 l  T5 V
    huart1.Init.Mode = UART_MODE_TX_RX;
  l+ d: ?2 a6 Q5 q6 I9 [7 N7 _- x    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
4 @* }& q, f3 o6 ^  V8 q    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
* q8 B9 O4 V( `4 q5 s0 S    HAL_UART_Init(&huart1);. S/ t5 ?" `/ ?' J% a8 x
}; G7 t& K! g& D5 h. r1 V8 u" L$ N! H
% h# e* x  F) k3 o8 p4 i% c9 W) k
voidUART_SendString(char* str)
$ M, D/ {9 Z% y+ U/ L- i{: s3 a9 }0 ]# u# m
    HAL_UART_Transmit(&huart1, (uint8_t*)str, strlen(str), HAL_MAX_DELAY);
6 X0 z/ t2 Z) {; d( Q* ?3 E& W( V}LL方式void UART_Config(void); z. w3 x% c$ \7 b4 a
{% o+ @& L: P* z: o  f( [7 O) |
    // 使能时钟
+ E. b3 d& y5 P$ L% C0 Y6 H    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1);/ N+ H* J- p/ d
    LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
. K+ e/ z3 Z/ M& K6 j0 f& l   
8 T1 v2 j3 w: N9 W0 F$ y    // 配置GPIO
- t' n6 U: f# b  @* C7 B    LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_9, LL_GPIO_MODE_ALTERNATE);- Q9 F$ @' ^4 T+ P, N! X/ J
    LL_GPIO_SetAFPin_0_7(GPIOA, LL_GPIO_PIN_9, LL_GPIO_AF_7);
; B; w. @! e5 \. o% M    LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_9, LL_GPIO_SPEED_FREQ_HIGH);
+ x0 L4 M4 y; H) e2 P0 ^   
: k- d- _& }# ~& a6 e    LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_10, LL_GPIO_MODE_ALTERNATE);
/ s7 [8 W; n- o+ h1 ]7 w    LL_GPIO_SetAFPin_8_15(GPIOA, LL_GPIO_PIN_10, LL_GPIO_AF_7);
2 x  j9 \& x/ ^4 p. H" k" f; ~    1 l/ l9 u3 I) e* m3 V
    // 配置UART
: |3 m6 b/ y* O: i* F# A    LL_USART_SetBaudRate(USART1, 115200);
! z/ {! J% U# m$ Q* w    LL_USART_SetDataWidth(USART1, LL_USART_DATAWIDTH_8B);
5 Y# A$ V1 l/ X' N- j0 r) h$ ^    LL_USART_SetStopBitsLength(USART1, LL_USART_STOPBITS_1);
7 S% X( o, v: K, H) M1 v    LL_USART_SetParity(USART1, LL_USART_PARITY_NONE);
+ _- w" h2 i& ?& C- c, X+ c    LL_USART_SetTransferDirection(USART1, LL_USART_DIRECTION_TX_RX);
/ }" Q6 {1 Q  U+ n0 h7 `+ m. m    LL_USART_Enable(USART1);$ `8 X' Z; E0 F3 b1 \
}+ c/ P8 o1 N( G0 `: f
! \" Y7 a7 F: a' ^& o1 }
voidUART_SendString(char* str)* ~% z9 {  {7 A" A3 u  H5 h8 p& o
{
* v& X8 l7 K3 B! L6 l" T! \; l1 q3 ^    while(*str) {8 k0 [; X) H' W
        while(!LL_USART_IsActiveFlag_TXE(USART1));: T8 K* c* B% P! l- {, i
        LL_USART_TransmitData8(USART1, *str++);% B, c3 h  O1 `; y% k
    }
6 n& @+ g' A+ G1 r; {}

! a, N+ O5 ^9 Z/ m, w+ S, `; S
0 e/ x( V* f4 @4 B0 H( h
收藏 评论0 发布时间:2025-10-16 16:33

举报

0个回答

所属标签

相似技术帖

官网相关资源

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