Red – Green Machine

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

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š“.

RedGreenMachine_pack

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.

Krabička s namontovanými tlačítky.

Z boku je vyříznuta díra pro nasazení reproduktoru o výkonu 10W a impedanci 8ohm.

Boční díra pro nasazení reproduktoru.

Z druhého boku je vyříznut otvor pro vkládaní SD karty.

Čtečka SD karet.

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.

Propojeni země mezi tlačítkem a LED diodou 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).

Detail připojení odporů k tlačítku a LED diodě.

K druhému vývodu tlačítka připájíme vodič, který připojíme k Arduinu.

V levo odpor mezi GND LED diody a tlačítkem, v pravo odpor u druhého vývodu diody.

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.

Spojení obou tlačítek společnou zemí.

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.

Zapojení použitého jednokanálového zasilovače.

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.

Připojení SD karty k Arduinu.

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.

Zapojená tlačítka a reproduktor v krabičce.

Arduino Uno připevníme na víčko krabičky pomocí tavné pistole.

Arduino přilepené na víčku krabičky.

Následně krabičku zaklopíme a víčko připevníme. Použil jsem univerzální izolepu :).

Finalní podoba.
Finalní podoba.
Finalní podoba.

One thought on “Red – Green Machine

Add yours

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *

Proudly powered by WordPress | Theme: Baskerville 2 by Anders Noren.

Up ↑