Forum: Mikrocontroller und Digitale Elektronik Lied abspielen ohne Programm-Blockade


von TM F. (p_richner)


Lesenswert?

Hallo zusammen

Ich möchte an meinem Signalgeber eine Melodie ausgeben. Das Ganze sieht 
etwa so aus:
1
void buzzer_play_tone(double frequenzy, uint8_t intervall)
2
{
3
  // Start the Timer1 with prescaler of 1024
4
  TCCR1B |= (1<<CS12) | (1<<CS10);
5
  uint16_t tone = 0;
6
  // Get the tone duration in micro seconds
7
  tone = 1000000/frequenzy;
8
  while(global_tone_duration<intervall)
9
  {
10
    OUTPUT_BUZZER |= 0x80;
11
    delay_us(tone);
12
    OUTPUT_BUZZER &= ~0x80;
13
    delay_us(tone);
14
  }
15
  // Stop the Timer1 
16
  TCCR1B &= ~((1<<CS12) | (1<<CS10));
17
  // Set back the tone duration, so that next tone is possible
18
  global_tone_duration = 0;
19
}
20
21
void buzzer_play_song(void)
22
{
23
  buzzer_play_tone(A7,VIERTEL_NOTE);
24
  buzzer_play_tone(E7,ACHTEL_NOTE);
25
  buzzer_play_tone(F7,ACHTEL_NOTE);
26
  buzzer_play_tone(G7,ACHTEL_NOTE);
27
}

Die ganze Tonausgabe funktioniert problemlos.

Jedoch blockiert mir die Funktion den restlichen Programmcode, so dass 
ich nichts mehr machen kann, vor allem wenn das Lied länger wird.

Meine Frage: Wie muss ich es implementieren, so dass bei jedem 
Funktionsaufruf nur ein Ton gespielt wird. Ich möchte jedoch nicht 20 
if-Abfragen mit einem Zähler. Gibt es mit Arrays eine Möglichkeit oder 
sonst irgendwas, so dass das Programm überschaubar bleibt?

MfG

von Kuno (Gast)


Lesenswert?

TM F. schrieb:
> Jedoch blockiert mir die Funktion den restlichen Programmcode

Ist doch klar, weil du mit Delays arbeitest.
Beschäftige dich mal mit Timern.
Du wirst staunen, was man damit alles machen kann :-)

von Falk B. (falk)


Lesenswert?

@TM FW (p_richner)

>Ich möchte an meinem Signalgeber eine Melodie ausgeben. Das Ganze sieht
>etwa so aus:

Dann gehört dein Beitrag aber nicht ins Unterforum Projekte & Code, dort 
gehören nur halbwegs getestete Projekte rein und keine Fragen.

>Jedoch blockiert mir die Funktion den restlichen Programmcode, so dass
>ich nichts mehr machen kann, vor allem wenn das Lied länger wird.

Logisch.

>Meine Frage: Wie muss ich es implementieren, so dass bei jedem
>Funktionsaufruf nur ein Ton gespielt wird. Ich möchte jedoch nicht 20
>if-Abfragen mit einem Zähler. Gibt es mit Arrays eine Möglichkeit oder
>sonst irgendwas, so dass das Programm überschaubar bleibt?

Sicher. Und wie schon gesagt gibt es Timer-Interrupts, damit 
wird deine CPU nicht blockiert. Siehe auch Multitasking.

von Peter D. (peda)


Lesenswert?

Speziell zur Tonausgabe bieten sich die PWM-Ausgänge Deines unbekannten 
AVRs geradezu an. Schau doch einfach mal ins Datenblatt.

TM F. schrieb:
> Ich möchte jedoch nicht 20
> if-Abfragen mit einem Zähler.

if/else Ketten sind extrem unleserlich, für sowas nimmt man switch/case.

TM F. schrieb:
> Gibt es mit Arrays eine Möglichkeit

Natürlich. Schreibe in ein Array die Tonhöhe und Dauer als Liste und 
setze einen Pointer darauf.

von TM F. (p_richner)


Lesenswert?

Peter D. schrieb:
> Natürlich. Schreibe in ein Array die Tonhöhe und Dauer als Liste und
> setze einen Pointer darauf.

Habe es mir nachträglich nochmals überlegt und werde es wohl so machen.

Danke für die Antwort

von Johnny B. (johnnyb)


Lesenswert?

Wenn Du nicht selber einen Scheduler programmieren willst und Dich mit 
Timerrinterrupts quälen, kannst Du sowas auch rel. simpel mit einem 
Realtime Betriebssystem lösen. z.B. FreeRTOS.
Die Einarbeitungszeit ist natürlich auch nicht ganz unerheblich, aber 
das ganze ist dann sehr flexibel in der Anwendung.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.