Подключение и работа с клавиатурой 4х4

Тема в разделе "Схемотехника, компоненты, модули", создана пользователем Festour, 23 авг 2013.

  1. Festour

    Festour Нерд

    Вчера приобрёл такую клавиатуру, и пытаюсь подключить и заставить её работать.
    Испольую следующий скетч:
    Код (C):
    void setup() {
      // put your setup code here, to run once:
    pinMode(2, OUTPUT);
    pinMode(3, OUTPUT);
    pinMode(4, OUTPUT);
    pinMode(5, OUTPUT);
    pinMode(6, INPUT);
    pinMode(7, INPUT);
    pinMode(8, INPUT);
    pinMode(9, INPUT);
    Serial.begin(9600);
    }

    void loop() {
      // put your main code here, to run repeatedly:
      for(int i = 0; i > 3; i++)
      {
        digitalWrite(i, HIGH);
        for(int j = 4; j > 7; j++)
        {
          if (digitalRead(j) == HIGH)
          {
            bouton(i,j);
          }
        }
        digitalWrite(i, LOW);  
      }
      delay(100);
    }
    void bouton (int i, int j)
    {

      char msg[2];
      if (i == 0)
      {
        if (j == 4)
        sprintf(msg, "1");
        else if (j == 5)
        sprintf(msg, "2");
        else if (j == 6)
        sprintf(msg, "3");
        else if (j == 7)
        sprintf(msg, "A");
        else
        sprintf(msg, "E");
      }
      else if (i == 1)
      {
        if (j == 4)
        sprintf(msg, "4");
        else if (j == 5)
        sprintf(msg, "5");
        else if (j == 6)
        sprintf(msg, "6");
        else if (j == 7)
        sprintf(msg, "B");
        else
        sprintf(msg, "E");
      }
      else if (i == 2)
        {
        if (j == 4)
        sprintf(msg, "7");
        else if (j == 5)
        sprintf(msg, "8");
        else if (j == 6)
        sprintf(msg, "9");
        else if (j == 7)
        sprintf(msg, "C");
        else
        sprintf(msg, "E");
        }
      else if (i == 3)
      {
        if (j == 4)
        sprintf(msg, "*");
        else if (j == 5)
        sprintf(msg, "0");
        else if (j == 6)
        sprintf(msg, "#");
        else if (j == 7)
        sprintf(msg, "D");
        else
        sprintf(msg, "E");
      }
     while (digitalRead(j) == HIGH)
      Serial.println(msg);
    }
    Собственно я ничего не получаю в мониторе serial порта, как это пофиксить?
    И как лучше идентифицировать какая кнопка была нажата?
     
  2. lerik2703

    lerik2703 Гик

    а где ты такой скетч надыбал :) for(int i = 0; i > 3; i++) это как так (цикл работает когда условие истинно!)? кстати в твоем случаи так for(int i = 2; i <= 5; i++) то есть устанавливаем выходы от 2 до 5 функцией digitalWrite() в высокий уровень! дальше проверяем нажатие for(int j = 6; j < =9; j++) соответственно входы 6-9 !
     
    Nickstalker нравится это.
  3. Festour

    Festour Нерд

    Сам написал. Спасибо за исправления, хоть что то начало выводиться в монитор. Но до сих пор не понятно на какие провода надо подавать напряжение, а на каких проводах надо искать. :(
     
  4. lerik2703

    lerik2703 Гик

  5. Festour

    Festour Нерд

    Разумеется, я понимаю что, нужно подавать питание на один из проводов первой четвёрки, и искать это питание, на одном из второй четвёрки. Но блин, как понять где на шлейфе от клавиатуре первая четвёрка, а где вторая?
     
  6. lerik2703

    lerik2703 Гик

    это кнопки и разницы нет к тому же и клавиатура у тебя 4х4, от того что ты подашь напряжение на 1-ю четверку а со 2-й снимешь или наоборот, разницы не будет!
     
  7. Илья2014

    Илья2014 Нерд

    Я джва дня хочу подключить эту клавиатуру к Arduino mega :)
    и имею сказать следующее:
    если цеплять её на 8 пинов, и делать примерно как в первом сообщении, то это НЕ работает. Из-за наводок 4 пина которые INPUT выдают пр-ревосходный белый шум. Ну натурально, бесконтактное управление - рукой проводишь над проводками - результат опроса клавы меняется.
    Пытался извращаться с Input_Pullup - та же петрушка, вид сбоку.
    Надо ставить подтягивающие резисторы, как в схеме 1 по ссылке из 4 сообщения. 10 кОм слишком мало, с ним всё сваливается в LOW, а других у меня пока нет. Беда, печаль, не повторяйте моих ошибок.

    Может Ардуино само как-нибудь может в подтягивающие резисторы, а? Или какой-нибудь shield или что-то такое есть, не знаете?
     
  8. lerik2703

    lerik2703 Гик

    сама ардуина этого не может только если её поросить :)

     
  9. Илья2014

    Илья2014 Нерд

    Благодарю вас!
    Вечером попробую, сообщу результат.
     
  10. lerik2703

    lerik2703 Гик

  11. Megakoteyka

    Megakoteyka Оракул Модератор

    Там как раз не советуют пользоваться внутренней подтяжкой.
    И Di Halt тоже не советовал (говорит, внутренняя подтяжка дохнет от любого чиха), а ему можно верить.
    Лучше не пожалеть внешнего резистора.
     
  12. lerik2703

    lerik2703 Гик

    согласен!вопрос-ответ :)
     
  13. Илья2014

    Илья2014 Нерд

    Изложенная там, в частности, идея о многократном опросе кнопки для удаления "дребезга" проста, но великолепна. Непременно использую.
     
  14. Megakoteyka

    Megakoteyka Оракул Модератор

    Для этого уже есть библиотека Bounce. Пример использования.
     
  15. Илья2014

    Илья2014 Нерд

    Читал код, мучительно пытался понять. :) Комменты на французском - это хорошо, это полезно.
    Убедил себя в том, что функция bounсe::update() то ли занимает время процессора в течение interval_millis от момента previous_millis, то ли в этот промежуток времени отвечает только FALSE.
    То есть на опрос 16 кнопок с её использованием я потрачу (16*interval_millis) времени. Хм... ну посмотрим.

    Внезапно обнаружил что читал вторую версию кода (bounce2). Прочитал первую (bounce), частично понял :).
     
    Последнее редактирование: 24 мар 2014
  16. Илья2014

    Илья2014 Нерд

    Попробовал. В соответствии с предупреждением :), внутренняя подтяжка не помогла или вовсе не сработала: на всех INPUT pin'ах непоколебимо стоит HIGH. Ну, почти: при замыкании 2 или 3 или 4 OUTPUT pin'ов на 4-й INPUT pin, первый INPUT pin падает в LOW, зато 2-й по-прежнему HIGH. (номера условны, в реальности это были 30-37 pins)

    Да и pin с ними. Буду паять внешние резисторы.
     
  17. Megakoteyka

    Megakoteyka Оракул Модератор

    Не торопитесь паять, отработайте на макетке :)
    "Семь раз отпей, один раз отъешь".
     
    atompost нравится это.
  18. Илья2014

    Илья2014 Нерд

    Здравствуйте!

    Коротко о клавном: всё работает, и работает хорошо. Кнопки у клавы хорошие, шума дают мало, он легко давится.

    Подробности:
    Подключил клавиатуру следующим образом:
    входы 1-4 к пинам Pin1-Pin4,
    входы 5-8 к пинам Pin5-Pin6 и через резистор 10 кОм к земле.
    ( при сопротивлении резистора 40 кОм есть ложный HIGH на Pin5-8, при 30 кОм - нормально, при 10 - тоже). Не паял пока, всё через макетку.

    Для работы с клавой сделал следующий класс (см в нём инструкцию про применению):
    keyb4x4.h:
    Код (Text):
    #include <Arduino.h>

    /* Как пользоваться классом:
    0) Создайте экземпляр класса. Сообщите конструктору номера пинов, к которым подключена ваша клавиатура, в порядке увеличения номера на разъеме клавы. Там есть нумерация, есличо.
    2) в setup() выполните begin()
    3) в loop() вставьте process() Он выполняется за 230-250 микросекунд (не милли-, а микро) + MicrosToAskOnePin (440-450 мкс всего) иногда
    ...
    Используйте get() чтобы извлечь нажатый юзером PROFIT в виде char'a.

    */

    // keyb4h4.h

    class Keyb4x4 {
      public:
        // constructor: give it number of pins connected to keyboard; three last values have reasonable defaults and usually should be omitted.
        // Pin numbering is printed on keyb's jack.
      Keyb4x4(int pin1, int pin2, int pin3, int pin4, int pin5, int pin6, int pin7, int pin8,  int NumberConsequentRepeats=7, int MicrosToAskOnePin=200, int UnknownValuePresumedAs=LOW);
     
    //Run it in Setup()
      //Keyb4x4::begin() Initiates pins, run this function in Setup
      void begin (boolean UseInternalPullingResistors=false); //default=false because they don't work ha-ha-ha.
     
    // Run it in loop()
      //Keyb4x4::process() Checks keyboard every loop() cycle, adding keys to buffer. Only _pressed and then released_ keys are added!
      void process();
     
     
      //Keyb4x4::ask()  Basic function. Quickly asks keyboard and returns: char '\0' if nothing pressed or char of KeyTable set if button is pressed.
      char ask(void);  //should be used not itself but in some wrap function like process()
     
      //Main function - use it to...
      //Keyb4x4::get().    ...get one char from buffer. Or '\0' if it is empty.
      char get(void);
     
      boolean KeyPressed;  //true if user have pressed something...
     
      void SetParameteres(int NumberConsequentRepeats, int MicrosToAskOnePin, int UnknownValuePresumedAs); //if you need to change it from defaults. To change just one param, omit  others - they will be ignored
      int version(void);  //для понтов
      private:
      int cols[4]; //here I store numbers of pins connected to one side of keyb matrix (let's call its "columns")
      int rows[4]; //here I store numbers of pins connected to other side of keyb matrix (let's call its "rows")
      long NumberConsequentRepeats;  // Function Ask will DigitalRead a pin form rows[] array until get "NumberConsequentRepeats" of the same consequent values, OR
      unsigned long MicrosToAskOnePin;        // until "MicrosToAskOnePin" time will pass. In this case it will ensure the pin is Unknown and
      int UnknownValuePresumedAs;                // presume it is HIGH or LOW (default) according to UnknownValuePresumedAs variable
      boolean UseInternalPullingResistors;      // use only external 10 kOm resistors and you'll get no problems.
      static const char KeyTable44[4][4]; //key values, see initialisation below
      char buffer[256]; //keyboard buffer for process() and get()
      int UsedBuffer; // pointer to last used place in buffer.
      char CurrentPressedKey; // for process()
    };
    keyb4x4.cpp:
    Код (Text):
    // keyb4x4.cpp
    #include "keyb4x4.h"
    #include "Arduino.h"

    //here we fill array of keyboard values. You can modify it if necessary.
    const char Keyb4x4::KeyTable44[][4]={{'1','2','3','A'},{'4','5','6','B'},{'7','8','9','C'},{'*','0','#','D'}};

    Keyb4x4::Keyb4x4(int pin1, int pin2, int pin3, int pin4, int pin5, int pin6, int pin7, int pin8, int NumberConsequentRepeats, int MicrosToAskOnePin, int UnknownValuePresumedAs)
    {
      this->cols[0] = pin1;        // pins keyboard connected to
      this->cols[1] = pin2;        // pins keyboard connected to
      this->cols[2] = pin3;        // pins keyboard connected to
      this->cols[3] = pin4;        // pins keyboard connected to
      this->rows[0] = pin5;        // pins keyboard connected to
      this->rows[1] = pin6;        // pins keyboard connected to
      this->rows[2] = pin7;        // pins keyboard connected to
      this->rows[3] = pin8;        // pins keyboard connected to
      this->NumberConsequentRepeats=NumberConsequentRepeats;
      this->MicrosToAskOnePin=MicrosToAskOnePin;
      this->UnknownValuePresumedAs=UnknownValuePresumedAs;
      this->UsedBuffer=-1;
      KeyPressed=false;
    }


    void Keyb4x4::begin(boolean UseInternalPullingResistors)
    {
        // setup the pins on the microcontroller:
      for (int i=0; i<4; i++) {
        pinMode(cols[i], OUTPUT); // to send voltage,
        pinMode(rows[i], INPUT);  // and to read results.
        //prepare OUTPUT pins:
        digitalWrite(cols[i], LOW);
       
        //prepare INPUT pins:
        if (UseInternalPullingResistors) {
            digitalWrite(rows[i], HIGH); // Here we enable internal pulling resistors between INPUT pins to ground. On my Arduino Mega they don't work at all :-(.
        }
        else {
            digitalWrite(rows[i], LOW);  // and here disable them: it's preferable if you already have external pulling resistors in your scheme.
        }
      } //cycle end
    }

    char Keyb4x4::ask(void)
    {
    //  char r='-';
      for (int i=0; i<4; i++) {
        for (int j=0; j<4;j++)      digitalWrite(cols[j], LOW);      //set OUTPUT pin's to zero. Don't remove or you'll get false positives
        digitalWrite(cols[i], HIGH); //set +5V to pin from column and
        for (int j=0; j<4;j++){      //check is it visible on any row?
          if (digitalRead(rows[j])==HIGH) {  // OK, if we got circuit so take several repeats to ensure it is not false positive because of induction, statics or other
            long counter=1;    // we already have 1 answer
            unsigned long TimeToStop=micros()+MicrosToAskOnePin;  //don't gonna fall to infifnite cycle if pin "free-float"
            while ((counter<NumberConsequentRepeats) && (micros()<TimeToStop)) {  //the investigation
              if (digitalRead(rows[j])==HIGH) {
                counter++;
              }
              else{  // negativ answer?
                counter=0;  //begin collect from zero!
              }
            }
            //here investigation over and we check it's result
            if (counter>=NumberConsequentRepeats) { //Yes! col[i] and row[j] connected! пришёл к успеху
              return KeyTable44[3-j][3-i];
            }
            else{ //Unknown result
              if (UnknownValuePresumedAs==HIGH) { //считать гуся карасём
                return KeyTable44[3-j][3-i];
              }
              else if (UnknownValuePresumedAs==LOW) {}//do nothing  не свезло, не пофартило
            }
          } //end of first If(DigitalRead...) statement
        }//end of rows cycle
      }//end columns cycle
      return '\0';
    }

    void Keyb4x4::process(void)
    {
      char t;
      t=ask();
      if (CurrentPressedKey==t) {return;} //key is still pressed from previous run
      else if  ((t=='\0') && (CurrentPressedKey!='\0')) { // key pressed now released - add it to buffer ранее нажатая кнопка отпущена - добавляем
        UsedBuffer++;
        buffer[UsedBuffer]=CurrentPressedKey;
        CurrentPressedKey='\0';
        if (UsedBuffer>255) UsedBuffer=-1; //BTW if overflow - just start from beginning.
        KeyPressed=true;
        return;
      }
      else if ((t!='\0') && (CurrentPressedKey=='\0')) { // key just pressed right now
        CurrentPressedKey=t; //и подождём while it releases
        return;
      }
      else if ((t!='\0') && (CurrentPressedKey!='\0')) { //other key pressed while first don't released. It's bad. It's undefinite situation because of matrix keyb structure. Don't do so!
        //do nothing как-нибудь так!
      }
    }

    char Keyb4x4::get(void)
    {
      char t='\0';
      if (UsedBuffer>=0) {
        t=buffer[0];
        for (int i=0; i<UsedBuffer;i++) buffer[i]=buffer[i+1];
        UsedBuffer--;
        if (UsedBuffer<0) KeyPressed=false;
      }
      return t;
    }

    void Keyb4x4::SetParameteres(int NumberConsequentRepeats=0, int MicrosToAskOnePin=0, int UnknownValuePresumedAs=LOW)
    {
      if (NumberConsequentRepeats!=0) this->NumberConsequentRepeats=NumberConsequentRepeats;
      if (MicrosToAskOnePin!=0) this->MicrosToAskOnePin=MicrosToAskOnePin;
      if (UnknownValuePresumedAs!=0) this->UnknownValuePresumedAs=UnknownValuePresumedAs;
    }

    int Keyb4x4::version(void)
    {
      return 3;
    }
    Для подавления шума в вышеприведенной функции ask после получения замыкания двух пинов оно проверяется до тех пор, пока не обнаружится NumberConsequentRepeats последовательных положительных результатов. Всё это проверяется за время не более чем MicrosToAskOnePin. Если не получено нужного числа последовательных результатов за это время, то для пинов принимается состояние UnknownValuePresumedAs.


    Программа для демонстрации работы клавы использует LCD 4х20 строчек, правьте под себя:

    Код (Text):
    #include <keyb4x4.h>
    #include <Arduino.h>
    // подключаем библиотеку для работы с LCD
    #include <LiquidCrystal.h>

      //создаем объект клавиатуры
      Keyb4x4 myKeyb (40,41,42,43,44,45,46,47);
      // сосздаем объект LCD, указывая контакты данных
      LiquidCrystal lcd(48, 49, 50, 51, 52, 53);

    int line=0;
    int column=0;
    unsigned long t=0;
     
    void setup()
    {
      // указываем размерность экрана и начинаем работать
      lcd.begin(20, 4);
      lcd.clear();

      lcd.print("Keyb input below:");
      lcd.setCursor(0, 1);

    //иниц. клав.
      myKeyb.begin(true);
    }
     
    void loop()
    {
      char k='\0';
      //вспомогательное - засечка времени
    t=micros(); //мне надо быстро, мне ещё много чего крутить в realtime
      //Опрос клавиатуры
    myKeyb.process();
      //вспомогательное - засечка времени
      t=micros()-t;

    if (myKeyb.KeyPressed) {
        k=myKeyb.get();

      lcd.setCursor(column, 1);
      lcd.print(k);
      column++;
      if (column>19) column=0;
      lcd.setCursor(0, 2);
      lcd.print("Run time, mcs: ");
      lcd.print(t);
      }
    }
    Буду рад, если кому-нибудь пригодится.
     
    Megakoteyka нравится это.