Ma trận phím là một thiết bị rất hay được sử dụng trong lập trình vi điều khiển, nó giúp tiết kiệm chân GPIO của vi điều khiển. Trong bài này chúng ta sẽ học cách quét ma trận, lý thuyết quét này cũng được sử dụng trong các loại LED ma trận khác nhau.
Bài này nằm trong Serie Học STM32 từ A tới Z
Ma trận bàn phím (Keypad) là gì?
Ma trận phím là tập hợp các nút nhấn kết nối với nhau theo các hàng và cột. Số nút nhấn sẽ bằng số hàng x số cột.
Ví dụ: ma trận phím 4×4 sẽ có 4 cột và 4 hàng, số lượng phím là 16 phím.
Để đọc 16 nút nhấn, thông thường chúng ta phải sử dụng 16 GPIO, nhưng nếu sử dụng ma trận phím chúng ta chỉ cần 8 GPIO.
Các nút nhấn sẽ nối hàng và cột với nhau. Khi nhấn nút, 1 dây Hàng (Row) sẽ được nối với 1 dây Cột (Column hay Col). Mỗi nút nhấn sẽ nối 1 cặp hàng – cột khác nhau.

Ví dụ: nút đầu tiên trong ma trận được nhấn sẽ nối Cột 1 (C1) với Hàng 1 (R1), nút liền kề bên phải được nhấn sẽ nối Cột 2 (C2) với Hàng 1 (R1). Tương tự như vậy với các nút khác. Giống như bàn cờ vua, chỉ cần biết tên cột và số hàng là xác định được đúng 1 ô.
Quét phím là gì? Hướng dẫn điều khiển ma trận phím
Trong bài về nút nhấn chúng ta đã được học cách đọc trạng thái của 1 chân (Read Input GPIO): nút nhấn được nối 1 đầu vào GPIO, 1 đầu vào GND hoặc VCC. Khi nhấn nút thì GPIO được nối với GND hoặc VCC, vậy nên khi đọc sẽ cho kết quả 0 hoặc 1.
Ý tưởng quét bàn phím như sau:
Thay vì nối 1 đầu nút nhấn với GND (hoặc VCC), chúng ta nối đầu đó với 1 GPIO khác. Chân GPIO đó chúng ta để là OUTPUT, vậy là chúng ta có thể điều khiển được điện áp trên đầu đó. Khi đó nếu nhấn nút, giá trị GPIO Input = giá trị GPIO Output.
Ở trạng thái bình thường, GPIO Input được để ở chế độ Pull Down (khi chưa nhấn nút sẽ có giá trị 0), GPIO Output ở trạng thái 0 (chưa active). Khi đó cho dù chúng ta ấn nút thì GPIO Input vẫn là giá trị 0.

Khi chúng ta đổi trạng thái GPIO Output sang 1 (active), nhấn nút thì GPIO Input sẽ đọc được giá trị 1.


Vậy khi nối nút nhấn thành ma trận 3×4:
Quét phím sẽ diễn ra như sau: khi quét cột 1, nếu các phím trong cột đó được nhấn, trạng thái GPIO của các hàng tương ứng sẽ thay đổi theo vị trí của nút nhấn. Các nút nhấn trong các cột khác dù được nhấn cũng không có tác dụng gì.
Khi quét đến cột 2, 3 cũng tương tự như vậy. Quá trình quét phải xảy ra rất nhanh, để có thể kiểm tra được tất cả các nút trong khoảng thời gian nhấn và thả ra.

Ví dụ với Keypad 3×4 và cách cấu hình trong bài này (hàng là Input Pull Up, cột là Output):
Để đọc được phím nhấn, vi điều khiển sẽ lần lượt kéo từng chân cột 3, 1, 5 xuống mức 0 (các cột còn lại giữ mức 1), sau đó đọc giá trị từ 4 chân hàng 2, 7, 6, 4. Vì các hàng có điện trở kéo lên, hàng nào đọc về 0 thì phím nằm ở giao điểm của cột đang quét và hàng đó đang được nhấn.
Ví dụ: khi đang kéo chân 3 xuống 0 mà chân 2 đọc được 0 => nút 1 được nhấn.
Tương tự với các nút còn lại.
Lưu ý: Phần lý thuyết ở trên dùng Pull Down và quét bằng mức 1, còn code trong bài dùng Pull Up và quét bằng mức 0. Hai cách đều đúng, chỉ là logic đảo ngược nhau. Khi tự viết code, bạn phải thống nhất: Input Pull Up thì cột đang quét đưa xuống 0, các cột khác giữ 1, và phím được nhấn khi đọc ra 0.
Cấu tạo của ma trận phím 3×4 (Keypad 3×4)
Bao gồm 3 cột và 4 hàng, sắp xếp theo thứ tự sau:


Trong bài viết này chúng ta sẽ sử dụng bàn phím cứng 3×4, Pinout tương tự như bàn phím mềm.
Lập trình STM32 quét ma trận phím 3×4
Cấu hình trong CubeMx
Chọn chip STM32F103C8T6. Cấu hình SYS – Debug – Serial Wire. Dùng thạch anh nội (HSI).
Trong GPIO chọn PA0 – PA3: Input Pull Up (4 hàng), PA4 – PA6: Output (3 cột)

Tab Connectivity chọn USART1 chế độ Asynchronous

Đặt tên và Gen Code

Download thư viện Keypad
Các bạn truy cập link: Hướng dẫn download tài liệu lập trình STM32
Download thư viện Device, trong đó có file KEYPAD.c và KEYPAD.h, copy file vào thư mục Src và Inc của project.
Click vào Add file, tìm tới file vừa tải về, nhấn Add để thêm file vào Project.

Sử dụng thư viện ma trận phím KEYPAD
Sau khi thêm các file vào, chúng ta include KEYPAD.h vào main.c. Tạo một biến Key để lưu trữ phím được đọc ra.

Khai báo 1 bàn phím tên là Keypad và một KeyMap (kí tự tương ứng với vị trí nút nhấn trên Keypad).

Trước while (1), khởi tạo Keypad, truyền các tham số KEYMAP, các chân cột và hàng vào.

Trong while, sử dụng hàm Readkey để đọc phím, sau đó in ra UART1 và delay 1 khoảng thời gian nhỏ.
Nhấn F7 để Build sau đó nạp code.
Sơ đồ phần cứng
3 cột tương ứng với chân 3, 1, 5 trên Keypad nối với PA4, PA5, PA6
4 hàng tương ứng với chân 2, 7, 6, 4 trên Keypad nối với PA0, PA1, PA2, PA3
Lưu ý: Nếu nhấn cùng lúc 2 phím nằm trên cùng 1 hàng, 2 chân cột Output (1 chân đang ở mức 0, 1 chân ở mức 1) sẽ bị nối tắt với nhau qua hàng đó. Với Keypad dùng thử thì không sao, nhưng khi làm sản phẩm thật nên cấu hình các chân cột là Output Open Drain, hoặc mắc thêm diode/điện trở nối tiếp trên mỗi cột.
Giải thích Code ma trận phím
Hàm Init khởi tạo các giá trị như KEYMAP, vị trí các chân cột và hàng, được copy vào struct Keypad đã khai báo.

Hàm Readkey tạo ra vòng lặp. Trong vòng lặp đó ta ghi giá trị vào lần lượt các cột, sau đó đọc các hàng.

Khi phát hiện có nút được nhấn, ta sẽ return giá trị tương ứng trong KEYMAP.

Hàm Config sẽ thay đổi KEYMAP, giúp việc chuyển đổi giá trị các nút nhấn trong quá trình code.
Kết
Phương pháp quét ma trận phím là một phương pháp rất hay khi sử dụng GPIO, nó cũng tương tự khi quét các loại ma trận LED hay các phương pháp quét khác. Các bạn có thể tự code theo lý thuyết mình đã nêu ra để hiểu rõ hơn về vấn đề này nhé.
Đừng quên tham gia nhóm Nghiện lập trình, để có thể kết nối với những anh em khác nhé!


Cho mình hỏi đoạn copy giá trị vào keypad là sao vậy, mình chưa hiểu là giá trị gán cho ColPort[0] là ở đâu mà có
Phần đấy được định nghĩa trong Struct Keypad ở file keypad.h bạn nhé.
anh ơi cho em hỏi tại sao em làm theo hướng dẫn thì báo lỗi , mặc dù em đã add đúng , đủ thư viện. Em cảm ơn
part1\part1.axf: Error: L6218E: Undefined symbol KEYPAD3X4_Readkey (referred from main.o).
part1\part1.axf: Error: L6218E: Undefined symbol KEYPAD3X4_Init (referred from main.o).
em chinh duong dan thu vien chua?
Anh ơi code em chạy được nhưng khi bấm phím 4 nó cứ hiện 2 số 14 thì nó bị lỗi gì vậy ạ
xem dây nối vào chân số 1 có chập với số 4 ko
anh ơi em dùng keypad kết hợp i2c lcd 1602 thì khi ấn nó bị loạn ký tự, cả khi mình in thẳng ký tự ra cũng bị sai k có nghĩa.anh chỉ cách fix giúp em với, em cảm ơn anh