[130] MIDI - język nie tylko instrumentów cz. 6
![[130] MIDI - język nie tylko instrumentów cz. 6](/_next/image?url=https%3A%2F%2Farduino.pl%2Fimgproxy%2Fe069zvTiAe8uz-gp0zsRjHhJ7EdKVrnrO0jRrOPJG-Q%2Ff%3Awebp%2Fw%3A1200%2FbG9jYWw6Ly8vaW1hZ2VzLzMwLTY4L2NlOGI3L2JiYTMzLzMwLTY4Y2U4YjdiYmEzMzU2NTg2ODU0ODYucG5n.webp&w=3840&q=75)
Jak pisałem w poprzednim artykule, dobry przełącznik sceniczny powinien mieć jakiś wskaźnik – najlepiej na diodzie świecącej. Zróbmy więc użytek z diody RGB, którą mam na płytce edukacyjnej TME, a każdy może sobie taką dołożyć. Jest pięć przycisków, więc będzie pięć kolorów: czerwony, pomarańczowy, zielony, niebieski i fioletowy. Są one jednoznaczne, ale jeśli ktoś chciałby mieć siedem przycisków, może zatrudnić jeszcze barwę turkusową i białą. I znowu pokombinujemy, by napisać obsługę kolorów nie na piechotę, jak to robiłem zwykle dotąd, a z wykorzystaniem kolejnych tablic.
const byte iloscKlawiszy = 5; // Liczba klawiszy.
const byte adresKlawiatury[] = { 5, 4, 8, 7, 6 }; // Adresy klawiszy.
const byte numerProgramu[] = { 0, 1, 2, 3, 4 }; // Numery programów przyporządkowane klawiszom w powyższej tablicy.
const byte adresRGB[] = { 9, 10, 11 }; // Adresy diod: R, G, B
const bool koloryRGB[5][3] = { // Pięć kolejnych stanów poszczególnych diod dla kolejnych numerów programów.
{ 1, 0, 0 },
{ 1, 1, 0 },
{ 0, 1, 0 },
{ 0, 0, 1 },
{ 1, 0, 1 }
};
void setup() {
Serial.begin(31250); // Inicjuj port z nietypową szybkością 31250 bps
for (byte x = 0; x < iloscKlawiszy; x++) // Dla każdego pstryczka...
pinMode(adresKlawiatury[x], INPUT_PULLUP); // Deklaruj pin jako wejście podciągnięte wewnętrznie do wysokiego stanu.
for (byte x = 0; x < 3; x++) // Dla każdej diody...
pinMode(adresRGB[x], OUTPUT); // Deklaruj pin jako wyjście.
Serial.write(192); // Wyślij komunikat "zmień program" na kanale pierwszym.
Serial.write(numerProgramu[0]); // Wyślij zerowy numer programu.
digitalWrite(adresRGB[0], koloryRGB[0][0]); // Ustaw kolor diod świecących dla zerowego programu.
}
void loop() {
for (byte x = 0; x < iloscKlawiszy; x++) // Wybieraj kolejne klawisze.
if (digitalRead(adresKlawiatury[x]) == HIGH) { // Jeśli kolejny przycisk został wciśnięty...
Serial.write(192); // Wyślij komunikat "zmień program" na kanale pierwszym.
Serial.write(numerProgramu[x]); // Wyślij numer programu.
for (byte y = 0; y < 3; y++) // Wybieraj kolejne diody świecące.
digitalWrite(adresRGB[y], koloryRGB[x][y]); // Ustaw stany diod według klucza z tablicy.
delay(50); // Zabezpieczenie na drgające styki.
while (digitalRead(adresKlawiatury[x]) == HIGH) {} // Czekaj aż przycisk zostanie puszczony.
delay(50); // Zabezpieczenie na drgające styki.
}
}
Podstawą będzie oczywiście szkic poprzedni. Zadeklarujemy dodatkowe dwie tablice: pierwsza adresRGB będzie zawierać adresy pinów, do których podłączę diody świecące – to już znamy, bo jest bliźniacze tablicy z adresami przycisków. Druga koloryRGB będzie nowością, bo to tablica dwuwymiarowa. Pierwszy wymiar ma pięć pozycji, dla każdego pstryczka własną. Drugi – trzy i opisuje stan każdej z diod dla kolejnych pstryczków. Tablice wielowymiarowe muszą mieć zadeklarowane wymiary, więc nie możemy zostawić nawiasów pustych.
const bool koloryRGB[5][3] = { // Pięć kolejnych stanów poszczególnych diod dla kolejnych numerów programów.
{ 1, 0, 0 },
{ 1, 1, 0 },
{ 0, 1, 0 },
{ 0, 0, 1 },
{ 1, 0, 1 }
};
Spójrzmy na dane: pierwsza kolumna to kolor czerwony, druga – zielony, trzecia – niebieski. Jadąc od góry możemy sobie zaprogramować kolory dla wszystkich programów. W części wstępnej programu oprócz stworzenia bliźniaczej pętli deklarującej porty ledów, postanowiłem wstępnie wybierać zerowy program i zapalać zerowego reprezentanta. Po co? Żeby cokolwiek po resecie się zaświeciło. Inaczej do momentu zmiany programu mielibyśmy diodę zgaszoną.
W głównej pętli pojawiła się dodatkowa pętla, która wybiera kolor diody RGB dla konkretnego numeru programu. Zauważmy, że zmienna x jest tutaj indeksem, czyli wartością wybranego programu, więc w pętli sterującej diodami musimy powołać do życia kolejną zmienną – y. Teraz y będzie wybierało po kolei diodę czerwoną, zieloną i niebieską, które będą zapalane bądź gaszone według indeksu x.

I to wszystko, po kompilacji całość pracuje jak poprzednio, dodatkowo informując nas o wybranym programie kolorem. To jest już jak najbardziej użyteczny przełącznik, ale uczyńmy jeszcze jeden, korzystając z wyświetlacza siedmiosegmetowego, który mam na płytce. W tym projekcie założenia będą następujące: dwa przyciski: w górę i w dół i 9 zapętlonych programów. Do roboty więc. Na początek odkopię stary szkic, który obsługiwał mi ósemkę siedzącą na brzegu płytki.
#include <Adafruit_MCP23008.h> // Dołącz bibliotekę sterującą układem MCP23008
Adafruit_MCP23008 ekspander; // Nadaj układowi nazwę "ekspander".
const byte pstryczekMinus = 4; // Adres pstryczka zmniejszającego numer programu.
const byte pstryczekPlus = 7; // Adres pstryczka zwiększającego numer programu.
const byte wyswietlacz[] = // Tablica zawierająca wzorce znaków wyświetlacza siedmiosegmentowego.
{
B0000110, // 1, połączenia: G-F-E-D-C-B-A
B1011011, // 2
B1001111, // 3
B1100110, // 4
B1101101, // 5
B1111101, // 6
B0000111, // 7
B1111111, // 8
B1101111, // 9
};
byte program = 0; // Numer aktualnego programu.
void setup() {
Serial.begin(31250); // Inicjuj port z nietypową szybkością 31250 bps
pinMode(pstryczekMinus, INPUT_PULLUP); // Deklaruj linie pstryczków jako wejścia podciągnięte wewnętrznie do wysokiego stanu.
pinMode(pstryczekPlus, INPUT_PULLUP);
ekspander.begin(36); // Inicjuj bibliotekę sterującą układem MCP23008 pod adresem 0x4
for (byte x = 0; x < 8; x++) // Zadeklaruj wszystkich osiem portów...
ekspander.pinMode(x, OUTPUT); // Jako wyjścia.
wyslij(); // Po resecie ustaw program pierwszy.
}
void loop() {
if (digitalRead(pstryczekPlus) == HIGH && program < 8) { // Jeśli wciśnięto plus i numer programu jest mniejszy od 8...
program++; // Zwiększ numer programu.
wyslij(); // Wyślij numer programu i wyświetl jego stan.
while (digitalRead(pstryczekPlus) == HIGH) {} // Czekaj aż przycisk zostanie puszczony.
delay(50); // Zabezpieczenie na drgające styki.
}
if (digitalRead(pstryczekMinus) == HIGH && program > 0) { // Jeśli wciśnięto minus i program jest większy od 0...
program--; // Zmniejsz numer programu.
wyslij(); // Wyślij numer programu i wyświetl jego stan.
while (digitalRead(pstryczekMinus) == HIGH) {} // Czekaj aż przycisk zostanie puszczony.
delay(50); // Zabezpieczenie na drgające styki.
}
}
void wyslij() { // Procedura zmieniająca program i wyświetlająca jego numer.
Serial.write(192); // Wyślij komunikat "zmień program" na kanale pierwszym.
Serial.write(program); // Wyślij numer programu.
for (byte x = 0; x < 7; x++) // Dla każdego segmentu wyświetlacza...
ekspander.digitalWrite(x, bitRead(wyswietlacz[program], x)); // Ustawiaj bit według wzorców z tablicy.
delay(50); // Zabezpieczenie na drgające styki.
}
Ponieważ mój wyświetlacz jest podłączony do ekspandera I2C, będziemy potrzebować biblioteki obsługi tej kostki. Na ten temat napisałem wiele we wspomnianym artykule, zatem dziś tylko krótko: musimy zadeklarować nazwę dla obiektu ekspander oraz zainicjować wszystkie piny kostki jako wyjścia.
Zadeklaruję także tablicę z wyglądem cyferek – od jedynki do dziewiątki. Wzorce pożyczyłem sobie ze wspomnianego szkicu. W pętli głównej mamy dwa bliźniacze warunki: na sprawdzanie obu przycisków. Akcja jednego wykona się po wciśnięciu plusa i wtedy, gdy numer aktualnego programu nie jest większy od ósemki. W drugim – podobnie, z tym że wciskamy minus i badamy, czy numer programu wciąż jest większy od zera.
Gdy warunki są akceptowalne, zwiększamy bądź zmniejszamy wartość programu, wysyłamy go, a także jego reprezentację na wyświetlacz. Tutaj należy pobrać stan każdego z siedmiu segmentów (siedmiu, gdyż kropkę zignorowałem) i wysłać go zgodnie z wartością bieżącego programu. Dlatego jest to zmienna globalna, dzięki czemu nie trzeba jej przekazywać do podprogramu. I na dziś to już wszystko. Taki przełącznik może być bardzo użyteczny na scenie. A jeszcze bardziej w wersji bateryjnej – oszczędnej – ale o tym napiszę innym razem.