Sử dụng bàn phím ma trận với AVR ATmega8

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.

Bàn phím 4×4

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.

Hoặc quét chân theo cột

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.

Leave a Reply

Your email address will not be published. Required fields are marked *