Какие диоды использовать в матричном вводе кнопок/клавиш? (Изготовление игровой клавиатуры)

При матричном вводе столбцов/строк NxM с помощью кнопок рядом с каждой кнопкой должен быть диод, чтобы предотвратить "двоение" и правильно считывать множество клавиш, нажатых вместе. Повсюду много картинок.

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


Подробнее:

Я бы использовал 5 Вольт Arduino (ATmega32U4), в техническом описании указано, что входное низкое напряжение не должно превышать 0,3 В пост. тока, что составляет 1,5 В, минимальное высокое входное напряжение 0,7 В пост. ; (Vcc-0,4 В / 3 мА)

Я хотел бы использовать декодер 74HC138 3-в-8 для адресации, который делает один из 8 выходов низким (максимум 0,1 В), а другие 7 высоким (минимум 4,5 В) и управляет входами Arduino низким , если кнопка нажата.

Чтобы быть в безопасности, я хотел бы также добавить резисторы на каждый контакт, чтобы убедиться, что неправильное программирование (сделайте входной контакт ВЫХОДНЫМ и ВЫСОКИМ и нажатием клавиши соедините его с выходом НИЗКИЙ на другой стороне) не может повредить цепи , так что это выглядит как 5 В / 20 мА = 250 & Омега; (и я буду надеяться, что это не приведет к большему количеству выводов, поэтому я не буду учитывать общие ограничения портов/чипов).

В типичном случае это будет 5 В - 1,5 kΩ подтягивание - ввод - 250 Ω - провода и кнопка - диод - 250 Ω - 0,1 В для выбранной линии.

Если диод будет теоретическим и идеальным, то (в худшем случае) обещано максимальное напряжение 1,2 В на входе, что немного меньше «максимально низкого» напряжения (1,5 В) и т.п. 5V/2kΩ = ток 2,5 мА.

Но диод не идеален и имеет некоторое прямое напряжение, что еще больше усугубляет ситуацию.

Поэтому я, вероятно, не могу использовать просто INPUT_PULLUP (поскольку это может сработать по счастливой случайности, но не гарантируется спецификациями), но мне нужно использовать INPUT и установить более высокую подтяжку там "сжечь" на нем побольше вольт для компенсации диода.

Входной ток для каждого контакта составляет 10 мкА (вход или выход), и я слышал некоторые рекомендации, что на резисторном делителе общий ток должен быть в 10 раз больше, чем входной ток, поэтому это будет означать 100 мкА = 0,1.  мА

Тогда подтягивание может достигать ((5 В - 0,1 В - Vf)/0,1 мА ) - 500 Ω Если бы прямое напряжение было бы 1 В (дикое предположение), оно достигло бы примерно 38,5 кОм. подтягивания и 1,15 В на входе. Максимальное прямое напряжение Vf будет равно 1,35 В (при 0,1 мА), подтягивание 35 кОм. и 1,5 В на входе.


Моя проблема в том, что многие онлайн-схемы Arduino работают только потому, что Arduino обычно работает хорошо даже в ситуациях, выходящих за рамки спецификации, а предлагаемые значения исходят из того, что автор просто случайно имел в руках, и это сработало по чистой случайности и, возможно, другие скрытые факторы, такие как паразитная емкость макета или около того. Поэтому я хочу понять, почему я должен выбрать некоторые части и как сам пришел к таким выводам.

Я хочу делать надежные проекты, а не просто проекты, которые работают большую часть времени и лишь изредка дают сбои.


  • Это правильный путь, как его вычислить или я ошибся?
  • Я хочу использовать частоту сканирования не менее 800 Гц (8 строк и результаты 100 раз в секунду) или больше (например, 10 кГц, чтобы работать быстро и иметь больше времени для общения с другими людьми). задачи, такие как отправка USB-пакетов, вычисление макросов, управление освещением эффекты и т. д.)
  • какие распространенные и дешевые SMD-диоды мне следует купить?
    • обратное напряжение более 5 В, ток более 100 мА, частота переключения более 10 кГц, прямое напряжение менее 1,3 В при 0,1 мА (значительно меньше, чтобы иметь безопасный разрыв от пределов)
    • действительно обычная дешевая модель, чтобы все знали ее, и чтобы я мог использовать ее везде в одинаковых условиях, не задумываясь (или даже вычисляя, как в предыдущем разделе)
    • желательно то, что вы (да и все остальные и его собака тоже) используете для таких случаев
    • Я хотел бы заказать на AliExpress, так что я предпочел бы более высокую маржу для гарантированных значений
    • желательно поместиться на универсальной печатной плате с шагом 0,1 дюйма (светодиоды 0805 SMD очень легко туда припаять (поэтому лучше не меньше), но она может быть и в два раза больше или что-то в этом роде)
    • Я бы купил несколько сотен таких диодов, чтобы они всегда были под рукой, и, вероятно, со временем я сделаю больше подобных проектов для себя и своих друзей

Спасибо за все комментарии и предложения

, 👍3

Обсуждение

Спасибо, что направили меня в отдел электротехники, где 1N4148 был настолько распространен в вопросах/ответах, что я погуглил и обнаружил, что он идеально подходит почти для всего, что я могу сделать с контактами ввода-вывода Arduino. Моя проблема РЕШЕНА, @gilhad


2 ответа


Лучший ответ:

2

Когда я использовал матрицу клавиатуры, я подключал ее следующим образом:

Матрица клавиатуры с диодами

Я использовал SMD-диоды 1N4148, которые купил по дешевке. Я вырезал дорожки на своей дешевой плате, купленной в Jaycar, и припаял их вот так:

1N4148 SMD-диоды

Точка — это катод (на моих диодах на конце катода выгравирована линия).

Резисторы номиналом 10 кОм эффективно превращают столбцы в подтягивающие, поэтому нет опасности, что плохой код повредит Arduino или что-то еще.

Пример кода для сканирования матрицы:

// Keypad_Decoder
//
// Автор: Ник Гэммон
// Дата: 17 февраля 2018 г.

// Вывод в Serial в формате: 0b1nnnnnn для нажатия клавиши и 0b0nnnnnn для нажатия клавиши
// nnnnnn будет текущей комбинацией строки/столбца
// Также каждый HEARTBEAT_TIME выводит 0xFF, если все ключи нажаты (пульс)

#include <limits.h>     /* for CHAR_BIT */

const byte ROWS = 4;
const byte COLS = 4;
const bool ENABLE_PULLUPS = true;  // сделайте false, если вы используете внешние подтягивания
const unsigned long DEBOUNCE_TIME = 10;     // миллисекунды
const unsigned long HEARTBEAT_TIME = 2000;  // миллисекунды
const bool DEBUGGING = false;               // делаем true для удобочитаемого вывода

// определяем здесь, где каждая строка и столбец соединены с
const byte rowPins [ROWS] = {6, 7, 8, 9}; //подключаемся к распиновке ряда клавиатуры
const byte colPins [COLS] = {2, 3, 4, 5}; //подключаем к колонке распиновку клавиатуры


// См.: http://c-faq.com/misc/bitsets.html

#define BITMASK(b) (1 << ((b) % CHAR_BIT))
#define BITSLOT(b) ((b) / CHAR_BIT)
#define BITSET(a, b) ((a)[BITSLOT(b)] |= BITMASK(b))
#define BITCLEAR(a, b) ((a)[BITSLOT(b)] &= ~BITMASK(b))
#define BITTEST(a, b) ((a)[BITSLOT(b)] & BITMASK(b))

// количество элементов в массиве
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

// общее количество ключей
const byte TOTAL_KEYS = ROWS * COLS;

// запомнить предыдущую настройку каждой клавиши
char lastKeySetting [(TOTAL_KEYS + CHAR_BIT - 1) / CHAR_BIT];  // по одному биту, 0 = вверх, 1 = вниз
unsigned long lastKeyTime [TOTAL_KEYS];       // когда этот ключ последний раз менялся
unsigned long lastHeartbeat;                  // когда мы в последний раз отправляли сердцебиение

void setup ()
{
  Serial.begin (115200);
  while (!Serial) { }  // ждем готовности Serial (Леонардо и т.д.)

  // установить для каждого столбца значение input-pullup (необязательно)
  if (ENABLE_PULLUPS)
    for (byte i = 0; i < COLS; i++)
      pinMode (colPins [i], INPUT_PULLUP);

}  // конец настройки

void loop ()
  {
  byte keyNumber = 0;
  unsigned long now = millis ();  // для устранения дребезга

  // проверяем каждую строку
  for (byte row = 0; row < ROWS; row++)
    {
    // устанавливаем для этой строки значение OUTPUT и LOW
    pinMode (rowPins [row], OUTPUT);
    digitalWrite (rowPins [row], LOW);

    // проверяем каждый столбец, чтобы убедиться, что переключатель не установил для этого столбца НИЗКИЙ уровень
    for (byte col = 0; col < COLS; col++)
      {
      // debounce - игнорировать, если с момента последнего изменения прошло недостаточно времени
      if (now - lastKeyTime [keyNumber] >= DEBOUNCE_TIME)
        {
        bool keyState = digitalRead (colPins [col]) == LOW; // true означает нажатие
        if (keyState != (BITTEST (lastKeySetting, keyNumber) != 0)) // изменилось?
          {
          lastKeyTime [keyNumber] = now;  // запоминаем время, когда оно изменилось
          // запомнить новое состояние
          if (keyState)
            BITSET (lastKeySetting, keyNumber);
          else
            BITCLEAR (lastKeySetting, keyNumber);
          if (DEBUGGING)
            {
            Serial.print (F("Key "));
            Serial.print (keyNumber);
            if (keyState)
              Serial.println (F(" down."));
            else
              Serial.println (F(" up."));
            }  // при отладке
          else
            Serial.write ((keyState ? 0x80 : 0x00) | keyNumber);
          }  // если состояние ключа изменилось
        }  // время устранения дребезга вверх
      keyNumber++;
      } // конец каждого столбца

    // возвращаем строку в состояние высокого импеданса (вход)
    pinMode (rowPins [row], INPUT);
    }  // конец каждой строки

  // Отправлять код сердцебиения (0xFF) каждые несколько секунд на случай, если
  // получатель случайно теряет нажатие клавиши.
  // Отправка только в том случае, если все клавиши не нажаты (предположительно нормальное состояние).
  if (now - lastHeartbeat >= HEARTBEAT_TIME)
    {
    lastHeartbeat = now;
    bool allUp = true;
    for (byte i = 0; i < ARRAY_SIZE (lastKeySetting); i++)
      if (lastKeySetting [i])
        allUp = false;
    if (allUp)
      {
      if (DEBUGGING)
        Serial.println (F("No keys pressed."));
      else
        Serial.write (0xFF);
      } // конец всех ключей вверх
    } // конец, если время для сердцебиения
  } // конец цикла

Что касается скорости, я измерил около 300 мкс при сканировании без нажатия клавиш. Если это время покажется вам слишком большим, вы всегда можете проверить время и сканировать каждые 5 мс или около того.

У меня есть сообщение обо всем этом на моем форуме. В этом посте я также упоминаю библиотеку, которая обрабатывает одновременное нажатие нескольких клавиш, поэтому вы можете обнаружить одновременное нажатие нескольких клавиш. Например, вы можете использовать A/B/C/D на клавиатуре в качестве клавиш «Shift», чтобы A+1 означало нечто иное, чем просто 1.


Матрица спереди:

Матрица клавиатуры


Моя проблема в том, какие диоды использовать, а также почему именно этот тип (или почему это не имеет значения).

Я не думаю, что конкретный диод в данном случае имеет решающее значение. Если бы это было очень высокоскоростное приложение, то мог бы потребоваться диод с быстрым переключением. Если бы это было высокое напряжение, то мог бы потребоваться диод с более высокими характеристиками. В некоторых случаях может применяться обратное напряжение. В данном конкретном случае, поскольку мы имеем дело с включением/выключением на логических уровнях, я не думаю, что это имеет большое значение, хотя скорость переключения может быть в определенной степени, однако я предполагаю из эмпирических наблюдений, что скорость 1N4148 достаточно быстро.

Также см.: Википедия — 1N4148:

Модуль 1N4148 полезен в коммутационных приложениях с частотой до 100 МГц и временем обратного восстановления не более 4 нс.

,

Спасибо, ваш ответ поможет многим читателям. Но мой вопрос заключался в том, какой тип диода использовать (как вы говорите IN4148) и, в основном, ПОЧЕМУ, так как я мог найти множество схем повсюду, мало говорится, какой диод используется, и никто не обсуждает, **почему именно этот тип** или почему неважно. В сети есть много других схем, где правильные значения критичны (например, какой-нибудь HiFi или около того) и много схем, где значения - это то, что было под рукой у автора, и в целом это не работает правильно, но ему просто повезло. время с нестандартным просто случайным образом работало на него. Я хотел понять этот момент., @gilhad

Насчет плохого программирования - я часто использую сокеты в своих проектах и переиспользую микроконтроллер в других проектах, когда один устарел или мне он просто сейчас не нужен. Позже я, возможно, вернусь к этому снова, поставлю MC в сокет и снова загружу исходный код. Поэтому я боялся помещать MC, запрограммированный для другого проекта (где он установит вывод для COL1 в High, а вывод для ROW1 в Low) в сокет и нажать левую верхнюю клавишу перед загрузкой правильного кода внутрь. Таким образом, эффективно замкните эти два контакта и подключите 5 В к 0 В через диод. ..., @gilhad

... Вот я и поставил туда ограничительные резисторы на 250 Ом, чтобы ограничить ток до 10мА даже при такой ошибке. (Похожее уже было со мной раньше, я вскоре понял, что проект не работает, но было уже поздно. Поэтому я стал более параноидальным по поводу "невозможных" программных багов и стараюсь сделать HW таким образом, чтобы ничего не было . гореть, даже если МС активно пытается сжечь себя), @gilhad

PS: Мне очень нравится ваш сайт и я часто его читаю :), @gilhad

Спасибо! В конце я добавил еще один абзац, объясняющий выбор диода., @Nick Gammon


0

Решение: диод 1N4148

как правило, если вы хотите подключить диод к контакту Arduino, используйте этот, так как он подходит практически для любого обычного использования

  • Обратное напряжение 75 В (там допускается намного больше 5В)
  • Прямое напряжение 1 В при 10 мА (меньше при меньшем токе)
  • Рекомендуемый ток 10 мА (разрушает при импульсе 1 А в 1 с) (и вы в любом случае не нужно больше 10 мА)
  • можно использовать до 100 МГц (поэтому при использовании digitalRead/digitalWrite и какая-то логика у вас все равно медленнее)
  • очень распространенный в течение длительного времени (даже 10 лет назад считался "классический") и до сих пор актуален (так что, когда состаришься, все равно будет здесь)
  • грязно дешево (купите несколько сотен прямо сейчас, и вам не нужно заботиться больше)
,