Forum: Projekte & Code Melody Player für AVR mittels Timer0 erzeugten Rechteckfrequenzen


von Ralph S. (jjflash)


Angehängte Dateien:

Lesenswert?

Alle Jahre wieder rieselt der Schnee leise auf Rudolf den rotnasigen 
Weihnachtsbaum (oder so ähnlich)!

Für eine Weihnachtsbastelei (wie alle Jahre wieder) brauchte ich einen 
"Melody-Player".

Mein bisherig verwendete Timer1 (welch Verschwendung), und den benötige 
ich nun für anderes.

Also muß 8-Bit Timer0 herhalten. Zu meinem Erschrecken (ich habe mit dem 
alten ATmega8 lange nichts gemacht) hat dieser keinen Compare-Match auf 
Timer0. (sollte ich mich hier irren und ich bin blind durchs Datenblatt 
gelatscht, bitte ich um Korrektur)

Damit der Melody-Player auf so ziemlich allen AVR's läuft habe ich das 
nun im


8-Bit Overflow Modus


gelöst und hoffe, dass ich das nicht noch einmal machen muß (für welche 
Bastelei auch immer).

Der Melody-Player wurde getestet auf:

ATtiny13, ATtiny2313, ATtiny44 / 84, ATtiny45 / 85, ATmega8, ATmega88, 
ATmega168 und ATmega328p.

Die benutzbaren Taktfrequenzen sind:

4,8MHz; 8MHz; 9,6MHz, 16MHz

Der Melody-Player spielt einen String, der die zu spielenden Noten 
enthält.

Dieser "Notenparser" versteht folgende Zeichen:

Buchstaben c d e f g a h  sowie C D F G A gefolgt von einer numerischen 
Ziffer.

Hierbei stellen die Buchstaben die zu spielende Note dar und die Ziffer 
die Tonlänge. Die Großbuchstaben sind hierbei Cis, Dis, Fis, Gis, Ais

Bsp.

a2 : spielt eine halbe Note "a"
C4 : spielt eine viertelnote "C"

Eine Besonderheit ist (weil mir die Ziffern ausgegangen sind) die Ziffer 
9. Diese spielt (abweichend von der sonstigen Notation) eine sechzehntel 
Note.

Das + Zeichen erhöht die zu spielende Oktave, - Zeichen vermindert die 
zu spielende Oktave.

Buchstabe "p" gefolgt von einer Ziffer fügt eine Pause mit der 
Notenlänge der Ziffer ein.

p2 : fügt eine Pause mit der Dauer einer halben Note ein.

------------------------------------------------------------

Die Frequenzen wurden mittels eines Libre-Office Calc Sheets ermittelt. 
Hier würde ich für eine Rückmeldung dankbar sein, ob dieses auch in 
Excel funktioniert, besonders die Berechnung der Abweichung von der 
gewünschten Frequenz.

Mit dieser Tabellenkalkulation kann der Melody-Player an andere 
CPU-Frequenzen angepasst werden.

Innerhalb des Headers toene_melodie.h ist die Angabe zu machen, an 
welchen Portpin der Lautsprecher angeschlossen ist:
1
  // -------------- Lautsprecheranschluss ---------------------
2
  #define speaker_port     B
3
  #define speaker_portnum  4

Aktuell ist hier Portpin PB4 (für die 8-poligen ATtinys) eingestellt.

toene_melodie.c beinhaltet eine globale Variable:

volatile uint8_t sound

Diese Variable wird im Interrupt ausgewertet. Mit ihr kann die 
Frequenzerzeugung an- oder ausgeschaltet werden:

sound = 0;      // Ton aus
sound = 1;      // Ton an

uint16_t playtempo= 5;

Diese Variable bestimmt die grundsätzliche Geschwindigkeit, mit der ein 
Notenstring abgespielt wird.

Makro von toene_melodie.h
-------------------------

speaker_init();
Initialisiert den im Kopf der Datei angegebenen Portpin als Ausgang

Funktionen von toene_melodie.c
------------------------------

void timer0_init(void);
Initialisiert den Timer0 als 8-Bit

void playnote(char note);
schaltet den Ton ein und spielt die angegebene Note solange, bis sie 
durch

   sound= 0;

wieder abgeschaltet wird

void playstring(const unsigned char* const s);
spielt einen Notenstring, der im Codespeicher abgelegt sein muß.

Bsp.
1
  const uint8_t tonleiter[] PROGMEM =  { "c4 d4 e4 f4 g4 a4 h4 + c4" }
2
  .
3
  .
4
  .
5
  playstring(&tonleiter[0]);

------------------------------------

Beispiel für den Anschluss eines Lautsprechers:
1
                     +Ub
2
                      ^
3
                      |
4
                     ,-,
5
                     | | 16 - 390  ( je nach gewuenschter Lautstaerke )
6
                     '-'
7
                      |
8
                      |
9
                     ,-,/|
10
                     | | |
11
                     '-'\|
12
                      |
13
            2,2k      |
14
            ___     |/
15
   o-------|___|----|  BC549
16
Input               |>
17
von Portpin           |
18
                      |
19
                      |
20
                      |
21
                     ---

Viel Spaß beim Noten zusammenbasteln und schöne Vorweihnachtszeit.

von Jasson J. (jasson)


Lesenswert?

Cool :)

hatte sowas ähnliches angefangen aber noch auf einem quicker and 
dirtiger Level. Bei sinds noch zwei 16 Bit Wertpaare - ebenfalls Tonhöhe 
und Dauer.
War auch schon auf den Trichter gekommen, das wie du es schon gemacht 
hast und sinnvoll ist auf die Notendarstellung zu ändern.

Ich hab bei mir noch vorgesehen, über UART neue Folgen reinspielen zu 
können.

Finde ich 1ne nice Idee mit dem + und - zur Oktavenänderung :)

von Ralph S. (jjflash)


Lesenswert?

Jasson J. schrieb:
> Ich hab bei mir noch vorgesehen, über UART neue Folgen reinspielen zu
> können.

kann man gerne machen, allerdings:

Hierfür braucht es einen RAM-Puffer aus dem abgespielt werden kann und 
zumindest bei einem ATtiny13 sieht das sehr düster aus.

Allerdings sollte das überhaupt kein Problem für die anderen AVR's sein, 
hier ist beim Array dann schlicht das "PROGMEM" weg zu lassen.

Hmmm, und wenn man schon so etwas macht, kann man den eingelesenen 
String auch gleich in das interne EEPROM packen, aus dem der 
Melodie-Player dann abspielt.

Das überlasse ich dann gerne den Bastlern, für meinen "Verwendungszweck" 
benötige ich das nicht !

Danke für das Feedback

von Jasson J. (jasson)


Lesenswert?

Ralph,

wie hast du das gelöst, wenn zwei gleiche Noten hinter einander folgen?
Wenn man für eine Note stumpf eine bestimmte Frequenz für eine gewisse 
Dauer erzeugt und danach die selbe nochmal würde man das auf unseren 
elektronischen Klimperkästen ja als einzelne längere Note wahrnehmen.

Bei richtigen Instrumenten hat man ja zum einen immer den Effekt, dass 
der Anschlag abklingt oder eben die minimale Pause zwischen einer 
vorrausgegangenen Note und dem neuen Anschlag.

Mir würde einfallen generisch von der Notendauer einen Prozentsatz als 
"tot" zu definieren.

: Bearbeitet durch User
von egberto (Gast)


Lesenswert?

Prozentsatz ist imho nicht richtig - eher ein kurze konstante Zeit (so 
lange, wie man halt z.B. bei einer Flöte zum Umgreifen braucht) - in 
meiner Klingel hänge ich einfach an jeden Ton ein 20ms Delay.

Grüße,

Egberto

von Ralph S. (jjflash)


Lesenswert?

Jasson J. schrieb:
> Wenn man für eine Note stumpf eine bestimmte Frequenz für eine gewisse
> Dauer erzeugt und danach die selbe nochmal würde man das auf unseren
> elektronischen Klimperkästen ja als einzelne längere Note wahrnehmen.

Jasson J. schrieb:
> Mir würde einfallen generisch von der Notendauer einen Prozentsatz als
> "tot" zu definieren.

Nun bin ich leider kein Musiker und habe auch leider niemals ein 
Instrument gelernt (das ist etwas, das mir in meinem Leben wirklich 
fehlt). Von daher kann ich nur ansatzweise erahnen was du meinst. Bei 
mir reicht es nur dafür aus dem Musikunterricht von vor fast 50 Jahren 
zum Lesen von Noten, was ein c,d etc. oder ein CIS ist... und was 
Achtel- , Viertel-, Halbenoten sind.

Von daher kann ich nur aus einem einfachen Notenblatt eben diesen 
Notenstring erzeugen.

Abgespielt wird er bspw. durch ein c2.

Das "c" startet die Frequenz und stellt den Ton an. Die "2" sagt wie 
lange er an ist und stellt diesen Ton wieder aus. Damit 2 gleiche Noten 
als solche erkannt werden gibt es eine (immer gleiche) Zeit  während der 
Lautsprecher aus ist. Vllt. meinst du das hier:
1
void tonlen(int w)
2
{
3
  int cx;
4
5
  w = w*100;
6
  for (cx= 0; cx< w; cx++) { _delay_us(100); }
7
  sound= 0;
8
  _delay_ms(30);
9
}

Wird tonlen aufgerufen (vom Stringparser), bestimmt diese Funktion wie 
Lange der Ton eingeschaltet ist. Nach Ablauf dieser Zeit ist der Ton für 
30ms aus bevor der nächste Ton wieder einsetzen kann.

von Ralph S. (jjflash)


Lesenswert?

So, jetzt habe ich mal auf die allerschnellste Art etwas "gecodet", habe 
aber kein Equipment hier um das zu testen.

In den Parser kann ich noch einen weiteren Buchstaben einführen, der 
interpretiert wird, sagen wir ein "j" (für mich halt so ähnlich wie ein 
Jitter - hey, ich sagte so ähnlich).

Mit diesem "j" kann man dann das "30ms Ton aus" am Ende einer Notendauer 
abschalten und einen direkten Notenübergang von einer Note zur anderen 
vornehmen.

Leider (oder für mich besser) habe ich Urlaub und kann das erst in ca. 1 
1/2 Wochen hier einstellen. Allerdings sollte eine solche Veränderung 
von jedem auch selbst durchgeführt werden können. : - )

von Ralph S. (jjflash)


Lesenswert?

Ach herjeh, außerdem sehe ich gerade, dass die Datei:

toene_melodie.c

Fehler hat. Sie beinhaltet Teile die dort nicht hingehören.
1
// -------------- Lautsprecheranschluss ---------------------
2
#define speaker_port     B
3
#define speaker_portnum  4

Sind ersatzlos zu löschen, da diese bereits in "toene_melodie.h" 
definiert sind.

Sowie
1
static const unsigned char schneew  [] PROGMEM = { "c4d4e2g4e2g4e1d4e4f2g4f2g4f1g4a4h2+f4-h2+f4-h1a4h4+c2e4c2-a4g1e4g4+c1-h1+d1c1-a2+c4-a2+c4-a1" };

ebenfalls ersatzlos zu löschen ist, weil dieser String ins Hauptprogramm 
gehört und dort ebenfalls bereits definiert ist.

Sorry

von Marcus H. (Firma: www.harerod.de) (lungfish) Benutzerseite


Angehängte Dateien:

Lesenswert?

Ich weiß nicht, wieviele Versionen von Quäkern ich in den letzten 25 
Jahren gebaut habe. Die ersten mit PIC, dann AVR AT90 und mittlerweile 
ATtiny.

Alle paar Jahre wieder braucht irgendjemand einen kleinen Quälgeist. In 
der letzten Interation wurde ein ATtiny412 verbaut, der kann sowohl PWM 
als auch 10bit-DAC.

Achtung kommerziell:
http://harerod.de/applications_ger.html#TQ412_melody

+ + +

Weil die Frage der Unterscheidbarkeit von aufeinanderfolgenden gleichen 
Tönen aufkam: ein echtes Instrument hat u.a. einen Anschlag. Beim 
PWM-Quäker kann man sich behelfen, indem man eine ganz kurze Pause 
zwischen den Tönen einfügt, das Ohr ist da sehr aufmerksam.

von Ralph S. (jjflash)


Lesenswert?

Schmunzeln muss: Das habe ich doch gemacht!

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.