Bàn phím ma trận (matrix keypad) bao gồm một lưới các nút với dây tương ứng có thể được đọc bởi một vi điều khiển. Như hình bên dưới cho thấy, số lượng chân cần thiết của bộ vi điều khiển được xác định bởi số hàng và cột. Trong đó một dây là cần thiết cho mỗi hàng và mỗi cột. Khi một nút được nhấn, kết nối giữa hàng và cột tương ứng được tạo. Kết nối này cho phép bàn phím được đọc bởi vi điều khiển.
Có nhiều cách để quét bàn phím ma trận. Phương pháp đơn giản được sử dụng trong các ứng dụng ví dụ là quét toàn bộ một trục (tức là hàng hoặc cột) tại một thời điểm.
Điều này được thực hiện bằng cách thiết lập một trong các trục để xuất ra mức điện áp đã biết và đọc mức điện áp của các dây dẫn của trục kia để biết dây nào đã được kéo đến điện áp đó.
Ví dụ các cột Co..C3 ở mức thấp, R0..R3 bình thường có điện trở treo cao nên ở mức cao. Khi một nút thuộc hàng R0 được nhấn, nó liên kết vào cột và bị kéo xuống mức thấp.
Cách quét chân đơn giản như vậy có ưu điểm là nhanh chóng, đơn giản nhưng chỉ có thể đọc 1 nút nhấn tại 1 thời điểm. Có nhiều kỹ thuật khác như quét cả hàng, cả cột hoặc sử dụng ngắt để đọc chân thay vì quét chân liên tục.
Trong ví dụ minh họa sau, chúng ta thực hiện chương trình đọc và kiểm tra mã được nhập. Khi mô phỏng thì Proteus chỉ có bàn phím 4×4 với thứ tự khác bàn phím mềm thường bán. Do vậy ta phải tự xác định lại giá trị được nhấn nếu không thích dùng kiểu bàn phím của Proteus.
Mã được thu bằng cách nhấn chữ và số trên bàn phím, xóa nhập lại bằng cách nhấn dấu sao (*) và kiểm tra tính hợp lệ bằng cách nhấn dấu thăng (#). Đèn LED tại PB0 nhấp nháy khi chân cắm hợp lệ và đèn LED PB1 nhấp nháy nếu mã không chính xác. Đèn LED PB1 cũng nhấp nháy nếu số ký tự tối đa (bằng 20) đạt được.
Lưu đồ thuật toán chương trình chính
Sau khi khởi tạo, kiểm tra mức điện áp xem có sự thay đổi ở cột khi có nút nhấn. Nếu đúng thì chờ 10ms tránh xung nhiễu. Sau đó nếu trạng thái vẫn thấp, gọi hàm đọc nút nhấn, kiểm tra mã và chờ kiểm tra xem nút nhất đã được nhả hay chưa. Lặp lại chương trình.
Chương trình
#define F_CPU 1000000UL
#include <avr/io.h>
#include <stdlib.h>
#include <util/delay.h>
#include <string.h>
volatile uint8_t key_pressed;
char input_pass[20];
uint8_t cursor = 0;
char passcode[20] = "123ABC";
// Macro for buttons in the grid
char btn_value[16] = "123A456B789C*0#D";
// Function prototypes
void scan_keys(void);
void check_passcode(void);
int main(void)
{
// PB2 and PB3 used as status LEDs
DDRB = 0xFF;
PORTB = 0x00;
// initialize rows and columns of keypad
DDRC = 0x0F;
DDRD = 0x00;
PORTD = 0x0F;
PORTC = 0x00;
while(1)
{
// Poll for low input values for the columns
if((PIND & 0b00001111) != 0x0F)
{
// Debounce
_delay_ms(10);
// If after 10 ms, the press is valid
if((PIND & 0b00001111) != 0x0F)
{
scan_keys();
check_passcode();
// Wait for all buttons to be released
while((PIND & 0b00001111) != 0x0F);
}
}
}
}
void scan_keys()
{
key_pressed = 0;
PORTC = 0b11111110;
_delay_ms(2);
//* If COLUMN 0 is pulled low
if(!(PIND & 0b00000001))
{
key_pressed = 0;
}
// If COLUMN 1 is pulled low
else if(!(PIND & 0b00000010))
{
key_pressed = 1;
}
// If COLUMN 2 is pulled low
else if(!(PIND & 0b00000100))
{
key_pressed = 2;
}
// If COLUMN 3 is pulled low
else if(!(PIND & 0b00001000))
{
key_pressed = 3;
}
//
PORTC = 0b11111101;
_delay_ms(2);
if(!(PIND & 0b00000001))
{
key_pressed = 4;
}
else if(!(PIND & 0b00000010))
{
key_pressed = 5;
}
else if(!(PIND & 0b00000100))
{
key_pressed = 6;
}
else if(!(PIND & 0b00001000))
{
key_pressed = 7;
}
//
PORTC = 0b11111011;
_delay_ms(2);
if(!(PIND & 0b00000001))
{
key_pressed = 8;
}
else if(!(PIND & 0b00000010))
{
key_pressed = 9;
}
else if(!(PIND & 0b00000100))
{
key_pressed = 10;
}
else if(!(PIND & 0b00001000))
{
key_pressed = 11;
}
//
PORTC = 0b11110111;
_delay_ms(2);
if(!(PIND & 0b00000001))
{
key_pressed = 12;
}
else if(!(PIND & 0b00000010))
{
key_pressed = 13;
}
else if(!(PIND & 0b00000100))
{
key_pressed = 14;
}
else if(!(PIND & 0b00001000))
{
key_pressed = 15;
}
//
PORTC = 0xFF;
_delay_ms(2);
PORTC = 0x00;
}
void check_passcode()
{
// If star is pressed
if(btn_value[key_pressed] == '*')
{
// Reset input_pass
memset(input_pass, 0, sizeof(input_pass));
cursor = 0;
}
// If pound is pressed
else if(btn_value[key_pressed] == '#')
{
// If input is the set passcode
if(!(strcmp(passcode, input_pass)))
{
// Reset input_pass
memset(input_pass, 0, sizeof(input_pass));
// Flash green LED
PORTB |= (1 << 0);
_delay_ms(500);
PORTB &= ~(1 << 0);
}
else
{
// Reset input_pass
memset(input_pass, 0, sizeof(input_pass));
// Flash red LED
PORTB |= (1 << 1);
_delay_ms(500);
PORTB &= ~(1 << 1);
}
cursor = 0;
}
// If no special character
else
{
// If length is
if(cursor < 20)
{
// Record press
input_pass[cursor] = btn_value[key_pressed];
cursor++;
}
else
{
// Flash red LED and reset input_pass //
cursor = 0;
PORTB |= (1 << 1);
_delay_ms(300);
PORTB &= ~(1 << 1);
_delay_ms(250);
PORTB |= (1 << 1);
_delay_ms(300);
PORTB &= ~(1 << 1);
//
memset(input_pass, 0, sizeof(input_pass));
}
}
}
Lưu đồ thuật toán phần kiểm tra mã nhập được cho như sau.
Hãy viết lưu đồ thuật toán cho phần quét bàn phím.