Forum: Mikrocontroller und Digitale Elektronik Projekt Melodiegenerator


von Paul P. (cpn)


Lesenswert?

Hallo Leute,
ich bin neu hier und Student.
Hab ein Projekt bekommen, einen Meldodiegenerator zu machen.
Habe ein Minimexle baord (www.minimexle.de)
mit einem ATmega88 und 4 Tastern, Lcd Display 16 zeichen 2 zeilen 
monochrom, einen ntc, lichtdiode, led und nen buzzer.
Nun wollte ich erst mal zum einsteigen anfangen ein Programm zu 
schreiben mit Hilfe eines Interrupts(oder Timer) womit ich mit 2 Tasten 
die Led schneller Blinken lassen kann und langsamer.
Das möchte ich dann auf den Buzzer erweitern.
Danach möchte ich mich mit Arras und Struckturen anfreunden, dh. die 8 
Lieder(Noten alle) in ein struct legen und dann für jedes Lied mit 
Pointern drauf zugreifen. Je nach Lied brauch ich dann auch nen andern 
Timer für die Geschwindigkeit.
Dann möchte ich ein einfaches Menü zu machen also Titel in der oberen 
Zeile im Display, unten ei Lied rauf/runter und Play/Stop eventuell mit 
play/stop(beide gedrückt, oder einfach play nochmals lang drücken) Pause 
Modus.
Nun alles schön und gut, bestimmt einfach realisierbar, aber ich bin 
anfänger, ne absolute Null, Displayausgabe, Taster einlesen, Led-ausgabe 
krieg ich noch hin, interrupt (blinken einer led) haben wir mal gemacht.

Also nur mal ein ansatz wie ich den Tei mim LED (schneller/langsamer) 
blinken Buzzer höher tiefer stellen.

Ein Programmteil oder Ansatz würde mir sehr helfen, bin seit Tagen dran 
des mit dem Interrupt zu verstehen, wie ich den schneller langsamer 
mach, für die anwendungen und wie ich die verschiedenen sachen ausgeb an 
den Buzzer, mit 256 werten? (Char?)
Keine Ahnung.

Danke für eure Hilfe
lg Paul

von Philipp B. (philipp_burch)


Lesenswert?

Hi,

dazu kann ich dir das AVR-Tutorial und das AVR-GCC-Tutorial an's 
Herz legen. Da ist die Interrupt-Geschichte und das ganze Timer-Zeug 
recht gut erklärt.

Aber im Grunde brauchst du etwa Folgendes: Einen Timer-Interrupt, 
sinnvollerweise von der Compare-Unit (ISR(TIMER_COMPA_vect) oder so) um 
das eigentliche Blinken zu erzeugen, sowie eine Schleife, in der du 
deine Taster abfragst. In der Schleife brauchst du dann eine 
Entprellung, um die Flanken ohne viel Müll zu erkennen. Bei jeder 
Flanke der entsprechenden Taste verstellst du dann dein OCR (OCR0A z.B. 
für die Output-Compare-Unit A an Timer0).

von MWS (Gast)


Lesenswert?

Für die Erzeugung eines Tons oder ein Blinken braucht's keinen 
Interrupt, ein Timer reicht, der einen OCx Pin toggelt.

Um ein Signal auf den Pin OC1A (PB1) zu bekommen, musst Du folgende 
Register konfigurieren:
TCCR1A, TCCR1B, TIMSK1

Wähle den CTC Modus und lass' den Port OC1A togglen, dann kannst Du mit 
dem Register OCR1A die Blink- oder Tonfrequenz einstellen.

Nur wenn sich etwas ändert soll, z.B. um die Tonlänge in einer Melodie 
zu steuern, würde sich ein Timerinterrupt anbieten.

von Paul P. (Gast)


Lesenswert?

Um diesen Besagten Pin zu toggeln, geht das auch mit dem Timer 0?
Oder geht das nur mit dem Timer 1?
Muss ich dann den Pin(PB1) zu meinem Ausgabepin(Buzzer PD5) 
rüberschleifen?
Oder kann ich direkt OC0B toggeln? Also mit Timer 0.
Und wie genau kann ich den Ton dann mit dem Register OCR1A einstellen?
Danke für Hinweise, (soll übrigens Töne und Tonlänge ohne interrupts 
machen).
Tonlänge = <util/delay.h>
Ton selber = Timer Compare?ohne Interrupt?

von Sound_Maker (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Paul,
hier mal eine Anregung für solch einen Melodien-Generator.
Ist zwar für einen 8051er geschrieben, dafür aber in C und die Tonhöhe 
und Tondauer werden ohne Interrupts erzeugt: die Tonhöhe durch Ausgabe 
einer entsprechenden Frequenz, mit einem Timer im Überlauf erzeugt und 
die Tondauer durch eine delay- bzw. wait-Funktion.
Als Kern hast Du einfach eine kleine Funktion, an die der gewünschte Ton 
und die Dauer übergeben wird und dann brummts.

Viel Spaß dabei

Sound_Maker

von MWS (Gast)


Lesenswert?

@Paul,


Timer 0 sollte auch gehen um einen Pin zu toggeln, nur ist Timer 0 ein 8 
Bit Timer und damit lassen sich die Frequenzen für die entsprechenden 
Noten nicht genau genug erzeugen. Musst Dir mal die erzeugbaren 
Frequenzen ausrechnen, um zu sehen ob das trotzdem reicht.

Der Portpin für Timer 1 ist in Hardware festgelegt und muss mit dem 
Buzzer verbunden werden, falls Timer 1 verwendet werden soll. Wenn der 
Buzzer bereits mit PD5 verbunden ist, dann kannst Du PD5 als Eingang 
definieren, den PB1/PB2 draufschalten, oder den Buzzer auftrennen und 
auf PB1/PB2 legen. Ich würde Letzteres machen, da sicherer.

Aber vielleicht geht auch Timer 0 für Dich, dann kannst Du Dir das 
Rumgelöte sparen.

Das Beispiel von Sound_Maker ist m.E. nur bedingt brauchbar für Dich, 
denn der Mega88 hat keinen Preload per Hardware, aber einen CTC Mode. 
Das ist aber etwas im Prinzip Ähnliches.

Der CTC funktioniert so, daß der Zähler bis zum Wert des entsprechenden 
OCRx Registers zählt und dann wieder von 0 anfängt. Wenn man ihn bei 0 
noch den entsprechenden Portpin toggeln lässt, dann bekommt man so eine 
einstellbare Ausgangsfrequenz. Weil getoggelt wird, ist die 
Ausgangsfrequenz 1/2 der CTC Frequenz.

Konsultier das Mega88 Datenblatt damit Du siehst, wie Prescaler, CTC, 
Toggle Modi und ORCx eingestellt werden, bzw. Einfluss auf die Frequenz 
haben.

Falls Du nicht klar kommst, melde Dich wieder.

von Paul P. (cpn)


Lesenswert?

Danke für die Tipps, hab jetzt so gemacht, dss der Timer0 im CTC 
Mode(Prescaler 256) mit OCR0A variabel zählt(je nach frequenz) und OCR0B 
fest auf 2 steht, somit den PD5 (Buzzer) immer toggelt(eingestellt durch 
COMB0 Modus). Töne hab ich mim Kollegen(Musiker) am Keyboard nach gehör 
genau eingstellt. 1,5 Oktaven und schon 4 lieder geschrieben.
Jetzt hab ich heut den Timer1 (16bit) eingestellt auch CTC aber 
Interrupt, und mit 1024 Prescaler und gleich auf die kleinste ms anzahl 
gestellt, also dass interruptservice routine alle 35ms kommt.
Jetzt muss ich nur noch die Lieder in arrays schreiben in der 
ISR(Timer1) auslesen lassen mit ner variablen, die dann immer eins 
erhöht wird nach (35ms, je nach ton -variabel).
und dann teil1(displaymenü) 14% bei jetztigen strings (Lied 1 bis Lied 
8)
und Teil 2 (lieder 4) mit 25% mit tastern und teil 3 (fast fertig, noch 
ISR und co.) zu vereinen.
Und dann theoretisch.... solltes gehn;) Dh. noch die 4 restlichen Lieder 
programmiern, und erst mal in arrays einlesen;)
Danke für eure Hilfe ich meld mich wenns probz gibt oder wenns mal 
funktioniert;)
lg Paul

von Paul P. (cpn)


Lesenswert?

PS: Ich habs jetzt fast soweit,
wer interesse hat kann sich melden, und ich poste dann hier meinen 
code;)
Ein Problem hatte ich noch bei auslesen eines 2 dim. arrays mit 
tonhöhe(timer0) und tonlänge(timer1, der gleichzeitig ISR macht, worin 
ausgelesen wird).
Und zwar: Ich mache play/ stop mit sei(); und cli(); set und clear 
interrupt, mit paar geeigneten einstallungen dazu hats auch 
funktioniert, aber wenn ich mal auf play drücke, dauert es zb 3sec. bis 
er das lied abspielt, manchmal und manchmal gehts.
Ebenso wenn ich mal mittem im lied stop mache oder bei mehrmaligen 
wiederholten abspielen spielt er den ersten ton zu lang ab, länger als 
im array steht(keine delay funkt. dazwischen, habe schon geschaut.)
Danke für hilfe lg  Paul

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.