[092] Przejmowanie kontroli nad urządzeniami - multiefekt gitarowy - cz. 5
![[092] Przejmowanie kontroli nad urządzeniami - multiefekt gitarowy - cz. 5](/_next/image?url=https%3A%2F%2Farduino.pl%2Fimgproxy%2FhScn1J81VCxxoQEH_wQDFSeL2fFkprC9AHGy715hE1M%2Ff%3Awebp%2Fw%3A1200%2FbG9jYWw6Ly8vaW1hZ2VzLzBlLTY3Lzk5MDA2LzU5ZmI0LzBlLTY3OTkwMDY1OWZiNDI4MDYzNzAzNjcucG5n.webp&w=3840&q=75)
Sterownik już działa i obsługuje go sześć gałek. A gdybyśmy chcieli ich więcej? Ze względów czysto technicznych ATMEGA328 w obudowie klasycznej ograniczono do 28 nóżek. Wnętrze tego układu obsługuje jednak dodatkowe dwa piny analogowe: A6 i A7. Obudowa do montażu powierzchniowego ma już 32 nóżki i tam owe porty są udostępnione. Arduino Nano, Mini i wiele innych wykorzystuje ten układ, więc na krawędzi możemy znaleźć dodatkowe dwa wejścia analogowe, do których można podłączyć leniące się dotąd potencjometry. Obsługa tych pinów nie różni się niczym – jeśli będziemy je traktować jako wejścia analogowe, ale nic ponadto z nich nie wyciśniemy. Zatem przy alternatywnym traktowaniu całego portu jako wyjście cyfrowe, piny te trzeba zignorować. One spełniają tylko jedną funkcję, tutaj akurat przydatną.
Nie będę już rozbudowywał programu, pozostawiając to czytelnikom. Obsługa tych wejść jest identyczna. Nadajemy im kolejne nazwy: A6 i A7. Należy sobie wybrać kolejne dwa elementy regulowane. Proponuję obsługę kompresora i symulator przesterów. Kompresor jest prosty: wyłączenie efektu i 15 pozycji mocy kompresji. W przypadku symulacji przesterów mamy aż 101 pozycji: 11 różnych wzmacniaczy, symulację gitary akustycznej i wyłączenie efektu. Używając płytki Micro możemy podłączyć 12 potencjometrów, a Mega - 16. W tym wypadku to i tak za dużo, bo możemy tutaj wybierać 11 elementów plus głośność. Program wyglądałby podobnie, tylko należałoby dopisać kolejne bloki.

Na koniec tego cyklu przedstawię projekt, który zbudowałem kilka lat temu i który służy mi na co dzień. Jest to gitarowy piecyk zasilany trzema akumulatorami 18650, z wbudowanym multiefektem Zooma tym razem, który sterowany jest zgodnie z ideą przedstawioną w ostatnich odcinkach, przy czym użyłem tutaj nie potencjometrów, a enkoderów. Ponieważ jest ich tu 13, potrzebowałem płytki z większą ilością pinów i wybór padł na tanią i bogatą w zasoby płytkę o zwyczajowej nazwie Bluepill – zapewne od koloru, w których te płytki występują. Przede wszystkim mamy tutaj 32-bitowy układ ARM, 64 kB pamięci FLASH i 20 kB RAM-u. Pinów mamy aż 32, przy czym wejść analogowych dostajemy dziesięć – dwunastobitowych.
Użycie tej płytki wymaga zaciągnięcia środowiska związanego z kontrolerami STM i wybrania posiadanej płytki, wraz z ustawieniem niezbędnych parametrów. Mogą się one nieco różnić w zależności od serii i od sprzedawcy powinniśmy otrzymać szczegóły ustawień. Trzeba uważać na sporą ilość podróbek. Sam stałem się posiadaczem takiego układu, w którym nie chciały pracować przetworniki analogowo-cyfrowe.
W tym przypadku mamy sytuację podobną do monitora, który hackowaliśmy w pierwszych odcinkach serii. Wybór edytowanego parametru pierwotnie realizowany jest potencjometrem z zapadkami, udającym przełącznik. Nasz sterownik tym razem generuje napięcia interpretowane przez multiefekt za pomocą wyjścia PWM. Napięcie to filtruję za pomocą prostego filtru drugiego rzędu, który składa się z dwóch rezystorów 1kR i dwóch kondensatorów 1uF zwierających składową zmienną do masy. W każdym bloku, w komentarzu opisałem środek napięcia interpretowanego przez multiefekt jako wybierające dany parametr. Nie będę analizował samego programu, tym bardziej, że jest on napisany w moim prywatnym „narzeczu”, czyli niezgodnym ze standardami zagęszczeniu kodu. Dla mnie taki sposób jest bardziej czytelny, jednak wystarczy wcisnąć Ctrl-T, by składnia przybrała postać standardową. Tak naprawdę wobec klasycznych płytek Arduino mamy tutaj niewiele zmian i dotyczą one nazewnictwa pinów. Oczywiście ta płytka może dużo więcej od ośmiobitowego Arduino. Należy też brać pod uwagę wszelkie działania wykraczające poza to, co zdefiniowano w składni Arduino, czyli na przykład zmianę częstotliwości pracy PWM, której potrzeba zupełnie innych parametrów. Do tej płytki kiedyś pewno powrócę, dziś tylko wrzucam temat jako ciekawostkę, wraz z listingiem, który także tak proszę traktować (acz program ten działa z powodzeniem).
#include // Sterownik enkoderowy do multiefektu Zoom G1n, wersja dla procesora STM32F103C8T6
const byte EncAL=PB4;
const byte EncAR=PB5;
const byte EncBL=PB6;
const byte EncBR=PB7;
const byte EncCL=PB9;
const byte EncCR=PB8;
const byte EncDL=PA15;
const byte EncDR=PB3;
const byte EncEL=PB1;
const byte EncER=PB10;
const byte EncFL=PA7;
const byte EncFR=PB0;
const byte EncGL=PA6;
const byte EncGR=PA5;
const byte EncHL=PB12;
const byte EncHR=PB11;
const byte EncIL=PB13;
const byte EncIR=PB14;
const byte EncJL=PB15;
const byte EncJR=PA8;
const byte EncKL=PC14;
const byte EncKR=PC15;
const byte EncLL=PA1;
const byte EncLR=PA2;
const byte EncML=PA3;
const byte EncMR=PA4;
const byte Select=PA0; // wyjście PWM na potencjometr G1N wybierający parametr, filtrować drugim rzędem: Arduino-1k-1u-1k-1u-G1n
const byte ValueL=PA10; // wyjście L na enkoder G1N wybierający wartość parametru, podłączyć bezpośrednio: Arduino-220-G1n
const byte ValueR=PA9; // wyjście R na enkoder G1N wybierający wartość parametru, podłączyć bezpośrednio: Arduino-220-G1n
const byte Led=PC13; // Led BUSY (równoległa do wbudowanej, opcjonalna)
const byte Service=PA14; // Przycisk serwisowy - L: dostęp do głośności ogólnej (EncB) i programu (EncD), H: normalna praca (SWCLK)
//const byte Reserve1=PA11; // (USB+)
//const byte Reserve2=PA12; // (USB+)
//const byte Reserve3=PA13; // (SWDIO)
//const byte Reserve4=PB2; // (BOOT1)
const int DelayLong=300; // Opóźnienie pomiędzy zmianą kolejnych parametrów, dobrać żeby nie zmieniało pośrednich parametrów dla skrajnych: wybór programu i DECAY
const byte DelayShort=2; // Opóźnienie pomiędzy zmianą kolejnych wartości parametru, dobrać żeby nie przeskakiwał enkoder
const long Return=131072; // Czas autopowrotu do wyświetlania i dostępu do numeru programu, dobrać dla wygody
byte LastEnc=0; // Zmienna do identyfikacji enkodera
long Count=0; // Licznik autopowrotu do wyświetlania i dostępu do numeru programu
byte x=0; // Zmienna uniwersalna
Rotary A=Rotary(EncAL,EncAR);
Rotary B=Rotary(EncBL,EncBR);
Rotary C=Rotary(EncCL,EncCR);
Rotary D=Rotary(EncDL,EncDR);
Rotary E=Rotary(EncEL,EncER);
Rotary F=Rotary(EncFL,EncFR);
Rotary G=Rotary(EncGL,EncGR);
Rotary H=Rotary(EncHL,EncHR);
Rotary I=Rotary(EncIL,EncIR);
Rotary J=Rotary(EncJL,EncJR);
Rotary K=Rotary(EncKL,EncKR);
Rotary L=Rotary(EncLL,EncLR);
Rotary M=Rotary(EncML,EncMR);
void setup(){
pinMode(Select,PWM);
analogWrite(Select,0);
pinMode(ValueL,OUTPUT_OPEN_DRAIN);
digitalWrite(ValueL,1);
pinMode(ValueR,OUTPUT_OPEN_DRAIN);
digitalWrite(ValueR,1);
LastEnc=0;
Count=0;
x=0;
pinMode(EncAL,INPUT_PULLUP);
pinMode(EncAR,INPUT_PULLUP);
pinMode(EncBL,INPUT_PULLUP);
pinMode(EncBR,INPUT_PULLUP);
pinMode(EncCL,INPUT_PULLUP);
pinMode(EncCR,INPUT_PULLUP);
pinMode(EncDL,INPUT_PULLUP);
pinMode(EncDR,INPUT_PULLUP);
pinMode(EncEL,INPUT_PULLUP);
pinMode(EncER,INPUT_PULLUP);
pinMode(EncFL,INPUT_PULLUP);
pinMode(EncFR,INPUT_PULLUP);
pinMode(EncGL,INPUT_PULLUP);
pinMode(EncGR,INPUT_PULLUP);
pinMode(EncHL,INPUT_PULLUP);
pinMode(EncHR,INPUT_PULLUP);
pinMode(EncIL,INPUT_PULLUP);
pinMode(EncIR,INPUT_PULLUP);
pinMode(EncJL,INPUT_PULLUP);
pinMode(EncJR,INPUT_PULLUP);
pinMode(EncKL,INPUT_PULLUP);
pinMode(EncKR,INPUT_PULLUP);
pinMode(EncLL,INPUT_PULLUP);
pinMode(EncLR,INPUT_PULLUP);
pinMode(EncML,INPUT_PULLUP);
pinMode(EncMR,INPUT_PULLUP);
pinMode(Service,INPUT_PULLUP);
pinMode(Led,OUTPUT);
digitalWrite(Led,1);
}void loop(){
// Autopowrót do wyświetlania numeru programu
if(Count!=0){Count--;if(Count==1){analogWrite(Select,0);digitalWrite(Led,0);LastEnc=1;delay(DelayLong);Count--;digitalWrite(Led,1);}}
//COMP/EFX 51-0.62V
x=A.process();
if(x==16){digitalWrite(Led,0);if(LastEnc!=4){analogWrite(Select,48);LastEnc=4;delay(DelayLong);}ValueDec();} // Select:-3
if(x==32){digitalWrite(Led,0);if(LastEnc!=4){analogWrite(Select,48);LastEnc=4;delay(DelayLong);}ValueInc();} // Select:-3
//DRIVE 68-0.84V, Service: LEVEL GLOBAL 0-0V
x=B.process();
if(x==16){digitalWrite(Led,0);if(LastEnc!=5){analogWrite(Select,65*(digitalRead(Service)));LastEnc=5;delay(DelayLong);}ValueDec();} // Select:-3
if(x==32){digitalWrite(Led,0);if(LastEnc!=5){analogWrite(Select,65*(digitalRead(Service)));LastEnc=5;delay(DelayLong);}ValueInc();} // Select:-3
//GAIN 85-1.05V, Service: LEVEL PATCH 34-0.4V
x=C.process();
if(x==16){digitalWrite(Led,0);if(LastEnc!=6){analogWrite(Select,30+51*(digitalRead(Service)));LastEnc=6;delay(DelayLong);}ValueDec();} // Select:-4
if(x==32){digitalWrite(Led,0);if(LastEnc!=6){analogWrite(Select,30+51*(digitalRead(Service)));LastEnc=6;delay(DelayLong);}ValueInc();} // Select:-4
//EQ LO 102-1.27V
x=D.process();
if(x==16){digitalWrite(Led,0);if(LastEnc!=7){analogWrite(Select,98);LastEnc=7;delay(DelayLong);}ValueDec();} // Select:-4
if(x==32){digitalWrite(Led,0);if(LastEnc!=7){analogWrite(Select,98);LastEnc=7;delay(DelayLong);}ValueInc();} // Select:-4
//EQ MID 119-1.51V
x=E.process();
if(x==16){digitalWrite(Led,0);if(LastEnc!=8){analogWrite(Select,117);LastEnc=8;delay(DelayLong);}ValueDec();} // Select:-2
if(x==32){digitalWrite(Led,0);if(LastEnc!=8){analogWrite(Select,117);LastEnc=8;delay(DelayLong);}ValueInc();} // Select:-2
//EQ HI 136-1.75V
x=F.process();
if(x==16){digitalWrite(Led,0);if(LastEnc!=9){analogWrite(Select,135);LastEnc=9;delay(DelayLong);}ValueDec();} // Select:-1
if(x==32){digitalWrite(Led,0);if(LastEnc!=9){analogWrite(Select,135);LastEnc=9;delay(DelayLong);}ValueInc();} // Select:-1
//ZNR/AMP 153-1.99V
x=G.process();
if(x==16){digitalWrite(Led,0);if(LastEnc!=10){analogWrite(Select,154);LastEnc=10;delay(DelayLong);}ValueDec();} // Select:-3
if(x==32){digitalWrite(Led,0);if(LastEnc!=10){analogWrite(Select,154);LastEnc=10;delay(DelayLong);}ValueInc();} // Select:-3
//MODULATION 170-2.22V
x=H.process();
if(x==16){digitalWrite(Led,0);if(LastEnc!=11){analogWrite(Select,170);LastEnc=11;delay(DelayLong);}ValueDec();}
if(x==32){digitalWrite(Led,0);if(LastEnc!=11){analogWrite(Select,170);LastEnc=11;delay(DelayLong);}ValueInc();}
//RATE 187-2.41V
x=I.process();
if(x==16){digitalWrite(Led,0);if(LastEnc!=12){analogWrite(Select,187);LastEnc=12;delay(DelayLong);}ValueDec();}
if(x==32){digitalWrite(Led,0);if(LastEnc!=12){analogWrite(Select,187);LastEnc=12;delay(DelayLong);}ValueInc();}
//DELAY 204-2.64V
x=J.process();
if(x==16){digitalWrite(Led,0);if(LastEnc!=13){analogWrite(Select,204);LastEnc=13;delay(DelayLong);}ValueDec();}
if(x==32){digitalWrite(Led,0);if(LastEnc!=13){analogWrite(Select,204);LastEnc=13;delay(DelayLong);}ValueInc();}
//TIME 221-2.85V
x=K.process();
if(x==16){digitalWrite(Led,0);if(LastEnc!=14){analogWrite(Select,221);LastEnc=14;delay(DelayLong);}ValueDec();}
if(x==32){digitalWrite(Led,0);if(LastEnc!=14){analogWrite(Select,221);LastEnc=14;delay(DelayLong);}ValueInc();}
//REVERB 238-3.08V
x=L.process();
if(x==16){digitalWrite(Led,0);if(LastEnc!=15){analogWrite(Select,238);LastEnc=15;delay(DelayLong);}ValueDec();}
if(x==32){digitalWrite(Led,0);if(LastEnc!=15){analogWrite(Select,238);LastEnc=15;delay(DelayLong);}ValueInc();}
//DECAY 255-3.29V
x=M.process();
if(x==16){digitalWrite(Led,0);if(LastEnc!=16){analogWrite(Select,255);LastEnc=16;delay(DelayLong);}ValueDec();}
if(x==32){digitalWrite(Led,0);if(LastEnc!=16){analogWrite(Select,255);LastEnc=16;delay(DelayLong);}ValueInc();}
}
void ValueInc(){digitalWrite(ValueL,0);delay(DelayShort);digitalWrite(ValueR,0);delay(DelayShort);digitalWrite(ValueR,1);delay(DelayShort);digitalWrite(ValueL,1);delay(DelayShort);Count=Return;digitalWrite(Led,1);}
void ValueDec(){digitalWrite(ValueR,0);delay(DelayShort);digitalWrite(ValueL,0);delay(DelayShort);digitalWrite(ValueL,1);delay(DelayShort);digitalWrite(ValueR,1);delay(DelayShort);Count=Return;digitalWrite(Led,1);}