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 28 – GPIO STM32F103: BSRR – CÁCH SET/CLEAR GPIO BẰNG 1 LỆNH

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

BÀI 28 – GPIO STM32F103: BSRR – CÁCH SET/CLEAR GPIO BẰNG 1 LỆNH

Ở Bài 27, chúng ta đã học GPIOx->ODR để điều khiển trạng thái chân GPIO.

Hôm nay chúng ta học một thanh ghi cực kỳ quan trọng trong STM32:

GPIOx->BSRR – Bit Set/Reset Register

Đây chính là cách STM32 điều khiển GPIO nhanh, an toàn và nguyên tử (atomic) hơn so với việc đọc–sửa–ghi ODR.


1. Nhắc lại ODR

Ví dụ:

GPIOA->ODR |= (1 << 5);

→ PA5 = HIGH.

Và:

GPIOA->ODR &= ~(1 << 5);

→ PA5 = LOW.

Vấn đề là các câu lệnh trên thực hiện theo kiểu:

Đọc ODR
   ↓
Thay đổi bit
   ↓
Ghi lại ODR

Trong một số tình huống, quá trình read-modify-write này không tối ưu.

STM32F103 cung cấp BSRR để giải quyết vấn đề đó.


2. BSRR là gì?

Với GPIO:

GPIOA->BSRR
GPIOB->BSRR
GPIOC->BSRR
...

Thanh ghi này rộng 32 bit.

Có thể hình dung:

31                         16 15                         0
+----------------------------+----------------------------+
|        RESET bits          |         SET bits           |
+----------------------------+----------------------------+
       GPIO pin 15...0              GPIO pin 15...0

Cụ thể:

Bit 0  → SET PA0
Bit 1  → SET PA1
...
Bit 15 → SET PA15

Bit 16 → RESET PA0
Bit 17 → RESET PA1
...
Bit 31 → RESET PA15

Công thức:

SET   pin n → bit n
RESET pin n → bit n + 16

3. SET một chân GPIO

Ví dụ muốn:

PA5 = HIGH

Ta viết:

GPIOA->BSRR = (1 << 5);

Tức là:

1 << 5

cho kết quả:

0000 0000 0000 0000
0000 0000 0010 0000

Bit 5 của vùng SET = 1.

STM32 hiểu:

Hãy SET PA5.

Kết quả:

PA5 = HIGH

4. RESET một chân GPIO

Muốn:

PA5 = LOW

ta sử dụng phần RESET của BSRR.

PA5 tương ứng:

5 + 16 = 21

Vì vậy:

GPIOA->BSRR = (1 << 21);

Hoặc viết dễ hiểu hơn:

GPIOA->BSRR = (1 << (5 + 16));

Kết quả:

PA5 = LOW

5. Cách nhớ cực kỳ quan trọng

Bạn chỉ cần nhớ:

BSRR bit 0...15   → SET
BSRR bit 16...31  → RESET

Ví dụ:

Chân SET RESET
PA0 1 << 0 1 << 16
PA1 1 << 1 1 << 17
PA2 1 << 2 1 << 18
PA5 1 << 5 1 << 21
PA8 1 << 8 1 << 24
PA13 1 << 13 1 << 29
PA15 1 << 15 1 << 31

6. Ví dụ với LED PC13

Blue Pill của bạn có LED tích hợp thường nằm ở:

PC13

Giả sử PC13 đã được cấu hình Output.

Bật PC13

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

Tắt PC13

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

hay:

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

7. Nhưng LED Blue Pill thường là Active LOW

Đây là chỗ rất dễ nhầm.

Trên nhiều board Blue Pill:

PC13 = LOW  → LED sáng
PC13 = HIGH → LED tắt

Vì LED được mắc theo kiểu active-low.

Do đó:

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

→ PC13 LOW → LED SÁNG

Trong khi:

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

→ PC13 HIGH → LED TẮT

Đây là lý do khi học STM32 bạn phải phân biệt:

GPIO HIGH/LOW

với:

Thiết bị ON/OFF

Hai khái niệm này không phải lúc nào cũng giống nhau.


8. So sánh ODR và BSRR

Ví dụ muốn bật PA5.

Cách 1 – ODR

GPIOA->ODR |= (1 << 5);

Cách 2 – BSRR

GPIOA->BSRR = (1 << 5);

Cả hai đều làm:

PA5 = HIGH

Nhưng cách hoạt động khác nhau.


9. ODR là Read–Modify–Write

Ví dụ:

GPIOA->ODR |= (1 << 5);

CPU phải thực hiện về bản chất:

Đọc ODR
   ↓
OR với bit 5
   ↓
Ghi ODR

Trong khi:

GPIOA->BSRR = (1 << 5);

chỉ cần ghi lệnh SET vào BSRR.

STM32 phần cứng thực hiện việc thay đổi GPIO.


10. Điều đặc biệt của BSRR: Atomic

Đây là khái niệm bạn cần bắt đầu làm quen từ bài này:

Atomic – nguyên tử

Hiểu đơn giản:

Một thao tác GPIO được thực hiện
mà không cần quá trình đọc–sửa–ghi ODR.

Điều này đặc biệt hữu ích khi chương trình có:

Interrupt
Timer
DMA
RTOS
nhiều phần mềm cùng tác động GPIO

Ở các bài nâng cao sau này, khái niệm atomic operation sẽ rất quan trọng.


11. Set nhiều chân cùng lúc

Ví dụ muốn:

PA0 = HIGH
PA1 = HIGH
PA2 = HIGH

Có thể viết:

GPIOA->BSRR =
    (1 << 0) |
    (1 << 1) |
    (1 << 2);

Hoặc:

GPIOA->BSRR = 0x00000007;

Vì:

bit 0 = 1
bit 1 = 1
bit 2 = 1

→ PA0, PA1, PA2 đều HIGH.


12. Reset nhiều chân cùng lúc

Muốn:

PA0 = LOW
PA1 = LOW
PA2 = LOW

ta dùng:

GPIOA->BSRR =
    (1 << 16) |
    (1 << 17) |
    (1 << 18);

Hoặc:

GPIOA->BSRR = 0x00070000;

13. Set và Reset các chân khác nhau trong cùng một lần ghi

Đây là một ưu điểm rất hay.

Ví dụ:

PA0 → HIGH
PA1 → LOW

Có thể:

GPIOA->BSRR =
    (1 << 0) |
    (1 << (1 + 16));

Tức là:

bit 0  = 1 → SET PA0
bit 17 = 1 → RESET PA1

Sau một lần ghi:

PA0 = HIGH
PA1 = LOW

14. Một ví dụ thực tế

Giả sử:

PA0 → LED đỏ
PA1 → LED xanh

Muốn:

LED đỏ ON
LED xanh OFF

nếu cả hai LED active-high:

GPIOA->BSRR =
    (1 << 0) |
    (1 << (1 + 16));

Sau đó muốn đảo:

LED đỏ OFF
LED xanh ON

thì:

GPIOA->BSRR =
    (1 << (0 + 16)) |
    (1 << 1);

15. BSRR không phải là một GPIO mới

Đây là điểm cần hiểu rõ.

Bạn có:

GPIOA

Bên trong GPIOA có nhiều thanh ghi:

GPIOA
 ├── CRL
 ├── CRH
 ├── IDR
 ├── ODR
 ├── BSRR
 ├── BRR
 └── ...

Trong đó:

CRL/CRH → cấu hình chân
IDR     → đọc chân
ODR     → trạng thái output
BSRR    → SET/RESET output

16. Nhìn GPIO như một hệ thống

Đến thời điểm này, bạn có thể hình dung:

                GPIOA
                  │
       ┌──────────┼──────────┐
       ↓          ↓          ↓
     CRL/CRH     IDR        ODR
       │          │          │
       │          │          └── trạng thái output
       │          │
       │          └───────────── đọc input
       │
       └──────────────────────── cấu hình GPIO

Và:

                 BSRR
                  │
          ┌───────┴───────┐
          ↓               ↓
        SET             RESET
          │               │
          └───────┬───────┘
                  ↓
                GPIO

17. Một câu lệnh cực kỳ quan trọng

Từ bây giờ, khi muốn bật GPIO:

GPIOA->BSRR = (1 << pin);

Khi muốn tắt:

GPIOA->BSRR = (1 << (pin + 16));

Ví dụ:

#define LED_PIN 13

Bật:

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

Tắt:

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

Đây là cách viết rất phù hợp khi bạn bắt đầu xây dựng driver GPIO riêng thay vì phụ thuộc vào Arduino API.


18. Một lỗi rất dễ mắc

Đừng viết:

GPIOA->BSRR |= (1 << 5);

trong cách sử dụng thông thường.

Hãy viết:

GPIOA->BSRR = (1 << 5);

Vì BSRR được thiết kế chủ yếu để ghi lệnh SET/RESET, không phải để bạn đọc nó rồi sửa giống ODR.


19. Bài tập Bài 28

Không cần HAL, không cần Arduino.

Giả sử:

#define LED_PIN 13

Hãy tự viết chương trình để:

Bài tập 1

PC13:

HIGH
→ chờ
→ LOW
→ chờ

Bài tập 2

Điều khiển:

PA0
PA1
PA2

theo thứ tự:

PA0 HIGH
PA1 HIGH
PA2 HIGH

PA0 LOW
PA1 LOW
PA2 LOW

Bài tập 3 – quan trọng nhất

Tạo hàm:

void GPIO_Set(GPIO_TypeDef *GPIOx, uint8_t pin);

và:

void GPIO_Reset(GPIO_TypeDef *GPIOx, uint8_t pin);

Ý tưởng:

void GPIO_Set(GPIO_TypeDef *GPIOx, uint8_t pin)
{
    GPIOx->BSRR = (1 << pin);
}

và:

void GPIO_Reset(GPIO_TypeDef *GPIOx, uint8_t pin)
{
    GPIOx->BSRR = (1 << (pin + 16));
}

Sau đó có thể gọi:

GPIO_Set(GPIOC, 13);

hoặc:

GPIO_Reset(GPIOC, 13);

20. Điều bạn cần nhớ sau Bài 28

Nếu chỉ nhớ 5 dòng, hãy nhớ:

ODR  → trạng thái Output
IDR  → đọc Input
BSRR → SET/RESET GPIO
BSRR bit 0..15  → SET
BSRR bit 16..31 → RESET

Và công thức:

// SET pin
GPIOx->BSRR = (1 << pin);

// RESET pin
GPIOx->BSRR = (1 << (pin + 16));

Lộ trình tiếp theo

Bài 29 rất phù hợp để học tiếp:

BRR – thanh ghi Reset GPIO và tại sao STM32F103 có cả BSRR lẫn BRR?

Sau đó chúng ta sẽ tiến tới một phần rất quan trọng: tự viết GPIO driver bằng thanh ghi, từ đó bạn sẽ thực sự hiểu bên trong các hàm kiểu digitalWrite() của Arduino hoạt động như thế nào.

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