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

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

[复制链接]
flyingstar 发布时间:2025-10-16 16:33
从寄存器操作到硬件抽象层:STM32开发库的演进。
演进历程
STM32微控制器自2007年推出以来,STMicroelectronics为其提供了多套软件开发库,经历了从直接寄存器操作到高度抽象化的演进过程:
发展时间线
  • • 2007-2010: 标准外设库(SPL)时代
  • • 2013-2015: HAL库引入,SPL逐步淘汰
  • • 2016-至今: HAL + LL双轨制,CubeMX工具链完善9 ^' c. W: f9 `
当前状态
  • • SPL: 已停止维护,支持F0/F1/F2/F3/F4系列
  • • HAL: ST官方主推,持续更新维护
  • • LL: 作为HAL的补充,提供更接近硬件的接口9 N/ O: `/ h% D0 U4 g/ n# G: W" @
三大库架构对比特性标准外设库(SPL)HAL库LL库
0 u& q% m  J# [4 r* @抽象层次中等高低* K+ ]" v6 y8 i2 _5 n" q! J
代码体积中等大小
) z, l; \" K; V8 `执行效率高中等高
/ t; ]- b0 W: D7 X1 d' R学习难度中等低高
9 @0 h4 f3 r+ D+ J$ K可移植性低高中等1 f7 O/ ~/ I* X; t& q
维护状态已停止活跃活跃7 Z4 e% X: v. ~9 P
工具支持无CubeMXCubeMX标准外设库(SPL)设计理念
SPL采用"一个外设一个文件"的设计理念,每个外设都有对应的.c和.h文件,提供中等层次的抽象。
核心特点// SPL典型用法示例
, t- N* I( R5 g! m0 w" e3 S  Ivoid GPIO_Config(void)
0 V$ R0 L- e, p5 u) Z9 d$ W: A{
: t7 C1 A) B$ i1 L3 Q    GPIO_InitTypeDef GPIO_InitStructure;
* S! F$ D4 Z8 Q) ^; M    " W8 {- Y) [$ e/ i0 j2 o$ w
    // 使能GPIO时钟
! m5 i% q0 |) x    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
0 a* O6 Y! p" X( i2 `! u% y1 ^    : \3 F/ H2 z9 x, l4 C( v6 N$ E' w
    // 配置GPIO0 a! b; y) ]  p6 T$ _( [
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;$ i: U, z6 ~* E5 b6 d  [
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
9 @  Q( Z7 o! P' p) l9 c5 X    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
$ Z3 R& z' G  B; i$ S( j% n( j9 d    GPIO_Init(GPIOA, &GPIO_InitStructure);' C/ B- X% H  S' M( e( ?$ S( x4 f
}优势
  • 1. 性能优异: 直接操作寄存器,执行效率高
  • 2. 代码紧凑: 相比HAL库,代码体积更小
  • 3. 逻辑清晰: 一个函数完成一个功能,易于理解
  • 4. 调试友好: 可以直接查看寄存器状态" U" @9 x* S* \
劣势
  • 1. 维护停止: 不再支持新系列MCU
  • 2. 移植困难: 不同系列间API差异较大
  • 3. 工具支持差: 无现代IDE集成支持
  • 4. 文档过时: 缺乏最新的技术文档! {- l& S* q: y1 H
HAL库设计理念
HAL库采用"硬件抽象层"设计,旨在提供跨系列的统一API接口,隐藏硬件细节。
核心特点// HAL库典型用法示例: A: J* y! a1 R  v
void GPIO_Config(void). |2 y- w6 b% M6 e* w5 W% i
{/ C4 X5 I9 a6 ^8 J3 ^/ |- S
    GPIO_InitTypeDef GPIO_InitStruct = {0};
0 X# G9 c- k. ]2 \   
: L# i6 F2 q9 h1 R$ x' {& `    // 使能GPIO时钟
( t/ V8 B9 S2 o    __HAL_RCC_GPIOA_CLK_ENABLE();
" M. O+ c# R( p" r    2 O& ^) N- q, i: V" H
    // 配置GPIO
+ Y8 c% ^2 m% s$ A/ n    GPIO_InitStruct.Pin = GPIO_PIN_5;
, F# C2 j: B+ F. V+ _0 `: m    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
0 `& ^" \2 X) ^4 G    GPIO_InitStruct.Pull = GPIO_NOPULL;
. B  Y3 W& x+ a% u/ j. b    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;2 U0 w" |, D' a' r
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
; D8 h8 E" L7 k" K}架构优势
  • 1. 统一接口: 跨系列API一致性
  • 2. 工具集成: 与CubeMX深度集成
  • 3. 功能丰富: 支持复杂外设如USB、以太网
  • 4. 持续维护: 定期更新和bug修复
    1 y2 d& ^# ^# F( J: J5 G! S
劣势
  • 1. 代码膨胀: 大量抽象层导致代码体积大
  • 2. 执行开销: 多层函数调用影响性能
  • 3. 内存消耗: 需要更多RAM存储状态信息
  • 4. 调试复杂: 抽象层增加调试难度6 q/ p1 Z. u7 r3 ]
LL库(低层库)设计理念
LL库是HAL库的补充,提供更接近硬件的接口,同时保持一定的可移植性。
核心特点// LL库典型用法示例1 Z& i  |) K6 o7 y0 X0 j
void GPIO_Config(void)
. i' A" G( x! u; Y5 x6 K  q6 A{
6 o7 p: s! Y8 R  z    // 使能GPIO时钟, L6 ^' ]4 p( @
    LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
# s  z: S" h9 z   
  M% u% w  S- x; V  X( A/ s    // 配置GPIO
; T: B* R4 T9 N- @, y    LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_5, LL_GPIO_MODE_OUTPUT);
6 F0 _( P. ^7 o; |    LL_GPIO_SetPinOutputType(GPIOA, LL_GPIO_PIN_5, LL_GPIO_OUTPUT_PUSHPULL);
. i$ G+ R% D5 s6 P, _, J    LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_5, LL_GPIO_SPEED_FREQ_HIGH);( o! \& X/ i& x/ ~6 w) G. d
}优势
  • 1. 性能接近寄存器: 大部分函数被内联优化
  • 2. 代码体积小: 相比HAL库显著减少
  • 3. 可读性好: 函数名自解释,代码更清晰
  • 4. 工具支持: 与CubeMX集成
    / Y4 G' X2 Z, H8 l& S9 c# N7 g
适用场景
  • • 对性能有较高要求的应用
  • • 资源受限的MCU
  • • 需要精确控制时序的场景
  • • 从SPL迁移的项目
    . Q2 G; T- Q0 `% I2 x& Z7 H- m5 c4 |5 M
实际代码示例对比UART配置与使用对比SPL方式void UART_Config(void)
' p4 z6 z% W; N: a0 B9 T; {# q' K{* U! m2 Z; M7 {' D3 B: M' H6 a
    USART_InitTypeDef USART_InitStructure;
6 e& I5 \4 n8 P& J! J5 z    GPIO_InitTypeDef GPIO_InitStructure;
  m  z. K* C* _5 [   
( |$ C5 q* D% s+ j3 ?& |" K    // 使能时钟
# ?( i3 |1 \3 Z0 w    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
0 ~0 V: @. Q; E' B   
; q2 a7 u8 G9 S" u    // 配置GPIO
/ b) b  t. z7 k# g- ]' a8 S0 ^    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;  // TX  z$ H- n& n: Z( k) G# P
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
" s" K. F- U, G. g* h, g    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;5 M) r4 |! U$ T4 d; S
    GPIO_Init(GPIOA, &GPIO_InitStructure);5 T) H6 p9 \7 J0 H4 G
    $ R* P9 b" b" Z% T! V9 p7 P5 X6 O) a3 `! k
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // RX
. P0 @5 Y: {* G7 t; f! V/ y1 l    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
% N5 R- o$ N9 B) u7 b* Q  m    GPIO_Init(GPIOA, &GPIO_InitStructure);$ R  w* Y: {  h+ i  k: B
   
  o8 w: m, }! ^3 g2 r7 x( R2 M9 W    // 配置UART5 n4 i% n; ]6 p4 }
    USART_InitStructure.USART_BaudRate = 115200;, r/ L. S! N6 K5 {* y
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;6 \7 D* z% A" q+ D7 |, A
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
& V! m& M" c' w    USART_InitStructure.USART_Parity = USART_Parity_No;$ x( I+ P( q# ~" O* O: W& [& P& I
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
# W& j' F+ i' V  p6 d  V    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;* ?* `* s+ a( P) e9 d
    USART_Init(USART1, &USART_InitStructure);  ?2 t, x$ `0 \
    7 ~: }+ _) i+ w% e
    USART_Cmd(USART1, ENABLE);
0 I( o: ]% j* a3 [}3 _, H# B+ B7 e

  ?0 ?2 q! v: T+ |; J( k* s, g: D  AvoidUART_SendString(char* str)
- p: w/ P3 N) K5 i  P1 n{# P6 A1 j" r! T; C
    while(*str) {' U4 c8 |# J' c+ j4 t: O0 H2 Y
        while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);: c" V. ?, H* u3 x- q4 m
        USART_SendData(USART1, *str++);
% u5 _+ ^' y$ c+ c) u% N    }! J( B1 e; w5 s3 a: ?+ ~, d: j( v5 K
}HAL方式void UART_Config(void). y) Z6 }6 v8 J( d0 B
{3 m% t, }6 ^% V9 E( h- s
    GPIO_InitTypeDef GPIO_InitStruct = {0};' Z/ H" \+ W. C* m8 S5 c
   
1 u4 E: F* H% |7 R    // 使能时钟2 |' E5 X  F( a* ], v1 L4 n
    __HAL_RCC_USART1_CLK_ENABLE();7 f6 k" T. l9 f
    __HAL_RCC_GPIOA_CLK_ENABLE();
; J8 i, P) m  k2 [: u2 @1 h3 k$ g   
6 w$ v2 e1 Z1 k! a/ ^& \9 h    // 配置GPIO
9 h% m" \* H* k6 t1 j. C  _    GPIO_InitStruct.Pin = GPIO_PIN_9;
3 G1 `% Y7 m5 ^4 M    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;7 V; ]; u5 {, M3 \. b0 R6 ?$ m) X
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;; W: a6 k" v' L
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
5 ^- R/ b3 C& n/ ]    & x! F5 v" J4 b3 I7 Z, i9 b! L
    GPIO_InitStruct.Pin = GPIO_PIN_10;- G3 I+ O# b. c/ f% Z; Y) m
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  `- p' ^! f+ x8 ?5 ^+ U7 e    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
5 e$ r8 r9 {# k6 D7 r- s9 ~6 O    ( q* ~# {9 t& V2 h* Z5 ^1 y
    // 配置UART; d; C$ e% d2 Q+ w; g* O
    huart1.Instance = USART1;% s: W! u4 Y3 ~7 y" P
    huart1.Init.BaudRate = 115200;
) r8 c5 y8 d% {$ q  I" @& I& \    huart1.Init.WordLength = UART_WORDLENGTH_8B;  J8 B2 K! x% f: V! n' I( }
    huart1.Init.StopBits = UART_STOPBITS_1;
- E! ?: C0 O$ b9 q    huart1.Init.Parity = UART_PARITY_NONE;5 j( ~& y7 k* c6 q
    huart1.Init.Mode = UART_MODE_TX_RX;
( C: P3 m3 r) u! [7 z. @" C    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;+ _. G7 P: B$ f( D; F
    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
0 O: @. C+ o+ x, J; S    HAL_UART_Init(&huart1);- g9 N, S4 ?4 x) i( c' p
}
$ E. _6 v1 U2 ~. |* e0 v9 a* q# n' f4 m  u" A* p: Q( `) g: J: g
voidUART_SendString(char* str)
) k% ^3 H; G6 t3 A9 |{; a2 K- W; G) y! s
    HAL_UART_Transmit(&huart1, (uint8_t*)str, strlen(str), HAL_MAX_DELAY);
3 K# l7 ]3 }7 ]}LL方式void UART_Config(void)
% R( _  R7 t5 X9 p+ o{6 q0 t( _2 V. s
    // 使能时钟* f5 A: g3 o; D. e3 Y, ?
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1);
8 t8 V% v- S+ V, Z# j    LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);- W+ f9 ~1 d. `
   
5 w' l4 ^) [9 Y, s    // 配置GPIO
& {; b# @3 q, r. s3 a    LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_9, LL_GPIO_MODE_ALTERNATE);
9 \7 H  P* t' U3 m0 ?8 ~1 |    LL_GPIO_SetAFPin_0_7(GPIOA, LL_GPIO_PIN_9, LL_GPIO_AF_7);$ `+ b; E5 w2 m( |5 Z; \- q
    LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_9, LL_GPIO_SPEED_FREQ_HIGH);
* S0 C+ ?( k0 d  J: p    + [8 I6 N4 b+ X' }" a5 P& ?) ~
    LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_10, LL_GPIO_MODE_ALTERNATE);6 p" V; w: o1 l1 C! J2 M
    LL_GPIO_SetAFPin_8_15(GPIOA, LL_GPIO_PIN_10, LL_GPIO_AF_7);
8 y6 s: w8 P  U. h: Y- O- S    7 r6 I* m3 S6 a0 K' g' I' B& J) D
    // 配置UART$ _! a5 T; a. e1 I. I
    LL_USART_SetBaudRate(USART1, 115200);! U0 _! U( A2 k4 ~1 K% W: S
    LL_USART_SetDataWidth(USART1, LL_USART_DATAWIDTH_8B);( c" r: @0 ^5 I
    LL_USART_SetStopBitsLength(USART1, LL_USART_STOPBITS_1);
" t: k" \( l4 Q* l8 }, q% [$ R# q    LL_USART_SetParity(USART1, LL_USART_PARITY_NONE);
5 F4 J! I5 o* W( v    LL_USART_SetTransferDirection(USART1, LL_USART_DIRECTION_TX_RX);
  G* U8 s5 G" m1 i! d5 _7 z8 I$ X& H    LL_USART_Enable(USART1);: h' A  @% ?5 x" t2 e+ x
}! j) T, O: u" G! t% W. a
; M( Y2 [! m0 E( e: ?% c5 T& c
voidUART_SendString(char* str)
6 I3 v: V; v/ T0 F, F" {( u* [{
) R& `$ `8 H" H$ Y/ E+ b    while(*str) {
. Z7 H9 d) V+ w0 S: ?2 p$ a# @        while(!LL_USART_IsActiveFlag_TXE(USART1));, A4 s9 \/ I9 k
        LL_USART_TransmitData8(USART1, *str++);
4 \0 T! T& C5 p. c, N- O    }# p: e) Q- v+ R& v0 i
}

  S- C0 P( |0 d  K4 v  W* v$ r9 C. Y7 D. \2 v" F0 X* W2 ?
赞 收藏 评论0 发布时间:2025-10-16 16:33

举报

0个回答

所属标签

相似技术帖

官网相关资源

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