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

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

BÀI 18 – GPIO STM32F103: TỪ THANH GHI ĐẾN CHÂN GPIO THỰC TẾ

Ở Bài 17, chúng ta đã học Memory Map của STM32F103 và hiểu rằng địa chỉ như:

0x40010800

không phải là một con số ngẫu nhiên. Nó là địa chỉ của một vùng thanh ghi ngoại vi.

Hôm nay chúng ta nối kiến thức đó với thứ rất thực tế:

Làm thế nào CPU STM32F103 điều khiển một chân GPIO bằng cách ghi vào thanh ghi?

Đây là bài cực kỳ quan trọng. Nếu hiểu bài này, sau này bạn sẽ hiểu được cả HAL, LL và lập trình thanh ghi trực tiếp.


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

Ví dụ bạn có Blue Pill:

  • PC13 → LED onboard
  • PA0 → nút nhấn
  • PA1 → LED
  • PB6/PB7 → I²C
  • PA9/PA10 → UART

Khi bạn nói:

GPIOC

thì GPIOC không phải là một chân.

Nó là một ngoại vi GPIO chứa rất nhiều thanh ghi điều khiển các chân:

STM32F103
CPU
│
┌───────┴───────┐
│ │
GPIOA GPIOB
│ │
PA0…PA15 PB0…PB15
│
GPIOC
│
PC0…PC15

Mỗi GPIO port có nhiều thanh ghi.

Ví dụ GPIOC có:

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

2. Một chân GPIO có những trạng thái gì?

Một chân STM32 không đơn giản chỉ có:

HIGH
LOW

Nó còn có chế độ hoạt động.

Ví dụ một chân có thể là:

INPUT
OUTPUT
ALTERNATE FUNCTION
ANALOG

Và nếu là output thì còn có:

Push-Pull
Open-Drain

Tốc độ output cũng có thể được cấu hình:

10 MHz
2 MHz
50 MHz

Vì vậy khi cấu hình một GPIO, chúng ta thực chất đang thiết lập nhiều bit trong các thanh ghi.


3. Thanh ghi CRL và CRH

Đây là điểm rất quan trọng với STM32F103.

STM32F103 chia 16 chân của một GPIO thành hai nhóm:

CRL → GPIO pin 0 → 7
CRH → GPIO pin 8 → 15

Ví dụ:

GPIOC
PC0 ─┐
PC1 │
PC2 │
PC3 │
PC4 │
PC5 │
PC6 │
PC7 ─┘ → CRL
PC8 ─┐
PC9 │
PC10 │
PC11 │
PC12 │
PC13 │
PC14 │
PC15 ─┘ → CRH

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

Đây là một quy tắc bạn nên nhớ:

Mỗi GPIO pin của STM32F1 sử dụng 4 bit trong CRL/CRH.

Ví dụ CRL:

31 0
┌───┬───┬───┬───┬───┬───┬───┬───┐
│ │ │ │ │ │ │ │ │
└───┴───┴───┴───┴───┴───┴───┴───┘
PC7 PC6 PC5 PC4 PC3 PC2 PC1 PC0

Mỗi pin:

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

tổng cộng:

2 bit CNF
+
2 bit MODE
=
4 bit

5. Ví dụ PC13

PC13 thuộc nhóm:

PC8 → PC15

nên nó nằm trong:

GPIOC->CRH

PC13 là pin số 13.

Trong CRH:

Pin 8 → bit 0..3
Pin 9 → bit 4..7
Pin 10 → bit 8..11
Pin 11 → bit 12..15
Pin 12 → bit 16..19
Pin 13 → bit 20..23
Pin 14 → bit 24..27
Pin 15 → bit 28..31

Do đó:

PC13 sử dụng bit 20 → 23 của GPIOC->CRH.

Đây chính là thứ bạn sẽ cần khi điều khiển LED PC13 bằng thanh ghi.


6. MODE là gì?

Hai bit MODE quyết định chế độ output/input.

Đối với output:

MODE = 01 → Output 10 MHz
MODE = 10 → Output 2 MHz
MODE = 11 → Output 50 MHz

Còn:

MODE = 00

là:

Input mode

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

MODE = 10

7. CNF là gì?

CNF quyết định kiểu cấu hình.

Ví dụ với output:

CNF = 00

→ General purpose output push-pull.

Đây là cấu hình rất phổ biến khi điều khiển LED.

Vì vậy:

MODE = 10
CNF = 00

ghép thành:

0010

hay:

0x2

Do PC13 nằm ở bit 20:

0x2 << 20

8. Tại sao lại phải SHIFT?

Đây chính là lúc kiến thức Bài 16 – bit và toán tử << phát huy tác dụng.

Ta có:

0x2

Nhưng 0x2 đang nằm ở bit 0.

Ta cần đưa nó tới bit 20:

0x2 << 20

Kết quả nằm ở:

bit 20..21

Tương tự CNF nằm ở:

bit 22..23

9. Nhưng còn CNF cũ thì sao?

Đây là lỗi rất nhiều người mới học thanh ghi mắc phải.

Không nên đơn giản:

GPIOC->CRH |= …

mà không xóa cấu hình cũ.

Ví dụ PC13 hiện đang có:

xxxx

Ta muốn thay bằng:

0010

Trước tiên phải xóa 4 bit cũ:

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

Sau đó ghi cấu hình mới:

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

Hai bước:

XÓA 4 BIT CŨ
↓
GHI 4 BIT MỚI

Đây chính là kỹ thuật:

Read → Modify → Write


10. Thanh ghi ODR

Sau khi cấu hình GPIO là output, chúng ta cần điều khiển mức logic.

Thanh ghi:

GPIOC->ODR

là:

Output Data Register

Có 16 bit:

bit 15 → PC15
bit 14 → PC14
…
bit 13 → PC13
…
bit 0 → PC0

Vì vậy:

PC13
↓
ODR bit 13

11. Bật PC13

Muốn đưa PC13 lên HIGH:

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

Ý nghĩa:

1

dịch sang trái 13 bit:

0000 0010 0000 0000

sau đó OR với ODR.


12. Tắt PC13

Muốn đưa PC13 xuống LOW:

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

Ta đang:

giữ nguyên các bit khác
+
xóa bit 13

13. Toggle PC13

Muốn đảo trạng thái:

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

Nếu:

PC13 = 0

thì:

0 XOR 1 = 1

Nếu:

PC13 = 1

thì:

1 XOR 1 = 0

Do đó:

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

có nghĩa:

Đảo trạng thái PC13.


14. Nhưng còn một vấn đề cực kỳ quan trọng

Bạn có thể viết:

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

nhưng trước đó GPIOC phải được cấp clock.

Nếu chưa cấp clock:

CPU
│
GPIOC
│
✖ chưa có clock

thì ngoại vi GPIOC chưa hoạt động đúng.


15. RCC xuất hiện

RCC = Reset and Clock Control.

GPIOC nằm trên:

APB2

Vì vậy phải bật clock cho GPIOC bằng:

RCC->APB2ENR

Ví dụ:

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

Trên STM32F103, bit 4 là:

IOPCEN

tức:

I/O Port C Clock Enable.


16. Bây giờ toàn bộ quá trình đã rõ

Muốn điều khiển PC13 bằng thanh ghi:

CPU
│
▼
RCC->APB2ENR
│
│ Enable GPIOC clock
▼
GPIOC
│
┌──────┴──────┐
│ │
GPIOC->CRH GPIOC->ODR
│ │
cấu hình PC13 HIGH/LOW

Đây là chuỗi tư duy bạn cần nhớ.


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

Nếu dùng CMSIS/register definitions phù hợp với STM32F103, ý tưởng cấu hình PC13 output push-pull 2 MHz là:

RCC->APB2ENR |= (1 << 4);
GPIOC->CRH &= ~(0xF << 20);
GPIOC->CRH |= (0x2 << 20);
GPIOC->ODR |= (1 << 13);

Ta hãy đọc từng dòng.

Dòng 1

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

→ bật clock GPIOC.

Dòng 2

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

→ xóa cấu hình cũ của PC13.

Dòng 3

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

→ cấu hình:

MODE = 10
CNF = 00

→ output push-pull 2 MHz.

Dòng 4

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

→ PC13 = HIGH.


18. Đây chính là lý do Bài 16 quan trọng

Nhìn đoạn:

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

bạn đang sử dụng đồng thời:

&
~
<<

Còn:

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

sử dụng:

|
<<

Và:

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

sử dụng:

^
<<

Cho nên:

Bit manipulation không phải kiến thức toán học khô khan. Nó chính là ngôn ngữ để điều khiển thanh ghi của vi điều khiển.


19. Một điều rất quan trọng về PC13 trên Blue Pill

Trên Blue Pill, LED onboard thường được mắc active-low.

Điều này có nghĩa:

PC13 = LOW
↓
LED sáng

và:

PC13 = HIGH
↓
LED tắt

Vì vậy nếu bạn thấy:

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

mà LED tắt, đó không phải lỗi.

Đó là do cách LED được mắc trên board.


20. GPIO không chỉ có ODR

STM32F103 còn có:

ODR
BSRR
BRR

Trong đó BSRR cực kỳ đáng chú ý.

Ví dụ:

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

→ set PC13.

Còn:

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

→ reset PC13.

Tức là BSRR cho phép thao tác set/reset GPIO mà không cần read-modify-write ODR theo cách thông thường.

Chúng ta sẽ đào sâu phần này sau.


21. Bảng cần nhớ của GPIOF1

Thành phần Ý nghĩa
RCC->APB2ENR bật clock GPIO
GPIOx->CRL cấu hình pin 0–7
GPIOx->CRH cấu hình pin 8–15
GPIOx->IDR đọc input
GPIOx->ODR xuất output
GPIOx->BSRR set/reset GPIO
GPIOx->BRR reset GPIO
GPIOx->LCKR khóa cấu hình

22. Công thức tư duy rất quan trọng

Khi gặp bất kỳ GPIO nào, hãy tự hỏi 4 câu:

Câu 1

Clock của GPIO đã bật chưa?

Ví dụ:

RCC->APB2ENR

Câu 2

Pin này nằm ở CRL hay CRH?

0–7 → CRL
8–15 → CRH

Câu 3

Pin này chiếm 4 bit nào?

Ví dụ PC13:

13 – 8 = 5

nên:

5 × 4 = 20

→ bit 20–23.

Câu 4

Sau khi cấu hình, dùng thanh ghi nào để điều khiển?

Output:

ODR
BSRR
BRR

Input:

IDR

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

Với Blue Pill STM32F103C8T6, hãy thử tự viết chương trình:

Bài tập 1

Cấu hình:

PC13 = Output Push-Pull

Bài tập 2

Cho LED PC13:

sáng 1 giây
tắt 1 giây

lặp lại.

Bài tập 3

Không được dùng:

HAL_GPIO_WritePin()
HAL_GPIO_TogglePin()

Mà phải dùng trực tiếp:

RCC->…
GPIOC->CRH
GPIOC->ODR

24. Và đây là kiến thức quan trọng nhất của Bài 18

Hãy ghi nhớ chuỗi này:

RCC
│
│ bật clock
▼
GPIO PORT
│
┌─────┴─────┐
▼ ▼
CRL/CRH IDR/ODR
│ │
cấu hình dữ liệu
│ │
└─────┬─────┘
▼
GPIO PIN

Và với PC13:

GPIOC
│
├── CRH
│ └── bit 20..23 → cấu hình PC13
│
└── ODR
└── bit 13 → mức logic PC13

Nếu Bài 17 giúp bạn hiểu “địa chỉ thanh ghi nằm ở đâu”, thì Bài 18 giúp bạn hiểu “dùng thanh ghi đó để điều khiển phần cứng như thế nào”.

Ở Bài 19, bước tiếp theo rất tự nhiên sẽ là GPIO Input: đọc nút nhấn bằng IDR, Pull-up/Pull-down, và vì sao một chân GPIO có thể “trôi” (floating). Đây là bài sẽ giúp bạn chuyển từ “điều khiển LED” sang “đọc thế giới bên ngoài”.

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