Какие диоды использовать в матричном вводе кнопок/клавиш? (Изготовление игровой клавиатуры)
При матричном вводе столбцов/строк 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 очень легко туда припаять (поэтому лучше не меньше), но она может быть и в два раза больше или что-то в этом роде)
- Я бы купил несколько сотен таких диодов, чтобы они всегда были под рукой, и, вероятно, со временем я сделаю больше подобных проектов для себя и своих друзей
Спасибо за все комментарии и предложения
@gilhad, 👍3
Обсуждение2 ответа
Лучший ответ:
Когда я использовал матрицу клавиатуры, я подключал ее следующим образом:
Я использовал SMD-диоды 1N4148, которые купил по дешевке. Я вырезал дорожки на своей дешевой плате, купленной в Jaycar, и припаял их вот так:
Точка — это катод (на моих диодах на конце катода выгравирована линия).
Резисторы номиналом 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
Решение: диод 1N4148
как правило, если вы хотите подключить диод к контакту Arduino, используйте этот, так как он подходит практически для любого обычного использования
- Обратное напряжение 75 В (там допускается намного больше 5В)
- Прямое напряжение 1 В при 10 мА (меньше при меньшем токе)
- Рекомендуемый ток 10 мА (разрушает при импульсе 1 А в 1 с) (и вы в любом случае не нужно больше 10 мА)
- можно использовать до 100 МГц (поэтому при использовании digitalRead/digitalWrite и какая-то логика у вас все равно медленнее)
- очень распространенный в течение длительного времени (даже 10 лет назад считался "классический") и до сих пор актуален (так что, когда состаришься, все равно будет здесь)
- грязно дешево (купите несколько сотен прямо сейчас, и вам не нужно заботиться больше)
- Нажать клавишу Windows, используя «keyboard.press();»
- Отправка мультимедийных клавиш клавиатуры с помощью библиотеки клавиатур
- Keyboard.print() пропускает клавиши
- Не удается заставить клавиатуру использовать Keyboard.write на Arduino Uno
- Не удается ввести обратную косую черту (\) с помощью библиотеки клавиатуры
- Может ли видеоигра потенциально обнаружить arduino leonardo?
- Использование Leonardo в качестве клавиатуры: добавление функций пробуждения и сна
- Почему Xbox360 не может определить Arduino Leonardo как клавиатуру?
Спасибо, что направили меня в отдел электротехники, где 1N4148 был настолько распространен в вопросах/ответах, что я погуглил и обнаружил, что он идеально подходит почти для всего, что я могу сделать с контактами ввода-вывода Arduino. Моя проблема РЕШЕНА, @gilhad