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 19 – GPIO STM32F103: TỪ REGISTER ĐẾN CHÂN GPIO THỰC TẾ

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

BÀI 19 – GPIO STM32F103: TỪ REGISTER ĐẾN CHÂN GPIO THỰC TẾ

Ở Bài 17, bạn đã học Memory Map của STM32F103.
Ở Bài 18, ta bắt đầu đi vào GPIO.

Bài 19 sẽ nối toàn bộ kiến thức lại:

Địa chỉ bộ nhớ → Peripheral → GPIO port → Register → Bit → chân vật lý → LED

Đây là bài rất quan trọng nếu mục tiêu của bạn là lập trình STM32 bằng C ở mức register, chứ không chỉ gọi HAL.


1. GPIO thực chất là gì?

GPIO = General Purpose Input/Output

Một chân GPIO có thể được cấu hình để:

  • xuất mức HIGH/LOW
  • đọc mức HIGH/LOW
  • Analog
  • Alternate Function
  • một số chức năng đặc biệt khác

Ví dụ:

STM32F103
   │
   ├── GPIOA
   │    ├── PA0
   │    ├── PA1
   │    ├── PA2
   │    └── ...
   │
   ├── GPIOB
   │    ├── PB0
   │    ├── PB1
   │    └── ...
   │
   └── GPIOC
        ├── PC13
        └── ...

Trên Blue Pill của bạn, LED onboard thường nối với:

PC13

Vì vậy PC13 là một ví dụ cực kỳ tốt để học GPIO.


2. Điều quan trọng: GPIOC không phải là một biến

Khi viết:

GPIOC

ta thường đang nói đến địa chỉ cơ sở của peripheral GPIOC.

Trong STM32F103, vùng GPIO nằm trong vùng Peripheral.

Một địa chỉ cơ sở quan trọng:

GPIOA = 0x40010800
GPIOB = 0x40010C00
GPIOC = 0x40011000
GPIOD = 0x40011400
GPIOE = 0x40011800

Đây chính là kiến thức từ Memory Map của Bài 17 được sử dụng trực tiếp.


3. GPIOC có rất nhiều register

GPIOC không chỉ có một register.

Có các register quan trọng:

GPIOC
 │
 ├── CRL
 ├── CRH
 ├── IDR
 ├── ODR
 ├── BSRR
 ├── BRR
 └── LCKR

Đối với STM32F103:

Register Chức năng
CRL cấu hình PA0–PA7 / PB0–PB7 / PC0–PC7
CRH cấu hình PA8–PA15 / PB8–PB15 / PC8–PC15
IDR đọc trạng thái chân
ODR xuất trạng thái
BSRR set/reset bit
BRR reset bit
LCKR khóa cấu hình

Và đây chính là lúc kiến thức về pointer + struct + bit manipulation từ các bài trước bắt đầu phát huy tác dụng.


4. Tại sao PC13 dùng CRH chứ không phải CRL?

Đây là câu hỏi rất quan trọng.

GPIO có 16 chân:

PC0
PC1
PC2
...
PC7

PC8
PC9
...
PC15

STM32 chia chúng thành hai nhóm:

CRL → pin 0 đến pin 7

CRH → pin 8 đến pin 15

PC13 nằm trong:

PC8 → PC15

nên:

PC13 → GPIOC_CRH

5. Mỗi chân chiếm 4 bit

Đây là điểm bạn cần đặc biệt hiểu.

Trong CRL/CRH:

Mỗi GPIO pin = 4 bit

Ví dụ CRH:

31                         0
┌────┬────┬────┬──── ... ────┐
│PC15│PC14│PC13│ ... │ PC8   │
└────┴────┴────┴──── ... ────┘

Mỗi chân:

MODE[1:0]
CNF[1:0]

Tổng cộng:

4 bit / pin

6. Vị trí PC13 trong CRH

PC8 bắt đầu ở bit:

0

PC9:

4

PC10:

8

PC11:

12

PC12:

16

PC13:

20

PC14:

24

PC15:

28

Vậy:

PC13 → CRH bit 20–23

Đây là một bài tập bit-shift cực kỳ thực tế.


7. MODE và CNF

Mỗi chân có:

CNF1 CNF0 MODE1 MODE0

Ví dụ:

PC13
│
├── MODE1
├── MODE0
├── CNF1
└── CNF0

MODE

MODE xác định tốc độ hoặc Input mode.

Các giá trị thường gặp:

00 = Input mode
01 = Output 10 MHz
10 = Output 2 MHz
11 = Output 50 MHz

Ví dụ muốn PC13 là output 2 MHz:

MODE = 10

8. CNF xác định kiểu GPIO

Với Output:

CNF = 00

→ General purpose push-pull.

Vậy:

MODE = 10
CNF  = 00

ta có:

0010

Cho PC13.


9. Tư duy quan trọng nhất: không sửa cả register

Giả sử:

GPIOC->CRH = 0x00000000;

thì bạn đang xóa cấu hình của:

PC8
PC9
PC10
...
PC15

Điều này rất nguy hiểm nếu những chân khác đang được sử dụng.

Thay vào đó phải sử dụng:

mask

Đây là lý do Bài 16 về:

&
|
~
<<

rất quan trọng.


10. Xóa cấu hình PC13

PC13 nằm ở bit 20–23.

Mask:

0xF << 20

Tương đương:

1111
dịch trái 20 bit

Sau đó:

GPIOC->CRH &= ~(0xF << 20);

Ý nghĩa:

Xóa đúng 4 bit cấu hình PC13, nhưng giữ nguyên các bit khác.

Đây chính là tư duy lập trình register.


11. Đặt PC13 thành Output Push-Pull 2 MHz

Sau khi xóa:

GPIOC->CRH &= ~(0xF << 20);

Ta đặt:

MODE = 10
CNF  = 00

Giá trị 4 bit:

0010

Vì vậy:

GPIOC->CRH |= (0x2 << 20);

Kết quả:

PC13 = Output Push-Pull 2 MHz

12. Nhưng vẫn còn một vấn đề

GPIOC chưa chắc đã được cấp clock.

STM32F1 có hệ thống clock cho peripheral.

GPIOC thuộc:

APB2

Clock của GPIOC được điều khiển bởi:

RCC

Cụ thể:

RCC_APB2ENR

Có bit:

IOPCEN

Nếu clock GPIOC chưa bật:

GPIOC

không hoạt động đúng.


13. Đây là chuỗi tư duy hoàn chỉnh

Khi muốn điều khiển PC13 bằng register, hãy nghĩ:

RCC
 │
 │ bật clock GPIOC
 ▼
GPIOC
 │
 ├── CRH
 │    └── cấu hình PC13
 │
 └── ODR / BSRR / BRR
      └── điều khiển PC13

Đây là kiến trúc mà bạn cần bắt đầu hình thành trong đầu.


14. Bật clock GPIOC

Ví dụ:

RCC->APB2ENR |= (1 << 4);

Tại sao là bit 4?

Các bit clock GPIO thường được bố trí:

bit 2 → IOPAEN
bit 3 → IOPBEN
bit 4 → IOPCEN
bit 5 → IOPDEN
bit 6 → IOPEEN

Do đó:

1 << 4

chính là:

0001 0000

15. Sau đó cấu hình PC13

GPIOC->CRH &= ~(0xF << 20);
GPIOC->CRH |=  (0x2 << 20);

Bây giờ PC13 là:

Output
Push-Pull
2 MHz

16. Xuất HIGH/LOW bằng ODR

ODR = Output Data Register.

Ví dụ:

GPIOC->ODR |= (1 << 13);

→ PC13 = HIGH.

Ngược lại:

GPIOC->ODR &= ~(1 << 13);

→ PC13 = LOW.

Bạn có thể nhìn thấy ngay mối liên hệ:

PC13
 ↓
bit 13
 ↓
1 << 13

17. Toggle PC13

Nếu muốn đảo trạng thái:

GPIOC->ODR ^= (1 << 13);

Nếu đang:

0

thì thành:

1

Nếu đang:

1

thì thành:

0

Đây chính là toán tử XOR mà bạn đã học.


18. Nhưng có cách tốt hơn ODR

STM32F1 có:

BSRR

Bit 0–15:

Set

Bit 16–31:

Reset

Ví dụ set PC13:

GPIOC->BSRR = (1 << 13);

Reset PC13:

GPIOC->BSRR = (1 << (13 + 16));

hay:

GPIOC->BSRR = (1 << 29);

19. Tại sao BSRR rất hay?

Giả sử:

GPIOC->ODR |= (1 << 13);

Đây là kiểu:

Read
Modify
Write

Trong một số tình huống nhiều phần mềm/ngắt cùng thao tác GPIO, điều này có thể gây vấn đề.

BSRR cho phép thao tác set/reset bit theo cơ chế phần cứng thuận tiện hơn.

Ví dụ:

GPIOC->BSRR = (1 << 13);

nghĩa là:

SET PC13

Còn:

GPIOC->BSRR = (1 << 29);

nghĩa là:

RESET PC13

20. Code hoàn chỉnh kiểu Register

Một ví dụ tối giản:

#include "stm32f1xx.h"

void GPIOC_PC13_Init(void)
{
    // 1. Enable clock GPIOC
    RCC->APB2ENR |= (1 << 4);

    // 2. Clear configuration PC13
    GPIOC->CRH &= ~(0xF << 20);

    // 3. PC13 = Output Push-Pull, 2 MHz
    GPIOC->CRH |= (0x2 << 20);
}

int main(void)
{
    GPIOC_PC13_Init();

    while (1)
    {
        GPIOC->BSRR = (1 << 13);   // SET PC13

        for (volatile int i = 0; i < 1000000; i++);

        GPIOC->BSRR = (1 << 29);   // RESET PC13

        for (volatile int i = 0; i < 1000000; i++);
    }
}

Lưu ý: LED onboard PC13 trên Blue Pill thường mắc theo kiểu active-low, nên có thể bạn sẽ thấy LED sáng khi PC13 ở LOW và tắt khi HIGH.


21. Điều tôi muốn bạn đặc biệt hiểu ở bài này

Đừng học thuộc:

GPIOC->CRH &= ~(0xF << 20);

Hãy hiểu nó.

Ta có:

PC13
 ↓
pin number = 13
 ↓
PC13 thuộc CRH
 ↓
mỗi pin 4 bit
 ↓
(13 - 8) × 4
 ↓
20

Vì vậy:

GPIOC->CRH

và:

20

không phải con số thần bí.

Nó được tính ra từ cấu trúc phần cứng.


22. Công thức cực kỳ quan trọng

Đối với STM32F1:

Pin 0–7

CRL

Vị trí:

pin × 4

Pin 8–15

CRH

Vị trí:

(pin - 8) × 4

Ví dụ:

PC5

CRL
bit = 5 × 4 = 20

PC13

CRH
bit = (13 - 8) × 4
    = 20

Bạn có thể tự tính cho bất kỳ GPIO nào.


23. Bài tập thực hành

Không cần học tiếp ngay. Hãy thử tự làm 5 câu này.

Câu 1

PC5 nằm trong:

CRL hay CRH?

Câu 2

PC5 bắt đầu ở bit số mấy?

Câu 3

PC10 nằm trong:

CRL hay CRH?

Câu 4

PC10 bắt đầu ở bit số mấy?

Câu 5

Muốn set PC13 bằng BSRR thì viết:

GPIOC->BSRR = ?

24. Bức tranh lớn sau Bài 19

Đến đây kiến thức của bạn đã nối được như sau:

Bài 1
Kiểu dữ liệu
     ↓
Bài 5
Pointer
     ↓
Bài 7–13
Struct / typedef / enum
     ↓
Bài 16
Bit / Mask / Shift
     ↓
Bài 17
Memory Map
     ↓
Bài 18
GPIO
     ↓
Bài 19
GPIO Register
     ↓
       ┌───────────────┐
       │ RCC           │
       │ GPIOC         │
       │ CRH           │
       │ ODR           │
       │ BSRR          │
       └───────────────┘
              ↓
            PC13
              ↓
             LED

Đây chính là bước chuyển từ “học C” sang “lập trình vi điều khiển bằng C”.

Ở Bài 20, chúng ta nên đi sâu vào GPIO Input: đọc nút nhấn bằng IDR, pull-up/pull-down, debounce, và quan trọng nhất là hiểu tại sao đọc một chân GPIO lại chỉ là đọc một bit trong một register.

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