Skip to content

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:

  1. Bật đồng hồ cho cổng GPIO
  2. Cấu hình tham số đầu ra của GPIO (mode, type, speed, pull-up/pull-down)
  3. Đ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:
c
void RCC_AHB1PeriphClockCmd(uint32_t RCC_AHB1Periph, FunctionalState NewState);

img

Trong đó:

  • RCC_AHB1Periph: macro xác định ngoại vi (ví dụ RCC_AHB1Periph_GPIOB).
  • NewState: ENABLE hoặc DISABLE.

Sau khi xác định, bạn có thể gọi:

c
// 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_Init dù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úc GPIO_InitTypeDef thườ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.

img

  • 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.

img

  • 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.

img

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

img

  • GPIO_OType: Loại đầu ra.

img

Đá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:

img

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à

c
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ình

3. Đ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:

c
// Đảo trạng thái PB2
GPIOB->ODR ^= (1 << 2);

4. Ví dụ hoàn chỉnh

c
#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 trong stm32f4xx_rcc.hstm32f4xx_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ả.