Мультиплексирование клавиатуры пианино с помощью arduino nano
Я пытаюсь использовать дешевую клавиатуру с 37 клавишами в качестве MIDI-контроллера, считывая мультиплексированные клавиши с помощью Arduino nano. Ключи сгруппированы в шесть групп, максимум по 8 ключей в каждой группе. Что приводит к тому, что я настраиваю 8 цифровых ВХОДОВ, которые вытягиваются ВЫСОКО, и 6 ВЫХОДОВ, которые вытягиваются НИЗКО, при считывании этой группы ключей. Это отлично работает, когда у меня в цикле всего 3 группы. Однако всякий раз, когда я добавляю другую группу, она больше не работает. Не имеет значения, какие группы активированы.
Одно групповое чтение выглядит так:
digitalWrite(A0, LOW);
for (byte j = 12; j > 4; j--)
{
uint8_t note = offset + 20 + (12-j);
uint8_t key_state = digitalRead(j);
if ( (key_state == 0) && (notes_pressed[note] == 1) )
{
notes_pressed[note] = 0;
Serial.write(note + 100);
} else if ( (key_state == 1) && (notes_pressed[note] == 0) )
{
notes_pressed[note] = 1;
Serial.write(note);
}
}
digitalWrite(A0, HIGH);
С A0, являющимся выводом группы.
Я думаю, что это связано с тем, что контакты не могут быть опущены так быстро из-за слабых драйверов вывода или чего-то подобного. К сожалению, у меня нет осциллографа, чтобы проверить уровни. Я добавил задержки, чтобы убедиться, что уровни установились, когда происходит считывание, но безрезультатно.
Редактировать: Схема в значительной степени заключается именно в этом. Диоды на клавиатуре я опустил, но они есть по мере необходимости:
#include "HardwareSerial.h"
#define offset 48
void midi_note_off(byte channel, byte key, byte velocity);
void midi_note_on(byte channel, byte key, byte velocity);
void midi_command(byte command, byte channel, byte param1, byte param2);
byte notes_pressed[37];
void setup() {
Serial.begin(115200);
pinMode(12, INPUT_PULLUP);
pinMode(11, INPUT_PULLUP);
pinMode(10, INPUT_PULLUP);
pinMode(9, INPUT_PULLUP);
pinMode(8, INPUT_PULLUP);
pinMode(7, INPUT_PULLUP);
pinMode(6, INPUT_PULLUP);
pinMode(5, INPUT_PULLUP);
pinMode(4, OUTPUT);
pinMode(3, OUTPUT);
pinMode(2, OUTPUT);
pinMode(A2, OUTPUT);
pinMode(A1, OUTPUT);
pinMode(A0, OUTPUT);
digitalWrite(4, HIGH);
digitalWrite(3, HIGH);
digitalWrite(2, HIGH);
digitalWrite(A0, HIGH);
digitalWrite(A1, HIGH);
digitalWrite(A2, HIGH);
}
void loop() {
digitalWrite(4, LOW);
for (byte j = 8; j > 4; j--)
{
uint8_t note = offset + (8-j);
uint8_t key_state = digitalRead(j);
if ( (key_state == 0) && (notes_pressed[note] == 1) )
{
notes_pressed[note] = 0;
Serial.write(note + 100);
} else if ( (key_state == 1) && (notes_pressed[note] == 0) )
{
notes_pressed[note] = 1;
Serial.write(note);
}
}
digitalWrite(4, HIGH);
digitalWrite(3, LOW);
for (byte j = 12; j > 4; j--)
{
uint8_t note = offset + 4 + (12 - j);
uint8_t key_state = digitalRead(j);
if ( (key_state == 0) && (notes_pressed[note] == 1) )
{
notes_pressed[note] = 0;
Serial.write(note + 100);
} else if ( (key_state == 1) && (notes_pressed[note] == 0) )
{
notes_pressed[note] = 1;
Serial.write(note);
}
}
digitalWrite(3, HIGH);
digitalWrite(2, LOW);
for (byte j = 12; j > 4; j--)
{
uint8_t note = offset + 12 + (12-j);
uint8_t key_state = digitalRead(j);
if ( (key_state == 0) && (notes_pressed[note] == 1) )
{
notes_pressed[note] = 0;
Serial.write(note + 100);
} else if ( (key_state == 1) && (notes_pressed[note] == 0) )
{
notes_pressed[note] = 1;
Serial.write(note);
}
}
digitalWrite(2, HIGH);
digitalWrite(A0, LOW);
for (byte j = 12; j > 4; j--)
{
uint8_t note = offset + 20 + (12-j);
uint8_t key_state = digitalRead(j);
if ( (key_state == 0) && (notes_pressed[note] == 1) )
{
notes_pressed[note] = 0;
Serial.write(note + 100);
} else if ( (key_state == 1) && (notes_pressed[note] == 0) )
{
notes_pressed[note] = 1;
Serial.write(note);
}
}
digitalWrite(A0, HIGH);
digitalWrite(A1, LOW);
for (byte j = 12; j > 4; j--)
{
uint8_t note = offset + 28 + (12-j);
uint8_t key_state = digitalRead(j);
if ( (key_state == 0) && (notes_pressed[note] == 1) )
{
notes_pressed[note] = 0;
Serial.write(note + 100);
} else if ( (key_state == 1) && (notes_pressed[note] == 0) )
{
notes_pressed[note] = 1;
Serial.write(note);
}
}
digitalWrite(A1, HIGH);
digitalWrite(A2, LOW);
for (byte j = 5; j > 4; j--)
{
uint8_t note = offset + 36 + (5-j);
uint8_t key_state = digitalRead(j);
if ( (key_state == 0) && (notes_pressed[note] == 1) )
{
notes_pressed[note] = 0;
Serial.write(note + 100);
} else if ( (key_state == 1) && (notes_pressed[note] == 0) )
{
notes_pressed[note] = 1;
Serial.write(note);
}
}
digitalWrite(A2, HIGH);
}
Я знаю, что последняя часть, зацикливающаяся на одном значении, не является обязательной, но она все равно должна работать.
@multikeys, 👍0
Обсуждение2 ответа
При разработке матрицы коммутатора для встроенного процессора необходимо учитывать несколько вопросов, независимо от того, является ли это музыкальная или компьютерная клавиатура:
- Контактный отскок: Это более важно для компьютерной клавиатуры , чем для музыкальной клавиатуры. Однако, если переключатель особенно плох, он может быть слышен. Программное обеспечение может быть использовано для устранения проблемы , но также добавит задержку между нажатием клавиши и началом звука ноты.
- Подтягивание: Любой логический вход не должен оставаться отключенным или плавающим. Это может привести к неожиданным результатам. Используйте подтягивающие резисторы (или потяните вниз в зависимости от вашей конструкции), чтобы смягчить эту проблему. Встроенный процессор Arduino Uno (the ATmega328P) поставляется со встроенными подтягивающими резисторами. IDE Arduino абстрагирует эту функцию, включив параметр в вызов функции pinMode() для вызова этой функции.
- Опрокидывание: В матрице переключателей может быть однозначно обнаружено 1 или 2 одновременных замыкания переключателей. Однако, если 3 замыкания переключателя соединяют 2 строки и 2 столбца вместе, они не могут быть однозначно обнаружены. Это связано с тем, что ток может протекать через 3 закрытых переключателя, активирующих обе строки и оба столбца, что сводит на нет возможность встроенного процессора сканировать отдельные строки или столбцы. Чтобы уменьшить эту проблему, ко всем переключателям в матрице переключателей добавляется диод, так что между строками или столбцами нет пути тока.
Со страницы ролловера в Википедии:
Большинство музыкальных клавиатур используют изолирующие диоды в матрице клавиатуры для реализации полного опрокидывания n-клавиш, что делает их невосприимчивыми как к появлению призраков , так и к заклиниванию клавиш
Это изображение, если из этого вопроса об обмене стеками:
Спасибо за ваш вклад. 1. Это то, что я хочу смягчить позже, если это необходимо. Однако сейчас я не получаю никакой реакции на нажатия или отпускания кнопок. 2. Я использую подтягивания Arduino 3. Клавиатура, которую я купил, имеет эти встроенные диоды, @multikeys
Похоже, вы уже приняли во внимание основы. Подожди ... Я думал, вам удалось создать несколько заметок? Если вы не создаете нот, это означает, что что-то может быть не так, включая MIDI-плеер! Хммм ... тогда тебе следует начать все сначала. Проверьте всю вашу проводку (используя тестовое оборудование, если оно у вас есть). Затем используйте версию вашего кода, которая не меняется между разными столбцами. Затем попробуйте 2 колонки. Добавьте задержки в код после изменения столбцов, чтобы увидеть, поможет ли это., @st2000
Извините, что я неправильно сформулировал это. Я не реагирую на нажатия кнопок всякий раз, когда раскомментирую более трех столбцов в цикле. Не имеет значения, какие из них комментируются, другие реагируют должным образом. Я пробовал с некоторыми задержками, но постараюсь добавить их в разных местах, чтобы, возможно, получить другое поведение., @multikeys
Re “_builded in Pull Up and Pull Down resistors_”: Uno имеет встроенные подтягивания, но не подтягивания. Re “_если два замыкания переключателя происходят в одной строке или столбце, они не могут быть однозначно обнаружены_”: Мне кажется, вам нужно нажать как минимум три переключателя, чтобы создать такую двусмысленность., @Edgar Bonet
Никаких спусков? Виноват, - поправил я ответ. Если сканирование путем понижения напряжений столбцов и 2 столбца электрически соединены 2 замкнутыми переключателями в одном ряду (без диодов), то я не вижу способа определить разницу ... о, я понимаю, что вы имеете в виду. Вам не нужно видеть разницу. Вам просто нужно обнаружить, что они оба закрыты. Ладно, это я тоже исправлю., @st2000
Несколько выдержек из программы:
#define offset 48
//...
byte notes_pressed[37]; // допустимые индексы: 0 – 36
//...
uint8_t note = offset + (8-j); // j ≤ 8, таким образом, примечание ≥ 48
//...
notes_pressed[note] = 0;
Эта последняя строка записывается после конца массива notes_pressed и
перезаписывает неизвестно что в памяти. Это может быть источником
проблемы, с которой вы столкнулись.
- avrdude ser_open() can't set com-state
- Загрузка Arduino Nano дает ошибку: avrdude: stk500_recv(): programmer is not responding
- Какое максимальное энергопотребление Arduino Nano 3.0?
- Как навсегда изменить скорость передачи данных ESP8266 (12e)?
- Питание светодиодной ленты - Сколько ампер?
- Arduino nano как клавиатура HID
- Как я могу запитать Arduino Nano от батареи LiPo, желательно 3,7 В
- В чем разница между библиотеками Software Serial? Какая из них совместима с Arduino Nano?
Выходы Arduino составляют около 25 Ом, тогда как внутреннее подтягивание составляет примерно 30 Ком, поэтому один
ВЫХОД
НИЗКИЙ
может тянуть много контактовINPUT_PULLUP
. Не могли бы вы показать схему настройки клавиатуры + Arduino?, @Edgar BonetВ строке 82 у вас несбалансированные круглые скобки., @Edgar Bonet
Спасибо, это, должно быть, произошло во время вставки сюда!, @multikeys
ваши циклы
for
перепутались ...порядок ключей в столбцах не одинаков (если ваша схема верна) ... первая колонка-от 5 до 8 ... вторая колонка-от 12 до 5 ... третий столбец-от 5 до 12 ... Четвертый столбец-от 5 до 12 ... пятая колонна - 12 к 5 ... шестой столбец-это один ключ, который не требует цикла "for", @jsotolaпрекратите вычислять примечание ...
примечание = смещение + 20 + (12-j)
... вместо этого используйте инкремент ... `примечание++, @jsotola