6 Bật đèn LED bằng thư viện chuẩn STM32F4xx Standard Peripheral Library 
Trong các dự án cũ hoặc khi không dùng HAL, bạn vẫn có thể điều khiển ngoại vi qua thư viện Standard Peripheral Library. Quy trình chung gồm các bước:
- Bật đồng hồ cho cổng GPIO
- Cấu hình tham số đầu ra của GPIO (mode, type, speed, pull-up/pull-down)
- Điều khiển chân GPIO để bật/tắt LED
Ví dụ dưới đây áp dụng cho LED nối với chân PB2.
1. Bật đồng hồ cho GPIOB 
Mặc định, mọi ngoại vi đều tắt clock. Trước khi dùng GPIOB, gọi:
- Bạn cần mở file stm32f4xx_rcc.hđể xem các hàm quản lý clock.
- Prototype hàm bật clock cho ngoại vi trên bus AHB1:
void RCC_AHB1PeriphClockCmd(uint32_t RCC_AHB1Periph, FunctionalState NewState);
Trong đó:
- RCC_AHB1Periph: macro xác định ngoại vi (ví dụ- RCC_AHB1Periph_GPIOB).
- NewState:- ENABLEhoặc- DISABLE.
Sau khi xác định, bạn có thể gọi:
// Kích hoạt clock cho AHB1, port GPIOB
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);2. Cấu hình tham số đầu ra của GPIOB_PB2 
Cấu hình tham số đầu ra của GPIO 
Cấu hình GPIO cho đầu ra cũng gồm hai bước, bước đầu là cấu hình chế độ đầu ra là đẩy đẩy hay mở mở, bước thứ hai là cấu hình tốc độ đầu ra của GPIO. Việc này cũng liên quan đến thao tác với GPIO, cần tra trong file STM32f4xx_gpio.h các hàm hoặc cấu trúc tương ứng.
- void GPIO_Init(GPIO_TypeDef GPIOx, GPIO_InitTypeDef GPIO_InitStruct)
Hàm
GPIO_Initdùng để khởi tạo cổng GPIO (đầu vào/đầu ra chung) của dòng vi điều khiển STM32. Nó dựa trên các tham số cung cấp để cấu hình chế độ hoạt động, tốc độ, kiểu đầu ra của cổng GPIO.
Giải thích tham số:
- GPIOx: Tham số này chỉ định cổng GPIO cần khởi tạo.
- GPIO_InitStruct: Đây là con trỏ trỏ tới cấu trúc
GPIO_InitTypeDef, chứa các thông tin cấu hình của cổng GPIO. Cấu trúcGPIO_InitTypeDefthường bao gồm các thành viên quan trọng sau:- Pin: Chỉ định chân GPIO cần cấu hình. Có thể là một chân hoặc tổ hợp nhiều chân.

- GPIO_Mode: Đặt chế độ hoạt động của chân như chế độ xuất, chế độ nhập, chế độ đa năng…
- Muốn sử dụng chức năng tái sử dụng cần sử dụng hàm GPIO_PinAFConfig để cấu hình.

- GPIO_PuPd: Thiết lập trạng thái của điện trở kéo lên/kéo xuống của chân.

- GPIO_Speed: Thiết lập tốc độ đầu ra của chân (thấp, trung bình, cao, rất cao).

- GPIO_OType: Loại đầu ra.

Đáp ứng được chức năng của chúng tôi. Các thành viên cụ thể của cấu trúc:

Cần cấu hình PB2 làm đầu ra đẩy-pull, tốc độ 100MHZ, chỉ cần truyền vào các tham số tương ứng. Chuyển sang mã nguồn là
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_2;// Chọn chân PB2
GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_OUT;// Chế độ output Push-Pull
GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;// Không dùng pull-up/pull-down
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;// Tốc độ chuyển mạch 100 MHz (Very High)
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;// Kiểu đầu ra Push-Pull
GPIO_Init(GPIOB, &GPIO_InitStructure);// Áp dụng cấu hình3. Điều khiển LED PB2 
Sau khi cấu hình, bạn có thể dùng các hàm sau:
- GPIO_SetBits(GPIOB, GPIO_Pin_2);// Đặt PB2 lên mức cao (LED sáng)
- GPIO_ResetBits(GPIOB, GPIO_Pin_2);// Đặt PB2 về mức thấp (LED tắt)
- GPIO_WriteBit(GPIOB, GPIO_Pin_2, Bit_SET);// Ghi giá trị cao
- GPIO_WriteBit(GPIOB, GPIO_Pin_2, Bit_RESET);// Ghi giá trị thấp
- GPIO_Write(GPIOB, 1 << 2);// Ghi toàn cổng (không khuyến khích)
Hoặc đơn giản hơn, dùng bit-toggle:
// Đảo trạng thái PB2
GPIOB->ODR ^= (1 << 2);4. Ví dụ hoàn chỉnh 
#include "stm32f4xx.h"
int main(void)
{
    // 1. Bật clock GPIOB
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
    // 2. Cấu hình PB2
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    // 3. Loop blink LED
    while (1)
    {
        GPIO_SetBits(GPIOB, GPIO_Pin_2);    // LED ON
        for (volatile uint32_t i = 0; i < 500000; i++); // Delay đơn giản
        GPIO_ResetBits(GPIOB, GPIO_Pin_2);  // LED OFF
        for (volatile uint32_t i = 0; i < 500000; i++);
    }
}Hiện tượng thí nghiệm 
Khi nạp chương trình vào board và khởi chạy, LED PB2 sẽ nhấp nháy với chu kỳ khoảng 500 ms:
- LED sáng trong thời gian delay đầu (~đảo PB2 lên mức cao).
- LED tắt trong thời gian delay sau (~đảo PB2 xuống mức thấp).
- Nhấp nháy ổn định, không có hiện tượng flicker bất thường nếu dùng HAL_Delay.
Bạn có thể điều chỉnh giá trị vòng lặp hoặc hàm HAL_Delay để thay đổi chu kỳ nhấp nháy phù hợp với ứng dụng.
Lưu ý 
- Các hàm và macro như RCC_AHB1PeriphClockCmd,GPIO_Init,GPIO_SetBitsđược định nghĩa trongstm32f4xx_rcc.hvàstm32f4xx_gpio.h.
So sánh thư viện chuẩn vs HAL 
Ưu điểm của Standard Peripheral Library: 
- Tương thích cao: Thư viện chuẩn chia theo từng họ chip (vd: stm32f4xx_*), nên nếu bạn đổi từ F405 sang F407 hoặc F429, mã gần như không cần chỉnh sửa.
- Gần phần cứng: Dễ chuyển đổi giữa các dòng chip cùng họ, ít abstraction hơn HAL.
Nhược điểm: 
- Mức trừu tượng thấp: Bạn phải cấu hình từng phần thủ công hơn.
- Thiếu tính năng nâng cao: Không có cơ chế quản lý lỗi hay callback sẵn như trong HAL.
- Khó bảo trì: Không phù hợp cho người mới hoặc các dự án cần bảo trì lâu dài.
Kết luận: Thư viện chuẩn mạnh và gần với phần cứng hơn HAL, nhưng bạn phải hiểu kỹ kiến trúc STM32 để dùng hiệu quả.