• Witaj na Forum Arduino Polska! Zapraszamy do rejestracji!
  • Znajdziesz tutaj wiele informacji na temat hardware / software.
Witaj! Logowanie Rejestracja


Ocena wątku:
  • 0 głosów - średnia: 0
  • 1
  • 2
  • 3
  • 4
  • 5
Problem z portem USB MIDI w Arduino LEONARDO
#1
Szanowni koledzy.
Widzę że będę musiał Was poprosić o pomoc albo jakąś sugestię.
Postanowiłem zrobić keyboard.
Skorzystałem z tego projektu (Projekr 1).

Oczywiście rozbudowałem go do matrycy 8x8.
Wgrałem szkic do Arduino UNO i wszystko ładnie zagrało.
Ale do tego potrzebne są na PC-ecie dwie aplikacje do wirtualnych portów, loopMIDI i hairless.
Wygodniej było by mi podłączyć USB i żeby komputer od razu go widział.
Wobec tego kupiłem sobie Arduino LEONARDO, ponieważ ma on USB natywne.
Niestety, po wgraniu tego szkicu komputer a ściśle programy, które grały
na UNO tutaj nie wydają żadnego dźwięku. Komputer widzi płytkę "Arduino Leonardo".
By się upewnić czy wszystko dobrze z płytką, wgrałem inny szkic z innego projektu (Projekt 2).
I on zagrał. tyle że jest to wersja bardzo uproszczona i mnie niezadowalająca, 16 dźwięków.

Być może jest to prosta sprawa ale nie mogę sobie z tym poradzić.
To prosił bym o jakąś radę albo sugestię w którym kierunku iść.
Chyba że w ogóle to nie jest możliwe.
Z góry dziękuję za zainteresowanie się moim projektem.

Załączam też szkice do obydwu tych projektów.


Załączone pliki Miniatury
       

.txt   Szkic 1.txt (Rozmiar: 6.31 KB / Pobrań: 14)
.txt   Szkic 2.txt (Rozmiar: 1.01 KB / Pobrań: 10)
 
Odpowiedź
#2
(29-02-2024, 09:55)RyGa napisał(a): Szanowni koledzy.
Widzę że będę musiał Was poprosić o pomoc albo jakąś sugestię.

Oczywiście rozbudowałem go do matrycy 8x8.

Komputer widzi płytkę "Arduino Leonardo".

Być może jest to prosta sprawa ale nie mogę sobie z tym poradzić.
To prosił bym o jakąś radę albo sugestię w którym kierunku iść.
Chyba że w ogóle to nie jest możliwe.
Z góry dziękuję za zainteresowanie się moim projektem.

Załączam też szkice do obydwu tych projektów.




Co widzi komputer jak wgrasz szkic 2?



Skoro pierwszy projekt rozbudowałeś sam do klawiatury matrycowej to wystarczy zrobić to samo z drugim projektem.

Wygląda jednak, że mniej roboty będzie jak weźmiesz projekt 1, zmienisz include na MIDIUSB.h i skopiujesz tam funkcje noteOn() i noteOff() z drugiego projektu, może jakieś proste dopasowanie kodu i powinno zadziałać.
 
Odpowiedź
#3
Dziękuję za szybką reakcję.
Jeśli chodzi o komputer to w UNO występuje jako USB-SERIAL CH340 a w LEONARDO w obu projektach jako "Arduino Leonardo". Jak już pisałem w pierwszym projekcie na LEONARDO nie działa z żadnym programem muzycznym MIDI.
Może i Twoja, oskarX rada jest dobra, ale może jej nie potrafię zastosować i dlatego w dalszym ciągu nie udaje mi się uruchomić płytki tak jak bym chciał.
W pierwszym projekcie na UNO działa przez porty wirtualne przez loopMIDI i hairless.
W drugim projekcie działa bezpośrednio przez USB i odrazu pracuje z programami muzycznymi.
Obydwa projekty są zbudowane na różnych kodach. Próba pogodzenia funkcji z obydwu kodów nie zabardzo mi wychodzi. Czy w jedną czy w drugą stronę. Wyskakuje za dużo błędów. A nie jestem na tyle obeznany w funkcjach i zawiłościach w programowaniu Arduino. Dlatego zamieściłem się w Piaskownicy.
Cały czas się edukuję i eksperymenuję. Prosząc o radę, chciałem pójść trochę na skróty.
Prosił bym jeszcze o inne sugestie i rady.
 
Odpowiedź
#4
Pierwszy szkic działa na Arduino UNO więc na Leonardo też powinien działać bez problemu jeżeli chodzi o klawiaturę matrycową. Różnica będzie tkwiła w sposobie komunikacji z komputerem. 

Na początek musisz w pierwszym skeczu dodać:
Kod:
#include "MidiUSB.h"


Midi to transmisja trzech danych: kanał, nuta, nacisk klawisza dlatego w pierwszym skeczu masz funkcję noteOn w postaci:
Kod:
void noteOn(int cmd, int pitch, int velocity) {
    Serial.write(cmd);
    Serial.write(pitch);
    Serial.write(velocity);
}

Program pcha przez seriala do kompa właśnie te trzy dane i stąd w kodzie dotyczącym poszczególnych klawiszy masz wywołania funkcji noteOn w postaci:
Kod:
      if (groupValue1 != 0 && !keyPressed[col]) {
           keyPressed[col] = true;
           noteOn(0x91, keyToMidiMap[col], noteVelocity);
      }

Jako kanał wszędzie użyta jest wartość 0x91, nuta jest określona w matrycy keyToMidiMap, a noteVelocity ma zadeklarowaną na początku kodu wartość 127.

W drugim kodzie działa to troszkę inaczej, ponieważ masz wykorzystywaną bibliotekę MidiUSB i funkcja noteOn ma towarzysza w postaci noteOff i ma postać:
Kod:
void noteOn(byte pitch) {
  MidiUSB.sendMIDI({0x09, 0x90, pitch, 127});
  MidiUSB.flush();
}

void noteOff(byte pitch) {
  MidiUSB.sendMIDI({0x08, 0x80, pitch, 0});
  MidiUSB.flush();
}
i w takiej formie ta funkcja powinna się znaleźć w pierwszym kodzie.

Wywołanie przy naciśnięciu klawisza powinno mieć najprawdopodobniej postać:
Kod:
if (groupValue1 != 0 && !keyPressed[col]) {
   keyPressed[col] = true;
   noteOn(keyToMidiMap[col]);
}


a po puszczeniu:
Kod:
if (groupValue1 == 0 && keyPressed[col]) {
   keyPressed[col] = false;
   noteOff(keyToMidiMap[col]);
}

Poniżej masz całość - kompiluje się poprawnie, ale czy działa tak jak powinno nie mam jak sprawdzić:
Kod:
#include <Keyboard.h>
#include "MIDIUSB.h"

const int row1 = 2;
const int row2 = 3;
const int row3 = 4;
const int row4 = 5;
const int row5 = 6;
const int row6 = 7;
const int row7 = 8;
const int row8 = 9;

const int clock = 10;
const int latch = 11;
const int data = 12;

uint8_t keyToMidiMap[64];

boolean keyPressed[64];

int bits[] = { B00000001, B00000010, B00000100, B00001000, B00010000, B00100000, B01000000, B10000000 };

void scanColumn(int value) {
    digitalWrite(latch, LOW);
    shiftOut(data, clock, MSBFIRST, value);
    digitalWrite(latch, HIGH);
}

void noteOn(byte pitch) {
    MidiUSB.sendMIDI({0x09, 0x90, pitch, 127});
    MidiUSB.flush();
}

void noteOff(byte pitch) {
    MidiUSB.sendMIDI({0x08, 0x80, pitch, 0});
    MidiUSB.flush();
}

void setup() {
    keyToMidiMap[0] = 43;
    keyToMidiMap[1] = 36;
    keyToMidiMap[2] = 37;
    keyToMidiMap[3] = 38;
    keyToMidiMap[4] = 39;
    keyToMidiMap[5] = 40;
    keyToMidiMap[6] = 41;
    keyToMidiMap[7] = 42;

    keyToMidiMap[8] = 51;
    keyToMidiMap[1 + 8] = 44;
    keyToMidiMap[2 + 8] = 45;
    keyToMidiMap[3 + 8] = 46;
    keyToMidiMap[4 + 8] = 47;
    keyToMidiMap[5 + 8] = 48;
    keyToMidiMap[6 + 8] = 49;
    keyToMidiMap[7 + 8] = 50;

    keyToMidiMap[16] = 59;
    keyToMidiMap[1 + 16] = 52;
    keyToMidiMap[2 + 16] = 53;
    keyToMidiMap[3 + 16] = 54;
    keyToMidiMap[4 + 16] = 55;
    keyToMidiMap[5 + 16] = 56;
    keyToMidiMap[6 + 16] = 57;
    keyToMidiMap[7 + 16] = 58;

    keyToMidiMap[24] = 67;
    keyToMidiMap[1 + 24] = 60;
    keyToMidiMap[2 + 24] = 61;
    keyToMidiMap[3 + 24] = 62;
    keyToMidiMap[4 + 24] = 63;
    keyToMidiMap[5 + 24] = 64;
    keyToMidiMap[6 + 24] = 65;
    keyToMidiMap[7 + 24] = 66;

    keyToMidiMap[32] = 75;
    keyToMidiMap[1 + 32] = 68;
    keyToMidiMap[2 + 32] = 69;
    keyToMidiMap[3 + 32] = 70;
    keyToMidiMap[4 + 32] = 71;
    keyToMidiMap[5 + 32] = 72;
    keyToMidiMap[6 + 32] = 73;
    keyToMidiMap[7 + 32] = 74;

    keyToMidiMap[40] = 83;
    keyToMidiMap[1 + 40] = 76;
    keyToMidiMap[2 + 40] = 77;
    keyToMidiMap[3 + 40] = 78;
    keyToMidiMap[4 + 40] = 79;
    keyToMidiMap[5 + 40] = 80;
    keyToMidiMap[6 + 40] = 81;
    keyToMidiMap[7 + 40] = 82;

    keyToMidiMap[48] = 91;
    keyToMidiMap[1 + 48] = 84;
    keyToMidiMap[2 + 48] = 85;
    keyToMidiMap[3 + 48] = 86;
    keyToMidiMap[4 + 48] = 87;
    keyToMidiMap[5 + 48] = 88;
    keyToMidiMap[6 + 48] = 89;
    keyToMidiMap[7 + 48] = 90;

    keyToMidiMap[56] = 99;
    keyToMidiMap[1 + 56] = 92;
    keyToMidiMap[2 + 56] = 93;
    keyToMidiMap[3 + 56] = 94;
    keyToMidiMap[4 + 56] = 95;
    keyToMidiMap[5 + 56] = 96;
    keyToMidiMap[6 + 56] = 97;
    keyToMidiMap[7 + 56] = 98;

    pinMode(data, OUTPUT);
    pinMode(clock, OUTPUT);
    pinMode(latch, OUTPUT);

    pinMode(row1, INPUT);
    pinMode(row2, INPUT);
    pinMode(row3, INPUT);
    pinMode(row4, INPUT);
    pinMode(row5, INPUT);
    pinMode(row6, INPUT);
    pinMode(row7, INPUT);
    pinMode(row8, INPUT);

    Serial.begin(38400);

    delay(1000);
}

void loop() {
    for (int col = 0; col < 8; col++) {

        scanColumn(bits[col]);

        int groupValue1 = digitalRead(row1);
        int groupValue2 = digitalRead(row2);
        int groupValue3 = digitalRead(row3);
        int groupValue4 = digitalRead(row4);
        int groupValue5 = digitalRead(row5);
        int groupValue6 = digitalRead(row6);
        int groupValue7 = digitalRead(row7);
        int groupValue8 = digitalRead(row8);

        if (groupValue1 != 0 || groupValue2 != 0 || groupValue3 != 0 || groupValue4 != 0 || groupValue5 != 0 || groupValue6 != 0 || groupValue7 != 0 || groupValue8 != 0) {

            if (groupValue1 != 0 && !keyPressed[col]) {
                keyPressed[col] = true;
                noteOn(keyToMidiMap[col]);
            }

            if (groupValue2 != 0 && !keyPressed[col + 8]) {
                keyPressed[col + 8] = true;
                noteOn(keyToMidiMap[col + 8]);
            }

            if (groupValue3 != 0 && !keyPressed[col + 16]) {
                keyPressed[col + 16] = true;
                noteOn(keyToMidiMap[col + 16]);
            }

            if (groupValue4 != 0 && !keyPressed[col + 24]) {
                keyPressed[col + 24] = true;
                noteOn(keyToMidiMap[col + 24]);
            }

            if (groupValue5 != 0 && !keyPressed[col + 32]) {
                keyPressed[col + 32] = true;
                noteOn(keyToMidiMap[col + 32]);
            }

            if (groupValue6 != 0 && !keyPressed[col + 40]) {
                keyPressed[col + 40] = true;
                noteOn(keyToMidiMap[col + 40]);
            }

            if (groupValue7 != 0 && !keyPressed[col + 48]) {
                keyPressed[col + 48] = true;
                noteOn(keyToMidiMap[col + 48]);
            }

            if (groupValue8 != 0 && !keyPressed[col + 56]) {
                keyPressed[col + 56] = true;
                noteOn(keyToMidiMap[col + 56]);
            }
        }

        if (groupValue1 == 0 && keyPressed[col]) {
            keyPressed[col] = false;
            noteOff(keyToMidiMap[col]);
        }

        if (groupValue2 == 0 && keyPressed[col + 8]) {
            keyPressed[col + 8] = false;
            noteOff(keyToMidiMap[col + 8]);
        }

        if (groupValue3 == 0 && keyPressed[col + 16]) {
            keyPressed[col + 16] = false;
            noteOff(keyToMidiMap[col + 16]);
        }

        if (groupValue4 == 0 && keyPressed[col + 24]) {
            keyPressed[col + 24] = false;
            noteOff(keyToMidiMap[col + 24]);
        }

        if (groupValue5 == 0 && keyPressed[col + 32]) {
            keyPressed[col + 32] = false;
            noteOff(keyToMidiMap[col + 32]);
        }

        if (groupValue6 == 0 && keyPressed[col + 40]) {
            keyPressed[col + 40] = false;
            noteOff(keyToMidiMap[col + 40]);
        }

        if (groupValue7 == 0 && keyPressed[col + 48]) {
            keyPressed[col + 48] = false;
            noteOff(keyToMidiMap[col + 48]);
        }

        if (groupValue8 == 0 && keyPressed[col + 56]) {
            keyPressed[col + 56] = false;
            noteOff(keyToMidiMap[col + 56]);
        }
    }
}
 
Odpowiedź
#5
Ja bym jeszcze dodał, że jeśli chcesz połączyć przyciski klawiatury muzycznej w matryce to musisz ją zabezpieczyć przed błędnym odczytem gdy przyciśniete są 3 lub więcej przycisków naraz - co zdarza się w muzyce. Na przykład można do każdego klawisza dodać diodę (w sumie 64 diody).
 
Odpowiedź
#6
Dziękuję bardzo. Biorę się za testowanie.
O diodach w matrycy wiem. Dziękuję.
 
Odpowiedź
#7
Może nie próbuj przeskakiwać etapów, na Leonardo najpierw zrób klawiaturę matrycową, są do tego gotowe biblioteki z przykładami. Jak już będziesz miał działające 64 przyciski to dopiero wróć do pożenienia tego z MIDI, to już prosta funkcja, odczyta jakieś wciśnięcie to dany przycisk wysyła z odpowiednim kodem MIDI.
Zwróć uwagę, że UNO ma SPI na pinach 11,12,13, a w Leonardo nie ma tego w tym miejscu, te piny są na złączu 6 pin do programowania. Z drugiej strony masz tak jakby 3 piny dodatkowe, 0 i 1 też nie jest podłączone do UART i też je tu można wykorzystać do matrycy, wiec w ogóle nie potrzebujesz scalaka rejestru przesuwnego, jeśli nic więcej nie podłączasz, masz 19 pinów I/O do dyspozycji.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#8
Dziękuję bardzo kolegom za pomoc szczególnie MadMrQ za poprawienie mojego kodu. Wszystko zadziałało. Mam teraz dobry punkt wyjścia do dalszej edukacji i dokładnej analizy, co i dlaczego. Wezmę też pod uwagę sugestie kolegi kaczakat.
 
Odpowiedź
#9
Cieszę się, że mogłem pomóc.
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości