GPIO STM32 - Các Chế Độ Xuất/Nhập và Thực Hành LED/Button

I. Bốn Chế Độ Xuất GPIO

GPIO (General-Purpose Input/Output) có 8 chế độ hoạt động, trong đó có 4 chế độ xuất và 4 chế độ nhập. Chế độ xuất cho phép điều khiển mức điện áp trên chân (cao/thấp) bằng cách ghi giá trị 0 hoặc 1. Chế độ nhập cho phép đọc trạng thái điện áp đầu vào của chân.

  • Xuất thường (General Purpose Output): Điều khiển bởi CPU.
  • Xuất thay thế (Alternate Function Output): Điều khiển bởi các ngoại vi trên chip (ví dụ: USART, SPI).

Chế Độ Push-Pull (Đẩy Kéo)

Trong chế độ push-pull, hai transistor (PMOS và NMOS) hoạt động luân phiên: Khi ghi 1, transistor PMOS đóng, chân được kết nối với nguồn điện (VDD) -> mức cao. Khi ghi 0, transistor NMOS đóng, chân được kết nối với đất (GND) -> mức thấp. Chế độ này cung cấp khả năng điều khiển dòng điện mạnh mẽ.

Chế Độ Open-Drain (Cực Mở)

Trong chế độ open-drain, chỉ có transistor NMOS hoạt động: Khi ghi 0, transistor NMOS đóng, chân nối với GND -> mức thấp. Khi ghi 1, transistor NMOS mở, chân ở trạng thái trở kháng cao (High-Z). Để đạt mức cao, cần có một điện trở kéo lên bên ngoài nối tới VDD. Chế độ này thường được dùng cho bus I2C hoặc khi cần ghép nối với các mức điện áp khác nhau.

II. Tốc Độ Xuất Tối Đa Của GPIO

Tốc độ xuất tối đa của một chân GPIO là tần số cao nhất mà ta có thể thay đổi trạng thái chân giữa 0 và 1 mà không làm méo tín hiệu. Các lựa chọn tốc độ thường gặp: 2MHz, 10MHz, 50MHz. Nên chọn tốc độ phù hợp với yêu cầu tối thiểu. Các cạnh tín hiệu quá dốc sẽ làm tăng mức tiêu thụ năng lượng và gây nhiễu điện từ (EMI).

III. Thực Hành: LED Nhấp Nháy

Thí nghiệm này sử dụng chế độ xuất push-pull của GPIO để điều khiển LED trên bo mạch.

// main.c - LED nhấp nháy trên PC13
#include "stm32f10x.h"
#include "delay.h"

int main(void) {
    // 1. Khởi tạo delay
    Delay_Init();

    // 2. Bật clock cho GPIO Port C
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

    // 3. Cấu hình chân PC13 dưới dạng cấu trúc
    GPIO_InitTypeDef GPIO_Config;
    GPIO_Config.GPIO_Pin = GPIO_Pin_13;
    GPIO_Config.GPIO_Mode = GPIO_Mode_Out_PP;  // Push-Pull
    GPIO_Config.GPIO_Speed = GPIO_Speed_2MHz;

    GPIO_Init(GPIOC, &GPIO_Config); // Áp dụng cấu hình

    // 4. Vòng lặp chính: nhấp nháy LED
    while(1) {
        GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_RESET); // Bật LED (mức 0)
        Delay(100);                                    // Chờ 100ms

        GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET);   // Tắt LED (mức 1)
        Delay(100);                                    // Chờ 100ms
    }
}

Tệp delay.h

#ifndef _DELAY_H_
#define _DELAY_H_

#include "stm32f10x.h"

void Delay_Init(void);    // Khởi tạo bộ định thời
void Delay(uint32_t ms);  // Trì hoãn mili giây
uint64_t GetTick(void);   // Lấy thời gian hiện tại

#endif

Tệp delay.c

#include "delay.h"

__IO uint64_t systemTicks;
static uint8_t delayInitialized = 0;

void Delay_Init(void) {
    if (!delayInitialized) {
        delayInitialized = 1;
        RCC_ClocksTypeDef clockInfo = {0};
        uint32_t timerLoadVal;

        SysTick->CTRL &= ~SysTick_CTRL_ENABLE; // Tắt SysTick
        systemTicks = 0;

        RCC_GetClocksFreq(&clockInfo);         // Lấy tần số HCLK

        SysTick->CTRL |= SysTick_CTRL_TICKINT; // Bật ngắt SysTick
        SCB->SHP[7] = 0;                       // Đặt ưu tiên ngắt là 0

        // Tính giá trị nạp để tạo ngắt mỗi 1ms
        timerLoadVal = clockInfo.HCLK_Frequency / 1000;
        if (timerLoadVal > 0x00FFFFFF) {
            timerLoadVal /= 8;
            SysTick->CTRL &= ~SysTick_CTRL_CLKSOURCE; // Dùng HCLK/8
        } else {
            SysTick->CTRL |= SysTick_CTRL_CLKSOURCE;  // Dùng HCLK trực tiếp
        }
        SysTick->LOAD = timerLoadVal - 1UL;
        SysTick->CTRL |= SysTick_CTRL_ENABLE; // Kích hoạt SysTick
    }
}

void Delay(uint32_t DelayMs) {
    Delay_Init();
    uint64_t expiryTime = systemTicks + DelayMs;
    while (systemTicks < expiryTime) {}
}

uint64_t GetTick(void) {
    Delay_Init();
    return systemTicks;
}

IV. Bốn Chế Độ Nhập

GPIO cũng có 4 chế độ nhập, mỗi chế độ phù hợp với một loại tín hiệu đầu vào khác nhau:

  • Input Floating (Nhập nổi): Chân ở trạng thái trở kháng cao, mức logic phụ thuộc hoàn toàn vào nguồn bên ngoài.
  • Input Pull-up (Nhập kéo lên): Khi không có tín hiệu bên ngoài, chân được kéo lên mức cao (VDD).
  • Input Pull-down (Nhập kéo xuống): Khi không có tín hiệu bên ngoài, chân được kéo xuống mức thấp (GND).
  • Analog (Tương tự): Dùng cho các tín hiệu tương tự, chân được kết nối trực tiếp với bộ chuyển đổi ADC/DAC.

V. Thực Hành: Điều Khiển LED Bằng Nút Nhấn

Thí nghiệm này kết hợp chế độ xuất và nhập. PA0 được cấu hình là đầu ra push-pull để điều khiển LED. PA1 được cấu hình là đầu vào với điện trở kéo lên (Pull-up). Khi nút nhấn (nối giữa PA1 và GND) được nhấn, đầu vào sẽ ở mức thấp.

// main.c - Điều khiển LED bằng nút nhấn
#include "stm32f10x.h"

int main(void) {
    // 1. Bật clock cho GPIO Port A
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    GPIO_InitTypeDef GPIO_Config;

    // 2. Cấu hình PA0 làm đầu ra push-pull (điều khiển LED)
    GPIO_Config.GPIO_Pin = GPIO_Pin_0;
    GPIO_Config.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Config.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_Init(GPIOA, &GPIO_Config);

    // 3. Cấu hình PA1 làm đầu vào kéo lên (đọc nút nhấn)
    GPIO_Config.GPIO_Pin = GPIO_Pin_1;
    GPIO_Config.GPIO_Mode = GPIO_Mode_IPU; // Input Pull-up
    GPIO_Init(GPIOA, &GPIO_Config);

    // 4. Vòng lặp chính: đọc nút và điều khiển LED
    while(1) {
        if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1) == Bit_RESET) {
            // Nút nhấn đang được giữ (mức thấp) -> bật LED
            GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
        } else {
            // Nút nhấn không được nhấn (mức cao) -> tắt LED
            GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);
        }
    }
}

Thẻ: GPIO STM32 GPIO configuration STM32F10x STD Periph Library

Đăng vào ngày 21 tháng 6 lúc 10:08