Thanh ghi là gì? Cách hoạt động của thanh ghi trong vi điều khiển

Thanh ghi là gì? Cách hoạt động của thanh ghi trong vi điều khiển

Trong bài này chúng ta sẽ cùng tìm hiểu thanh ghi là gì, thanh ghi nằm ở đâu trong vi điều khiển, có những loại thanh ghi nào, và cách đọc, ghi, thao tác từng bit của thanh ghi bằng ngôn ngữ C. Đây là khái niệm nền tảng nhất của lập trình nhúng, hiểu được thanh ghi là hiểu được cách code thực sự điều khiển phần cứng nhé.

Bài này nằm trong phần kiến thức cơ bản về vi điều khiển của Serie Học lập trình 8051 từ A tới Z

Thanh ghi là gì

Thanh ghi là gì?

Thanh ghi (register) là một ô nhớ rất nhỏ, thường 8, 16 hoặc 32 bit, nằm ngay bên trong CPU hoặc bên trong các khối ngoại vi của vi điều khiển. Thanh ghi có tốc độ truy cập nhanh nhất trong toàn bộ hệ thống nhớ.

Ví dụ đời thường nhé: nếu RAM giống như tủ hồ sơ trong phòng làm việc, thì thanh ghi giống như mặt bàn ngay trước mặt các bạn. Tủ hồ sơ chứa được nhiều, nhưng muốn dùng thì phải đứng dậy mở tủ lấy ra. Mặt bàn thì chỉ đặt được vài tờ giấy, nhưng với tay là lấy được ngay.

Nếu chưa rõ CPU và bộ nhớ hoạt động thế nào, các bạn đọc trước 2 bài CPU là gì? Cấu tạo và nguyên lý hoạt động của CPU và Bộ nhớ là gì? Phân loại và cấu tạo của bộ nhớ nhé.

Thanh ghi điều khiển phần cứng như thế nào?

Đây là điều kỳ diệu nhất của thanh ghi ngoại vi: mỗi bit trong thanh ghi được nối thẳng với một mạch điện thật bên trong chip.

Lấy ví dụ thanh ghi P1 của 8051. Thanh ghi này có 8 bit, mỗi bit nối với một chân P1.0 – P1.7 của chip. Khi chương trình ghi số 1 vào bit 0 của P1, mạch điện bên trong lập tức đưa chân P1.0 lên mức điện áp cao. Ghi số 0 thì chân P1.0 xuống 0V.

Nói cách khác, lập trình vi điều khiển chính là đọc và ghi các thanh ghi. Mọi hàm thư viện như digitalWrite() của Arduino hay HAL_GPIO_WritePin() của STM32, xét cho cùng cũng chỉ là ghi một giá trị vào một thanh ghi nào đó.

Các loại thanh ghi

Thanh ghi đa dụng

Thanh ghi đa dụng (general purpose register) là các thanh ghi CPU dùng để chứa dữ liệu tạm thời khi tính toán. Trên 8051 có:

  • A (Accumulator): thanh ghi tích lũy, hầu hết phép tính đều đi qua A.
  • B: dùng cùng A trong phép nhân, chia.
  • R0 – R7: 8 thanh ghi đa dụng, có 4 bộ (bank) để chuyển đổi nhanh khi vào ngắt.

Khi lập trình C, trình biên dịch tự quyết định dùng các thanh ghi này, chúng ta hầu như không phải quan tâm.

Thanh ghi chức năng đặc biệt (SFR)

SFR (Special Function Register) là các thanh ghi điều khiển ngoại vi và trạng thái của chip. Đây là các thanh ghi chúng ta làm việc nhiều nhất. Trên 8051, SFR nằm ở vùng địa chỉ 0x80 – 0xFF:

Thanh ghi Địa chỉ Chức năng
P0, P1, P2, P3 0x80, 0x90, 0xA0, 0xB0 4 cổng vào ra
TMOD 0x89 Chọn chế độ Timer
TCON 0x88 Điều khiển Timer và ngắt ngoài
TH0, TL0 0x8C, 0x8A Giá trị đếm của Timer0
SCON 0x98 Điều khiển UART
SBUF 0x99 Bộ đệm dữ liệu UART
IE 0xA8 Cho phép ngắt

Danh sách đầy đủ có trong datasheet của chip, ví dụ datasheet AT89S52 của Microchip.

Các thanh ghi đặc biệt của CPU

  • PC (Program Counter): chứa địa chỉ lệnh tiếp theo sẽ chạy.
  • SP (Stack Pointer): con trỏ ngăn xếp, dùng khi gọi hàm và vào ngắt.
  • PSW (Program Status Word): chứa các cờ trạng thái như cờ nhớ, cờ tràn.
  • DPTR (Data Pointer): con trỏ 16 bit để truy cập bộ nhớ ngoài và bảng hằng số.

Thao tác với thanh ghi bằng ngôn ngữ C

Trong Keil C, các thanh ghi SFR đã được định nghĩa sẵn tên trong file header REGX52.H. Chúng ta dùng tên thanh ghi như một biến bình thường.

Ghi cả thanh ghi

P1 = 0xFF;                 // ghi ca thanh ghi: 8 chan P1 len muc 1

Cách này đơn giản nhưng ghi đè cả 8 bit cùng lúc.

Thao tác từng bit

Muốn thay đổi 1 bit mà giữ nguyên các bit khác, chúng ta dùng các phép toán bit kết hợp với mặt nạ (mask):

P1 &= ~(1 << 3);           // xoa bit 3: P1.3 xuong 0, cac bit khac giu nguyen
P1 |= (1 << 3);            // dat bit 3: P1.3 len 1
P1 ^= (1 << 3);            // dao bit 3

if (P1 & (1 << 4))         // kiem tra bit 4
{
	P1_0 = 0;              // dung ten bit co san trong REGX52.H
}
  • Đặt bit n lên 1: REG |= (1 << n). OR với 1 thì bit thành 1, OR với 0 thì giữ nguyên.
  • Xóa bit n về 0: REG &= ~(1 << n). AND với 0 thì bit thành 0, AND với 1 thì giữ nguyên.
  • Đảo bit n: REG ^= (1 << n). XOR với 1 thì đảo, XOR với 0 thì giữ nguyên.
  • Kiểm tra bit n: REG & (1 << n). Kết quả khác 0 nghĩa là bit đang bằng 1.

(1 << n) là dịch số 1 sang trái n bit, tạo ra mặt nạ chỉ có bit n bằng 1. Ví dụ 1 << 3 là 0000 1000 = 0x08.

Các phép toán bit này các bạn sẽ dùng ở mọi dòng chip, từ 8051, AVR tới STM32. Phần toán tử bit trong C các bạn xem lại bài Cách sử dụng toán tử trong lập trình C.

Thanh ghi đánh địa chỉ bit trên 8051

8051 có một tính năng đặc biệt: các thanh ghi SFR có địa chỉ chia hết cho 8 (như P0, P1, TCON, IE, SCON) có thể truy cập từng bit riêng lẻ bằng một lệnh duy nhất. Trong Keil C, chúng ta khai báo bằng từ khóa sbit:

sbit LED = P1^0;    // LED la bit 0 cua thanh ghi P1
LED = 0;            // chi tac dong toi chan P1.0

Đó là lý do trong các bài 8051 các bạn thấy viết TR0 = 1;, EA = 1; thay vì phải dùng phép OR với mặt nạ.

Lưu ý: Lỗi kinh điển khi làm việc với thanh ghi là ghi đè cả thanh ghi trong khi chỉ muốn đổi vài bit. Ví dụ thanh ghi TMOD chứa cấu hình cho cả Timer0 lẫn Timer1, viết TMOD = 0x01; để chọn chế độ cho Timer0 sẽ xóa luôn cấu hình Timer1 đang dùng cho UART, và UART tự nhiên ngừng chạy. Hãy xóa đúng các bit cần đổi rồi mới OR giá trị mới vào, như TMOD &= 0xF0; TMOD |= 0x01;.

Thanh ghi trên STM32 khác gì 8051?

Trên STM32, thanh ghi ngoại vi rộng 32 bit và được ánh xạ vào bộ nhớ (memory-mapped): mỗi thanh ghi có một địa chỉ trong không gian 4GB, đọc ghi như một biến con trỏ. Ví dụ bật chân PC13:

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

Cách thao tác bit vẫn y hệt 8051, chỉ là số bit nhiều hơn và số thanh ghi nhiều hơn rất nhiều. STM32 còn có kỹ thuật bit-band để truy cập từng bit nhanh như sbit của 8051, các bạn xem trong bài Lập trình STM32 Bit Banding điều khiển GPIO.

Kết

Thanh ghi là cầu nối giữa phần mềm và phần cứng: viết code nhúng thực chất là đọc, ghi đúng bit vào đúng thanh ghi. Nắm chắc các phép toán bit và thói quen đọc bảng thanh ghi trong datasheet, các bạn sẽ học bất kỳ dòng vi điều khiển nào cũng nhanh hơn rất nhiều.

Bước tiếp theo, các bạn hãy áp dụng ngay vào bài Lập trình 8051 GPIO bật tắt led bằng nút nhấn để thấy thanh ghi P1, P3 hoạt động thực tế. Nếu thấy bài viết có ích, hãy chia sẻ cho bạn bè cùng học nhé!

Rate this post

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *