tone()-Funktion: Jeder Song extra abspielen

Hallo an alle, ich bin neu hier, das ist mein erster Post im Forum, und mit Arduino bin ich auch recht neu.

Der untere Code spielt array "song1" ab, das funktioniert alles soweit gut.

Ich möchte das man per Button UP/Down oder mehrere Buttons, den nächsten Song aufrufen kann.
Dafür dachte ich mir das alles aus der loop in eine eigene Funktion zB.
void Abspielen() {}
eingefügt wird und in der loop steht dann nur sowas wie:

if(But1==LOW){Abspielen(song1);}
if(But2==LOW){Abspielen(song2);}
//...usw.

drin steht.
Ich wollte den Songname der Funktion übergeben aber das klappt aber absolut nicht, ausser Fehlermeldungen kommt nichts gescheites raus.

Ich kenne die c-Sprache leider noch nicht so gut :frowning:

#define nC4  262
#define nCS4 277
#define nD4  294
#define nDS4 311
#define nE4  330
#define nF4  349
#define nFS4 370
#define nG4  392
#define nGS4 415
#define nA4  440
#define nAS4 466
#define nB4  494

#define nC5  523
#define nCS5 554
#define nD5  587
#define nDS5 622
#define nE5  659
#define nF5  698
#define nFS5 740
#define nG5  784
#define nGS5 831
#define nA5  880
#define nAS5 932
#define nB5  988
#define nC6  1047

#define nPP  0 //Pause

int16_t song1[]={//Array: Note, Dauer: 1=ganze Note, 2=halbe Note, 4=Viertelnote usw.
 nC4,8, nD4,8, nE4,8, nF4,8, nG4,8, nA4,8, nB4,8, nC5,4, nPP,2
};

int16_t song2[]={
 nC5,8, nD5,8, nE5,8, nF5,8, nG5,8, nA5,8, nB5,8, nC6,4, nPP,2
};

int buz=13;   //Lautsprecher an diesem Pin angeschlossen
int spd=1200; //Dauer einer ganzen Note in Millisekunden
int allNote=0, dur=0, i=0;

void setup()
 {pinMode(buz,OUTPUT); allNote=sizeof(song1)/2;
  Serial.begin(9600);
  Serial.print("Melodielänge: ");
  Serial.print(allNote/2); Serial.println(" Noten\n-----------------------------------------------------");
  delay(1000);
 }

void loop()
 {for(i=0; i<allNote; i=i+2)
   {dur=spd/song1[i+1]; //Notenlänge in Millisec berechnen
    char buf[50]; sprintf(buf,"Note: %2d | Freq.:%4d Hz | Länge: %2d",i/2, song1[i], song1[i+1]);
    Serial.println(buf);
    tone(buz,song1[i],dur);
    delay(dur*1.33); //Note abspielen und warten vor naechster Note
   }
  Serial.println("-----------------------------------------------------");
 }

Du musst den Zustand (Button gedrückt) in einer Variablen speichern. Sonst spielt dein Song ja nur so lange du den Button drückst.

Es ging mir eigentlich um die Abspielfunktion, das läuft nicht.
Ok ich habe jetzt mal 3 buttons mit Up/Down und Reset eingebaut.

Da ist dann auch der Funktionsaufruf zum abspielen
//PlaySong(cnt);
dabei und noch auskommentiert, da komme ich nicht weiter.

2: #####################################
Ausserdem stört mich beim starten den arduino, das

Playing Song 2/5
Playing Song 1/5
Reset: Playing Song 1

ausgeführt wird, aber es wurde doch kein button geklickt ?

3: #####################################
sizeof kappiere ich garnicht, warum muß man durch 2 teilen um auf die anzahl der
indexe zu kommen?

Hier das ganze script:

#define But1    2
#define But2    3
#define But3    4
byte newState1=0, newState2=0, newState3=0;
byte oldState1=0, oldState2=0, oldState3=0;
int cnt=0;

//Warum is sizeof array 10, es sind doch nur 5 Einträge drin ???
char* title[]={"Playing Song 1","Playing Song 2","Playing Song 3","Playing Song 4","Playing Song 5"}; //Displaytext
//Warum :2 um auf die richtige Größe zu kommen ???
byte allSongs=sizeof(title)/2-1;

void setup()
 {Serial.begin(9600);
  pinMode(13,OUTPUT); //Piezo
  pinMode(But1,INPUT_PULLUP); pinMode(But2,INPUT_PULLUP); pinMode(But3,INPUT_PULLUP);
 }

void loop()
 {newState1=digitalRead(But1);
  newState2=digitalRead(But2);
  newState3=digitalRead(But3);

  if(butDebounce(newState1,But1)!=oldState1) //Button UP: newState mit oldState vergleichen
   {if(newState1==1)
     {cnt++; tone(13,2000,8);
      if(cnt>allSongs){cnt=0;}
      Serial.print(title[cnt]); Serial.print("/"); Serial.println(allSongs+1);
      //PlaySong(cnt);
     }
   }
  oldState1=newState1;

  if(butDebounce(newState2,But2)!=oldState2) //Button DN: newState mit oldState vergleichen
   {if(newState2==1)
     {--cnt; tone(13,2000,8);
      if(cnt<0){cnt=allSongs;}
      Serial.print(title[cnt]); Serial.print("/"); Serial.println(allSongs+1);
      //PlaySong(cnt);
     }
   }
  oldState2=newState2;

  if(butDebounce(newState3,But3)!=oldState3) //Button Reset: newState mit oldState vergleichen
   {if(newState3==1)
     {cnt=0; tone(13,500,8);
      Serial.print("Reset: "); Serial.println(title[cnt]);
      //PlaySong(cnt);
     }
   }
  oldState3=newState3;
 }

bool butDebounce(bool butState, byte butPin)
 {bool stateNow=digitalRead(butPin);
  if(butState!=stateNow){delay(10); stateNow=digitalRead(butPin);} //Delay 10 löst das Debounceproblem
  return butState;
 }

OnlySketching:
2: #####################################
Ausserdem stört mich beim starten den arduino, das

Playing Song 2/5
Playing Song 1/5
Reset: Playing Song 1

ausgeführt wird, aber es wurde doch kein button geklickt ?

Ok, Stück für Stück.

Du verwendest die internen PullUp, dann musst du im Sketch die Taster auf LOW abfragen.
So wie du es machst, erkennen die immer HIGH.

Ahh ok...hab jetzt alle 3 auf LOW gesetzt -> if(newState1==0)

Frage zu diesem HIGH und LOW,
gibt es einen Unterschied ob man HIGH oder 1 schreibt,
bzw 0 oder LOW ?
Bei Buttons und states ist das doch kein Problem oder?

Weißt du warum das mit sizeof() so komisch ist?
Ich kenne das aus javascript und php, da ist sizeof IMMER so groß
wie die anzahl der Elemente im array!

OnlySketching:
Ahh ok...hab jetzt alle 3 auf LOW gesetzt -> if(newState1==0)

Frage zu diesem HIGH und LOW,
gibt es einen Unterschied ob man HIGH oder 1 schreibt,
bzw 0 oder LOW ?
Bei Buttons und states ist das doch kein Problem oder?

Das funktioniert so, also kein Problem.

Weißt du warum das mit sizeof() so komisch ist?
Ich kenne das aus javascript und php, da ist sizeof IMMER so groß
wie die anzahl der Elemente im array!

Das muss ich mir noch ansehen.

Hi

sizeof gibt den Speicherplatzverbrauch zurück, ein INT hat eine Größe von 2 Byte, ein BYTE eine Größe von einem Byte, Long, Double, Float mehr (Näheres in den Tiefen des Arduino-Universum).

Du kannst aber sizeof(element)/sizeof(int) schreiben, wenn 'element' auf INTs besteht.

sizeof(int) ergibt also 2, da ein INT genau zwei Byte einnimmt.

MfG

Normal macht man sizeof(array) / sizeof(array[0]). Dann passt es sich automatisch an

Serenifly:
Normal macht man sizeof(array) / sizeof(array[0]). Dann passt es sich automatisch an

Echt? Das ist ja sowas von umständlich! Da zähl ich die Elemente lieber und lass so ein
oschi weg! -> byte allSongs=sizeof(title)/sizeof(title[0])-1;

Hat diese lange schreibweise mit dieser IDE zu tun oder mit C++ allgemein?
Ein Javascript oder PHP-ler lacht sich da ja kaputt! :slight_smile:

sizeof(); gibts in vielen sprachen um stringinhalt oder arrayelemente zu ermitteln,
aber einfach nur so: sizeof(myStr); oder sizeof(myArray);

Du kannst dir einmal ein Makro schreiben das die Anzahl der Elemente berechnet und fertig.

Es gibt auch einige Sachen bei deinen man wirklich die Anzahl der Bytes braucht. z.B. memset() und memcmp(). Oder Funktionen die irgendwas Byte-weise übertragen (egal wie die Daten aussehen). Das gibt es in der Arduino-Welt häufig. Seriell, I2C, SPI, diverse Funk-Schnittellen. Das basiert alles auf Bytes.
Im Gegensatz du den von dir genannten Sprachen hat C/C++ halt mal als Low Level Sprache angefangen und man hat direkten Zugriff auf den Speicher.

Um die Länge von C Strings zu ermitteln gibt es strlen() (was allerdings eine Funktion in kein Operator ist), und String Klassen haben ihre eigene Methode dafür.

Hi

Es ist, wie Es ist.
Du musst Das ja nicht benutzen - dann aber halt nicht wundern, warum Das nicht so funktioniert, wie in Deiner rosaroten Welt vorgesehen.

Das Teil gibt nun Mal den verbratenen Speicherplatz zurück - ob Dir Das nun recht ist, oder nicht.

Auch in PHP und JavaScript muß man sich an die Eigenarten der Sprachen halten - aber keine Angst, ich hätte auch besser mit C++ angefangen, statt PHP, JavaScript, (mySQL), Assembler, Basic :wink:

strlen() könnte aber hier ebenfalls anders funktionieren, als in php (sollte ich mich jetzt nicht stark irren, daß der Befehl ebenso in php vorkommt)

MfG

Ok kann mir jemand mit dem sketch helfen?
Ich habe das Menü fertig gemacht, jetzt wäre das problem mit dem sound abspielen aus einem Funktionsaufruf.

Als Anregung:

#define nC4  262
#define nCS4 277
#define nD4  294
#define nDS4 311
#define nE4  330
#define nF4  349
#define nFS4 370
#define nG4  392
#define nGS4 415
#define nA4  440
#define nAS4 466
#define nB4  494

#define nC5  523
#define nCS5 554
#define nD5  587
#define nDS5 622
#define nE5  659
#define nF5  698
#define nFS5 740
#define nG5  784
#define nGS5 831
#define nA5  880
#define nAS5 932
#define nB5  988
#define nC6  1047

#define nPP  0 //Pause

uint16_t song1[] = { //Array: Note, Dauer: 1=ganze Note, 2=halbe Note, 4=Viertelnote usw.
  nC4, 8, nD4, 8, nE4, 8, nF4, 8, nG4, 8, nA4, 8, nB4, 8, nC5, 4, nPP, 2
};

uint16_t song2[] = {
  nC5, 8, nD5, 8, nE5, 8, nF5, 8, nG5, 8, nA5, 8, nB5, 8, nC6, 4, nPP, 2
};

const int buz = 13; //Lautsprecher an diesem Pin angeschlossen
const int spd = 1200; //Dauer einer ganzen Note in Millisekunden

void setup()
{
  pinMode(buz, OUTPUT);
  Serial.begin(9600);
  Serial.println("Anfang");
  delay(1000);
}

void loop()
{
  Abspielen(song1, sizeof(song1) / sizeof(song1[0]));
  Abspielen(song2, sizeof(song2) / sizeof(song2[0]));
}

void Abspielen(uint16_t * lied, uint16_t groesse)
{
  Serial.print("Melodielaenge: ");
  Serial.print(groesse / 2);
  Serial.println(" Noten\n-----------------------------------------------------");
  for (uint16_t i = 0; i < groesse; i = i + 2)
  {
    uint16_t dur = spd / lied[i + 1]; //Notenlänge in Millisec berechnen
    char buf[50]; sprintf(buf, "Note: %2d | Freq.:%4d Hz | Laenge: %2d", i / 2, lied[i], lied[i + 1]);
    Serial.println(buf);
    tone(buz, lied[i], dur);
    delay(dur * 1.33); //Note abspielen und warten vor naechster Note
  }
  Serial.println("-----------------------------------------------------");
}

OnlySketching:
... Echt? Das ist ja sowas von umständlich! Da zähl ich die Elemente lieber und lass so ein
oschi weg! -> byte allSongs=sizeof(title)/sizeof(title[0])-1;

Guck mal hier ganz unten („Formelfreakfutter“).

OnlySketching:
Hat diese lange schreibweise mit dieser IDE zu tun oder mit C++ allgemein?
Ein Javascript oder PHP-ler lacht sich da ja kaputt! :slight_smile:

Probier' doch mal, das in BF zu programmieren. Ja, es gibt schlimmeres als JS und PHP :wink:

@agmue: Ich habe mir angewöhnt, statt #define Konstante zu benutzen. Ich meine

const int nC4=262;

statt

#define nC4  262

Das Problem mit den #defines ist, dass damit die Typprüfung des Compilers „ausgehebelt“ wird.

Gruß

Gregor

gregorss:
@agmue: Ich habe mir angewöhnt, statt #define Konstante zu benutzen.

Ja, ich stimme Dir grundsätzlich zu. Wäre dies mein Thema und mein Sketch, wäre meine Antwort: "Danke, mache ich."

Wenn ich einen fremden Sketch verändere, dann befinde ich mich in einer Zwickmühle, wie viel Veränderung notwendig ist. Ein Sketch mit einem gewissen Wiederkennungswert findet nach meiner Erfahrung eine höhere Akzeptanz als ein komplett neuer. Der TO möchte häufig wissen, warum sein Ansatz nicht funktioniert hat. Kann ich auch verstehen.

Manche Variablentypen habe ich verändert, Konstanten als solche markiert. Aber #define ist weder falsch noch unüblich, daher habe ich es unverändert gelassen. Auch könnte man über die blockierenden Elemente tone und delay nachdenken. Aber das ist halt nicht die Fragestellung.

const int nC4=262;

statt

#define nC4 262

Das Problem mit den #defines ist, dass damit die Typprüfung des Compilers „ausgehebelt" wird.

Du meinst sicher

const [b]unsigned[/b] int nC4=262;

Merkregel: Datentypintist oft ein Hinweis darauf, dass über den Datentyp nicht nachgedacht wurde.

Aber ob tone(13, -1000); zur Compilierzeit als Fehler auffällt, oder was dann tatsächlich passiert, habe ich nicht nur was den Compiler angeht, ausprobiert.

const unsigned int a = -880;  // leider kein Fehler
unsigned int a2 = -880;  // auch kein Fehler
  • vermutlich statt a' eher ein für mich unhörbarer Ton mit 64648 Hz
    (Schade eigentlich)

Im übrigen stimme ich agmue zu, dass ungefragte Verbesserungstips gern und teilweise zu Recht ignoriert werden.
Wenn z.B. Blockieren nicht das Thema ist und ein Sketch mit delay das eigentliche Problem demonstriert, sollte man diese Struktur im Verbesserungsvorschlag so lassen, finde ich.

michael_x:
Du meinst sicher

const [b]unsigned[/b] int nC4=262;

Nein, meinte ich nicht. Aber Du hast natürlich recht.

michael_x:
... dass über den Datentyp nicht nachgedacht wurde.

Oder dass nicht lange genug nachgedacht wurde. Das nächste Mal werde ich mir eine Minute mehr nehmen.

Gruß

Gregor