GPIO — GPIO 翻转输出(LL 库)
HAL vs LL:PUYA 固件库提供 HAL 和 LL 两套 API。
- HAL 库:封装度高,可移植性强,适合快速开发
- LL 库:接近寄存器操作,代码精简效率高,适合性能敏感场景 本文使用 LL 库版本。
固件库: PY32F0xx_Firmware V1.5.0
芯片: PY32F030(PY32F002A / F003 同库可参考)
源文件:PUYA/PY32F0xx_Firmware_V1.5.0/Projects/PY32F030-STK/Example_LL/GPIO/GPIO_Toggle/Src/main.c
功能简介
本示例与 HAL 版功能完全相同:让一个 GPIO 引脚工作于输出模式,主循环里周期性翻转电平,板载 LED(PA11,丝印 LED3)闪烁。区别只在于底层 API 用的是 LL 库而非 HAL 库。
通过这一最简单示例,可以直观体会 HAL 与 LL 的写法差异:
- HAL 用
HAL_GPIO_Init()传一个GPIO_InitTypeDef结构体完成配置; - LL 直接调用
LL_GPIO_SetPinMode()一行设置模式,更接近“操作寄存器”,代码更短、依赖更少。
硬件准备
- PY32F030 开发板(或 PY32F002A / F003 官方 STK 板)
- 板载 LED(PA11,对应
LED3) - 一根 USB 数据线用于供电与下载
- 无需额外外接元件
提示:若你手上板子的 LED 不在 PA11,修改下方
LED3_PIN相关宏即可。
完整代码
|
|
代码分段讲解
1. LL 没有“统一初始化入口”
HAL 版第一行是 HAL_Init(),它顺手初始化了 HAL 库、SysTick、中断优先级等。LL 版没有这个总入口,所以你需要自己调用 APP_SystemClockConfig() 把系统时钟配好,否则 LL_mDelay() 的时基是错的。
2. 时钟使能:LL 更“裸”
- HAL:
__HAL_RCC_GPIOA_CLK_ENABLE()(由LED_GPIO_CLK_ENABLE()宏展开)。 - LL:
LED_GPIO_CLK_ENABLE()这个宏本身两版都用,但它的底层就是直接写 RCC 寄存器。关键点:LL 不会在初始化时自动开时钟,忘记开时钟是 LL 初学者最常见的 bug。
3. 引脚配置:结构体 vs 直接函数
- HAL:
HAL_GPIO_Init()接收GPIO_InitTypeDef,一次设置 Pin/Mode/Pull/Speed。 - LL:
LL_GPIO_SetPinMode()单功能函数,一行只做一件事。优点是不需要构造结构体、代码更短;缺点是多个属性要分多行写(不过多数属性复位值就是你要的)。
4. 翻转与延时
LL_GPIO_TogglePin()与HAL_GPIO_TogglePin()语义一致,都是读-反-写。LL_mDelay(100)对应 HAL 的HAL_Delay(100),都是基于 SysTick 的阻塞毫秒延时。注意 LL 版延时前必须先调LL_Init1msTick()设定正确的 tick 频率(在APP_SystemClockConfig里已做)。
实验现象
- 板载 LED(PA11)以约 5Hz(每 100ms 一次)的频率闪烁,比 HAL 版(250ms)更快。
- 用示波器/逻辑分析仪测量 PA11,可见周期约 200ms 的方波。
常见问题
-
LED 不闪 / 闪得很怪?
- 先确认
APP_SystemClockConfig()里LL_Init1msTick()的参数和LL_SetSystemCoreClock()与实际 HSI 频率一致(本例 8MHz)。参数不对,LL_mDelay时序会整体偏移。 - 确认 LED 实际引脚与
LED3_PIN一致。
- 先确认
-
编译报
LL_GPIO_xxx未定义?- LL 函数分散在
stm32py32..._ll_gpio.h等头文件中,确认工程已包含py32f030xx_ll_Start_Kit.h以及对应的 LL 驱动头。
- LL 函数分散在
-
想改成非阻塞闪烁?
- 同 HAL 版思路,用 TIM 更新中断翻转引脚;LL 里对应
LL_TIM_xxx系列函数(见TIM1_PWM_Init示例)。
- 同 HAL 版思路,用 TIM 更新中断翻转引脚;LL 里对应
小结
- LL 版 GPIO 输出三步依然是:开时钟 → 设模式 → 翻转/写电平,但全部由
LL_GPIO_*/LL_RCC_*直接操作完成。 - 与 HAL 的最大区别:LL 没有
HAL_Init()这种“一站式”初始化,系统时钟、LL_mDelay时基都要自己配。 - 代码更短、编译体积更小、对寄存器行为更透明——这是 LL 的核心价值。
拓展应用
- 把
LL_mDelay换成 TIM 中断,做多 LED 不同频率非阻塞闪烁。 - 配合
LL_GPIO_SetPinOutputType()把引脚设为开漏(LL_GPIO_OUTPUT_OPENDRAIN),驱动需要线与的总线设备。 - 用
LL_GPIO_ReadInputPort()读取按键,实现按键控制 LED(LL 版GPIO_INPUT思路同 HAL)。 - 结合
TIM1_PWM_Init示例,用LL_TIM_OC_SetCompareCHx()做呼吸灯。