Всегда было интересно поиграть на пианино, но всё никак не доходили руки купить MIDI клавиатуру.
Поэтому решил собрать её сам, естественно из говна и палок.
К сожалению, у меня не было даже игрушечной MIDI клавиатуры, чтобы переделать в нормальную. А самому делать механическую клавиатуру - очень сложно.
Поэтому решил остановиться на сенсорном варианте.
Идея простая - берём листовую жесть, вырезаем из неё кусочки по форме кнопок пианино, крепим на любую подходящую по размерам дсоку.... и всё, готово!
С электричествой точки зрения там всё просто. Берём кусочек фольги/жести, подключаем к GPIO и всё, готово:
Да, чтобы сделать сенсорную кнопку больше ничего не нужно. %)
Как же это работает?
На самом деле всё просто. МК в бесконечном цикле замеряет время, за которое пин gpio переходит из состояния 0 в 1.
Если пин gpio подключен не напрямую к питанию, а через резистор, то этот переход будет занимать достаточно большое время.
Весь алгоритм выглядит так:
Но когда мы приближаем палец к сенсорной кнопке, происходит утечка тока + ловятся наводки (палец=антенна). Из-за этого время заряда/разряда начинает отклоняться в большую и меньшую сторону.
Вот наличие этого отклонения считаем за "нажатую кнопку".
Как видно из алгоритма, я использую встроенные pullup/pulldown резисторы.
Скорость работы STM32F103 позволяет так делать.
В ином случае случае мне пришлось бы к каждому "сенсору" припаивать более высокоомный резистор, который управлялся бы с дополнительного пина gpio.
У меня этот код выглядит так:
Остаётся только при включении устройства измерить эталонное время и далее сравнивать с ним текущее измеренное.
Далее добавить алгоритм дебоунсинга по вкусу и подобрать порог срабатывания. Вот и всё.
Разработка хардварной части
Естественно, рисовать вручную все эти кнопочки занятие долгое и неинтересное, поэтому я написал скрипт на PHP, который генерирует чертёж MIDI клавиатуры.
Найти его можно тут: https://github.com/Azq2/stm32-sensor-midi-keyboard/blob/master/gen-piano.php
Скрипт поддерживает MIDI клавиатуры: 13, 25, 37, 49, 61, 76 и 88 кнопок.
Так же внутри скрипта можно тюнить отступы и размеры кнопок.
Использование простое:
На выходе получаем три чертежа в /tmp
Вот пример для 25-клавишной клавиатуры (для этого проекта):
1. Чертёж ддя вырезания белых кнопок
Хвостики нужны чтобы было удобно устанавливать кнопки на доску + припаивать к ним провода.
2. Чертёж для вырезания чёрных кнопок
Чёрные кнопки сгибаются в букву П, чтобы было удобнее их "нажимать", при этом не задевая белые кнопки.
3. Чертёж для сверления доски
Здесь кнопки расположены уже с рабочими отступами и нарисованы метки для сверления.
Все чертежи для проекта можно найти тут: https://github.com/Azq2/stm32-sensor-midi-keyboard/tree/master/docs
Скрипт генерирует картинки с разрешением 300ppi, т.е. достаточно создать в фотошопе или GIMP лист A4 с 300ppi и вставить туда одну из картинок.
А далее распечатать и вырезать!
За основу клавиатуры я выбрал коробку от фруктов:
К сожалению тогда я ещё не прридумал делать хвостики у белых клавиш и вырезал их в виде обычных пластин.
Поэтому пришлось выкручиваться из положения и припаивать к каждой пластине кусочек проволки, чтобы потом закрепить обратной стороны:
В актуальных чертежах я исправил эту ошибку.
После окончательной установки выглядит так:
Далее необходимо припаять все 9999999 проводов к bluepill.
Порядок на самом деле не так важен, его можно потом исправить в коде, главное не использовать: PA9 и PA10 (USART1), PA11 и PA12 (USB)
Вот порядок, который изначально прописан в коде:
На самом деле в этом списке нет никакой логики, т.к. паял я их от балды
Их слишком много, чтобы заудымваться о каком-либо логичном порядке))))
После этого нужно покрыть конакты чем-нибудь диэлектрическим.
Это на самом деле важный этап, чтобы все эти потанцевалы ~110V не спалили лапки микроконтроллёра.
Я пробовал эпоксидную смолу, но ничего хорошего с ней у меня не получилось из-за её текучести и скорости застывания.
Лучше всего себя показал обычный лак для ногтей. У него и слой тонкий получается и застывает быстро.
Главное чтобы девушка/жена/мамка не змаетила пропажу лака
Конечный вариант конструкции выглдяит так:
Not great not terrible)))))
Оставил место для будущих кнопок, если вдруг захочется расширить 37 или 49 клавиш.
Кстати, тут нехватает одной кнопки в конце, мне пока лень её вырезать
Демо
Как доказательство того, что эта странная конструкция действительно работает, я записал демо-видео:
P.S. Играть я не умею, просто попытался сыграть начало рандомной композии, ровно до первого сложного момента
Настройка
Если вдруг кто-нибудь решиться повторить эту конструкцию, то, скорее всего, ничего у ничего не заработает с первого раз.
Получается, эта статья обман???
На самом деле нет!
Дело в том, что у разных конструкций будут разные физические параметры, разная паразитная ёмкость, разная площадь контактов, разная длина проводов... На самом деле это всё очень сильно влияет.
Сразу после сборки, скорее всего, придётся подтюнить несколько параметров:
Остальные настройки:
Все эти настройки можно найти в файле src/App.h
Исправления порядка клавиш
1. Сначала устанавливаем DEBUG_SORT_KEYS=true и подключаемся по USART.
2. Нажимаем все кнопки по очереди, слева на право.
3. Копируем содержимое структуры, которое вывело в USART.
4. Заменяем содержимое структуры App::m_pins в файле: src/App.cpp
Настройка чувствительности
1. Сначала устанавливаем DEBUG_PRESS_KEYS=true и подключаемся по USART.
2. Нажимает на интересующие клавиши.
3. Если что-то не нравится, меняем SENSOR_BLACK_KEY_THRESHOLD и SENSOR_WHITE_KEY_THRESHOLD до тех пор, пока не начнёт работать нормально.
4. Если нажатия троят, то увеличиваем DEBOUNCE_CYCLES (если тормозят, то уменьшаем).
Сборка прошивки
Для сборки необходим любой дистрибутив Linux. Хоть даже WSL под Windows.
Для сборки необходимо установить компилятор arm-none-eabi: https://developer.arm.com/downloads/-/gnu-rm
Его нужно распаковать в /opt и прописать в конец файла ~/.bashrc строчку вида:
Сама сборка:
После сборки вы получите app.bin и app.elf
Вы можете прошить один из этих файлов любым удобным для вас способом.
В случае использования Black Magic Probe достаточно выполнить команду:
Как это использовать?
Под Linux достаточно просто подключить по USB и всё сразу заработает
А вот что делать под OSX/Windows я честно говоря понятия не имею
В коде я использую стандартные pid/vid для DIY MIDI устройств:
Исходный код
Репозиторий проекта на github: https://github.com/Azq2/stm32-sensor-midi-keyboard
Поэтому решил собрать её сам, естественно из говна и палок.
К сожалению, у меня не было даже игрушечной MIDI клавиатуры, чтобы переделать в нормальную. А самому делать механическую клавиатуру - очень сложно.
Поэтому решил остановиться на сенсорном варианте.
Идея простая - берём листовую жесть, вырезаем из неё кусочки по форме кнопок пианино, крепим на любую подходящую по размерам дсоку.... и всё, готово!
С электричествой точки зрения там всё просто. Берём кусочек фольги/жести, подключаем к GPIO и всё, готово:
Да, чтобы сделать сенсорную кнопку больше ничего не нужно. %)
Как же это работает?
На самом деле всё просто. МК в бесконечном цикле замеряет время, за которое пин gpio переходит из состояния 0 в 1.
Если пин gpio подключен не напрямую к питанию, а через резистор, то этот переход будет занимать достаточно большое время.
Весь алгоритм выглядит так:
- Переключаем пин в INPUT с PULL-UP
- Замеряем время, за которое пин перейдёт в состояние 1 (на этом этапе напряжение >1.88V)
- Далее переводим пин в OUTPUT=1, чтобы паразитный конденсатор полностью зарядился до 3.3V
- Переключаем пин в INPUT с PULL-DOWN
- Замеряем время, за которое пин перейдёт в состояние 0 (на этом этапе напряжение <1.23V)
- Далее переводим пин в OUTPUT=1, чтобы паразитный конденсатор полностью разрядился до 0V
Но когда мы приближаем палец к сенсорной кнопке, происходит утечка тока + ловятся наводки (палец=антенна). Из-за этого время заряда/разряда начинает отклоняться в большую и меньшую сторону.
Вот наличие этого отклонения считаем за "нажатую кнопку".
Как видно из алгоритма, я использую встроенные pullup/pulldown резисторы.
Скорость работы STM32F103 позволяет так делать.
В ином случае случае мне пришлось бы к каждому "сенсору" припаивать более высокоомный резистор, который управлялся бы с дополнительного пина gpio.
У меня этот код выглядит так:
C++:
int App::measureRechargeTime(const Pin &p) {
int start = 0, count = 0;
for (int i = 0; i < SAMPLES_CNT; i++) {
// Switch to input
gpio_clear(p.port, p.pin);
gpio_set_mode(p.port, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, p.pin);
// Charge to >1.88V and measure elapsed time
start = DWT_CYCCNT;
gpio_set(p.port, p.pin);
while (!gpio_get(p.port, p.pin));
count += DWT_CYCCNT - start;
// Complete charge to 3.3V
gpio_set_mode(p.port, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, p.pin);
// Discharge to <1.23V and measure elapsed time
gpio_set_mode(p.port, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, p.pin);
start = DWT_CYCCNT;
gpio_clear(p.port, p.pin);
while (gpio_get(p.port, p.pin));
count += DWT_CYCCNT - start;
// Complete discharge to 0V
gpio_set_mode(p.port, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, p.pin);
}
return count / SAMPLES_CNT;
}
Далее добавить алгоритм дебоунсинга по вкусу и подобрать порог срабатывания. Вот и всё.
Разработка хардварной части
Естественно, рисовать вручную все эти кнопочки занятие долгое и неинтересное, поэтому я написал скрипт на PHP, который генерирует чертёж MIDI клавиатуры.
Найти его можно тут: https://github.com/Azq2/stm32-sensor-midi-keyboard/blob/master/gen-piano.php
Скрипт поддерживает MIDI клавиатуры: 13, 25, 37, 49, 61, 76 и 88 кнопок.
Так же внутри скрипта можно тюнить отступы и размеры кнопок.
Использование простое:
Bash:
# php gen-piano.php <number of keys>
php gen-piano.php 25
Вот пример для 25-клавишной клавиатуры (для этого проекта):
1. Чертёж ддя вырезания белых кнопок
Хвостики нужны чтобы было удобно устанавливать кнопки на доску + припаивать к ним провода.
2. Чертёж для вырезания чёрных кнопок
Чёрные кнопки сгибаются в букву П, чтобы было удобнее их "нажимать", при этом не задевая белые кнопки.
3. Чертёж для сверления доски
Здесь кнопки расположены уже с рабочими отступами и нарисованы метки для сверления.
Все чертежи для проекта можно найти тут: https://github.com/Azq2/stm32-sensor-midi-keyboard/tree/master/docs
Скрипт генерирует картинки с разрешением 300ppi, т.е. достаточно создать в фотошопе или GIMP лист A4 с 300ppi и вставить туда одну из картинок.
А далее распечатать и вырезать!
За основу клавиатуры я выбрал коробку от фруктов:
К сожалению тогда я ещё не прридумал делать хвостики у белых клавиш и вырезал их в виде обычных пластин.
Поэтому пришлось выкручиваться из положения и припаивать к каждой пластине кусочек проволки, чтобы потом закрепить обратной стороны:
В актуальных чертежах я исправил эту ошибку.
После окончательной установки выглядит так:
Далее необходимо припаять все 9999999 проводов к bluepill.
Порядок на самом деле не так важен, его можно потом исправить в коде, главное не использовать: PA9 и PA10 (USART1), PA11 и PA12 (USB)
Вот порядок, который изначально прописан в коде:
Pin | Note |
---|---|
PB13 | C3 |
PB14 | C3# |
PB15 | D3 |
PB12 | D3# |
PA8 | E3 |
PB8 | F3 |
PB9 | F3# |
PB7 | G3 |
PB3 | G3# |
PA1 | A3 |
PB1 | A3# |
PA0 | B3 |
PB4 | C4 |
PB0 | C4# |
PA7 | D4 |
PA2 | D4# |
PA4 | E4 |
PB5 | F4 |
PB11 | F4# |
PA5 | G4 |
PA15 | G4# |
PA3 | A4 |
PA6 | A4# |
PB6 | B4 |
PB10 | C5 |
На самом деле в этом списке нет никакой логики, т.к. паял я их от балды
Их слишком много, чтобы заудымваться о каком-либо логичном порядке))))
После этого нужно покрыть конакты чем-нибудь диэлектрическим.
Это на самом деле важный этап, чтобы все эти потанцевалы ~110V не спалили лапки микроконтроллёра.
Я пробовал эпоксидную смолу, но ничего хорошего с ней у меня не получилось из-за её текучести и скорости застывания.
Лучше всего себя показал обычный лак для ногтей. У него и слой тонкий получается и застывает быстро.
Конечный вариант конструкции выглдяит так:
Not great not terrible)))))
Оставил место для будущих кнопок, если вдруг захочется расширить 37 или 49 клавиш.
Кстати, тут нехватает одной кнопки в конце, мне пока лень её вырезать
Демо
Как доказательство того, что эта странная конструкция действительно работает, я записал демо-видео:
P.S. Играть я не умею, просто попытался сыграть начало рандомной композии, ровно до первого сложного момента
Настройка
Если вдруг кто-нибудь решиться повторить эту конструкцию, то, скорее всего, ничего у ничего не заработает с первого раз.
Получается, эта статья обман???
На самом деле нет!
Дело в том, что у разных конструкций будут разные физические параметры, разная паразитная ёмкость, разная площадь контактов, разная длина проводов... На самом деле это всё очень сильно влияет.
Сразу после сборки, скорее всего, придётся подтюнить несколько параметров:
Parameter | Default | Description |
---|---|---|
SENSOR_WHITE_KEY_THRESHOLD | 1000 | Порог срабатывания, чтобы считать кнопку нажатой Это значение на самом деле проценты умноженные на 100 (чтобы использовать целые числа вместо float) 100000=100% 100=1% |
SENSOR_BLACK_KEY_THRESHOLD | 1300 | Порог срабатывания, чтобы считать кнопку нажатой Это значение на самом деле проценты умноженные на 100 (чтобы использовать целые числа вместо float) 100000=100% 100=1% |
Остальные настройки:
Parameter | Default | Description |
---|---|---|
NOTE_OFFSET | 48 | Нота MIDI для первой кнопки: 36 - C2, 48 - C3. Вот тут полный список можно посмотреть: https://studiocode.dev/resources/midi-middle-c/ |
KEY_VELOCITY | 64 | Сила нажатия, 0-127. |
DEBOUNCE_CYCLES | 1000000 | Время дебоунсинга в циклах CPU, нужно увеличить, если есть "дребезг" нажатия и уменьшить, если вдруг нехватает скорости нажатия одной кнопки. (Для тех, кто хочет сыграть Bad Apple со скоростью 999999 нажатий в наносекунду? ) |
CALIBRATION_CYCLES | 100 | Кол-во циклов для усреднения значения при калибровке. |
SAMPLES_CNT | 8 | Кол-во циклов для усреднения при чтении времени заряда/разряда паразитной ёмкости. |
DEBUG_SORT_KEYS | false | Режим для генерации нового App::m_pins с правильной сортировкой. |
DEBUG_PRESS_KEYS | false | Режим отладки, при котором выводится текущее отклонение от калибровочного значения и дельта между нажатиями Используется для подбора порогов срабатывания и дебоунсинга. |
Все эти настройки можно найти в файле src/App.h
Исправления порядка клавиш
1. Сначала устанавливаем DEBUG_SORT_KEYS=true и подключаемся по USART.
2. Нажимаем все кнопки по очереди, слева на право.
3. Копируем содержимое структуры, которое вывело в USART.
4. Заменяем содержимое структуры App::m_pins в файле: src/App.cpp
Настройка чувствительности
1. Сначала устанавливаем DEBUG_PRESS_KEYS=true и подключаемся по USART.
2. Нажимает на интересующие клавиши.
3. Если что-то не нравится, меняем SENSOR_BLACK_KEY_THRESHOLD и SENSOR_WHITE_KEY_THRESHOLD до тех пор, пока не начнёт работать нормально.
4. Если нажатия троят, то увеличиваем DEBOUNCE_CYCLES (если тормозят, то уменьшаем).
Сборка прошивки
Для сборки необходим любой дистрибутив Linux. Хоть даже WSL под Windows.
Для сборки необходимо установить компилятор arm-none-eabi: https://developer.arm.com/downloads/-/gnu-rm
Его нужно распаковать в /opt и прописать в конец файла ~/.bashrc строчку вида:
Bash:
export PATH="$PATH:/opt/gcc-arm-none-eabi-10.3-2021.10/bin"
Bash:
git clone https://github.com/Azq2/stm32-sensor-midi-keyboard
cd stm32-sensor-midi-keyboard
git submodule init && git submodule update
./build_libopencm3.sh
make
Вы можете прошить один из этих файлов любым удобным для вас способом.
В случае использования Black Magic Probe достаточно выполнить команду:
Bash:
make install
Под Linux достаточно просто подключить по USB и всё сразу заработает
А вот что делать под OSX/Windows я честно говоря понятия не имею
В коде я использую стандартные pid/vid для DIY MIDI устройств:
Код:
Bus 001 Device 019: ID 16c0:05e4 Van Ooijen Technische Informatica Free shared USB VID/PID pair for MIDI devices
Репозиторий проекта на github: https://github.com/Azq2/stm32-sensor-midi-keyboard
Изменено: