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 16 – BIT, BYTE, MASK, &, |, ^, ~, <<, >> CÁCH STM32 THỰC SỰ ĐIỀU KHIỂN THANH GHI

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

📘 BÀI 16 – BIT, BYTE, MASK, &, |, ^, ~, <<, >>

CÁCH STM32 THỰC SỰ ĐIỀU KHIỂN THANH GHI

Đây là một trong những bài quan trọng nhất trong quá trình học C để lập trình STM32.

Từ bài này, bạn bắt đầu chuyển từ:

"Học cú pháp C"

sang:

"Điều khiển phần cứng bằng C"

Đặc biệt với STM32F103C8T6 Blue Pill của bạn, kiến thức này sẽ giúp bạn hiểu sâu hơn cách GPIO, Timer, UART, ADC… thực sự hoạt động.


1. Trước tiên: BIT là gì?

Một máy tính chỉ làm việc với:

0
1

Một bit chỉ có thể có hai trạng thái:

0 hoặc 1

Ví dụ một byte 8 bit:

Bit:   7 6 5 4 3 2 1 0
       ─────────────────
       1 0 1 1 0 0 1 0

Giá trị:

10110010

Trong đó:

bit 7 = 1
bit 6 = 0
bit 5 = 1
bit 4 = 1
bit 3 = 0
bit 2 = 0
bit 1 = 1
bit 0 = 0

2. BYTE là gì?

Thông thường:

1 byte = 8 bit

Ví dụ:

00000000

là 0.

00000001

là 1.

00000010

là 2.

00000100

là 4.

00001000

là 8.

Bạn hãy chú ý quy luật:

Bit:     7 6 5 4 3 2 1 0
         │ │ │ │ │ │ │ │
Giá trị:128 64 32 16 8 4 2 1

Vì vậy:

00001010

=

8 + 2 = 10

3. Tại sao STM32 cực kỳ quan tâm đến BIT?

Bởi vì các peripheral của STM32 được điều khiển bằng register – thanh ghi.

Một thanh ghi có thể có 32 bit:

31                              0
┌────────────────────────────────┐
│00000000000101010000100000000101│
└────────────────────────────────┘

Mỗi bit hoặc nhóm bit có thể mang một ý nghĩa khác nhau.

Ví dụ giả tưởng:

Register CONTROL

Bit 0 → Enable
Bit 1 → Interrupt
Bit 2 → Reset
Bit 3 → Direction
Bit 4 → Mode
...

Muốn bật một chức năng, bạn phải thay đổi đúng bit.


4. Toán tử & – AND

Ví dụ:

A = 1010
B = 1100

AND:

1010
1100
----
1000

Quy tắc:

0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1

Chỉ khi cả hai đều bằng 1 thì kết quả mới là 1.


5. & dùng để kiểm tra BIT

Đây là một ứng dụng cực kỳ quan trọng.

Giả sử:

uint8_t value = 0b00001010;

Ta muốn kiểm tra bit 3.

Tạo mask:

uint8_t mask = 0b00001000;

Sau đó:

if (value & mask)
{
    // bit 3 đang bằng 1
}

Tại sao?

value = 00001010
mask  = 00001000
        --------
        00001000

Kết quả khác 0 → bit 3 đang bằng 1.


6. | – OR

Quy tắc:

0 | 0 = 0
0 | 1 = 1
1 | 0 = 1
1 | 1 = 1

Ví dụ:

1010
1100
----
1110

OR rất hữu ích để SET bit = đưa bit lên 1.


7. Ví dụ SET một bit

Có:

uint8_t REG = 0;

Muốn bật bit 3:

REG = REG | (1 << 3);

hoặc viết ngắn:

REG |= (1 << 3);

Ban đầu:

REG
00000000

Tính:

1 << 3

được:

00001000

Sau:

00000000
00001000
--------
00001000

Bit 3 được bật.


8. << – dịch trái

Đây là toán tử bạn phải rất quen.

1 << 0

=

00000001
1 << 1

=

00000010
1 << 2

=

00000100
1 << 3

=

00001000
1 << 4

=

00010000

Bảng:

Biểu thức Nhị phân Giá trị
1 << 0 00000001 1
1 << 1 00000010 2
1 << 2 00000100 4
1 << 3 00001000 8
1 << 4 00010000 16
1 << 5 00100000 32
1 << 6 01000000 64
1 << 7 10000000 128

Vì vậy:

(1 << n)

là cách cực kỳ phổ biến để tạo mask cho bit n.


9. >> – dịch phải

Ngược lại:

0b10000000 >> 1

→

01000000

Tiếp:

00100000

Ví dụ:

uint8_t value = 0b00100000;

value >> 5

→

00000001

10. Tại sao >> hữu ích?

Giả sử register chứa:

10110100

Bạn muốn lấy bit 4.

Ta có thể:

uint8_t bit4 = (value >> 4) & 1;

Ví dụ:

value
10110100

dịch phải 4:

00001011

AND với 1:

00001011
00000001
--------
00000001

→ bit 4 = 1.


11. ~ – NOT

~ đảo tất cả bit.

Ví dụ:

value = 10110010

thì:

~value = 01001101

Quy tắc:

0 → 1
1 → 0

12. ^ – XOR

XOR có quy tắc:

0 ^ 0 = 0
0 ^ 1 = 1
1 ^ 0 = 1
1 ^ 1 = 0

Điểm đặc biệt:

Hai bit giống nhau → 0; khác nhau → 1.

Ví dụ:

1010
1100
----
0110

13. XOR rất hay dùng để TOGGLE bit

Giả sử:

uint8_t REG = 0;

Muốn đảo bit 3:

REG ^= (1 << 3);

Lần đầu:

00000000
00001000
--------
00001000

Bit 3:

0 → 1

Lần nữa:

00001000
00001000
--------
00000000

Bit 3:

1 → 0

Vậy:

REG ^= (1 << 3);

có nghĩa:

Toggle bit 3.


14. Đây là 4 thao tác bạn phải thuộc

SET bit

REG |= (1 << n);

→ bit n = 1

CLEAR bit

REG &= ~(1 << n);

→ bit n = 0

TOGGLE bit

REG ^= (1 << n);

→ đảo bit n

READ bit

(REG >> n) & 1

→ lấy giá trị bit n


15. CLEAR bit – cực kỳ quan trọng

Giả sử:

REG = 10110111

Muốn xóa bit 4.

Tạo:

(1 << 4)

=

00010000

Đảo:

~(1 << 4)

=

11101111

AND:

10110111
11101111
--------
10100111

Bit 4:

1 → 0

Vì vậy:

REG &= ~(1 << 4);

16. MASK là gì?

Mask là một giá trị nhị phân được tạo ra để thao tác với một hoặc một nhóm bit.

Ví dụ:

#define BIT0_MASK   (1 << 0)
#define BIT1_MASK   (1 << 1)
#define BIT2_MASK   (1 << 2)
#define BIT3_MASK   (1 << 3)

hoặc:

#define GPIO_ENABLE_MASK    (1 << 0)
#define GPIO_ERROR_MASK     (1 << 1)
#define GPIO_MODE_MASK      (3 << 2)

Mask là một khái niệm bạn sẽ gặp liên tục khi đọc Reference Manual của STM32.


17. Không chỉ một bit – có thể có một nhóm bit

Ví dụ register:

Bit 7 6 5 4 3 2 1 0
    ─────── ───────
      MODE    CONTROL

Giả sử:

Bit 2-3 = MODE

Có 2 bit:

00
01
10
11

→ có 4 trạng thái.

Mask:

#define MODE_MASK (0b11 << 2);

=

00001100

18. Ghi giá trị vào một nhóm bit

Đây là kỹ thuật rất quan trọng.

Giả sử:

uint8_t REG = 0b10110011;

Ta muốn đặt:

bit 2-3 = 01

Đầu tiên xóa hai bit:

REG &= ~(0b11 << 2);

Sau đó đưa giá trị mới vào:

REG |= (0b01 << 2);

Đây chính là cách thao tác với field trong register.


19. Tại sao STM32 cần kỹ thuật này?

Bởi một register có thể chứa rất nhiều chức năng.

Ví dụ giả tưởng:

REGISTER
31                         0
┌────┬────┬────┬────┬──────┐
│MODE│IRQ │EN  │DIR │...   │
└────┴────┴────┴────┴──────┘

Bạn muốn thay đổi MODE.

Bạn không được phép vô tình thay đổi IRQ hoặc EN.

Vì vậy phải:

1. Xóa đúng các bit MODE
2. Ghi giá trị MODE mới
3. Giữ nguyên các bit khác

Đây chính là sức mạnh của:

&
|
~
<<

20. Liên hệ trực tiếp với STM32

Trong STM32F103, các peripheral có rất nhiều thanh ghi.

Ví dụ GPIO có các register như:

CRL
CRH
IDR
ODR
BSRR
BRR

Mỗi register lại có các bit/field riêng.

Ví dụ bạn muốn cấu hình GPIO:

Input
Output
Pull-up
Pull-down
Push-pull
Open-drain
50 MHz
10 MHz
2 MHz
...

Tất cả cuối cùng đều được biểu diễn bằng các bit trong register.


21. Ví dụ với LED PC13

Bạn đang dùng Blue Pill có LED onboard ở:

PC13

Ở mức register, việc điều khiển GPIO cuối cùng vẫn quy về:

đọc/ghi các bit của register

Ví dụ ý tưởng:

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

có nghĩa:

GPIOC->ODR
      │
      └── set bit 13

Tức:

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

22. Tắt bit 13

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

Tư duy:

ODR
 ↓
xóa bit 13
 ↓
PC13 output = 0

Tuy nhiên, trên Blue Pill LED onboard thường là active-low, nên:

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

Đây là ví dụ rất hay cho thấy:

Logic của phần cứng không nhất thiết giống logic “1 = ON”.


23. Một cách khác: BSRR

STM32F1 còn có register:

GPIOx_BSRR

Register này được thiết kế để set/reset GPIO theo cơ chế phần cứng.

Ví dụ ý tưởng:

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

set chân.

Reset có thể dùng vùng bit reset tương ứng của BSRR.

Điểm quan trọng ở đây:

Bạn đang bắt đầu nhìn thấy cách các thư viện HAL/LL cuối cùng cũng phải thao tác với register và bit.


24. HAL không làm mất kiến thức Register

Ví dụ bạn viết:

HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);

Bạn không trực tiếp viết:

GPIOC->ODR

nhưng bên dưới thư viện vẫn phải cuối cùng điều khiển phần cứng thông qua register.

Tư duy:

HAL
 ↓
Driver
 ↓
Register
 ↓
Bit
 ↓
Silicon STM32
 ↓
GPIO PC13

Vì vậy học bitwise operation không hề thừa, ngay cả khi bạn dùng CubeMX + HAL.


25. Bảng “phải thuộc”

Mục đích Code
Set bit n `REG
Clear bit n REG &= ~(1U << n);
Toggle bit n REG ^= (1U << n);
Read bit n (REG >> n) & 1U
Tạo mask bit n (1U << n)

Hãy thuộc 5 dòng này.


26. Một ví dụ tổng hợp

Giả sử:

uint8_t REG = 0;

Bật bit 2

REG |= (1U << 2);

Kết quả:

00000100

Bật tiếp bit 5

REG |= (1U << 5);

Kết quả:

00100100

Kiểm tra bit 5

if (REG & (1U << 5))
{
    // bit 5 = 1
}

Xóa bit 2

REG &= ~(1U << 2);

Kết quả:

00100000

Toggle bit 5

REG ^= (1U << 5);

Kết quả:

00000000

27. Một điều bạn cần đặc biệt chú ý

Không nên viết:

REG = (1U << 3);

nếu mục tiêu của bạn chỉ là set bit 3.

Vì câu lệnh này ghi đè toàn bộ register.

Ví dụ:

REG ban đầu:

10110100

Bạn muốn bật bit 3.

Nếu:

REG = (1U << 3);

thì:

00001000

Toàn bộ các bit khác bị mất.

Trong khi:

REG |= (1U << 3);

sẽ giữ nguyên các bit khác:

10110100
00001000
--------
10111100

Đây là điểm cực kỳ quan trọng khi thao tác register.


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

🧪 Bài 1 – tính nhị phân

Không dùng máy tính, hãy tính:

1 << 0
1 << 1
1 << 2
1 << 3
1 << 4
1 << 5

🧪 Bài 2 – SET

Cho:

uint8_t reg = 0b00000000;

Hãy set:

bit 1
bit 4
bit 7

Kết quả cuối cùng là bao nhiêu?


🧪 Bài 3 – CLEAR

Cho:

uint8_t reg = 0b11111111;

Xóa:

bit 2
bit 5

Kết quả?


🧪 Bài 4 – TOGGLE

Cho:

uint8_t reg = 0b10101010;

Thực hiện:

reg ^= (1U << 1);

Kết quả?

Sau đó:

reg ^= (1U << 7);

Kết quả?


29. 🧪 Bài 5 – cực kỳ quan trọng

Cho:

uint8_t reg = 0b10110100;

Hãy viết code để:

  1. Set bit 0
  2. Clear bit 4
  3. Toggle bit 6
  4. Kiểm tra bit 3
  5. Kiểm tra bit 7

Không được sử dụng if để thực hiện thao tác set/clear/toggle.


30. 🧪 Bài 6 – STM32 Blue Pill

Hãy thử suy nghĩ về câu lệnh:

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

Giải thích từng thành phần:

GPIOC
  ↓
ODR
  ↓
|
  ↓
1U
  ↓
<<
  ↓
13

Bạn phải hiểu được toàn bộ câu lệnh này, không chỉ học thuộc.


🎯 BÀI 16 CẦN THUỘC LÒNG

Nếu chỉ được phép mang theo 5 công thức vào Bài 17, hãy nhớ:

REG |=  (1U << n);       // SET
REG &= ~(1U << n);       // CLEAR
REG ^=  (1U << n);       // TOGGLE
(REG >> n) & 1U          // READ
(1U << n)                // MASK

Và hãy nhớ tư duy:

             STM32
               │
               ▼
            REGISTER
               │
       ┌───────┼───────┐
       ▼       ▼       ▼
      BIT     BIT     BIT
       │       │       │
       └───────┼───────┘
               ▼
          PHẦN CỨNG

Bài 17 chúng ta sẽ nối tất cả những gì đã học từ Bài 1 → 16 vào một chủ đề cực kỳ quan trọng:

🔥 BÀI 17 – MEMORY MAP STM32F103: FLASH, SRAM, PERIPHERAL, REGISTER VÀ ĐỊA CHỈ 0x40000000 THỰC SỰ CÓ Ý NGHĨA GÌ?

Ở bài đó, bạn sẽ bắt đầu hiểu tại sao một câu như:

GPIOC->ODR

lại có thể điều khiển một transistor bên trong con chip STM32.

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