Skip to content

Công nghệ 9 giây

“Website hướng dẫn, thử nghiệm và giải thích công nghệ theo cách dễ hiểu cho mọi người.”

Menu
  • Home
  • Công nghệ
  • STM32
  • ESP32
  • Altium Desinger
  • Kiến thức điện máy
Menu

Bài 32 GPIO Input + Pull-up/Pull-down

Posted on August 21, 2026August 23, 2026 by congnghe9s

BÀI 32 – GPIO INPUT + PULL-UP / PULL-DOWN TRÊN STM32F103

Đây là bài rất quan trọng, bởi vì sau khi hiểu bài này bạn sẽ có thể đọc nút nhấn đúng cách, hiểu tại sao chân input bị floating, và đặc biệt hiểu một điểm rất thú vị của STM32F103:

Khi GPIO ở chế độ Input Pull-up/Pull-down, thanh ghi ODR lại được dùng để lựa chọn kéo lên hay kéo xuống.


1. GPIO Input dùng để làm gì?

Ở các bài trước, chúng ta chủ yếu dùng GPIO như:

STM32 → GPIO → LED

Tức là STM32 điều khiển tín hiệu.

Ví dụ:

PC13 → LED

Bây giờ chúng ta đổi chiều:

Nút nhấn → GPIO → STM32

Ví dụ:

Button → PA0

STM32 phải biết:

PA0 = HIGH

hay:

PA0 = LOW

Để làm việc đó, chúng ta đọc:

GPIOA->IDR

2. IDR – Input Data Register

IDR là thanh ghi dùng để đọc trạng thái thực tế của chân GPIO.

Ví dụ:

GPIOA->IDR

Có 16 bit tương ứng:

        GPIOA->IDR

bit15 → PA15
bit14 → PA14
...
bit1  → PA1
bit0  → PA0

Nếu:

PA0 = HIGH

thì:

GPIOA->IDR & GPIO_PIN_0

sẽ khác 0.

Nếu:

PA0 = LOW

thì:

GPIOA->IDR & GPIO_PIN_0

sẽ bằng 0.


3. Ví dụ đọc PA0

Bạn có thể viết:

if (GPIOA->IDR & GPIO_PIN_0)
{
    // PA0 = HIGH
}
else
{
    // PA0 = LOW
}

Hoặc với Driver chúng ta đã xây dựng ở Bài 31:

if (GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET)
{
    // HIGH
}

Đây chính là lý do chúng ta viết Driver.

main.c không cần quan tâm trực tiếp đến IDR.


4. Vấn đề cực kỳ quan trọng: Floating Input

Giả sử bạn cấu hình:

PA0 = Input

và để chân PA0 hoàn toàn không nối với gì.

Bạn có thể tưởng tượng:

             PA0
              │
              │
              ?

Điện áp trên chân này không được xác định rõ.

Nó có thể đọc:

HIGH

rồi:

LOW

rồi:

HIGH

mặc dù bạn không làm gì cả.

Đây gọi là:

Floating Input


5. Tại sao Floating nguy hiểm?

GPIO input có trở kháng rất cao.

Nó gần giống như:

GPIO input
    │
    │
    └──── rất ít dòng điện

Do đó các nhiễu điện từ môi trường có thể làm điện áp chân GPIO thay đổi.

Ví dụ:

PA0
 │
 ├── dây dài
 ├── nhiễu nguồn
 ├── nhiễu motor
 ├── nhiễu relay
 └── tín hiệu xung quanh

STM32 có thể liên tục nhìn thấy:

0 → 1 → 0 → 1 → 0

mặc dù không có ai nhấn nút.


6. Giải pháp: Pull-up và Pull-down

Ta cần một điện trở để ép chân GPIO về một trạng thái xác định.

Có hai cách:

Pull-up

và:

Pull-down

7. Pull-up là gì?

Pull-up nghĩa là:

Kéo chân GPIO về HIGH khi không có tín hiệu bên ngoài.

Sơ đồ:

             VCC
              │
             R
              │
              ├──── PA0
              │
           Button
              │
             GND

Khi button không nhấn:

VCC
 │
 R
 │
 PA0

nên:

PA0 = HIGH

Khi button nhấn:

PA0
 │
Button
 │
GND

nên:

PA0 = LOW

8. Logic của nút nhấn Pull-up

Button PA0
Không nhấn HIGH
Nhấn LOW

Đây là kiểu rất phổ biến.

Vì vậy bạn sẽ thường thấy:

if (GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)
{
    // Button đang nhấn
}

Chứ không phải:

if (GPIO_ReadPin(...) == GPIO_PIN_SET)

9. Pull-down là gì?

Pull-down làm ngược lại.

Sơ đồ:

             VCC
              │
           Button
              │
              ├──── PA0
              │
              R
              │
             GND

Khi không nhấn:

PA0 = LOW

Khi nhấn:

PA0 = HIGH

Bảng logic:

Button PA0
Không nhấn LOW
Nhấn HIGH

10. So sánh Pull-up và Pull-down

PULL-UP

Không nhấn → HIGH
Nhấn       → LOW

Trong khi:

PULL-DOWN

Không nhấn → LOW
Nhấn       → HIGH

Bạn chỉ cần nhớ:

Pull-up kéo mặc định lên 1.

Pull-down kéo mặc định xuống 0.


11. STM32F103 có điện trở Pull nội không?

Có.

Đây là điểm rất tiện.

Bạn không nhất thiết lúc nào cũng phải mắc điện trở bên ngoài.

STM32F103 có thể cấu hình:

Input Pull-up

hoặc:

Input Pull-down

bằng chính GPIO configuration.


12. Nhưng STM32F103 có một điểm rất đặc biệt

Khi cấu hình:

Input Pull-up/Pull-down

thì MODE = 00.

Còn CNF được đặt:

CNF = 10

Tức là cấu hình 4 bit:

CNF MODE
 10  00

thành:

1000

hay:

0x8

Vậy:

Input Pull-up/Pull-down
=
1000

13. Và đây là chỗ rất thú vị

Bạn có thể nghĩ:

“Nếu đang Input thì tại sao lại dùng ODR?”

Đúng.

Thông thường chúng ta nghĩ:

ODR
↓
Output

Nhưng trên STM32F1:

Input Pull-up/Pull-down

thì:

ODR bit
↓
chọn Pull-up hoặc Pull-down

14. Cơ chế cụ thể

Giả sử PA0:

CRL bit3:0 = 1000

tức:

Input Pull-up/Pull-down

Sau đó:

GPIOA->ODR |= GPIO_PIN_0;

thì:

ODR0 = 1

→ Pull-up

Ngược lại:

GPIOA->ODR &= ~GPIO_PIN_0;

thì:

ODR0 = 0

→ Pull-down


15. Đây là điều bạn nên ghi nhớ

Với STM32F103:

Input Pull-up/Pull-down

thì:

ODR = 1 → Pull-up
ODR = 0 → Pull-down

Đây là một đặc điểm rất quan trọng của GPIO STM32F1.


16. Cấu hình PA0 Pull-up bằng thanh ghi

Ta có:

GPIOA->CRL

PA0 sử dụng:

CRL[3:0]

Muốn:

Input Pull-up/Pull-down

ta ghi:

1000

Do đó:

GPIOA->CRL &= ~(0xF << 0);
GPIOA->CRL |=  (0x8 << 0);

Sau đó:

GPIOA->ODR |= GPIO_PIN_0;

PA0 trở thành:

Input Pull-up

17. Cấu hình PA0 Pull-down

Phần CRL vẫn giống hệt:

GPIOA->CRL &= ~(0xF << 0);
GPIOA->CRL |=  (0x8 << 0);

Nhưng ODR thay đổi:

GPIOA->ODR &= ~GPIO_PIN_0;

Kết quả:

PA0 = Input Pull-down

18. Đây chính là lý do Driver rất hữu ích

Nếu không có Driver, bạn phải nhớ:

GPIOA->CRL &= ~(0xF << 0);
GPIOA->CRL |=  (0x8 << 0);

GPIOA->ODR |= GPIO_PIN_0;

Nhưng với Driver, chúng ta có thể thiết kế:

GPIO_Init(GPIOA,
          GPIO_PIN_0,
          GPIO_INPUT_PULLUP,
          0);

Hoặc:

GPIO_Init(GPIOA,
          GPIO_PIN_0,
          GPIO_INPUT_PULLDOWN,
          0);

GPIO.c sẽ lo toàn bộ việc cấu hình thanh ghi.


19. Thiết kế Driver tốt hơn

Ở Bài 31 chúng ta có thể mở rộng enum:

typedef enum
{
    GPIO_MODE_INPUT_FLOATING,
    GPIO_MODE_INPUT_PULLUP,
    GPIO_MODE_INPUT_PULLDOWN,

    GPIO_MODE_OUTPUT_PP,
    GPIO_MODE_OUTPUT_OD

} GPIO_Mode;

Sau đó:

GPIO_Init(GPIOA,
          GPIO_PIN_0,
          GPIO_MODE_INPUT_PULLUP,
          0);

Rất dễ đọc.


20. Đọc trạng thái nút nhấn

Sau khi cấu hình:

GPIO_Init(GPIOA,
          GPIO_PIN_0,
          GPIO_MODE_INPUT_PULLUP,
          0);

Ta có:

while (1)
{
    if (GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)
    {
        // Button được nhấn
    }
}

Nhớ:

Pull-up:

Không nhấn → 1
Nhấn       → 0

21. Điều khiển LED PC13 bằng Button PA0

Đây là bài thực hành rất tốt.

Phần cứng:

Blue Pill

PA0 ─── Button
         │
        GND


PC13 ─── LED onboard

Cấu hình:

PA0 = Input Pull-up
PC13 = Output

Logic:

PA0 = HIGH
      ↓
Không nhấn
      ↓
LED OFF


PA0 = LOW
      ↓
Nhấn
      ↓
LED ON

22. Code ứng dụng

Với Driver của chúng ta:

int main(void)
{
    GPIO_Init(GPIOA,
              GPIO_PIN_0,
              GPIO_MODE_INPUT_PULLUP,
              0);

    GPIO_Init(GPIOC,
              GPIO_PIN_13,
              GPIO_MODE_OUTPUT_PP,
              GPIO_SPEED_2MHZ);

    while (1)
    {
        if (GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)
        {
            GPIO_WritePin(GPIOC,
                          GPIO_PIN_13,
                          GPIO_PIN_RESET);
        }
        else
        {
            GPIO_WritePin(GPIOC,
                          GPIO_PIN_13,
                          GPIO_PIN_SET);
        }
    }
}

Lưu ý: LED trên Blue Pill thường mắc active-low, vì vậy PC13 = LOW thường là LED sáng.


23. Tại sao không dùng Pull-up ngoài?

Có thể dùng.

Ví dụ:

        3.3V
         │
        10k
         │
         ├──── PA0
         │
       Button
         │
        GND

Đây là:

External Pull-up

Trong khi STM32 có:

Internal Pull-up

Hai cách đều có thể sử dụng.


24. Internal Pull-up và External Pull-up

Internal Pull-up

3.3V
 │
[resistor bên trong STM32]
 │
PA0

Ưu điểm:

  • Không cần thêm linh kiện.
  • Mạch đơn giản.
  • Tiết kiệm PCB.

External Pull-up

3.3V
 │
[10k]
 │
PA0

Ưu điểm:

  • Bạn chủ động chọn giá trị điện trở.
  • Có thể phù hợp hơn với một số mạch tốc độ cao/nhiễu cao.
  • Dễ kiểm soát đặc tính điện.

25. Giá trị điện trở Pull-up

Ví dụ phổ biến:

4.7k
10k
22k
47k

Với nút nhấn thông thường, 10kΩ là một giá trị rất dễ gặp.

Nhưng không nên hiểu rằng:

“Mọi GPIO đều bắt buộc phải dùng 10k.”

Giá trị phù hợp còn phụ thuộc:

  • tốc độ tín hiệu
  • nhiễu
  • dòng tiêu thụ
  • điện dung đường mạch
  • thiết kế phần cứng

26. Một vấn đề khác: Button Bounce

Giả sử bạn nhấn nút một lần.

Bạn nghĩ STM32 sẽ thấy:

0

một lần.

Nhưng thực tế tiếp điểm cơ khí có thể tạo:

0
1
0
1
0
0

trong vài mili-giây.

Đây gọi là:

Mechanical Bounce

Vì vậy:

Một lần nhấn

không nhất thiết tạo:

Một lần chuyển trạng thái

27. Đây sẽ là bài học tiếp theo rất hay

Chúng ta có thể xử lý debounce bằng:

Cách 1

Delay:

delay_ms(20);

Cách 2

Timer.

Cách 3

State machine.

Cách 4

Interrupt + debounce.

Trong firmware thực tế, state machine + timer thường là cách rất đáng học.

Nhưng hiện tại chưa cần vội.


28. Một câu hỏi kiểm tra kiến thức

Giả sử:

GPIOA->CRL

của PA0 là:

1000

Bạn biết PA0 đang ở chế độ:

Input Pull-up/Pull-down

Nếu:

GPIOA->ODR |= GPIO_PIN_0;

thì PA0 là:

Pull-up.

Nếu:

GPIOA->ODR &= ~GPIO_PIN_0;

thì PA0 là:

Pull-down.

Đây là một câu hỏi bạn nên tự trả lời được mà không cần nhìn tài liệu.


29. Sơ đồ tư duy của Bài 32

Bạn hãy ghi nhớ toàn bộ bài bằng sơ đồ này:

                 GPIO INPUT
                     │
             ┌───────┴───────┐
             │               │
        Floating          Pull
             │               │
        Không ổn định   ┌────┴────┐
                        │         │
                     Pull-up   Pull-down
                        │         │
                       HIGH       LOW
                     mặc định   mặc định
                        │         │
                     ODR=1      ODR=0

Còn dữ liệu thực tế của chân vẫn được đọc bằng:

              GPIOx->IDR
                   │
             ┌─────┴─────┐
             │           │
            HIGH        LOW

30. Bốn thanh ghi GPIO bạn đã học đến đây

Sau Bài 32, bạn nên bắt đầu hình thành bảng này trong đầu:

Thanh ghi Chức năng
CRL Cấu hình PA0–PA7
CRH Cấu hình PA8–PA15
IDR Đọc trạng thái GPIO
ODR Output / chọn Pull-up-Pull-down
BSRR SET/RESET GPIO

Đặc biệt:

CRL/CRH → GPIO configuration
IDR     → GPIO input
ODR     → GPIO output + Pull selection
BSRR    → Atomic SET/RESET

31. Bài thực hành của bạn

Tôi muốn bạn làm một bài duy nhất nhưng rất quan trọng:

STM32 Blue Pill

Kết nối:

PA0 ─── Button ─── GND

Không cần điện trở ngoài.

Cấu hình:

PA0  → Input Pull-up
PC13 → Output Push-Pull

Yêu cầu:

Không nhấn nút → LED tắt

Nhấn nút        → LED sáng

Và trong main.c không được phép viết trực tiếp:

GPIOA->CRL
GPIOA->CRH
GPIOA->IDR
GPIOA->ODR
GPIOA->BSRR

Chỉ được sử dụng:

GPIO_Init()
GPIO_ReadPin()
GPIO_WritePin()

Như vậy bạn sẽ thực sự bắt đầu lập trình bằng Driver, thay vì chỉ thao tác thanh ghi.


32. Và đây là bước tiếp theo rất quan trọng

Sau khi bạn làm xong bài này, chúng ta nên sang:

BÀI 33 – EXTI: GPIO INTERRUPT TRÊN STM32F103

Lúc đó chúng ta sẽ chuyển từ:

CPU liên tục hỏi:

"Button đã nhấn chưa?"
"Button đã nhấn chưa?"
"Button đã nhấn chưa?"

sang:

Button nhấn
     ↓
GPIO
     ↓
EXTI
     ↓
NVIC
     ↓
CPU bị ngắt
     ↓
Interrupt Handler

Đây chính là bước đầu tiên để bạn hiểu Interrupt thực sự hoạt động như thế nào trên STM32, thay vì chỉ gọi một hàm HAL có sẵn.

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Recent Posts

  • Bạn có thể hướng dẫn tôi quy trình sửa chữa một mainboard laptop cũng như mainboard của máy tính để bàn không?
  • Có những mức nguồn DC nào trên một bo mạch mainboard laptop?Kỹ thuật đốt dòng để kiểm tra nguồn laptop được thực hiện như thế nào?
  • bài tiếp theo hợp lý là: BÀI 63 – SENSOR FUSION THỰC CHIẾN: ENCODER + IMU MPU6050 + EKF + ODOMETRY X,Y,θ TRÊN STM32F103
  • BÀI 62 – EKF (EXTENDED KALMAN FILTER) CHO ROBOT 2 BÁNH: FUSION ENCODER + IMU + ƯỚC LƯỢNG X, Y, θ, V, ω
  • BÀI 61 – KALMAN FILTER CHO ENCODER + IMU: ƯỚC LƯỢNG TỐC ĐỘ, GÓC θ VÀ SENSOR FUSION

Recent Comments

No comments to show.

Archives

  • September 2026
  • August 2026
  • July 2026
  • June 2026
  • May 2026
  • February 2026

Categories

  • Altium Desinger
  • Công nghệ
  • ESP32
  • Khác
  • Kiến thức điện máy
  • STM32
Live 3D Globes Visitor
©2026 Công nghệ 9 giây | Design: Newspaperly WordPress Theme