V kanceláři občas nadáváme a občas se dokonce potřebujeme pochválit. Proto mě napadlo pro tyto případy vytvořit krabičku, která to udělá za nás a přidá prvek překvapení.
Nazval jsem ji Red-Green Machine a slovy klasika „Princip je jednoduchý…“. Červené tlačítko vybere nějaký nelichotivý výrok a na účel zeleného už přijdete sami.
1. Komponenty
- krabička 100x85x90mm (můžete přizpůsobit velikosti tlačítek a reproduktoru)
- čtečka SD karet
- SD karta
- dvě tlačítka (čím větší, tím lepší) požil jsem arkádová tlačítka s podsvícením
- Arduino UNO
- reproduktor o impedanci 8ohmu
- zesilovač 3W
- odpory 2x 10K, 2x 220ohm
- kablíky na propojení
2. Jak to funguje
Na kartě jsou dva adresáře „red“ a „green“ v každém jsou uloženy zvukové soubory s požadovaným obsahem. Soubory jsou ve formátu wav 16Hz, 8bit mono. Při stisku tlačítka se náhodně vybere jeden ze souborů ve zvoleném adresáři a přehraje se.
Pro zelené tlačítko jsou použity superlativy z Apple KeyNote a pro červené tlačítko „Lakatoš“.
3. Zapojení
Základní zapojení je uvedeno na začátku zdrojového kódu. Podle popisu propojíme jednotlivé komponenty.
Na SD kartu, naformatovanou FAT32, rozbalíme obsah zip souboru RedGreenMachine_pack.
4. Program
//SDCard - Uno - Mega //GND - GND - GND //3.3V - 3.3V - 3.3V //CS - 10 - 53(SS) //MOSI - 11 - 51 //SCK - 13 - 52 //MISO - 12 - 50 //Repro //- - GND - GND //+ - 9 - 5, 6, 11, 46 //Red button //press - 4 - 4 //light - 5 - 5 //Green button //press - 2 - 2 //light - 3 - 3 #include <SD.h> #include <TMRpcm.h> #include <SPI.h> #define MIN_VOLUME 1 #define MAX_VOLUME 5 #define BLINK_DELAY 1000//1sec in ms #define BLINK_DURATION 500//0.5sec in ms #define TIME_TO_SET_VOLUME 3000//3s in ms #define SD_ChipSelectPin 10//pin 10 on most Arduino boards, 53 on a mega #define VERSION 0.07 // 0.07 - Dont create list of files to save memory (filse must be in format x.wav, where x is number from 0 to file count) // 0.06 - Support for change volume at begin // 0.05 - Debug under preprocessor // 0.04 - Documentatiorn for connection // 0.03 - Support for lights in buttons // 0.02 - Support for buttons // 0.01 - TMRpcm test //#define DEBUG 1//with debug on no sfx while play //variables declaration TMRpcm tmrpcm;//https://github.com/TMRh20/TMRpcm int redFileCount; int greenFileCount; int sfxVolume = 1; bool initialized = false; String FILE_EXTENSION = ".WAV"; const int greenButtonPin = 2; const int greenLedPin = 3; const int redButtonPin = 4; const int redLedPin = 5; int buttonState = 0; uint32_t lastBlink; uint32_t endTimeToSetVolume; bool redButtonPressed = false; bool greenButtonPressed = false; void setup() { Serial.begin(115200); #ifdef DEBUG Serial.print("RedGreen machine starting in version:"); Serial.println(VERSION); #endif //DEBUG randomSeed(analogRead(0));//initialize random generator from analog input //set pin mode pinMode(SD_ChipSelectPin, OUTPUT); pinMode(redLedPin, OUTPUT); pinMode(greenLedPin, OUTPUT); pinMode(redButtonPin, INPUT); pinMode(greenButtonPin, INPUT); tmrpcm.speakerPin = 9;//set to 5,6,11 or 46 for Mega, 9 for Uno, Nano, etc. #ifdef DEBUG Serial.println("Initializing SD Card"); #endif //DEBUG if (!SD.begin(SD_ChipSelectPin)) { #ifdef DEBUG Serial.println("SD cart init fail!"); #endif //DEBUG return; } #ifdef DEBUG Serial.println("Reading files from SD Card"); #endif //DEBUG File directory = SD.open("/red"); redFileCount = getFileCount(directory, FILE_EXTENSION); directory.close(); directory = SD.open("/green"); greenFileCount = getFileCount(directory, FILE_EXTENSION); directory.close(); #ifdef DEBUG Serial.print("Redn files:"); Serial.println(redFileCount); Serial.print("Green files:"); Serial.println(greenFileCount); #endif //DEBUG #ifdef DEBUG Serial.print("Set default volume:"); Serial.println(sfxVolume); #endif //DEBUG tmrpcm.setVolume(1); tmrpcm.quality(1); endTimeToSetVolume = millis() + TIME_TO_SET_VOLUME;//set end time for set volume #ifdef DEBUG Serial.println("Basic setup done"); #endif //DEBUG } void loop() { if (initialized) { ProcessRedGreenMachine(); } else { uint32_t nowTime = millis(); if (nowTime < endTimeToSetVolume) { //allow set volume ProcessSetVolume(); } else { initialized = true;//ready for machine } } } //Allow to set volume //red button - volume down //green button - volume up void ProcessSetVolume() { BlinkWithLights(); //read green button state buttonState = digitalRead(greenButtonPin); if (buttonState == HIGH) { if (!greenButtonPressed) { greenButtonPressed = true; //volume up sfxVolume++; //check volume maximum if (sfxVolume > MAX_VOLUME) { sfxVolume = MAX_VOLUME;//set max } //set volume to library tmrpcm.setVolume(sfxVolume); playRandomFile("/green", greenFileCount);//play file to check volume //extend time for set volume endTimeToSetVolume = millis() + TIME_TO_SET_VOLUME;//set end time for set volume #ifdef DEBUG Serial.print("Set volume up:"); Serial.println(sfxVolume); #endif //DEBUG } } else { greenButtonPressed = false; } //read red button state buttonState = digitalRead(redButtonPin); if (buttonState == HIGH) { if (!redButtonPressed) { redButtonPressed = true; //volume downp sfxVolume--; //check volume maximum if (sfxVolume < MIN_VOLUME) { sfxVolume = MIN_VOLUME;//set min volume } //set volume to library tmrpcm.setVolume(sfxVolume); playRandomFile("/red", redFileCount);//play random file to check volume //extend time for set volume endTimeToSetVolume = millis() + TIME_TO_SET_VOLUME;//set end time for set volume #ifdef DEBUG Serial.print("Set volume down:"); Serial.println(sfxVolume); #endif //DEBUG } } else { redButtonPressed = false; } } //Read red and green button and according to states play random sfx. void ProcessRedGreenMachine() { buttonState = digitalRead(greenButtonPin); // check if the pushbutton is pressed. // if it is, the buttonState is HIGH: if (buttonState == HIGH) { // turn green LED on: digitalWrite(greenLedPin, HIGH); if (!greenButtonPressed) { greenButtonPressed = true; playRandomFile("/green", greenFileCount); #ifdef DEBUG Serial.println("Green button pressed"); #endif //DEBUG } } else { // turn LED off: digitalWrite(greenLedPin, LOW); greenButtonPressed = false; } buttonState = digitalRead(redButtonPin); if (buttonState == HIGH) { // turn red LED on: digitalWrite(redLedPin, HIGH); if (!redButtonPressed) { redButtonPressed = true; playRandomFile("/red", redFileCount); #ifdef DEBUG Serial.println("Red button pressed"); #endif //DEBUG } } else { // turn LED off: digitalWrite(redLedPin, LOW); redButtonPressed = false; } } //play random files in format x.wav //where x is random number from files count void playRandomFile(String directoryName, int fileCount) { int randomFileIndex = random(fileCount); String fullFileName = directoryName + "/" + randomFileIndex + FILE_EXTENSION; #ifdef DEBUG Serial.print("Selected random file:"); Serial.println(fullFileName); #endif //DEBUG tmrpcm.play(fullFileName.c_str()); } //Return number of files of specific extension in selected dictionary int getFileCount(File directory, String extension) { int fileCount = 0; while (true) { File entry = directory.openNextFile(); if (!entry) { // no more files break; } //is file if (!entry.isDirectory()) { String fileName = String(entry.name()); //is file with expected extension if (fileName.endsWith(extension)) { fileCount++; } } entry.close(); } directory.rewindDirectory();//return at first file in directory return fileCount; } //Blink with lights to show possibility to change volume. void BlinkWithLights() { uint32_t nowTime = millis(); //time to blink with lights if (nowTime > lastBlink) { if (nowTime < lastBlink + BLINK_DURATION) { digitalWrite(greenLedPin, HIGH); digitalWrite(redLedPin, HIGH); } else { lastBlink = nowTime + BLINK_DELAY; digitalWrite(greenLedPin, LOW); digitalWrite(redLedPin, LOW); } } }
Obvod si zapojíme na nepájivém poli. Ještě jednou zkontrolujeme a připojíme Arduino k počítači. Otevřeme vývojové prostředí s programem a nahrajeme program do Arduina.
6. Krabička
Základem je krabička o rozměrech 100x85x90mm, kterou jsem si vyrobil z bukové 5mm překližky. Po zkušenostech s výrobou bych příště raději použil nějakou plastovou. Jen upozorňuji, že krabička musí mít určitou pevnost, aby odolala návalu vzteku uživatelů.
Do krabičky jsou ze zhora vyvrtány dvě díry o průměru 25mm pro nasazení arkádových tlačítek.
Z boku je vyříznuta díra pro nasazení reproduktoru o výkonu 10W a impedanci 8ohm.
Z druhého boku je vyříznut otvor pro vkládaní SD karty.
6. Kompletace
6.1 Tlačítka
Podle schématu zapojení si na vyvodu LED osvětlení vytvoříme společnou zem (GND), kterou pomocí odporu 10k spojíme s kontaktem tlačítka.
Na druhoý vývod LED kontaktu připájíme odpor 220Ohm a za něj vývod, který připojíme k Arduinu (v obrázku vodič směřujicí nahoru).
K druhému vývodu tlačítka připájíme vodič, který připojíme k Arduinu.
Na červeném tlačíku uděláme připojení stejně, jen GND si spojíme s GND od zeleného tlačítka. Na obrázku je ještě spojení s reproduktorem, které bylo později nahrazeno připojením k vlastnímu zesilovači.
6.2 Zesilovač
Nejprve jsem zkoušel reproduktor připojit na výkonový tranzistor, později na zesilovač, ale v obou připadech to nefungovalo moc dobře. Takže jsem nakonec použil zkompletovaný integrovany obvod s výkonem 3W.
Podle schématu připojíme zesilovač do obvodu.
6.3 SD karta
SD kartu jsem do krabičky vlepil pomocí tavné pistole a připojil k Arduino. Připojení je dobré udělat ještě před montáží tlačítek, protože pak je v krabičce už málo místa pro manipulaci.
6.4 Všechno do krabičky
Jednotlivé součásti máme připojené, takže přichází nejtěžší úkol, dostat to vše do krabičky.
Jednotlivá tlačítka nacvakneme do jejich pouzder, která máme již připevněná v krabičce. Následně nasadíme reproduktor a přišroubujeme ho.
Arduino Uno připevníme na víčko krabičky pomocí tavné pistole.
Následně krabičku zaklopíme a víčko připevníme. Použil jsem univerzální izolepu :).