Самодельный MIDI Controller (6 онлайн)

dim3740

Active Member
28 Фев 2013
385
67
28
Уфа
@Astranome, Ваш подход мне очень нравится)) с STM немного поигрался, очень классно, кроме библиотек или умения их искать. Исключительно инертность заставляет меня клепать приборы по старинке на Ардуинках. Ну и гуру наверное мне нужен... Может все же начну портацию, и попрошу помощи. Удачи и развития!

Ваш проект в IDE не открывается. Правда, у меня не стоит поддержка плат STM, но это же не имеет значения.
 

Gregory

Active Member
17 Май 2005
478
49
28
54
Санкт-Ленинград
www.dubrovenko.ru
Ну давайте, пройдите испытания
Ну давайте, пройдите испытания для Эзернета опираясь исключительно на схемотехнику.


Рекомендовано во всех учебниках и даташитах
Очень любите повторять данную фразу.
Плиз, конкретные ссылки?


весьма дорогая стрельба
Так, шашечки, или ехать?
Специализированные устройства и есть - вещь весьма дорогая.

не судьба поискать?
С завтрашнего дня беру отпуск за свой счёт и сажусь за поиск! :Dle76:
Вы серьёзно полагаете, что мне больше заняться нечем?



резистор дает бОльший диапазон работоспособных напряжений за счет обратной связи
Вадим!
Если Вы используете для транзистора напряжение большее, чем напряжение питания выходного буфера, используйте буфер с OD.
Судя по сказанному, Вы используете обычный пуш-пулл, и пытаетесь дополнительным резистором повысить запирающее напряжение на базе.
Но, напряжение на базе - напряжение на выходе буфера (хоть и через резистор).
Поэтому, либо OD, либо питайте одинаковым напряжением.


не ставят там обычные оптопары
Как же не ставят?
Выше приводил ссылку с вариантами от различных производителей.




Речь, если я правильно понял, об адресных светодиодах.
Там всё малость не так.
 

Rst7

Well-Known Member
10 Янв 2010
1.846
1.869
113
48
Kharkiv-city
Ну давайте, пройдите испытания для Эзернета опираясь исключительно на схемотехнику.
Какое именно испытание? Тип? нс/мкс/статразряд/радиоизлучение?

В общем-то проходил все, не особо морочась с разводкой. С микросекундными помехами, конечно, тяжело, типичные широкораспространенные ограничители на вторичной стороне (в виде сборок супрессоров возле PHY) с большой вероятностью выстреливали. Но оставшийся безвестным какой-то из зачинателей пионернетов когда-то изобрел грозозащиту для эзернета при помощи банальных диодов 1N4007, которая микросекундные помехи держит аж бегом, а 20пФ емкости диодов очень даже ок придавливает наносекундные помехи.

Плиз, конкретные ссылки?
Ну же, табличка из банального Х-Х:
220222


У нас процессор 3.3В, что есть "HC/AC при 3.3В" по вертикали (т.е. "от").
По горизонтали у нас "к". Смотрим там
HCT/ACT - "ОК"
HC/AC - "NO".

Ч.Т.Д.

И вообще, там прямо в Х-Х есть глава "Сопряжение цифровых и аналоговых сигналов", а в ней целый подраздел про разную логику. Все разжевано для студентов.

В общем, я все сказал, и можете более не утруждать себя еще какими-либо вопросами/претензиями/etc ко мне, отвечать не буду.
 

Astranome

New Member
17 Сен 2022
9
0
1
58
@Astranome, Ваш подход мне очень нравится)) с STM немного поигрался, очень классно, кроме библиотек или умения их искать. Исключительно инертность заставляет меня клепать приборы по старинке на Ардуинках. Ну и гуру наверное мне нужен... Может все же начну портацию, и попрошу помощи. Удачи и развития!

Ваш проект в IDE не открывается. Правда, у меня не стоит поддержка плат STM, но это же не имеет значения.
Наверное, имя файла длинное или содержит запрещённые символы.
Вот листинг , попробуйте скопировать и вставить в новый файл проекта :

///// https://github.com/astranome/MIDI-Controller-on-STM32 /////
#include <Arduino.h>
#include <USBComposite.h>
#include <Wire.h>
#include <LiquidCrystal_I2C_STM32.h> // https://github.com/lightcalamar/LiquidCrystal_I2C_STM32
LiquidCrystal_I2C_STM32 lcd(0x3E, 16, 2); // Устанавливаем дисплей

USBMIDI midi;
// Pin Definitions //
/////////////////////////////////
const uint8 pot_pin = 5;
const uint8 pot_pin0 = 0;
const uint8 pot_pin1 = 1;
const uint8 pot_pin2 = 2;
const uint8 pot_pin3 = 3;
const uint8 pot_pin4 = 4;
const int selectPins[3] = {9, 6, 7}; // S0~PA9, S1~PA6, S2~PA7
const uint8 zInput = PB1; //A11; // Connect common (Z) to B1 (analog input)
const uint8 BUTTON1 = PB3; //1
const uint8 BUTTON2 = PB4; //2
const uint8 BUTTON3 = PB5; //3

unsigned int Val = 0;
unsigned int Val_7 = 0;
unsigned int Val_6 = 0;

int buttonState1 = LOW;
int buttonState2 = LOW;
int buttonState3 = LOW;

int buttonPrevState1 = LOW;
int buttonPrevState2 = LOW;
int buttonPrevState3 = LOW;

const uint8 threshold = 2;

const unsigned int midi_channel =6; // this might show up as channel 6 depending on start index
const unsigned int midi_channel0 = 1;
const unsigned int midi_channel1 = 2;
const unsigned int midi_channel2 = 3;
const unsigned int midi_channel3 = 4;
const unsigned int midi_channel4 = 5;



const unsigned int cc_command = 7; // bank select command 0
const unsigned int cc_command6 = 71; // bank select command 0
const unsigned int cc_command7 = 74; // bank select command 0


unsigned int old_value = 0;
unsigned int new_value = 0;
unsigned int old_value0 = 0;
unsigned int new_value0 = 0;
unsigned int old_value1 = 0;
unsigned int new_value1 = 0;
unsigned int old_value2 = 0;
unsigned int new_value2 = 0;
unsigned int old_value3 = 0;
unsigned int new_value3 = 0;
unsigned int old_value4 = 0;
unsigned int new_value4 = 0;
unsigned int old_valMux6 = 0;
unsigned int new_valMux6 = 0;
unsigned int old_valMux7 = 0;
unsigned int new_valMux7 = 0;

void setup() {
Serial.begin(9600); // Initialize the serial port
// product id taken from library example
USBComposite.setProductId(0x0031);

pinMode(pot_pin, INPUT);
pinMode(pot_pin0, INPUT);
pinMode(pot_pin1, INPUT);
pinMode(pot_pin2, INPUT);
pinMode(pot_pin3, INPUT);
pinMode(pot_pin4, INPUT);

pinMode(BUTTON1, INPUT_PULLUP);
pinMode(BUTTON2, INPUT_PULLUP);
pinMode(BUTTON3, INPUT_PULLUP);

// Set up the select pins as outputs:

for (int i=0; i<3; i++)
{
pinMode(selectPins, OUTPUT);
digitalWrite(selectPins, HIGH);
}

pinMode(zInput, INPUT); // Set up Z as an input

midi.begin();
delay(1000);
//-------------- Init display ----------------
lcd.begin();
lcd.backlight();// Включаем подсветку дисплея
lcd.print(" MIDI Controller ");
lcd.setCursor(0, 1);
lcd.print(" LCD 1602 ");
delay(1500);
lcd.noBacklight();// Выключаем подсветку дисплея
delay(100);
lcd.backlight();// Включаем подсветку дисплея
}

void loop() {

int temp = analogRead(pot_pin); // a value between 0-4095
int temp0 = analogRead(pot_pin0);
int temp1 = analogRead(pot_pin1); // a value between 0-4095
int temp2 = analogRead(pot_pin2);
int temp3 = analogRead(pot_pin3); // a value between 0-4095
int temp4 = analogRead(pot_pin4);
buttonState1 = digitalRead(BUTTON1);
buttonState2 = digitalRead(BUTTON2);
buttonState3 = digitalRead(BUTTON3);



new_value = temp / 32; // convert to a value between 0-127
new_value0 = temp0 / 32;
new_value1 = temp1 / 32; // convert to a value between 0-127
new_value2 = temp2 / 32;
new_value3 = temp3 / 32; // convert to a value between 0-127
new_value4 = temp4 / 32;
////////////////////////////////////////////////////////////////////////////////
if (buttonState1 != buttonPrevState1) {
button1Handler(); ///////////// Detecting pressing or releasing the button
}
if (buttonState2 != buttonPrevState2){
button2Handler();
}
if (buttonState3 != buttonPrevState3){
button3Handler();
}
////////////////////////////////////////////////////////////////////////////////////
///////////// reading values on multiplexed inputs ------------
selectMuxPin(7); // Select one at a time

int inputValue = analogRead(zInput); // and read Z

new_valMux7 = inputValue / 32;

// Serial.print("7 = ");
//Serial.println(Val_7);

selectMuxPin(6); // Select one at a time

int inputValue6 = analogRead(zInput); // and read Z

new_valMux6 = inputValue6 / 32;

////////////////////////////////////////////////////////////////////////////////////////////////

// If difference between new_value and old_value is grater than threshold mux 666666666666666
if (new_valMux6 > old_valMux6 && new_valMux6 - old_valMux6 > threshold ||
new_valMux6 < old_valMux6 && old_valMux6 - new_valMux6 > threshold) {
/////------------ sending a midi CC command ----------------
midi.sendControlChange(midi_channel0, cc_command6, new_valMux6);
lcd.clear();
lcd.print("CH00 CC");
lcd.print(cc_command6);
lcd.print(" val ");
lcd.print(new_valMux6);

//------------ Update old_value---------
old_valMux6 = new_valMux6;
}

// If difference between new_value and old_value is grater than threshold mux 77777777777
if (new_valMux7 > old_valMux7 && new_valMux7 - old_valMux7 > threshold ||
new_valMux7 < old_valMux7 && old_valMux7 - new_valMux7 > threshold) {
/////------------ sending a midi CC command ----------------
midi.sendControlChange(midi_channel0, cc_command7, new_valMux7);
lcd.clear();
lcd.print("CH00 CC");
lcd.print(cc_command7);
lcd.print(" val ");
lcd.print(new_valMux7);



//----------- Update old_value --------------
old_valMux7 = new_valMux7;
}


// If difference between new_value and old_value is grater than threshold
if (new_value > old_value && new_value - old_value > threshold ||
new_value < old_value && old_value - new_value > threshold) {
/////------------ sending a midi CC command ----------------
midi.sendControlChange(midi_channel, cc_command, new_value);
lcd.clear();
lcd.print("CH06 CC");
lcd.print(cc_command);
lcd.print(" val ");
lcd.print(new_value);


// Update old_value
old_value = new_value;
}

// 00000 If difference between new_value6 and old_value6 is grater than threshold
if (new_value0 > old_value0 && new_value0 - old_value0 > threshold ||
new_value0 < old_value0 && old_value0 - new_value0 > threshold) {

midi.sendControlChange(midi_channel0, cc_command, new_value0);
lcd.clear();
lcd.print("CH01 CC");
lcd.print(cc_command);
lcd.print(" val ");
lcd.print(new_value0);

// Update old_value
old_value0 = new_value0;
}
// 1111 If difference between new_value1 and old_value1 is grater than threshold
if (new_value1 > old_value1 && new_value1 - old_value1 > threshold ||
new_value1 < old_value1 && old_value1 - new_value1 > threshold) {

midi.sendControlChange(midi_channel1, cc_command, new_value1);
lcd.clear();
lcd.print("CH02 CC");
lcd.print(cc_command);
lcd.print(" val ");
lcd.print(new_value1);

// Update old_value
old_value1 = new_value1;
}
// 2222 If difference between new_value2 and old_value2 is grater than threshold
if (new_value2 > old_value2 && new_value2 - old_value2 > threshold ||
new_value2 < old_value2 && old_value2 - new_value2 > threshold) {

midi.sendControlChange(midi_channel2, cc_command, new_value2);
lcd.clear();
lcd.print("CH03 CC");
lcd.print(cc_command);
lcd.print(" val ");
lcd.print(new_value3);

// Update old_value
old_value2 = new_value2;
}
// 3333 If difference between new_value3 and old_value3 is grater than threshold
if (new_value3 > old_value3 && new_value3 - old_value3 > threshold ||
new_value3 < old_value3 && old_value3 - new_value3 > threshold) {

midi.sendControlChange(midi_channel3, cc_command, new_value3);
lcd.clear();
lcd.print("CH04 CC");
lcd.print(cc_command);
lcd.print(" val ");
lcd.print(new_value3);

// Update old_value
old_value3 = new_value3;
}
// 4444 If difference between new_value4 and old_value4 is grater than threshold
if (new_value4 > old_value4 && new_value4 - old_value4 > threshold ||
new_value4 < old_value4 && old_value4 - new_value4 > threshold) {

midi.sendControlChange(midi_channel4, cc_command, new_value4);
lcd.clear();
lcd.print("CH05 CC");
lcd.print(cc_command);
lcd.print(" val ");
lcd.print(new_value4);

// Update old_value
old_value4 = new_value4;
}


// Wait 50ms before reading the pin again
delay(50);
}

// The selectMuxPin function sets the S0, S1, and S2 pins

// accordingly, given a pin from 0-7.

void selectMuxPin(byte pin)

{

for (int i=0; i<3; i++)

{

if (pin & (1<<i))

digitalWrite(selectPins, HIGH);

else

digitalWrite(selectPins, LOW);

}

}
/////------------ this function handles events that have occurred with buttons ----------------
void button1Handler() {
buttonPrevState1 = buttonState1;
//digitalWrite(LED1, buttonState1);
if (buttonState1 == HIGH) {
//Serial.println("Button 1 is pressed");
//-------- Sending Realtime category messages -----------
midi.sendStart();
lcd.clear();
lcd.print("Start");

}
}

void button2Handler() {
buttonPrevState2 = buttonState2;
//digitalWrite(LED1, buttonState2);

if (buttonState2 == HIGH) {
//Serial.println("Button 2 is pressed");
midi.sendStop();
lcd.clear();
lcd.print("Stop");
}
}

void button3Handler() {
buttonPrevState3 = buttonState3;
//digitalWrite(LED1, buttonState3);

if (buttonState3 == HIGH) {
//Serial.println("Button 3 is pressed");
//-------- Sending Realtime category messages -----------
midi.sendContinue();
lcd.clear();
lcd.print("Cont");
}
}
 

Astranome

New Member
17 Сен 2022
9
0
1
58
Я вот думаю, может проще отображение состояния контролов сделать только на экране? Экран божно взять достаточно большой. Или это будет неудобно для считывания глазом?
Не совсем понятно, какое именно устройство проектируете. Если это микшерский пульт, то кольцевые огоньки, несомненно, добавляют неповторимый антураж изделию, но смотреть на экран, где изображен пульт очень даже удобно, там еще и индикаторы уровня красиво прыгают и , самое главное, назначения крутилок подписано, не надо писать на полоске бумаги и приклеивать под крутилкой-энкодером.
Но вы, вероятнее всего, ваяете что то вроде аппаратной части виртуального МиниМуга от Артурии , И в этом случае смотреть на экран тоже удобно, а если во время игры нужно крутануть какой то эффект, типа частоты среза, то смотреть вообще никуда не надо.
ИМХО
 
Последнее редактирование:

Astranome

New Member
17 Сен 2022
9
0
1
58
Собираюсь добавить поддержку энкодеров и добавить 12 кнопочек, чтобы в случае чего использовать их как примитивную клавиатуру на 1 октаву. Вопрос знатокам: обязательно ли энкодеры вешать на прерывания (как это сказано в issue к проекту ControlSurface) ? А клавиатуру тоже желательно реалиазовывать , используя аппаратные прерывания? Но в UNO всего лишь 2 входа, поддерживающие прерывания, к примеру, как в таких случаях поступают, мультиплексор, чтоли подключают (а это вообще канает?) ? В STM32, слава создателям, любые ГПИО понимают прерывания, но всё же?
 

Gregory

Active Member
17 Май 2005
478
49
28
54
Санкт-Ленинград
www.dubrovenko.ru
проходил все, не особо морочась с разводкой
Мы тоже проходили, "особо не заморачиваясь", а потом повезли в гейопу, где не попали даже в промышленные допуски, после чего стали всё-таки заморачиваться. :Dle18:


табличка из банального Х-Х
Сейчас не могу добраться до своего бумажного издания, но допустим, что опечаток нет.
У нас такой затянувшийся спор, что я уже подзабыл первопричину.
Ну не согласуется 3-вольтовый КМОП с 5-вольтовым. Разве кто-то об этом спорил?
А вот с 3-вольтовым согласуется. И таблица тому подтверждение.
Но меня-то больше интересовали как-раз даташиты (в которых 40 лет рекомендуют).
P.S.: Нашёл начало дискуссии: всё началось с Вашего утверждения, что в МИДИ надо обязательно подавать 5V.
Затем перешли на 5V АТМегу, которую надо подключать исключительно через HCT (хотя даже приведённая Вами таблица указывает обратное).
Потом вообще ударились в обсуждение проблем ЭМС (отойдя от МИДИ к "специализированным устройствам").
Так и собственно, при чём тут 3V КМОП? :Dle76:


отвечать не буду
"Не подходи ко мне! Я обиделась!" :Dle75:



Там каждый светодиод, как отдельное адресное управляемое устройство.
На него подаётся питание, а управляется по последовательному интерфейсу (один на все светодиоды).
Сейчас попробую статейку найти на эту тему.
Только я пока не очень понял, что сэр user811 с ними делать хочет?
Вот статейка (там ещё ссылки есть).
 

Rst7

Well-Known Member
10 Янв 2010
1.846
1.869
113
48
Kharkiv-city
Затем перешли на 5V АТМегу, которую надо подключать исключительно через HCT (хотя даже приведённая Вами таблица указывает обратное).
Покажите пальцем, где я это говорил:
буфер питается от 5В. Если питание процессора 3.3В, то порог буфера должен быть примерно 1.6В, что соответствует TTL-порогу, а значит - нужен именно HCT. А вот если процессор тоже пятивольтовый, то нужен порог у буфера в районе 2.5В, что соответствует HC.
Специально для Вас выделил.

"Не подходи ко мне! Я обиделась!"
Вы меня вынудили ответить, к сожалению. Ибо не люблю, когда мои слова перевирают.
 

Rst7

Well-Known Member
10 Янв 2010
1.846
1.869
113
48
Kharkiv-city
Ну так, чтобы уже закрыть тему.

Но меня-то больше интересовали как-раз даташиты
По быстрому нашел довольно старый Logic Selection Guide от TI - http://layer.uci.agh.edu.pl/~maglay/wrona/pl/podstrony/dydaktyka/Technika_Cyfrowa/Bramki/sdyu001m.pdf

Начиная со страницы 28 и на странице 31 таблица, аналогичная таблице в Х-Х.

Искать еще более ранние версии мне лень. Если что, второе издание Х-Х (оригинальное на английском имеется в виду, таблица взята из русского перевода) - оно 1989 года, а взяты все эти таблицы у них из даташитов и user manual'ов производителей (о чем в авторском предисловии всех изданий прямо указано). Так что точно более 33х лет этой таблице.
 

mrf

Well-Known Member
19 Сен 2013
369
348
63
Екатеринбург
Но такие кольца явно избыточны: не вижу, для чего можно использовать RGB-многоцветие, а главное, такие адресные диоды WS2812
слишком мощные и много потребляют. Они скорее осветительные, чем индикаторные.
работаю с какими-то подобными адресными на индикации. в софте преобразование HSV-RGB
никто не заставляет использовать полную шкалу яркости и все цвета разом, можно же просто задавать один цвет. к примеру у меня внутри прибора шкала полная, но на выходе все пропускается через параметр общей яркости, который настроен примерно на 1/16. если по току ограничение, то можно просто не позволять поднимать это значение выше определенного.
H-S можно использовать для индикации страницы параметров
V - для интерполяции между двумя светодиодами (сабпиксель)
на мой взгляд нет ничего удобнее, не нужно никакие матрицы разводить, драйвера-транзисторы ставить, никаких сдвиговых регистров.
из минусов разве что более навороченный софт управления, и нагрузка на контроллер, но если не писать это на высокоуровневых стеках под ардуину, то проблем никаких.
вообщем я бы советовал использовать эти кольца, ,т.к. больший простор для экспериментов с интерфейсом. а еще кстати, у большой яркости есть плюс, что на панель можно поставить протравленную стеклотекстолитину, и просвечивать ее сзади (на еврорековых модулях такое можно встретить иногда).
 

soundpro

Well-Known Member
4 Май 2006
1.808
1.136
113
Там каждый светодиод,
Я знаю как работаю эти светодиоды Много чего ваял с ws28xx. Яркостью там управляет ШИМ, в каждом чипе. Поэтому энергопотребление, о чём переживает ТС, можно в расчет не брать. Только это хотел сказать.
 

Astranome

New Member
17 Сен 2022
9
0
1
58
Конечно, дико извиняюсь, но слово "спойлер" Вам о чём-нибудь говорит?
Я настолько тупой, что не знаю, как здесь отредактировать или вовсе удалить своё сообщение, а вы про какие то антикрылья спойлеры выговариваете...
 

Gregory

Active Member
17 Май 2005
478
49
28
54
Санкт-Ленинград
www.dubrovenko.ru
где я это говорил:
Каюсь, сорри!
Из серии: думал об одном, написАл другое.
Конечно же всё с точностью до наоборот.
А говорили начиная с этой страницы.
Кстати, могли бы и Сами понять, что описка, а не корчить обиженного.
Я же не юродствую, что Вы вместо вопросительного знака двоеточие поставили, и по правилам грамматики русского языка, я должен "тыкать пальцем" совсем в другую ссылку. :Dle26:
Так и собственно, при чём тут 3V КМОП?


аналогичная таблице в Х-Х
Опять Вы за своё: всё доказываете, что 3-вольтовый КМОП с 5-вольтовым не согласуется, хотя никто об этом, вроде, и не спорит.
Где сказано, что использование HCT в качестве транслятора уровней - "самый правильный способ"? :Dle13:


Вы меня вынудили
Разумеется, Вы виноватым быть не можете.



о чём переживает ТС
Он переживает, но не очень, ибо не ТС. :Dle18:
А Вы уверены насчёт ШИМа.
Я, честно говоря, собственно только протокол управления подробно смотрел.
Ибо штука, конечно, занимательная, но как-то я придумал только пару вариантов использования, где бы получался выигрыш по сравнению с обычными РГБ (или даже монохромными), а реализация протокола управления (без специализированных микросхем) довольно геморройная.



у некоторых автомобилей
Так зачем Вы тогда здесь постите?
И шли бы на форум автолюбителей.
:Dle76:
 

Rst7

Well-Known Member
10 Янв 2010
1.846
1.869
113
48
Kharkiv-city
Кстати, могли бы и Сами понять, что описка, а не корчить обиженного.
Ну хватит, уважаемый, уже возить птичий помет по емкостям для стирки. Описка бывает в одном слове, а когда там целая фраза построена - это не описка, а заведомо ложное высказывание. Вот оно:
Затем перешли на 5V АТМегу, которую надо подключать исключительно через HCT (хотя даже приведённая Вами таблица указывает обратное).
Все, счастливо оставаться. В игноре.
 

Gregory

Active Member
17 Май 2005
478
49
28
54
Санкт-Ленинград
www.dubrovenko.ru
заведомо ложное высказывание
"Где бы что ни говорили, всё одно сведёт на баб".
Разумеется, всё так и есть.
Кроме того, оно долго и тщательно разрабатывалось и готовилось.
Всё же жаль, что мы так и не услышали начальника транспортного цеха ответа на один простой вопрос.
Видимо потому, что нет его (ответа). :Dle75:


Это типа, я теперь могу про Вас всякие гадости писАть, а Вы их даже видеть не будете? :Dle26:
Мудрое решение!
P.S.: Эдак Вы скоро пол форума в игноры отправите...
 

Сейчас онлайн (Пользователей: 0, Гостей: 6)