3.3 Bäromat

Bäromat Prototyp
Bäromat Prototyp

Ein Bär erzählt Geschichten und Kinder hören zu. Audio kommt von DFPlayer mini und steuert Bewegung der Sprache-Servos.

Steckplatine
Steckplatine erster Test mit UNO (Ich bin zu ungeduldig für fritzing)

Ablauf (vereinfacht)

  • Nach Münzeinwurf wird zufällig ein Stück vorgeschlagen.
  • Das Stück kann mit Taste Ja angenommen oder mit Taste Nein abgelehnt werden, dabei wird ein neues Stück vorgeschlagen.
  • Wird nach 8 Sekunden keine Entscheidung getroffen, wird das vorgeschlagene Stück gespielt.
  • Im mp3-Verzeichnis der SD-Karte sind die Stücke 1..ANZ_STUECKE als Beschreibung und ANZ_STUECKE+1..2*ANZ_STUECKE die abzuspielenden Stücke, Beispiel für 30 Stücke:
    • 1..30 Ansagen
    • 31..60 Spielstücke

Automat wurde deutlich komplexer und mit Arduino Mega realisiert. Ist ein Einzelstück…

Zustandsdiagramm
Zustandsdiagramm
SETUP-TasterMünzeinwurfKooper-InfoSTART-TasteJA-TasteNEIN-TasteRelais-ServosRelais-Opt
EingangP_SETUP 3P_MUENZE A3P_KO_INFO 4P_START 5P_JA A4P_NEIN A5
Ausgang / LEDP_MUENZE_L 22P_START_L 23P_JA_L 24P_NEIN_L 25P_REL_SER 26P_REL_OPT 27
Münzeinwurf und Taster mit PullUp 4,7kΩ

Zufall erzeugen, den Samen setzen?

Synopsis: Arduino random()🔗 Arduino randomSeed()🔗
Damit der Pseudo-Zufallsgenerator nach dem Reset nicht immer genau die gleiche Zahlenfolge ausgibt soll mit einer zufälligen Zahl, dem Samen (unsigned long) andere Zufallsfolge ermöglicht werden. Dieser Samen wird im Doku-Beispiel mit analogRead(0) erzeugt, dies ergibt bei meinem Test hier 0, ist also wirkungslos ☹️. Ein Test mit freiem Eingang A8 ergab 1023, den Maximalwert, also auch immer die selbe Zahl..

Programm

Hinweis zu analogReference(INTERNAL) Zeile 51: Beim UNO ist die Referenzspannung mit INTERNAL und beim Mega mit INTERNAL1V1 einzutragen.
Siehe docs.arduino.cc/language-reference/en/functions/analog-io/analogReference/🔗

Automaten Software

// Bäromat V1.0 © 9.03.25 Oliver Mezger MezMedia.de CC BY-SA 4.0
#include <SoftwareSerial.h>
#include <DFPlayerMini_Fast.h>
#include "SchwaetzoLib.h"

//#define DEBUG_ME 1  // Zum Messen der Ausführungsdauer von Schwaetzo:go()
#define ANZ_STUECKE 11   // 1..20 Frage 31..60 Stück
#define SPIEL_STUECKE 20 // Beginn der Spielstücke
#define EXTRA_STUECKE 40 // Beginn der Extrastücke
// Pin Definitionen
#define P_BUSY 2      // MP3-Player: Busy-Pin, low aktiv
#define P_POTI A2     // Pin des Potentiometers
#define P_SETUP 3    // Taster gegen GND zu Justieren
#define P_MUENZE A3   // Muenzpruefer prellend low aktiv
#define P_MUENZE_L 22 // LED high aktiv
#define P_KO_INFO 4   // Kooperationsinfo der anderen Automaten high aktiv
#define P_START 5     // START-Taste prellend low aktiv
#define P_START_L 23  // LED high aktiv
#define P_JA A4       // Ja-Taste prellend low aktiv
#define P_JA_L 24     // LED high aktiv
#define P_NEIN A5     // Nein-Taste prellend low aktiv
#define P_NEIN_L 25   // LED high aktiv
#define P_REL_SER 26  // Relais für Servos low aktiv
#define P_REL_OPT 27  // Optionales Relais
#define P_SERVO_R 7   // Zusätzlicher Servo für Bewegung
#define P_SERVO_L 6   // Zusätzlicher Servo für Bewegung
// Abfrage Definitionen
#define T_JA !digitalRead(P_JA)
#define PLAYER_FERTIG digitalRead(P_BUSY)
#define KO_INFO digitalRead(P_KO_INFO)

SoftwareSerial mySerial(10, 11); // RX, TX, fuer DF-Player
DFPlayerMini_Fast myMP3;
// Endpositionen der Servos für mundZu und mundAuf kennen z.B. 1800µs -> 180 eintragen
Schwaetzo schwaetzoL(A1,9,180,140); // AudioIn, ServoOut, mundZu, mundOffen
Schwaetzo schwaetzoR(A0,8,170,130);
//Schwaetzo schwaetzoL(A1,9); // AudioIn, ServoOut, noch unjustiert
//Schwaetzo schwaetzoR(A0,8);
Servo papaServo;
Servo kidsServo;
Taster t_muenz(P_MUENZE,false); // Taster MUENZE entprellt low active
//Taster t_ja(P_JA,false);        // Taster JA entprellt low active
Taster t_nein(P_NEIN,false);    // Taster NEIN entprellt low active
Taster t_setup(P_SETUP,false);  // Taster SETUP entprellt low active
Taster t_start(P_START,false);  // Taster START entprellt low active
Wecker weck1;                   // Wecker1

enum zustandstyp {RUHE_ENTRY,RUHE,WERBUNG_ENTRY,WERBUNG,PROLOG_ENTRY,PROLOG,NEIN_ENTRY,NEIN,OPTION_ENTRY,OPTION,JA,SPIELEN_ENTRY,SPIELEN,EPILOG,ENDE}; // definiere Aufzählungstyp
enum zustandstyp zustand = RUHE_ENTRY; // Definiere und initialisiere Variable
byte lautstaerke = 20; // 0..30
byte stueck=1; // das zu spielende Stueck
bool sprechen = false; // wenn true werden die Mundservos in der loop belebt
int servoPapa = 1500;
int servoKids = 1500;

void einstellenLautstaerke(){ // Poti einlesen und MP3 Lautstärke einstellen
  unsigned int l = 15+analogRead(P_POTI)/100; // POTI einlesen und 0..1023 auf 20..30 umsetzen
  if (l>30) l=30;
  if (l!=lautstaerke){
    lautstaerke=l;
    Serial.print(F("Neue Lautstaerke: "));
    Serial.println(l);
    myMP3.volume(l);
    delay(200); // Zeit zum Verarbeiten
  }
}

void setup() {
  Serial.begin(9600);      // Ausgabe ueber serieller Monitor
  mySerial.begin(9600);      // Anbindung des DF-Player
  myMP3.begin(mySerial);     // gibt immer true aus
  analogReference(INTERNAL1V1); // A/D Referenzspannung https://www.arduino.cc/reference/en/language/functions/analog-io/analogreference/
  einstellenLautstaerke();
  delay(1000);
  //myMP3.stopDAC(); // Player ausschalten?
  pinMode(P_BUSY,INPUT);    // Abfragen ob MP3-Player spielt
  pinMode(P_SETUP,INPUT_PULLUP); 
  //pinMode(P_MUENZE,INPUT_PULLUP);
  pinMode(P_JA,INPUT_PULLUP);
  //pinMode(P_NEIN,INPUT_PULLUP);
  pinMode(P_MUENZE_L,OUTPUT);
  pinMode(P_KO_INFO,INPUT);
  pinMode(P_START_L,OUTPUT);
  pinMode(P_JA_L,OUTPUT);
  pinMode(P_NEIN_L,OUTPUT);
  pinMode(P_REL_SER,OUTPUT);
  digitalWrite(P_REL_SER,HIGH);
  pinMode(P_REL_OPT,OUTPUT);
  digitalWrite(P_REL_OPT,HIGH);
  selbsttest();
  //Serial.print(F("Anzahl Ordner auf SD-Karte: "));
  //Serial.println(myMP3.numFolders());
}

#ifdef DEBUG_ME 
  unsigned long maxSchwaetzoTime = 0;
  unsigned long tmp=0;
#endif

byte zufallStueck(){ // wählt aus der Anzahl ein zufälliges Stück aus
  static byte anzReststuecke=0;
  static byte stueckliste[ANZ_STUECKE]; // Permutationsliste der Stücke
  if(anzReststuecke==0){ // keine Stücke mehr in der Liste, neue Liste erstellen
    for(byte i=0;i<ANZ_STUECKE;i++){ // Auffüllen
      stueckliste[i]=i+1;
    }
    for (byte i = ANZ_STUECKE - 1; i > 0; i--) { // Permutation
      byte j = random(0, i + 1); // Zufälliger Index zwischen 0 und i
      // Elemente tauschen
      byte temp = stueckliste[i];
      stueckliste[i] = stueckliste[j];
      stueckliste[j] = temp;
    }
    anzReststuecke=ANZ_STUECKE; // wieder genug da
    Serial.print(F("Neue Stückliste erstellt: "));
    for(byte i=0;i<ANZ_STUECKE;i++){
      Serial.print(stueckliste[i]);
      Serial.print(F(" "));
    }
    Serial.println();
  }
  return stueckliste[--anzReststuecke];
}
void spieleStueck(byte s){
  Serial.print(F("Spiele Stueck: "));
  Serial.println(s);
  digitalWrite(P_REL_SER,LOW); // Servos kriegen Strom
  schwaetzoL.an(); // Servosignal anschalten
  schwaetzoR.an();
  sprechen = true; // Mundservos beleben
  myMP3.playFromMP3Folder(s);
  delay(700); // warten bis Player spielt
}
void einschaltenServos(){ // Hier Code zum Einschalten
  papaServo.attach(P_SERVO_R,1000,2000);
  kidsServo.attach(P_SERVO_L,1000,2000);
}
Wecker weckers; // Wecker für Servosteuerung
void bewegeBaer(){ // Hier während des Spielens Servobewegungen
  static int ziel = 1500;
  static int schritt = 3;
  if(weckers.fertig()){
    weckers.stellen(100); // 0,1s
    int diff = servoPapa-ziel;
    if(abs(diff)<=schritt+2){ // am Ziel, neues Ziel
      weckers.stellen(random(500,1200)); // Innehalten
      ziel = random(1100,1900); // Endpunkte festlegen
      schritt = random(4,10);
      Serial.print(F("Ziel: "));
      Serial.print(ziel);
      Serial.print(F(" Schritt: "));
      Serial.println(schritt);
    } else {
      servoPapa += ((diff>0)?-schritt:schritt);
      //if(servoPapa>1800||servoPapa<1200)return; // Sicherung
      papaServo.writeMicroseconds(servoPapa);
    }
  }
}
void baerZurRuhe(){ // Hier Code zum Ruheposition einnehmen und ausschalten
  bool r = 1500>servoPapa;
  while(abs(servoPapa-1500)>10){
    servoPapa+=(r?8:-8);
    papaServo.writeMicroseconds(servoPapa); // in die Mitte
    delay(100);
  }  
}
void ausRelais(){
  digitalWrite(P_REL_SER,HIGH);
  digitalWrite(P_REL_OPT,HIGH);
}
byte werbung = 41;
int wziel=1500; // wohin der Bär bei Werbung schaut
void spieleWerbung(){
  spieleStueck(werbung);
  switch(werbung){
    case 41: wziel=1500; break;
    case 42: wziel=1000; break;
    case 43: wziel=2000; break;
    case 44: wziel=1500; break;
  }
  if(werbung<44)werbung++;
  else werbung=41;
  weck1.stellen(30000); // 30 s
}
void baerWerbung(){
  static int schritt = 10;
  if(weckers.fertig()){
    weckers.stellen(100); // 0,1s
    int diff = servoPapa-wziel;
    if(abs(diff)<=schritt+2);
    else {
      servoPapa += ((diff>0)?-schritt:schritt);
      papaServo.writeMicroseconds(servoPapa);
    }
  }
}
void jaNeinLed(){ // Wechselblinken
  static bool ja = false;
  if(millis()%600==0){ // alle 600 ms
    if(ja){
      digitalWrite(P_JA_L,HIGH);
      digitalWrite(P_NEIN_L,LOW);
    } else {
      digitalWrite(P_JA_L,LOW);
      digitalWrite(P_NEIN_L,HIGH);
    }
    ja = !ja;
  }
}
void dreheKids(){ // für das Nein-sagen die Kinderbären drehen lassen
  if(weckers.fertig()){
    weckers.stellen(300);
    if(servoKids>1500) servoKids=1400;
    else servoKids=1600;
    kidsServo.writeMicroseconds(servoKids);
  }
}
void loop() {
  if(sprechen){
    schwaetzoL.go();  // Audio messen und auf Servo ausgeben
    schwaetzoR.go();
  }
  digitalWrite(P_START_L,KO_INFO); // LED zeigt Zustand der KO_INFO an
  if(t_setup.enter())zustand=ENDE;
  switch (zustand){
    case RUHE_ENTRY: // alles zurücksetzen
      Serial.println(F("RUHE_ENTRY "));
      sprechen = false;
      schwaetzoL.aus();
      schwaetzoR.aus();
      ausRelais();
      myMP3.pause();
      digitalWrite(P_MUENZE_L,HIGH); // Bereit für Münzeinwurf
      zustand=RUHE;
      break;
    case RUHE: // Warten auf Münzeinwurf
      if (t_muenz.enter())   zustand=PROLOG_ENTRY;
      else if(t_start.enter()){
        if (KO_INFO) zustand=PROLOG_ENTRY;
        else if(weck1.fertig()) zustand=WERBUNG_ENTRY;
      }
      break;
    case WERBUNG_ENTRY:
      Serial.println(F("WERBUNG_ENTRY "));
      spieleWerbung();
      einschaltenServos();
      zustand = WERBUNG;
      break;  
    case WERBUNG:
      baerWerbung();
      if (t_muenz.enter())   zustand=PROLOG_ENTRY;
      else if(PLAYER_FERTIG) zustand=RUHE_ENTRY;
      break;  
    case PROLOG_ENTRY:
      Serial.println(F("PROLOG_ENTRY "));
      digitalWrite(P_MUENZE_L,LOW); // Münzer LED aus
      randomSeed(millis());  // Guten Zufall erzeugen
      stueck=zufallStueck(); // zufälliges Stück
      einstellenLautstaerke();
      spieleStueck(stueck);
      zustand = PROLOG;
      break;
    case PROLOG:
      jaNeinLed();
      if(T_JA) {
        spieleStueck(45);
        zustand = JA;
      }
      else if(PLAYER_FERTIG)   zustand = OPTION_ENTRY;
      else if(t_nein.enter())  zustand = NEIN_ENTRY;
      break;
    case NEIN_ENTRY:
      Serial.println(F("NEIN_ENTRY "));
      spieleStueck(46);
      einschaltenServos();
      zustand = NEIN;
      break;  
    case NEIN:
      if(PLAYER_FERTIG) zustand=PROLOG_ENTRY;
      dreheKids();
      break;  
    case OPTION_ENTRY:
      Serial.println(F("OPTION_ENTRY "));
      weck1.stellen(5000); // 5 Sekunden
      zustand = OPTION;
      break;
    case OPTION:
      jaNeinLed();
      if(T_JA){
        spieleStueck(45);
        zustand = JA;
      }
      else if(weck1.fertig()) zustand = SPIELEN_ENTRY;
      else if(t_nein.enter()) zustand = NEIN_ENTRY;
      break;
    case JA:
      if(PLAYER_FERTIG) zustand=SPIELEN_ENTRY;
      break;  
    case SPIELEN_ENTRY:
      Serial.println(F("SPIELEN_ENTRY "));
      digitalWrite(P_JA_L,LOW);
      digitalWrite(P_NEIN_L,LOW);
      einschaltenServos();
      spieleStueck(stueck+SPIEL_STUECKE);
      weck1.stellen(10000); // 10s Totzeit
      zustand = SPIELEN;
      break;  
    case SPIELEN: 
      bewegeBaer();
      if(PLAYER_FERTIG){ // MP3 spielt? Low aktiv
        zustand=EPILOG;
        spieleStueck(47); 
      }
      else if(t_nein.enter() && weck1.fertig()){
        zustand=EPILOG;
        spieleStueck(48); // vorzeitiges Ende
      }
      else if(t_muenz.enter()) zustand = PROLOG_ENTRY;
      break;  
    case EPILOG:
      if(PLAYER_FERTIG || t_nein.enter()){ // MP3 spielt? Low aktiv
        zustand = ENDE;
      }
      else if(t_muenz.enter()) zustand = PROLOG_ENTRY;
      break;
    case ENDE:
      baerZurRuhe();
      //papaServo.detach(); // Signal abschalten
      //kidsServo.detach();
      zustand=RUHE_ENTRY;
      break;
  }
}
void selbsttest(){
  Serial.println(F("Selbsttest"));
  if (!digitalRead(P_SETUP)){Serial.println(F("SETUP gedrückt"));return;} // SETUP-Taste
  digitalWrite(P_MUENZE_L,HIGH);
  if (t_muenz.active()) return;
  delay(500);
  digitalWrite(P_MUENZE_L,LOW);
  if (digitalRead(P_KO_INFO)) {Serial.println(F("Kooper Info aktiv"));return;}
  digitalWrite(P_START_L,HIGH);
  if (t_start.active()) return;
  delay(500);
  digitalWrite(P_START_L,LOW);
  digitalWrite(P_JA_L,HIGH);
  if (T_JA) return;
  delay(500);
  digitalWrite(P_JA_L,LOW);
  digitalWrite(P_NEIN_L,HIGH);
  if (t_nein.active()) return;
  delay(500);
  digitalWrite(P_NEIN_L,LOW);
  digitalWrite(P_REL_SER,LOW);
  delay(500);
  digitalWrite(P_REL_SER,HIGH);
  digitalWrite(P_REL_OPT,LOW);
  delay(500);
  digitalWrite(P_REL_OPT,HIGH);
  Serial.println(F("Selbsttest fertig"));
}

Schwätzomat-Library

// SchwaetzoLib.h V1.5 © 19.02.2025 Oliver Mezger MezMedia.de CC BY-SA 4.0
#ifndef SchwaetzoLib_h
#define SchwaetzoLib_h
#endif

#include "Arduino.h"
#include <Servo.h>
#define DEFAULT_MIN_AUDIO 20 // Voreinstellung Minimaler Audiolevel bei rauschenden Aufnahmen
#define DEFAULT_MAX_AUDIO 60 // Voreinstellung Maximaler Audiolevel
#define STILL_SCHWELLE 3     // Schwelle 1/4 Maximum (nicht verwendet)

class Schwaetzo{
  public:
    Schwaetzo(byte ein,byte aus); // AudioEingang ServoAusgang
    Schwaetzo(byte ein,byte aus,byte mzu, byte moffen); // AudioEingang ServoAusgang Servopositionen
    void setMundZu(byte zu);      // Servoposition für mundZu einstellen
    void setMundOffen(byte auf);  // Servoposition für mundAuf einstellen
    void go(); // periodisch aufrufen um Analog einzulesen und Servo zu steueren
    void an(); // Servo wird angeschlossen
    void aus();// Servo wird deaktiviert
    byte getMaxAudio();  // Audio Maximalwert
    byte getLastAudio(); // letzer ermittelter Audiowert für Servo
    void moveServo(byte n); // Servo an Position n bewegen zur Justage
    void schreibeEEPROM();  // Servodaten ins EEPROM schreiben
    void leseEEPROM();      // Servodaten aus EEPROM lesen
  private:
    static byte instanzen;           // Klassenvariable
    byte instanzNummer;              // die Schwaetzoinstanzen werden durchnummeriert für EEPROM Adressen
    Servo servo;                     // Servo-Instanz
    byte audioEingang;               // AnalogPin fuer Sound
    byte servoAusgang;               // Servoanschluss
    byte mundZu = 150;               // Servoposition wenn Mund zu {100..200}
    byte mundOffen = 150;            // Servoposition wenn Mund offen {100..200}
    byte servoWeg = 0;               // mundOffen-nunZu
    byte soundSampels = 0 ;          // Zaehler fuer Messungen in einer Epoche
    byte minAudio = DEFAULT_MIN_AUDIO; // leisester Wert eines Stueckes (Rauschen)
    byte maxAudio = DEFAULT_MAX_AUDIO; // lautester Wert eines Stueckes
    uint16_t audio = 0;              // lautester Wert von n Messungen
    byte audioShift = 1;             // analogReadWert >> 1 wird bei lautem Audio erhöht um innerhalb 8 Bit zu bleiben
    byte lastAudio = 0;              // für Ausgabe auf Seriellem Plotter
};
class Taster{ // Klasse zum Entprellen von Tastern
  public:
    Taster(byte p, bool ha); // Pin, highactive
    bool enter();            // Taste gedrückt
    bool exit();             // Taste losgelassen
    bool active();           // Taste aktiv
  private:
    byte pin;
    bool highactive;
    bool old;
};
class Wecker{  // Klasse für Wecker
  public:
    Wecker();
    void stellen(unsigned int n);
    bool fertig();
  private:
    unsigned long weckzeit;
};
// SchwaetzoLib.cpp V1.5 © 19.02.2025 Oliver Mezger MezMedia.de CC BY-SA 4.0

#include "Arduino.h"
#include "SchwaetzoLib.h"
#include <EEPROM.h>

byte Schwaetzo::instanzen = 0; // Klassenvariable für Instanznummer

Schwaetzo::Schwaetzo(byte ein,byte aus){ // AudioEingang ServoAusgang für Verfahren Servo-Justage mit Automat
  instanzNummer = instanzen++; // die Instanzen nummerieren wegen EEPROM
  audioEingang = ein;
  servoAusgang = aus;
  pinMode(aus, OUTPUT);  // Servosignal = 0
  digitalWrite(aus,LOW); // einstellen
}

Schwaetzo::Schwaetzo(byte ein,byte aus,byte mzu, byte moffen):Schwaetzo(ein,aus){ // AudioEingang ServoAusgang MundZu MundOffen
  setMundZu(mzu);
  setMundOffen(moffen);
}

void Schwaetzo::setMundZu(byte zu){     // Servoposition für mundZu einstellen
  if (zu>=100 && zu<= 200) mundZu=zu;
  else{
    Serial.print(F("setMundZu: Wert passt nicht: "));
    Serial.println(zu);
  } 
  servoWeg = abs(mundOffen-mundZu);
}

void Schwaetzo::setMundOffen(byte auf){     // Servoposition für mundOffen einstellen
  if (auf>=100 && auf<= 200) mundOffen = auf;
  else{
    Serial.print(F("setMundOffen: Wert passt nicht: "));
    Serial.println(auf);
  } 
  servoWeg = abs(mundOffen-mundZu);
}

void Schwaetzo::go(){ // Sample aufnehmen braucht 130µs somit bei 2 Kanälen 3,846 kHz Abtastfrequenz
  static uint16_t n;
  if (soundSampels >=100){ // wurden genug Sampels in Epoche aufgenommen 3846Hz/50Hz=77 
    soundSampels = 0;
    if (audio > 255){ // wenn es zu laut ist Messungen abschwächen
      audio = 255;
      audioShift++;   // mehr Vorteilen, Messwert halbieren
      minAudio = DEFAULT_MIN_AUDIO;
      maxAudio = DEFAULT_MAX_AUDIO;
    } else {
      if (audio > maxAudio) maxAudio = audio;  // Maximallautstärke des Stückes merken
      if (audio < minAudio) minAudio = audio;  // Minimallautstärke des Stückes merken
      if(audio>=minAudio) audio -= minAudio;   // Rauschen abziehen
      if (audio < maxAudio/2){  // leise Stellen verstärken
        n = audio * servoWeg * 2 / maxAudio; // Servoausschlag berechnen
      } else {
        n = audio * servoWeg / maxAudio;     // Servoausschlag berechnen
      }
      if(n>servoWeg) n = servoWeg; // Servoausschlag begrenzen
      if(mundOffen>mundZu) n = mundZu + n;
      else n = mundZu - n;
      servo.writeMicroseconds(n*10); // Servo Pulsweite ausgeben
    }
    /*if (audio > (maxAudio>>stillSchwelle)){ // Schwelle 1/8 Maximum
    //sprachSituation |= 1;
    //ausTimer =0;
    }*/
    lastAudio = audio; // letzten Wert merken
    audio=0;
  }
  else{ // Audio-Messung
    n = analogRead(audioEingang)>>audioShift; // Audiosignal lesen 
    if(n>audio) audio=n; // Maximum finden
    soundSampels++;
    lastAudio=0;
  }
}

void Schwaetzo::an(){  // Servo wird angeschlossen, bekommt Signal
  minAudio = DEFAULT_MIN_AUDIO; // neues Stück neues Glück
  maxAudio = DEFAULT_MAX_AUDIO;
  audio = 0;
  soundSampels = 0;
  lastAudio = 0;
  audioShift = 1; // Abschwächen von analogRead
  if(!servo.attached())servo.attach(servoAusgang,1000,2000);  // Servo anschließen 
  Serial.print(F("Servo angeschlossen "));
  Serial.println(servoAusgang);
}

void Schwaetzo::aus(){  // Servosignal wird abgeschaltet
  servo.writeMicroseconds(mundZu*10); // Mund schließen 
  delay(100);                         // warten bis ausgeführt
  servo.detach();                     // Servosignal abschalten
  Serial.print(F("Servo aus, audioShift: ")); // Infos über das Stück ausgeben
  Serial.print(audioShift);
  Serial.print(F(" MinLevel: "));
  Serial.print(minAudio);
  Serial.print(F(" MaxLevel: "));
  Serial.println(maxAudio);
}

byte Schwaetzo::getMaxAudio(){ // maximaler Audiowert
  return maxAudio;
}

byte Schwaetzo::getLastAudio(){ // letzter Audiowert, 0 während Messung
  return lastAudio;
}

void Schwaetzo::moveServo(byte n){ // Servo einstellen während Justage
  servo.writeMicroseconds(n*10);
}

void Schwaetzo::schreibeEEPROM(){  // Servodaten ins EEPROM schreiben
  EEPROM.update((instanzNummer+1)*2, mundZu);
  EEPROM.update((instanzNummer+1)*2+1, mundOffen);
}

void Schwaetzo::leseEEPROM(){      // Servodaten aus EEPROM lesen
  byte i;
  i = EEPROM.read((instanzNummer+1)*2);
  setMundZu(i);
  i = EEPROM.read((instanzNummer+1)*2+1);
  setMundOffen(i);
}

Taster::Taster(byte p, bool ha){ // Pin, highactive
  old=false; // Taste nicht gedrückt
  pin=p;
  highactive=ha;
  pinMode(p,INPUT);
}
bool Taster::enter(){          // Taste gedrückt
  bool ausgabe = false;
  bool test = digitalRead(pin);
  if (old != test){ // hat sich was getan?
    delay(10); // 10 ms warten
    test=digitalRead(pin); // noch mal einlesen
    if (old != test){  // immer noch anders?
      ausgabe = highactive?(!old & test):(old & !test); // steigende:fallende Flanke
      old = test;
    }
  }
  return ausgabe;
} 
bool Taster::exit(){             // Taste losgelassen
  bool ausgabe = false;
  bool test = digitalRead(pin);
  if (old != test){ // hat sich was getan?
    delay(10); // 10 ms warten
    test=digitalRead(pin); // noch mal einlesen
    if (old != test){  // immer noch anders?
      ausgabe = highactive?(old & !test):(!old & test); // fallende:steigende Flanke
      old = test;
    }
  }
  return ausgabe;
}
bool Taster::active(){
  return digitalRead(pin)==highactive;
}

Wecker::Wecker(){
  weckzeit = millis();
}
void Wecker::stellen(unsigned int n){
  weckzeit = millis()+n;
}
bool Wecker::fertig(){
  return millis()>=weckzeit;
}