Матричная клавиатура

О подключении матричной клавиатуры, чаще всего 4х4, к микроконтроллерам AVR написано немеряно постов. Кто-то в своих разработках пользуется готовыми библиотеками, кто-то пишет свои. Я отношусь к последним, хотя перед написанием любой программы внимательно изучаю уже готовые по тематике. При написании библиотек для себя  я стараюсь делать их максимально простыми и универсальными.  В представленном здесь примере обработки матричной клавиатуры использован следующий принцип.
В микроконтроллере для обслуживания столбцов матрицы разряды портов используются как входы с pull-up резисторами, а для обслуживания строк — как выходы с лог. «1». Поочерёдно на каждую строку подаётся лог. «0»,  при этом проверяется состояние столбцов. Зная номер строки с «нулём» — a, находим столбец с «нулём» — b;  из этого делается вывод, что нажата клавиша Sa-b. Как видите ничего сложного.
Примеры программной реализации вышеописанного алгоритма я неоднократно встречал в интернете. Но в них всегда была привязка к конкретным портам, по крайней мере строк или столбцов. У меня в проекте, в заголовочном файле, для управления столбцами и строками можно назначить любые свободные разряды любых портов. Т.е. нет привязки к конкретным портам — это очень удобно! Для того, чтобы собрать схему на макете или использовать в своём устройстве, в файлах kk.h и lcd.h распределите разряды портов для обслуживания клавиатуры и управления ЖКИ и будет вам счастье! Пример чисто демонстрационный: выводит на ЖКИ символ нажатой клавиши (я использовал телефонную тастатуру 3×4). Столбцы и строки распихал по контроллеру в случайном порядке.
Функции файла kk.c — это заготовки. Поэтому к их применению в своих проектах подходите творчески. Проще всего вызывать функцию опроса клавиатуры с определённой периодичностью по таймеру (раз в 50 ms) — таким образом решится заодно и проблема дребезга контактов.
Также не составит труда изменить/дополнить функции при другом количестве строк или/и столбцов.

В архиве папка с проектом.

Успехов, уважаемые коллеги!

Запись опубликована в рубрике Микроконтроллерный конструктор с метками . Добавьте в закладки постоянную ссылку.

8 комментариев: Матричная клавиатура

  1. Kazemir говорит:

    Доброго времени суток!
    Сразу скажу, что программист я начинающий, так что сразу не ругайте сильно. Публикация,а именно «Матричная клавиатура», опубликованная 05.10.2011 автором s_black, мне понравилась, познал для себя много нового в плане методики построения самой программы и ньюансов по обработке матричной клавиатуры с пом. МК AVR. Спасибо, все толково и доходчиво! Единственный вопрос — в конце файла lcd.c имеются две функции, одна из них — функция вывода строки из FLASH на LCD по адресу, а другая — функция вывода строки из ROM на LCD по адресу. Если можно проясните пож. как эти функции работают в данном конкретном коде. Если они приведены в тексте кода на дальнейшее домысливание, то как их можно применить. Заранее благодарен, с уважением, Kazemir.

  2. s_black говорит:

    Спасибо!
    Насчёт Вашего вопроса… В общем-то Вы на него сами и ответили. Одна функция выводит строку на заданное знакоместо ЖКИ из флеша, а вторая — из ОЗУ. Использовать их очень просто. Разместите соответствующую строку в памяти (или флеш или ОЗУ). В программе вызывайте функцию, задавая знакоместо на ЖКИ (adress) и адрес строки через указатель (*string). Следите за длиной строки (чтобы поместилась на ЖКИ).

  3. Alex говорит:

    Нехорошая идея использовать активные выходы с 1 и 0. Настанет время, будут нажаты несколько кнопок — и Ваша активная 1 встретится с вашим активным 0.
    Все должно быть на pull-up.

  4. s_black говорит:

    Да… Вы абсолютно правы ((( Правильнее строки тоже оставить входами с подключенным резистором. И, сканируя, переключать их на выход с нулём. Завтра исправлю и проверю. Спасибо.

  5. Ravsan говорит:

    Привет s_black я новичок на этом сайте и хотел бы спросить почему у меня символы выводятся сами по себе когда я подвожу руку к клаве и стоит один символ не меняясь когда рука не прикасается к ней? Программирую я в CVAVR и клава 4 на 4.
    Клаву подключил к порту D контроллера Atmega16, задал направления отдельных битов, присвоил строкам лог 1 а столбцы не стал трогать, они на выход. В общем последовательно в цикле while присваивал лог 0 каждой строке и проверял на 0 столбцы.

     void main(void)
    {
    PORTD=0x00;
    DDRD=0x0F;
    lcd_init(16);
    PORTD.0=1;//stroka0
    PORTD.1=1;//stroka1
    PORTD.2=1;//stroka2
    PORTD.3=1;//stroka3
     
     
    while (1)
          {
          PORTD.0=0;
          if((PIND.4)==0)//knopka1
          {
          lcd_clear();
          lcd_putsf("1");
          }       
          delay_ms(50);
          PORTD.0=1;
          delay_ms(50); //
          PORTD.1=0;
    ...................................
    }
    }
  6. Ravsan говорит:

    столбцы на вход и все линии подключил через резисторы по 2 КОМ, строки на выход.

  7. s_black говорит:

    Трудно сказать не видя монтажа… Скопируйте и проверьте мой код — он стопроцентно рабочий.

  8. Ravsan говорит:

    Я не использую готовый код а только идею обработки нажатий клавиш. Код не использую. Вот структура клавы http://s018.radikal.ru/i516/1305/1c/f64642cb6453.png
    и сам проект DDS-генератора
    http://s41.radikal.ru/i094/1305/ba/ef7ec2452ee6.jpg
    http://s017.radikal.ru/i400/1305/e3/8a6fbaa19eb0.jpg
    http://i080.radikal.ru/1305/cf/37a28616d6ff.jpg
    Биты порта D 3,2,1 и 0 установил как выходы, а 4,5,6 и 7 как входы. Поочерёдно присваиваю строкам лог. 0, а столбцы неактивны. Создал переменную и верчу её в цикле «for» от 0 до 3 и проверяю нажатие в операторе «if». Вот код:
    Другие инициализации портов я опустил.

    #include 
     
    // Alphanumeric LCD Module functions
    #include 
    #include 
    // Declare your global variables here
     
    void main(void)
    {
    int i;
    // Port D initialization
    // Func7=In Func6=In Func5=In Func4=In Func3=Out Func2=Out Func1=Out Func0=Out 
    // State7=T State6=T State5=T State4=T State3=0 State2=0 State1=0 State0=0 
    PORTD=0x00;
    DDRD=0x0F;
    lcd_init(16);//инициализация дисплея
    for(i=0; i<=3;i++)
          {
          switch(i)
          {
          case '0': 
          PORTD.0=0;
          if((PIND.4)==0)//knopka1
          {
          lcd_clear();
          lcd_putsf("1");
          delay_ms(50);
          PORTD.0=1;      
          }   
          if((PIND.5)==0)//knopka2
          {
          lcd_clear();
          lcd_putsf("2");
          delay_ms(50);
          PORTD.0=1;    
          } 
          if((PIND.6)==0)//knopka3
          {
          lcd_clear();
          lcd_putsf("3");  
          delay_ms(50);
          PORTD.0=1;    
          }  
          if((PIND.7)==0)//knopkaH
          {
          lcd_clear();
          lcd_putsf("H");
          delay_ms(50);
          PORTD.0=1;          
          } 
          break;
          case '1':
          PORTD.1=0; 
          if((PIND.4)==0)//knopka4
          {
          lcd_clear();
          lcd_putsf("4");
          delay_ms(50); 
          PORTD.1=1;      
          }  
          if((PIND.5)==0)//knopka5
          {
          lcd_clear();
          lcd_putsf("5");
          delay_ms(50); 
          PORTD.1=1;       
          } 
          if((PIND.6)==0)//knopka6
          {
          lcd_clear();
          lcd_putsf("6"); 
          delay_ms(50); 
          PORTD.1=1;  
          }
          if((PIND.7)==0)//knopkaK
          {
          lcd_clear();
          lcd_putsf("K");
          delay_ms(50); 
          PORTD.1=1;       
          }
          break;
          case '2':
          PORTD.2=0;
          if((PIND.4)==0)//knopka7
          {
          lcd_clear();
          lcd_putsf("7");
          delay_ms(50);
          PORTD.2=1;     
          }
          if((PIND.5)==0)//knopka8
          {
          lcd_clear();
          lcd_putsf("8"); 
          delay_ms(50);
          PORTD.2=1;    
          }  
          if((PIND.6)==0)//knopka9
          {
          lcd_clear();
          lcd_putsf("9");
          delay_ms(50);
          PORTD.2=1;    
          }  
          if((PIND.7)==0)//knopkaM
          {
          lcd_clear();
          lcd_putsf("M");
          delay_ms(50);
          PORTD.2=1;          
          }    
          break;
          case '3':
          PORTD.3=0;
          if((PIND.4)==0)//knopka0
          {
          lcd_clear();
          lcd_putsf("0"); 
          delay_ms(50);
          PORTD.3=1;   
          } 
          if((PIND.5)==0)//knopka.
          {
          lcd_clear();
          lcd_putsf(".");  
          delay_ms(50);
          PORTD.3=1;  
          }
          if((PIND.6)==0)//knopkaC
          {
          lcd_clear();
          lcd_putsf("C");
          delay_ms(50);
          PORTD.3=1;    
          }  
          if((PIND.7)==0)//knopkaF
          {
          lcd_clear();
          lcd_putsf("F"); 
          delay_ms(50);
          PORTD.3=1;   
          } 
          break;
          }
    }
    }

Добавить комментарий

Ваш e-mail не будет опубликован.