下面把 HAL 庫 和 標準外設庫(SPL) 初始化 GPIO 點亮/熄滅 LED 的完整步驟、示例代碼和常用 API 逐一說清楚。用例默認 PC13 接 LED(藍板常見;低電平點亮,高電平熄滅——若板子相反,只把寫 1/0 對調即可)。
一、HAL 庫:GPIO 初始化與點亮/熄滅 LED
步驟(通用順序)
使能端口時鐘
__HAL_RCC_GPIOx_CLK_ENABLE()
填寫
GPIO_InitTypeDef
結構體(Pin/Mode/Speed …)調
HAL_GPIO_Init(GPIOx, &init)
完成配置用
HAL_GPIO_WritePin / TogglePin / ReadPin
控制或讀引腳
(可選)5) 若需 EXTI:還要配置中斷優先級并使能 NVIC,使用HAL_GPIO_EXTI_IRQHandler
/HAL_GPIO_EXTI_Callback
示例代碼(HAL)
led.h
#ifndef __LED_H__
#define __LED_H__#include "stm32f1xx_hal.h"/* ====== 硬件相關宏定義 ====== */
#define LED_GPIO_PORT GPIOC // LED 所在的端口(此處為 GPIOC)
#define LED_GPIO_PIN GPIO_PIN_13 // LED 引腳號(PC13)/* ====== LED 控制函數聲明 ====== */
void LED_Init(void); // 初始化 LED 引腳
void LED_On(void); // 點亮 LED
void LED_Off(void); // 熄滅 LED
void LED_Toggle(void); // 翻轉 LED 狀態#endif
led.c:
#include "led.h"/*** @brief 初始化 LED 引腳* @note 配置為推挽輸出,默認熄滅(PC13高電平)*/
void LED_Init(void)
{/* 1. 使能 GPIOC 時鐘(如果不打開,GPIO 寄存器無法操作) */__HAL_RCC_GPIOC_CLK_ENABLE();/* 2. 配置 GPIO 參數 */GPIO_InitTypeDef gpio = {0}; // 定義配置結構體并清零gpio.Pin = LED_GPIO_PIN; // 選擇 PC13gpio.Mode = GPIO_MODE_OUTPUT_PP; // 推挽輸出模式gpio.Speed = GPIO_SPEED_FREQ_LOW; // 低速輸出(足夠驅動 LED)HAL_GPIO_Init(LED_GPIO_PORT, &gpio); // 初始化 GPIOC 的 13 引腳/* 3. 缺省熄滅 LED(PC13 高電平 = 滅) */HAL_GPIO_WritePin(LED_GPIO_PORT, LED_GPIO_PIN, GPIO_PIN_SET);
}/*** @brief 點亮 LED*/
void LED_On(void)
{HAL_GPIO_WritePin(LED_GPIO_PORT, LED_GPIO_PIN, GPIO_PIN_RESET); // PC13 輸出低電平
}/*** @brief 熄滅 LED*/
void LED_Off(void)
{HAL_GPIO_WritePin(LED_GPIO_PORT, LED_GPIO_PIN, GPIO_PIN_SET); // PC13 輸出高電平
}/*** @brief 翻轉 LED 狀態*/
void LED_Toggle(void)
{HAL_GPIO_TogglePin(LED_GPIO_PORT, LED_GPIO_PIN); // HAL 內部用 BSRR 實現
}
main.c
#include "stm32f1xx_hal.h"
#include "led.h"/* 系統時鐘配置函數(具體實現依賴 CubeMX 或手寫) */
static void SystemClock_Config(void);int main(void)
{/* 1. HAL 庫初始化:包括時鐘源、SysTick 配置等 */HAL_Init();/* 2. 配置系統時鐘(比如 HSE=8MHz → SYSCLK=72MHz) */SystemClock_Config();/* 3. 初始化 LED 引腳 */LED_Init();/* 4. 主循環:控制 LED 閃爍 */while (1){LED_On(); // 點亮HAL_Delay(300); // 延時 300 msLED_Off(); // 熄滅HAL_Delay(300); // 延時 300 msLED_Toggle(); // 翻轉狀態HAL_Delay(300); // 延時 300 ms}
}/* ===== 系統時鐘配置函數(此處僅示意,實際需根據工程生成) ===== */
static void SystemClock_Config(void)
{/* 如果使用 CubeMX,一般會自動生成這里的代碼。自己手寫時,需要配置 HSE/PLL,把 SYSCLK 提升到 72MHz。如果不寫,默認 SystemInit() 可能只運行在 8MHz HSI。 */
}
HAL 結構體/參數要點(F1)
Pin
:引腳位圖,可或起來(如GPIO_PIN_0 | GPIO_PIN_1
)。Mode
:GPIO_MODE_OUTPUT_PP / _OD
(推挽/開漏)GPIO_MODE_INPUT
、GPIO_MODE_ANALOG
GPIO_MODE_AF_PP / _AF_OD
(復用推挽/開漏)GPIO_MODE_IT_RISING/FALLING/RISING_FALLING
(外部中斷)GPIO_MODE_EVT_*
(事件)
Speed
:GPIO_SPEED_FREQ_LOW/MEDIUM/HIGH
(≈2/10/50 MHz)
注:F1 的 HAL 不帶
Pull
字段(上拉/下拉由 CRL/CRH 的 CNF 決定;若要上拉/下拉,需把Mode
設為輸入并用ODR
置 1/0 完成上/下拉,或直接用 HAL 的GPIO_MODE_INPUT
+ 后續寫 ODR)。
二、標準外設庫(SPL):GPIO 初始化與點亮/熄滅 LED
步驟
使能端口時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOx, ENABLE)
填
GPIO_InitTypeDef
(Pin/Mode/Speed)調
GPIO_Init(GPIOx, &init)
用
GPIO_SetBits / ResetBits / WriteBit
控制
示例代碼(SPL)
led.h:
#ifndef __LED_H__
#define __LED_H__#include "stm32f10x.h"/* ====== 硬件相關宏定義 ====== */
#define LED_GPIO_PORT GPIOC // LED 所在端口
#define LED_GPIO_PIN GPIO_Pin_13 // LED 引腳 PC13
#define LED_GPIO_CLK RCC_APB2Periph_GPIOC // GPIOC 時鐘/* ====== LED 控制函數聲明 ====== */
void LED_Init(void); // 初始化 LED 引腳
void LED_On(void); // 點亮 LED
void LED_Off(void); // 熄滅 LED
void LED_Toggle(void); // 翻轉 LED 狀態#endif
led.c:
#include "led.h"/*** @brief 初始化 LED 引腳* @note PC13 配置為推挽輸出,默認熄滅*/
void LED_Init(void)
{/* 1. 使能 GPIOC 時鐘 */RCC_APB2PeriphClockCmd(LED_GPIO_CLK, ENABLE);/* 2. 配置 PC13 為推挽輸出 */GPIO_InitTypeDef gpio;gpio.GPIO_Pin = LED_GPIO_PIN; // 選擇引腳gpio.GPIO_Speed = GPIO_Speed_2MHz; // 輸出速度 2MHzgpio.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽輸出GPIO_Init(LED_GPIO_PORT, &gpio);/* 3. 缺省熄滅 LED(PC13 高電平 = 滅) */GPIO_SetBits(LED_GPIO_PORT, LED_GPIO_PIN);
}/*** @brief 點亮 LED*/
void LED_On(void)
{GPIO_ResetBits(LED_GPIO_PORT, LED_GPIO_PIN); // 低電平
}/*** @brief 熄滅 LED*/
void LED_Off(void)
{GPIO_SetBits(LED_GPIO_PORT, LED_GPIO_PIN); // 高電平
}/*** @brief 翻轉 LED 狀態*/
void LED_Toggle(void)
{if (GPIO_ReadOutputDataBit(LED_GPIO_PORT, LED_GPIO_PIN))GPIO_ResetBits(LED_GPIO_PORT, LED_GPIO_PIN); // 如果當前是 1 → 清零elseGPIO_SetBits(LED_GPIO_PORT, LED_GPIO_PIN); // 如果當前是 0 → 置 1
}
main.c:
#include "stm32f10x.h"
#include "led.h"/* 時鐘配置函數 */
static void Clock_Config(void);int main(void)
{/* 1. 配置系統時鐘(如果需要) */Clock_Config();/* 2. 初始化 LED 引腳 */LED_Init();/* 3. 主循環:控制 LED 閃爍 */while (1){LED_On(); // 點亮for(volatile int i=0;i<600000;i++); // 簡單延時LED_Off(); // 熄滅for(volatile int i=0;i<600000;i++);LED_Toggle(); // 翻轉狀態for(volatile int i=0;i<600000;i++);}
}/*** @brief 時鐘配置* @note SPL 啟動文件里默認調用 SystemInit(),會把 HSE/PLL 配置成 72MHz。* 如果已經夠用,這里可以留空。*/
static void Clock_Config(void)
{/* 一般用默認 SystemInit 即可 */
}
SPL 結構體/參數要點
GPIO_Mode
:GPIO_Mode_AIN
(模擬輸入)GPIO_Mode_IN_FLOATING
(浮空輸入)GPIO_Mode_IPD / GPIO_Mode_IPU
(下拉/上拉輸入)GPIO_Mode_Out_PP / _Out_OD
(通用推挽/開漏輸出)GPIO_Mode_AF_PP / _AF_OD
(復用推挽/開漏輸出)
GPIO_Speed
:GPIO_Speed_2MHz / 10MHz / 50MHz
(僅對輸出/復用輸出有效)
三、圖里 HAL GPIO 其他函數的作用(并給出 SPL 對應函數)
HAL 函數 | 作用(要點) | 關鍵參數 | SPL/等價做法 |
---|---|---|---|
HAL_GPIO_Init(GPIOx, &init) | 根據 Pin/Mode/Speed 配置端口(本質寫 CRL/CRH) | GPIOx :端口;Pin 位圖;Mode ;Speed | GPIO_Init(GPIOx, &init) |
HAL_GPIO_DeInit(GPIOx, GPIO_Pin) | 復位指定引腳到缺省(模擬輸入),清除 EXTI 綁定 | GPIO_Pin 位圖 | GPIO_DeInit(GPIOx) (注意 SPL 是“整個端口復位”;單獨復位需手寫寄存器) |
HAL_GPIO_WritePin(GPIOx, GPIO_Pin, GPIO_PinState) | 通過 BSRR 原子置 1/清 0 | GPIO_PinState :GPIO_PIN_SET/RESET | GPIO_WriteBit/SetBits/ResetBits 或 GPIOx->BSRR/BRR |
HAL_GPIO_TogglePin(GPIOx, GPIO_Pin) | 翻轉輸出(對 ODR 異或) | GPIO_Pin 位圖 | 無直接 API,可 GPIO_WriteBit(GPIOx,pin, (BitAction)!GPIO_ReadOutputDataBit(...)) 或操作 ODR |
HAL_GPIO_ReadPin(GPIOx, GPIO_Pin) | 讀 IDR,返回 GPIO_PIN_SET/RESET | GPIO_Pin | GPIO_ReadInputDataBit(GPIOx, pin) |
HAL_GPIO_LockPin(GPIOx, GPIO_Pin) | 通過 LCKR 鎖定配置,直到下次復位(防誤改) | GPIO_Pin 位圖 | GPIO_PinLockConfig(GPIOx, pin) |
HAL_GPIO_EXTI_IRQHandler(GPIO_Pin) | 通用 EXTI 線中斷處理:清掛起位并調用回調 | GPIO_Pin :哪條線觸發 | SPL:在 EXTIxx_IRQHandler 里 EXTI_GetITStatus /EXTI_ClearITPendingBit ,然后自己回調 |
HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) | 弱定義(__weak)回調,用戶重寫做業務 | GPIO_Pin :觸發的線 | SPL:自己寫回調或在 IRQHandler 里直接處理 |
EXTI 的初始化(兩庫都需要額外步驟)
HAL:把引腳
Mode
設為GPIO_MODE_IT_*
,然后用HAL_NVIC_SetPriority
與HAL_NVIC_EnableIRQ
開中斷即可。SPL:
GPIO_EXTILineConfig(AFIO_PORTx, PinSourcex) + EXTI_Init(&cfg) + NVIC_Init(&nvic)
。
四、常見易錯點與小技巧
時鐘別忘開:F1 的 GPIO 都在 APB2,HAL 用
__HAL_RCC_GPIOx_CLK_ENABLE()
;SPL 用RCC_APB2PeriphClockCmd(...)
。藍板 PC13 低電平點亮:別把“寫 1 點亮”寫反。
原子操作首選 BSRR:HAL 的
WritePin/TogglePin
已經用 BSRR,SPL 用GPIOx->BSRR/BRR
更安全。速度只對輸出有效:輸入模式時
Speed
無意義。鎖定功能:量產固件防誤改時可用
HAL_GPIO_LockPin / GPIO_PinLockConfig
。多腳同時配置:
Pin
可位或(如GPIO_PIN_0|GPIO_PIN_1
),一次初始化多個引腳。