Клавиатура 4х4

Тема в разделе "Arduino & Shields", создана пользователем DrProg, 9 июн 2015.

  1. DrProg

    DrProg Вечный нерд

    Эксперементирую с такой вот клавиатурой. В принципе все с ней понятно, подключил все восемь ножек к Ардуине, последовательно дергаю проводки строк и считываю проводки столбцов. Программка получилась без проблем и работает отлично (см ниже).
    Вопрос в следующем: можно ли каким либо образом уменьшить количество используемых пинов при этом без использования входного и выходного регистров? Например собрать RC цепь на входящих ножках и искать сигналы по задержке на выходящих? Смутно кажется, что придумать что то можно, я прав?

    Код (Text):
    // пины строк
    const int P[] = {11, 10, 9, 8};
    // пины столбцов
    const int M[] = {7, 6, 5, 4};

    // символы на клаве
    const char k4x4 [4][4] = {
      {'1', '2', '3', 'A'},
      {'4', '5', '6', 'B'},
      {'7', '8', '9', 'C'},
      {'*', '0', '#', 'D'}
    };


    void setup() {
      // выставляем пины строк на выход, столбцов на вход
      for (int i = 0; i <= 3; i++) {
        pinMode(P[i], OUTPUT);
        pinMode(M[i], INPUT_PULLUP);
        digitalWrite(P[i], HIGH);
      }


      Serial.begin(9600);
    }

    void loop() {
      GetKey4x4(); // обработку клавы убрал в функцию
    }

    void GetKey4x4() {
    // последовательно выставляем по одной строке в LOW
      for (int p = 0; p <= 3; p++) {
        digitalWrite(P[p], LOW);
    // и считываем столбцы вылавливая где LOW происходит
        for (int m = 0; m <= 3; m++) {
          if (!digitalRead(M[m])) {
            delay(10); // простейшим способом пропускаем дребезг
            char a = k4x4[p][m]; // считываем соотвествующий символ для комбинации столбца и строки
            Serial.print(a);
            while (!digitalRead(M[m])); // ждем отпуска кнопки
          }
        }
        digitalWrite(P[p], HIGH); // возвращем строку в HIGH и крутим дальше
      }
    }
     
     
  2. Vad33

    Vad33 Капитан-оригинал

    Собирайте резистивные цепочки и на аналоговый вход, только нажимать по одной кнопке. При желании, можно вообще все 16 кнопок на один провод повесить. :)
    На контроллере считывать аналоговый вход и анализировать значение.
     
  3. Megakoteyka

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

    Вроде можно так подобрать резисторы, что будет видно и одновременное нажатие нескольких кнопок. Под степень двойки как-то подбирается.
     
  4. DrProg

    DrProg Вечный нерд

    Спасибо, идея интересная, буду пробовать!
     
  5. DrProg

    DrProg Вечный нерд

    Народ, я правильно понимаю, что одинаковыми резисторами тут не обойтись? Надо на каждую ножку ставить резистор с разным сопротивлением?
     
  6. ANV

    ANV Гуру

    Правильно. Иначе как кнопки отличать?
     
  7. DrProg

    DrProg Вечный нерд

    Доделал уже чисто из спортивного интереса, такой мороки не надо больше. )

    Мало того что схема сборки сложнее, с четырьмя достаточно разноомными резисторами (подобранными опытным путем), так еще и программа получилась не такая красивая как в цифровом варианте подключения. Но, тем не менее, справился, от чего почувствовал удовлетворение.

    Есть еще способ сделать все через регистры, но это схема еще на порядок сложнее. Потом. Может быть.

    Выводы: Все три способа по своему хороши. Цифровой с прямым подключением самый быстрый и простой. Аналоговый заменяет 8 цифровых пинов на 4 аналоговых (экономия). Для работы с несколькими подобными устройствами, которые используют несколько входов и выходов одновременно, подойдет только подключение через регистры.

    Код (Text):
    const int A[] = {A0, A1, A2, A3};
    int P; // нажатый столбец
    int M; // нажатая строка
    int an; // показание активного пина

    // символы на клаве
    const char k4x4 [4][4] = {
      {'1', '2', '3', 'A'},
      {'4', '5', '6', 'B'},
      {'7', '8', '9', 'C'},
      {'*', '0', '#', 'D'}
    };


    void setup() {
      for (int i = 0; i <= 3; i++) {
        pinMode(A[i], INPUT);
      }

      Serial.begin(9600);
    }

    void loop() {
      //  по кругу опрашиваем аналоговые пины (столбцы), если на каком то из них показание менее 1000, значит есть нажатие
      for (int i = 0; i <= 3; i++) {
        an = analogRead(A[i]);
        if (an < 1000) {
          P = i; // определили номер нажатого столбца
    // далее по значению напряжения вычисляем номер строки
    // резисторы на выходящих ножках притянутые к земле установил в порядке убывания: 100кОм, 33кОм, 10кОм и 1КОм, что соответсвтует примерным значениям на пинах 500, 250, 100, 10
    // на всех входящих ножках установлены резисторы 100кОм
    // так как показания немного колеблются, берем диапазон с запасом:
          if (an > 400) {
            M = 0;
          } else if ((an < 300) && (an > 200)) {
            M = 1;
          } else if ((an < 150) && (an > 50)) {
            M = 2;
          } else if (an < 50) {
            M = 3;
          }
          char a = k4x4[P][M]; // считываем соотвествующий символ для комбинации столбца и строки
          Serial.print(a);
          while (analogRead(A[i]) < 1000); // ждем отжатия кнопки
        }
      }
    }
     
  8. Vad33

    Vad33 Капитан-оригинал

    Больше вредных советов слушайте. :D
    Можно было обойтись и одним номиналом, соединить в цепочку и к узлам уже кнопки подключать.
     
  9. DrProg

    DrProg Вечный нерд

    Покажите как, я пробовал, получалось что ножки контактируют между собой через резисторы и ничего не работает.
     
  10. iglooshtosser

    iglooshtosser Гик

    Самый простой способ:
    20150610_120056.jpg
    Резисторы могут быть одинаковыми. Получается ступеньчатый переменный делитель. Измеряя напряжение делаем вывод о нажатой кнопке.
    Основной недостаток - нельзя различить две одновременно нажатые кнопки.
    Есть похожий способ, при котором можно различать одновременно нажатые кнопки, только я его не помню :)
     
  11. Megakoteyka

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

    Я об этом и говорил. Если подобрать номиналы резисторов так, чтобы падение напряжения было пропорционально степени двойки, то можно будет различать несколько кнопок одновременно. Возможно не совсем верно сформулировал, но смысл примерно такой.
     
  12. iglooshtosser

    iglooshtosser Гик

  13. DrProg

    DrProg Вечный нерд

    Примерно так я сначала и пробовал сделать, т.к. это самое очевидное. Почему то не получилось. Попробую еще раз вечером, может быть что то напутал.
     
  14. iglooshtosser

    iglooshtosser Гик

    Вот такая схема:
    20150610_130947.jpg
    при очень правильном подборе сопротивлений должна дать возможность различать одновременные нажатия...
     
  15. DrProg

    DrProg Вечный нерд

    Хорошая статья, спасибо. Голову сломать можно с непривычки. )
     
  16. DrProg

    DrProg Вечный нерд

    У меня смутное подозрение, что я не до конца понимаю как работает вольметр вообще и аналоговый пин в частности. Между чем и чем он измеряет вольтаж? Почему в некоторых случаях он вообще не работает, в других показывает ерунду. Объясните кто нибудь на пальцах или дайте ссылку где почитать.
     
  17. iglooshtosser

    iglooshtosser Гик

    Вольтметр измеряет напряжение между своими щупами :)

    Аналоговый вход меряет напряжение между собой и GND. Но значение, которое возвращает analogRead относительное. 0В = 0; 5в = 1023.
     
  18. DrProg

    DrProg Вечный нерд

    Почему то работает не так как хотелось бы. При отжатых кнопках на всех пинах 1024, при нажатии любой кнопки на нижнем ряд 770, 517, 265, 14, при нажатии любой на верхнем - 97, 97, 97, 97. То есть нажатие на любою кнопку влияет на все остальные в клавиатуре. Почему так происходит и как избавиться?
     
  19. DrProg

    DrProg Вечный нерд

    Все, разобрался! Уф. Работает отлично, спасибо за информацию. Мультитач пока не нужен, с ним буду разбираться немного позже. )