Matris buton yapısı basitçe, satırları ve sütunları ortaklayarak belirli bir tarama ve kesişim mantığı ile basılan butonun algılanmasına dayanır. Bu yapının dezavantajlarından biri aynı anda sadece bir butona basılabilmesidir. Ancak bu şartın gerekli olmadığı sistemlerde bağlantı sayısından oldukça tasarruf edilmesini sağlar. Bu yazımdaki örnek üzerinden konuşmak gerekirse 36 adet butonu mikrodenetleyici üzerinden normal bağlantı ile kontrol etmek istersek 36 farklı giriş pini tanımlamamız gerekir. Ancak matris buton mantığında ise bu sayı 6 satır ve 6 sütun olmak üzere yalnızca 12 pin ile gerçekleştirilebilir.
6x6 Matris Buton Yapısı
KiCad ile 6x6 buton matris yapısı için örnek bir kart tasarladım. İki adet pin header 36 led ve 36 adet buton bulunmakta. 6 satır ve 6 sütunun mikrodenetleyici bağlantısı için iki adet dişi header kullandım.
Kod kısmında ise satırlar ve sütunların giriş ve çıkış olarak iki farklı şekilde tanımlanması gerekiyor. Satırlar çıkış sütunlar ise giriş olarak tanımlanır. Satırlar sırası ile aktifleştirilip o satırda bulunan herhangi bir sütunda bulunan butona basılıp basılmadığı kontrol edilir. İlgili satır pini lojik 1 diğerleri lojik 0 değerine çekilerek sütunlar sırası ile okunur. Eğer herhangi bir sütun pininde 1 değeri okunursa o satır ve o sütundaki butona basıldığı program tarafından anlaşılır. Program içerisinde istenilen durum gerçekleştirilir. Ben buton uygulamamda klavye mantığı ile STM32F746VGT6 mikrodenetleyicisini kullanarak USB_OTG_FS üzerinden Virtual Com Port class'ı ile C# arayüzü üzerinden haberleşerek her butona basıldığında bir karakter gönderdim. Konumuz matris buton algoritması olduğu için kod kısmında USB haberleşmesinden bahsetmeyeceğim.
GPIOA 0-5 pinlerini çıkış, GPIOD7, GPIOB 3-7 pinleri ise giriş olarak tanımlandı. Çıkış pinleri (satırlar) sırası ile 1 konumuna çekildikten sonra tüm girişler (sütunlar) okunarak butona basılıp basılmadığı kontrol ediliyor. Basıldığı durum için benim kodumda USB üzerinden ilgili karakteri gönderiyor. Bu sayede daha az bağlantı ile daha fazla buton kullanarak mikrodenetleyici pinlerimizden tasarruf etmiş oluyoruz. Ancak yukarıda da belirttiğim gibi aynı anda iki butona basmak mümkün değil. Projenizde bu koşulun sağlanması gerekiyorsa ve daha az pin kullanmanız gerekiyorsa shift register kullanarak yine pinden tasarruf edip buton sayısını artırabilirsiniz.
/*
* GPIOA_0 ROW1 | GPIOD_7 COLUMN1
* GPIOA_1 ROW2 | GPIOB_3 COLUMN2
* GPIOA_2 ROW3 | GPIOB_4 COLUMN3
* GPIOA_3 ROW4 | GPIOB_5 COLUMN4
* GPIOA_4 ROW5 | GPIOB_6 COLUMN5
* GPIOA_5 ROW6 | GPIOB_7 COLUMN6
*/
#include "main.h"
#include "usb_device.h"
uint8_t buffer[64];
char* data;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
void column1(void);
void column2(void);
void column3(void);
void column4(void);
void column5(void);
void column6(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USB_DEVICE_Init();
while (1)
{
column1();
HAL_Delay(5);
column2();
HAL_Delay(5);
column3();
HAL_Delay(5);
column4();
HAL_Delay(5);
column5();
HAL_Delay(5);
column6();
HAL_Delay(5);
}
}
void column1(void)
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); //ROW1
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);//ROW2
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);//ROW3
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);//ROW4
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);//ROW5
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);//ROW6
if(GPIOA -> IDR & (1<<0))
{
if((GPIOD -> IDR & (1<<7)))//COLUMN1
{
data = "1";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<3)))//COLUMN2
{
data = "2";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<4)))//COLUMN3
{
data = "3";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<5)))//COLUMN4
{
data = "4";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<6)))//COLUMN5
{
data = "5";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<7)))//COLUMN6
{
data = "6";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
}
}
void column2(void)
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET); //ROW2
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
if(GPIOA -> IDR & (1<<1))
{
if((GPIOD -> IDR & (1<<7)))
{
data = "7";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<3)))
{
data = "8";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<4)))
{
data = "9";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<5)))
{
data = "10";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<6)))
{
data = "11";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<7)))
{
data = "12";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
}
}
void column3(void)
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET); //ROW3
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
if(GPIOA -> IDR & (1<<2))
{
if((GPIOD -> IDR & (1<<7)))
{
data = "13";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<3)))
{
data = "14";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<4)))
{
data = "15";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<5)))
{
data = "16";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<6)))
{
data = "17";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<7)))
{
data = "18";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
}
}
void column4(void)
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET); //ROW4
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
if(GPIOA -> IDR & (1<<3))
{
if((GPIOD -> IDR & (1<<7)))
{
data = "19";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<3)))
{
data = "20";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<4)))
{
data = "21";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<5)))
{
data = "22";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<6)))
{
data = "23";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<7)))
{
data = "24";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
}
}
void column5(void)
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); //ROW5
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
if(GPIOA -> IDR & (1<<4))
{
if((GPIOD -> IDR & (1<<7)))
{
data = "25";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<3)))
{
data = "26";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<4)))
{
data = "27";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<5)))
{
data = "28";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<6)))
{
data = "29";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<7)))
{
data = "30";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
}
}
void column6(void)
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); //ROW6
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
if(GPIOA -> IDR & (1<<5))
{
if((GPIOD -> IDR & (1<<7)))
{
data = "31";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<3)))
{
data = "32";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<4)))
{
data = "33";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<5)))
{
data = "34";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<6)))
{
data = "35";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
else if((GPIOB -> IDR & (1<<7)))
{
data = "36";
CDC_Transmit_FS((uint8_t *) data,strlen(data));
HAL_Delay(10);
}
}
}