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

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

[复制链接]
flyingstar 发布时间:2025-10-16 16:33
从寄存器操作到硬件抽象层:STM32开发库的演进。
演进历程
STM32微控制器自2007年推出以来,STMicroelectronics为其提供了多套软件开发库,经历了从直接寄存器操作到高度抽象化的演进过程:
发展时间线
  • • 2007-2010: 标准外设库(SPL)时代
  • • 2013-2015: HAL库引入,SPL逐步淘汰
  • • 2016-至今: HAL + LL双轨制,CubeMX工具链完善  a* n. b: T) J6 ?2 q% i) A& n& Q. ~
当前状态
  • • SPL: 已停止维护,支持F0/F1/F2/F3/F4系列
  • • HAL: ST官方主推,持续更新维护
  • • LL: 作为HAL的补充,提供更接近硬件的接口2 {7 i, N* |7 n
三大库架构对比特性标准外设库(SPL)HAL库LL库
, m8 G& N. B& J5 D7 O抽象层次中等高低
) a( b1 j1 i" l& s8 a) `( B代码体积中等大小
" \9 |% S% q" m执行效率高中等高- f1 e' C* L. @5 p9 P" \# |3 b3 S
学习难度中等低高/ m6 `3 o( V7 \# O  S
可移植性低高中等3 r8 c  I. O2 U3 P5 w) c+ D- O
维护状态已停止活跃活跃
. S2 g$ o) q* i9 B( |+ A" w工具支持无CubeMXCubeMX标准外设库(SPL)设计理念
SPL采用"一个外设一个文件"的设计理念,每个外设都有对应的.c和.h文件,提供中等层次的抽象。
核心特点// SPL典型用法示例
+ L: `* n: ^( A6 F3 ?4 bvoid GPIO_Config(void)
, k% j2 R% i, N* M' V* L{
1 J- t2 c6 w- Q5 T% S: ~    GPIO_InitTypeDef GPIO_InitStructure;3 A* S: i0 W1 d6 f
   
4 S$ [, J! p, z3 y  L2 a    // 使能GPIO时钟
$ e$ r9 \$ N% {" |    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);/ F1 d  I; X+ j' O. f+ ^9 ^) v2 Z
   
( v9 f. T; A( F. B6 d5 f    // 配置GPIO5 f. K) T/ T; \$ |7 B1 @' ?
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;$ p! h# Z. A/ n' F6 ~
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;2 o1 ?7 P5 m  F: B9 |0 }
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
" O; [3 [+ a8 A! w3 |0 ]    GPIO_Init(GPIOA, &GPIO_InitStructure);
# u+ Y( Y7 L8 x}优势
  • 1. 性能优异: 直接操作寄存器,执行效率高
  • 2. 代码紧凑: 相比HAL库,代码体积更小
  • 3. 逻辑清晰: 一个函数完成一个功能,易于理解
  • 4. 调试友好: 可以直接查看寄存器状态
    ! }, l5 ~4 ^- F: N8 [# F1 s
劣势
  • 1. 维护停止: 不再支持新系列MCU
  • 2. 移植困难: 不同系列间API差异较大
  • 3. 工具支持差: 无现代IDE集成支持
  • 4. 文档过时: 缺乏最新的技术文档6 s0 L0 P% I8 K
HAL库设计理念
HAL库采用"硬件抽象层"设计,旨在提供跨系列的统一API接口,隐藏硬件细节。
核心特点// HAL库典型用法示例
7 l! l2 i$ i2 I- T: h; Hvoid GPIO_Config(void)3 t( {; ~2 A0 t! [
{
5 N& E; U+ i. ?# ^! _+ r    GPIO_InitTypeDef GPIO_InitStruct = {0};
7 ]5 X3 d* R4 ]* B4 e   
/ @% {3 o# J7 f! o- p; \    // 使能GPIO时钟
9 D  o: H! u( R, G! {    __HAL_RCC_GPIOA_CLK_ENABLE();& C0 i, p0 D" P8 L
   
$ l' f) k0 B+ p6 K    // 配置GPIO
/ j7 `4 Q- a  _# t    GPIO_InitStruct.Pin = GPIO_PIN_5;6 [! S. D! W0 g
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
' O2 [0 w9 J  [" n# X    GPIO_InitStruct.Pull = GPIO_NOPULL;+ o2 X7 }. u% K# b3 B
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
( |& [9 k4 \7 R0 T7 ^    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
- {6 K% G5 k; L; `$ s3 h}架构优势
  • 1. 统一接口: 跨系列API一致性
  • 2. 工具集成: 与CubeMX深度集成
  • 3. 功能丰富: 支持复杂外设如USB、以太网
  • 4. 持续维护: 定期更新和bug修复- m; f( Q7 d9 ~( T% h& D
劣势
  • 1. 代码膨胀: 大量抽象层导致代码体积大
  • 2. 执行开销: 多层函数调用影响性能
  • 3. 内存消耗: 需要更多RAM存储状态信息
  • 4. 调试复杂: 抽象层增加调试难度( S9 L5 h2 N9 r1 l4 O# w' k
LL库(低层库)设计理念
LL库是HAL库的补充,提供更接近硬件的接口,同时保持一定的可移植性。
核心特点// LL库典型用法示例8 b# c. }- M& {9 D3 j2 J  s
void GPIO_Config(void)0 b0 x$ Y% o" }+ @# a
{
9 ^( b2 V/ @" _# [0 w0 h8 K& L9 ^    // 使能GPIO时钟
- w5 z' n( [2 m! [+ |    LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
+ H) S# M/ N) @+ T. b: g   
, i& z6 F' N" p. C, @" P    // 配置GPIO
: F: h" Y6 M5 N, T( N; q% [3 l- m    LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_5, LL_GPIO_MODE_OUTPUT);
. t: G  f2 f* Z: e4 H% Z8 R6 W    LL_GPIO_SetPinOutputType(GPIOA, LL_GPIO_PIN_5, LL_GPIO_OUTPUT_PUSHPULL);( N0 f. m7 m& r; m. W' R9 J$ F8 \
    LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_5, LL_GPIO_SPEED_FREQ_HIGH);
' z4 G4 c/ |5 U4 u- S}优势
  • 1. 性能接近寄存器: 大部分函数被内联优化
  • 2. 代码体积小: 相比HAL库显著减少
  • 3. 可读性好: 函数名自解释,代码更清晰
  • 4. 工具支持: 与CubeMX集成8 J0 J0 Z6 E; n$ \
适用场景
  • • 对性能有较高要求的应用
  • • 资源受限的MCU
  • • 需要精确控制时序的场景
  • • 从SPL迁移的项目3 J& ~; F1 L" M& ?% N: h# R$ S
实际代码示例对比UART配置与使用对比SPL方式void UART_Config(void)" e+ [; y6 ]7 V% x
{) C. q7 K4 C: y* \; V) m  G7 t
    USART_InitTypeDef USART_InitStructure;2 n3 L1 ^1 K( Z4 I  d: j9 }
    GPIO_InitTypeDef GPIO_InitStructure;2 B$ P& s9 I0 ^0 e' _; Q
   
4 b% i' Q" I" p1 S' t) G8 C; U    // 使能时钟
" {3 u  k4 U$ X' Y1 W' G    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);3 l  W. U% k/ ?  i- m( C: _
   
% p3 v9 I' X6 x6 C" h. [    // 配置GPIO
' A6 ]& [( c3 G6 {8 H7 b5 ]1 v6 p    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;  // TX% V$ E! ^% K9 A
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+ |2 M1 f! V  O6 Q; X. y    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
, X1 H) ~( K. a; [# B    GPIO_Init(GPIOA, &GPIO_InitStructure);6 ?2 `2 v( B  n& k
   
/ o" D" J" H/ N" f6 I9 Y    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // RX* o, l+ k9 T" R2 K
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;' u0 {4 j6 t# m$ i& z6 P1 d
    GPIO_Init(GPIOA, &GPIO_InitStructure);
* `) E; d3 o. `( t; k4 t: J6 V2 S   
9 |( g, S: B* B$ p    // 配置UART/ p! U% Z" }7 P: t9 v3 x# W) k- \
    USART_InitStructure.USART_BaudRate = 115200;& F: c2 T; d' }  u0 w
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
; }( s3 x0 n4 @/ T$ h  c    USART_InitStructure.USART_StopBits = USART_StopBits_1;3 s  d1 E* A8 t1 T& \
    USART_InitStructure.USART_Parity = USART_Parity_No;0 K0 e4 n9 j+ X9 f( t
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
! j3 Z  P) V6 o    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
; Y6 ^$ m  o2 Q$ r+ p* `    USART_Init(USART1, &USART_InitStructure);0 {( f% m1 O8 r1 ^5 j
   
2 q/ u4 |* w6 T* m4 i# D    USART_Cmd(USART1, ENABLE);
! _5 G0 o1 T1 Y) U; A0 L}
, ^4 R" h9 V1 i& W! S! Y- p% e& l1 U- z9 \0 V+ A& `
voidUART_SendString(char* str)6 Q2 T* y6 @. D- ~3 w/ o6 @% z
{
8 t5 J8 P$ X) S! H    while(*str) {
; y# S% O% J; w; i        while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);. Q7 }/ D/ M9 L/ ~4 v1 F) ^% G
        USART_SendData(USART1, *str++);  N: k3 x7 C7 E8 e) G
    }
' C4 B7 G2 d# y}HAL方式void UART_Config(void)- A' K7 W8 M9 Y% K8 }1 t1 ^0 J
{
. O4 n  f2 q6 r7 @$ v+ c    GPIO_InitTypeDef GPIO_InitStruct = {0};
/ l* u5 g0 d' B/ s   
8 a* R2 m  H8 t! E' \" T* X6 P9 Z4 p    // 使能时钟
; _, E( U5 P) P. q: P" S    __HAL_RCC_USART1_CLK_ENABLE();6 ^, \; d& Q, h
    __HAL_RCC_GPIOA_CLK_ENABLE();" A5 |$ k) }$ n% r
   
/ P, A4 s, t6 ]2 l& a& w    // 配置GPIO8 ?- g% O+ G! ?6 w" Q) W9 E
    GPIO_InitStruct.Pin = GPIO_PIN_9;8 k& x* v* Y! ^3 {0 e% q. d# e
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;' ]. O2 K$ O3 X: l2 |2 a' \
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
3 S6 h2 H3 @" i3 Z% ^    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
# R- N1 w5 e* B   
; y/ O! I+ U& B7 M* w3 p    GPIO_InitStruct.Pin = GPIO_PIN_10;0 d& g. H: q" N- U
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;3 n7 I  w# O6 j. n
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);* R' ~% h) `5 U) W
   
* a9 f; B& c2 l4 J5 K- O& b5 `    // 配置UART
$ A9 E4 b& i2 c: ^/ E    huart1.Instance = USART1;. V+ r5 ]& W. p
    huart1.Init.BaudRate = 115200;
: [- ?4 m5 c0 S" l    huart1.Init.WordLength = UART_WORDLENGTH_8B;( S% u/ @8 X% @6 P
    huart1.Init.StopBits = UART_STOPBITS_1;
% _9 {  l: R( E* S3 S    huart1.Init.Parity = UART_PARITY_NONE;
$ v% k- _# ?! O( U7 A( s- P" l    huart1.Init.Mode = UART_MODE_TX_RX;
$ t& |! k: x* b- v& j. [' g    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
+ B" r6 j0 N  O    huart1.Init.OverSampling = UART_OVERSAMPLING_16;( C  r0 S: b8 t( p
    HAL_UART_Init(&huart1);8 {# b: ?; D. \$ {3 q8 m
}: Z& _( D; @- P. T

: e% n% `' z' x! O/ zvoidUART_SendString(char* str). y9 l2 c/ o0 H; i$ R
{) Q0 P+ u! S6 F  E8 N3 P
    HAL_UART_Transmit(&huart1, (uint8_t*)str, strlen(str), HAL_MAX_DELAY);
  r# b  i" k( s* b}LL方式void UART_Config(void)
5 H2 }. Z3 i% N% F3 u{
% o" |/ I/ D8 d0 }! U# F    // 使能时钟' m1 ]# t( n. ], X) t
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1);/ A/ D/ Q# j) C: @3 k# Z
    LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
3 K  }7 }* m$ B4 u. ~% x    ' I+ i% f/ Z2 I- H  P. L
    // 配置GPIO
+ N1 J6 r. B- I3 B+ y    LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_9, LL_GPIO_MODE_ALTERNATE);5 I, [1 R$ t5 X0 u; b
    LL_GPIO_SetAFPin_0_7(GPIOA, LL_GPIO_PIN_9, LL_GPIO_AF_7);
2 Y' L7 Q, H" F8 k2 ~, O    LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_9, LL_GPIO_SPEED_FREQ_HIGH);, ^( s& s( w1 ~" V. L" j
   
% K% u* k- Q+ n( g7 ~    LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_10, LL_GPIO_MODE_ALTERNATE);
" [' G; y4 }+ |    LL_GPIO_SetAFPin_8_15(GPIOA, LL_GPIO_PIN_10, LL_GPIO_AF_7);
8 X( t5 Y: e* x4 m    % q, f5 e( r8 Y! H- f9 R0 s
    // 配置UART+ h& H* i: u, y+ v  {
    LL_USART_SetBaudRate(USART1, 115200);
  x. J/ g4 U! _- j    LL_USART_SetDataWidth(USART1, LL_USART_DATAWIDTH_8B);
( u8 e( p: |9 z" J& @% L0 G    LL_USART_SetStopBitsLength(USART1, LL_USART_STOPBITS_1);
3 p# i* v- D) v1 `/ B    LL_USART_SetParity(USART1, LL_USART_PARITY_NONE);: S( c- u+ c6 l. Y! ^3 W
    LL_USART_SetTransferDirection(USART1, LL_USART_DIRECTION_TX_RX);
( l$ S( O. `/ `+ c2 d; `# W3 T    LL_USART_Enable(USART1);
& j) a: |  H- w9 y- P: ?& P: q2 m}
# t4 Y& v, j! _9 j9 B1 S
! @, o, Y* r5 J. z6 kvoidUART_SendString(char* str)& H" h2 E( P$ [) n7 O( _& E
{
  I9 y" n3 X0 {! \" A    while(*str) {
. f4 a5 X6 a' s* _' h8 W* T5 a. {        while(!LL_USART_IsActiveFlag_TXE(USART1));; d5 G: Q& h* N- E: y9 G* I6 D$ i
        LL_USART_TransmitData8(USART1, *str++);
. }; W! Z, f0 N- I, C$ u3 M    }
. |, \# _* {. G7 o}

! f4 V* r+ ?' B( K6 B9 b" n" d9 I- z) d& S* u9 C- K' j
赞 收藏 评论0 发布时间:2025-10-16 16:33

举报

0个回答

所属标签

相似技术帖

官网相关资源

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