## HAL vs LL ## 判别规则(核心,唯一要记的) 1. **选档看需求**:图开发快/要移植/外设复杂 → **HAL**(+CubeMX);图性能/资源紧/精细控制 → **LL 或寄存器** 2. **HAL 三模式看数据**:低速调试 → 轮询;要异步/不定长 → 中断(IT);大批量 → DMA 3. **认风格**:有句柄结构体(`UART_HandleTypeDef`)+ 回调 + `HAL_` 前缀 = **HAL**;轻量直读寄存器、无句柄 = **LL** 一句话:**"开发快、要移植选 HAL;资源紧、要极致选 LL/寄存器;认风格看有没有句柄和回调。"** ## 抽象描述(一句话本质) 写 STM32 有三档"档位"——**寄存器 = 手动挡**(直接拨寄存器)、**HAL = 自动挡**(全封装,好用但沉)、**LL = 半自动挡**(封装很薄,贴着寄存器,快但轻)。面试核心就一件事:**什么情况该开哪一档**。 ## 三档对比 | 档位 | 长啥样 | 优点 | 缺点 | 何时用 | | ------- | ----------------------------------- | --------------------------------- | ---------------------------- | -------------------------- | | 寄存器 | `RCC->APB2ENR \|= ...` | 最透、最快、最省 | 开发慢、移植全重写 | 学底层、性能极致 | | **HAL** | `HAL_UART_Transmit(&huart1,...)` | 开发快、跨型号可移植、CubeMX 生成 | 代码大、慢、结构重 | 快速开发、复杂外设、要移植 | | **LL** | `LL_USART_TransmitData8(USART1, x)` | 比 HAL 轻、快、省资源 | 要自己管细节、可移植不如 HAL | 资源紧张、性能敏感、驱动层 | ## HAL 内部三种模式 | 模式 | 行为 | 适用 | | ---------- | -------------------- | --------------------------- | | 轮询 | 阻塞死等 | 调试、低速(I2C 读 EEPROM) | | 中断(IT) | 非阻塞,到点回来处理 | 不定长串口接收 | | DMA | 硬件搬运,CPU 零参与 | 大批量(ADC 多通道) | ## HAL 为什么"重/慢"(它多做了这些事) - 每个外设一个**句柄结构体**(状态全记在里面) - 每次调用**参数校验**(`IS_XXX` 宏) - 带**超时/错误处理** - **MspInit 分层**(时钟、引脚单独配) - **回调注册**机制(`HAL_XXX_Callback`) 多这几层 = 代码大、调用慢,但换来"你只管调 API,底层差异我罩着"。 ## 为什么 HAL 能跨芯片移植(别答反了) 不是"寄存器定义不一致所以不能移植"——**恰恰相反**:HAL 把芯片差异**藏在库内部**(F1、F4 各有自己的 `stm32f1xx_hal_uart.c` / `stm32f4xx_hal_uart.c`,对外提供同一个 `HAL_UART_Transmit`)。你的代码只调 API、从不碰寄存器 → 换芯片只换库 + CubeMX 重生成,业务代码不动。 ## 正反例(建立直觉) - **正例1**:快速原型、要以后换芯片 → HAL + CubeMX(可移植性优先) - **正例2**:Flash/RAM 吃紧、中断响应要极致、团队熟底层 → LL 或寄存器(性能优先) - **反例1**:以为"性能第一,永远选 LL" → 错,开发速度、维护性、可移植性往往才是成本大头 - **反例2**:以为 HAL 就是慢的代名词,正式产品不该用 → 错,量产产品用 HAL 的到处都是,那点开销大多可忽略 ## 易混对比 ### HAL vs LL vs 寄存器(三档快速认) | 特征 | 寄存器 | LL | HAL | | ---------- | ---------------- | ------- | ------------------ | | 句柄结构体 | 无 | 无/极少 | 有(每个外设一个) | | 回调函数 | 无 | 无 | 有 | | 函数前缀 | 无(直接寄存器) | `LL_` | `HAL_` | | 代码量 | 最小 | 小 | 大 | | 可移植性 | 差 | 中 | 好 | ## 变体验证(3 题,全过=学会) 1. 量产产品,Flash/RAM 吃紧、中断响应要极致、团队熟底层 → **LL/寄存器**(资源紧 + 性能优先 + 熟底层,选它最合适) 2. 陷阱题:"HAL 比 LL 慢,所以正式产品永远不该用 HAL" → **错**。那点性能开销大多可忽略;开发速度、可维护性、可移植性才是大头,量产用 HAL 很常见 3. 陷阱题:认代码——`HAL_UART_Receive_IT(&huart1, buf, 10)` 是 **HAL**(句柄 + IT 模式 + 回调);`LL_USART_ReceiveData8(USART1)` 是 **LL**(直接读寄存器、无句柄) ## 口述要点(面试怎么讲) - **结论先行**:开发快/要移植 → HAL;资源紧/要极致 → LL/寄存器;认风格看句柄和回调 - **HAL 重在哪**:句柄、参数校验、超时/错误处理、MspInit 分层、回调——换来"只管调 API" - **HAL 为什么可移植**:芯片差异藏在库内部,你只调统一 API 不碰寄存器,换芯片只换库 - **选型是综合权衡**:性能只是其中之一,开发时间、维护成本、可移植性、团队熟悉度都是硬指标,有时比性能更硬 - **易错点**:以为性能第一;以为 HAL 不能用于量产;把 HAL 回调流程和中断服务函数混在一起 ## 关系网络 | 相邻概念 | 关系 | 孤立理解会犯的错 | | ---------- | ----------------------------------------------- | ---------------------------------- | | 中断优先级 | HAL 的 IT 模式本质是中断,也要配 NVIC | 只调 HAL_XX_IT 不配 NVIC,中断不来 | | DMA | HAL 的 DMA 模式就是主题 33 那套 | 以为 DMA 是 HAL 独有,寄存器也有 | | 时钟树 | CubeMX 的 `SystemClock_Config` 就是主题 34 那套 | 改时钟忘配 Flash 等待,HAL 也死机 | | 元学习法 | 每个主题背后都是"选型判别规则" | 背 API 名不背"什么时候用哪个" | ## 学习日期 2026-08-18 --- _每主题一页,复习时只翻本目录。_