//relátkový attenuator #include #include "U8g2lib.h" // nastavení propojovacích pinů, OLED displej přes I2S #define D0 13 #define D1 11 #define DC 9 #define CS 8 #define RES 10 // inicializace OLED displeje z knihovny U8glib U8G2_SSD1306_128X64_NONAME_1_4W_SW_SPI mujOled(U8G2_R0, D0, D1, CS, DC, RES); #define LCDWidth 128 #define ALIGN_CENTER(t) ((LCDWidth - (mujOled.getUTF8Width(t))) / 2) #define ALIGN_RIGHT(t) (LCDWidth - mujOled.getUTF8Width(t)) //adresa je v tomto formátu: 0 1 0 0 A2 A1 A0 RW //0100xxx where xxx are the jumpers //přepínač s páčkami dole je tedy 0100000 to je 0x20 #define ATTENUATOR1_ADDR 0x21 //páčky A0 #define ATTENUATOR2_ADDR 0x22 //páčky A1 #define ATTENUATOR3_ADDR 0x23 //páčky A1 A0 // proměnná pro uchování času poslední obnovy displeje long int prepis = 0; int volume = 0; int lastVolume = 0; int relatka = 0; // Rotační enkodér KY-040 const int pinDT = 2; const int pinCLK = 3; const int pinSW = 4; byte lastCLK = 0; //typ volatile nastaví, že kompilátor nebude dělat optimalizace (např. ukládání do registrů) //zajistí, že hodnotu je možné měnit v přerušení volatile boolean CLKchanged = false; volatile boolean DTfirst = false; int stavyRele[64]={ B000000, B000001, B000010, B000011, B100000, B100001, B100010, B100011, B010000, B010001, B010010, B010011, B110000, B110001, B110010, B110011, B001000, B001001, B001010, B001011, B101000, B101001, B101010, B101011, B011000, B011001, B011010, B011011, B111000, B111001, B111010, B111011, B000100, B000101, B000110, B000111, B100100, B100101, B100110, B100111, B010100, B010101, B010110, B010111, B110100, B110101, B110110, B110111, B001100, B001101, B001110, B001111, B101100, B101101, B101110, B101111, B011100, B011101, B011110, B011111, B111100, B111101, B111110, B111111}; void setup() { // initialize digital pin LED_BUILTIN as an output. pinMode(LED_BUILTIN, OUTPUT); mujOled.begin(); Wire.begin(); //creates a Wire object // nastaví I/O piny v MCP23008 na výstupy Wire.beginTransmission(ATTENUATOR3_ADDR); //begins talking to device Wire.write(0x00); //selects the IODIRA register Wire.write(0x00); //this sets all port A pins to outputs Wire.endTransmission(); //stops talking to device // komunikace přes sériovou linku rychlostí 9600 baud - pro debug // Serial.begin(2000000); lastCLK = digitalRead(pinDT); attachInterrupt(digitalPinToInterrupt(pinCLK), encoderMovedCLK, CHANGE); attachInterrupt(digitalPinToInterrupt(pinDT), encoderMovedDT, CHANGE); pinMode(4, INPUT_PULLUP); //aktivuje interní pull up rezistor (bez toho dělá blbosti) } /* dostupné příklady na youtube apod. nefungují, protože enkodér KY-040 se chová takto: stavy pinů (DT levá číslice, CLK pravá číslice) doprava: 11 -> 10 -> 00 -> 01 -> 11 doleva> 11 -> 01 -> 00 -> 10 -> 11 přičemž 10 a 01 jsou pouze mezistavy mezi aretací, tzn. chceme brát v potaz pouze dokončení kroku, např.: 11 -> 10 -> 00 zároveň je třeba počítat s chybami (bounce), kdy se kontakty náhodně na krátký okamžik rozpojí (takže např.: 11 -> 10 -> 11 -> 10 -> 00) */ void encoderMovedCLK() { if(CLKchanged) return; CLKchanged = true; } void encoderMovedDT() { if(CLKchanged) return; DTfirst = true; } void loop() { encoderCheck(); // porovnání uloženého a aktuálního času // při rozdílu větším než 100 ms se provede // obnovení displeje, čas můžeme nastavit dle potřeby if (millis()-prepis > 100) { // následující skupina příkazů // obnoví obsah OLED displeje mujOled.firstPage(); do { // funkce vykresli vykreslí žádanou obsah vykresli(); } while( mujOled.nextPage() ); // uložení posledního času obnovení prepis = millis(); } /* //rozsvěcování diod ruší displej ??? if(volume % 2 == 0) digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level) else digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW */ volumeCheck(); //nastavení delay dle potřeby aplikace delay(10); } void encoderCheck() { //dokud se CLK nezmění, tak nic nedělej if(CLKchanged==false) return; //ještě se nedokončil pohyb -> hodnoty obou pinů jsou různé if(digitalRead(pinCLK) != digitalRead(pinDT)) return; //hodnoty pinů už jsou stejné, ale došlo k otočení nebo jen návratu zpět? if(lastCLK == digitalRead(pinCLK)){ //k otočení nedošlo, vrátilo se to zpět - chyba - vše resetuj encoderReset(); // Serial.print("chyba, reset hodnot!: actualDT: "); // Serial.println(lastDT); return; } //byl pinDT změněn jako první? pak jde o pohyb doleva if(DTfirst){ volume--; } else{ //první byl CLK volume++; } //maxima/minima if(volume>63) volume = 63; if(volume<0) volume = 0; // Serial.println(volume); //reset hodnot encoderReset(); } void encoderReset() { DTfirst = false; CLKchanged = false; lastCLK = digitalRead(pinCLK); } void volumeCheck() { if(lastVolume == volume) return; //pokud se jedná o změnu z 31 na 32 a naopak, tak je třeba přidat mezikrok, jinak je na signálu 100mV prda třeba 1,5V ! (při vstupu 3V peak) //zde se totiž přepínají všechna relé a na milisekundu nejsou některé články uzemněné if((lastVolume == 31 && volume == 32) || (lastVolume == 32 && volume == 31)){ relatka = stavyRele[15]; //sepne/vypne nejdřív relé s druhou nejvyšší hodnotou Wire.beginTransmission(ATTENUATOR3_ADDR); //starts talking to slave device Wire.write(0x09); //selects the GPIO pins Wire.write(relatka); // posilat v HEX 0x nebo na zacatku musi byt B jako bity (B00001100) Wire.endTransmission(); //ends communication with the device delay(20); } //zde je také nutné přidat mezikrok, jinak je tam i 2x větší prda ! //zde také přepínají skoro všechna relé if((lastVolume == 47 && volume == 48) || (lastVolume == 48 && volume == 47)){ relatka = stavyRele[35]; Wire.beginTransmission(ATTENUATOR3_ADDR); //starts talking to slave device Wire.write(0x09); //selects the GPIO pins Wire.write(relatka); // posilat v HEX 0x nebo na zacatku musi byt B jako bity (B00001100) Wire.endTransmission(); //ends communication with the device delay(20); } lastVolume = volume; relatka = stavyRele[volume]; //odesílá na MCP23008-E/P je použito GP0 až GP5 Wire.beginTransmission(ATTENUATOR3_ADDR); //starts talking to slave device Wire.write(0x09); //selects the GPIO pins Wire.write(relatka); // posilat v HEX 0x nebo na zacatku musi byt B jako bity (B00001100) Wire.endTransmission(); //ends communication with the device delay(10); } // funkce vykresli pro nastavení výpisu informací na OLED void vykresli(void) { static char buffer[40]; // nastavení písma mujOled.setFont(u8g2_font_ncenB18_tf); // nastavení pozice výpisu v pixelech // souřadnice jsou ve tvaru x, y // souřadnice 0, 0 je v levém horní rohu // výpis textu na zadanou souřadnici mujOled.drawStr(10, 20, "hlasitost"); mujOled.setFont(u8g2_font_ncenB24_tf); sprintf(buffer, "%d", volume); mujOled.setCursor(ALIGN_CENTER(buffer), 55); mujOled.print(buffer); }