Forum: Mikrocontroller und Digitale Elektronik RTTTL Player


von Achim S. (achims)


Lesenswert?

Hallo Gemeinde
Den folgenden Code habe ich versucht anzupassen. Er wird ohne Fehler 
copieliert, bringt aber keine Funktion .- sagt gar nichts
Leider ist mir die Sache nicht klar was los ist.
Daten AT1284p, C, 16 MHZ, Taster PC2, Lsp. PC7
1
/* ********************************************************************
2
 Melodiegenerator fuer AT1284p (tiny8)           Uwe Berger; 2009 
3
 Inputformat der Melodien ist Nokias RTTTL-Format. Der Rest ist aus dem Quelltext ersichtlich!
4
 Wobei im vorliegenden Programm aber der RTTTL-Parser gleich mit drin ist und somit ohne externen   
5
 Konverter auskommt. Man kann RTTTL-Klingeltoene ohne Anpassung an der entsprechenden Stelle im  
6
 Programm eingefuegt werden
7
 * Nachteil: es wird etwas mehr Speicherplatz fuer das Programm verbraucht
8
 * Hardware:
9
 (ATtiny85) AT1284p in Standardbeschaltung Folgende Peripherie:
10
 - an PC7 ist ein Lautsprecher angeschlossen. Ich habe dazu eine dieser laermenden Geburtstagskarten   
11
 gepluendert. Dieser Lautsprecher wurde direkt angeschlossen, eventuell sollten aber bei anderen Modellen Strombegrenzungswiderstaende vorgesehen werden.
12
 - an PC2 ist ein Taster angeschlossen, der den Tiny aus dem Schlaf reisst und ihn die naechste Melodie dudeln laesst. Der geschlossene Taster legt GND an den Pin, es sollte ein PullUp-Widerstand von    10kOhm vorgesehen werden.
13
*********************************************************************/
14
#ifndef F_CPU
15
#define F_CPU 16000000UL           
16
#endif
17
18
#include <avr/io.h>
19
#include <util/delay.h>
20
#include <avr/interrupt.h>
21
#include <avr/pgmspace.h>
22
#include <avr/sleep.h>
23
24
// Lautsprecherport
25
#define SPEAKER_DDR    DDRC
26
#define SPEAKER_PORT  PORTC
27
#define SPEAKER      PC7
28
29
// Taster
30
#define TASTER_DDR  DDRC
31
#define TASTER_PORT PORTC
32
#define TASTER_PIN  PC2
33
#define TASTER_INT  PCINT18
34
35
// Vorteiler fuer Timer0 (in ctc_on() TCCR0B entsprechend mit anpassen!)
36
#define PRESCALE 8
37
38
// Tonfrequenzen
39
const uint16_t freq[] PROGMEM = {
40
  //   C,   C#,    D,   D#,    E,    F,   F#,    G,   G#,    A,   A#,    B
41
   262,  277,  294,  311,  330,  349,  370,  392,  415,  440,  466,  494,   // Oktave 5
42
   523,  554,  587,  622,  659,  698,  740,  784,  831,  880,  932,  988,   // Oktave 6
43
  1046, 1109, 1175, 1244, 1328, 1397, 1480, 1568, 1661, 1760, 1865, 1975,  // Oktave 7
44
  2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951 // Oktave 8
45
};
46
47
const char m1[] PROGMEM = "99luv:d=4,o=5,b=180:d6,8e6,c6,e.6,d6,8c6,a.,8p,8a,8f6,f6,f6,f.6,8f6,e6,d6,c.6,d6,8e6,c6,e.6,d6,8c6,a.,8p,8a,f6,f6,f6,f6,8f6,e6,d.6,8c6,8d6,e6,c6,e.6,d6,8c6,a.,8p,8a,c6,8a,c6,f6,f6,e6,d.6,8c6,d6,e6,c6,e.6,d6,8c6,a.,8p,8f6,f6,8f6,f6,f6,f6,e6,2d6";
48
49
const char m2[] PROGMEM = "letitbe:d=4,o=5,b=112:16g.,8g,g,8g,a,8e,8g,g.,8c6,d.6,e6,8e6,e6,8d6,8d6,8c6,2c6,e6,8e6,f6,8e6,8e6,d.6,8e6,8d6,2c6";
50
51
const char m3[] PROGMEM = "Peter Schilling - Major Tom:d=4,o=6,b=200:c.,8p,c,c,c.,8p,c.,8p,2a5,2c,c,8a#5,8a5,g.5,8p,2a#5,2d,2d,c.,8p,2a5,2c,c,8a#5,8a5,g.5,8p,2a#5,2d,2d,e.,8p,1f,2e,d,c,2d.,c,2d,e.,8p,1f,2e,d,c,2d.,c,2d,2";
52
53
const char m4[] PROGMEM = "yday:d=4,o=5,b=125:g,8f,f,p,8a,8b,8c#6,8d6,e6,8p,8f6,e6,8d6,d6,p,8d6,8d6,8c6,8a#,8a,8g,8a#,8a,8a,a,8p,g,f,8a,8g,g,8p,8d,f,8p,8a,a";
54
55
//const char ma[] PROGMEM = {m4,  m1,  m2,  m3};
56
const char ma[] PROGMEM = "m4,  m1,  m2,  m3";  
57
58
//*********************************************************************
59
ISR(PCINT0_vect)
60
  {
61
    // vorhanden, um MCU definiert aus dem Sleep-Mode zu holen
62
  }
63
64
//*********************************************************************
65
static void ctc_on(void) 
66
  {
67
    // CTC mode mit toggeln von OC0A/OC0B (Tiny85)
68
    TCCR0A |= (1<<COM0A0 | 1<<COM0B0 | 1<<WGM01);
69
    // Prescaler 8
70
    TCCR0B = 1<<CS01;
71
  }
72
73
//*********************************************************************
74
static void ctc_off(void) 
75
  {
76
    TCCR0A = 0;
77
    TCCR0B = 0;
78
  }
79
80
//*********************************************************************
81
int f(int n, int o) 
82
  {  // lustiger Nebeneffekt des Zugriffs auf den Flash-RAM: die Zeit die dazu notwendig ist, fuegt // eine kleine Pause zwischen den Toenen ein, die auch ganz sinnvoll ist...
83
            // lt. Datenblatt fuer CTC-Mode ist Focnx = Fclk / (2 * Prescale * (1 + OCRnx)
84
            // umgestellt nach OCRnx: OCRnx = (Fclk / Focnx / 2 / Prescale) - 1
85
    return (F_CPU/pgm_read_word(&freq[n+(o-5)*12])/2/PRESCALE)-1;
86
  }
87
88
//**********************************************************************
89
char rf(const char *p) 
90
  {
91
    return pgm_read_byte(p);
92
  }
93
94
//**********************************************************************
95
void my_delay_ms(uint16_t ms) 
96
  {
97
    uint16_t i;
98
    // es ist mir nicht gelungen, die Pause via Timer zu realsieren: es gab merkwuerdige Seiteneffekte, 
99
    // denen ich nicht auf die Spur gekommen bin...
100
    // _delay_ms generiert nur dann wenig Maschinencode, wenn es mit konstanten Werten gefuettert   
101
    // wird, also deshalb dieser Konstrukt....
102
    for (i=0; i<ms; i++) _delay_ms(1);
103
  }
104
105
//**********************************************************************
106
void play(uint8_t i) 
107
  {
108
    const char *p;
109
    uint16_t def_noten_laenge = 4; 
110
    uint8_t def_oktave = 6;
111
    uint16_t def_bpm = 63;
112
    // Anfangspointer setzen
113
    p = (const char*)(pgm_read_word(&(ma[i])));
114
    // Titel ueberspringen
115
    while (rf(p) && rf(p) != ':') p++;
116
    if (!rf(p)) return;
117
    p++;
118
    // als naechstes kommen die Song-Defaults
119
    while (rf(p)) 
120
      {
121
        uint8_t param;
122
        uint16_t value;
123
        // fuehrende Leerzeichen ueberspringen
124
        while (rf(p) == ' ') p++;
125
        if (!rf(p)) return;
126
        // hier ist das Ende des Default-Bereiches erreicht  
127
        if (rf(p) == ':') break;
128
        param = rf(p);
129
        p++;
130
        if (rf(p) != '=') return;
131
        p++;
132
        value = 0;
133
        while (rf(p) >= '0' && rf(p) <= '9') 
134
          {
135
            value = value * 10 + (rf(p) - '0');
136
            p++;
137
          }
138
        switch (param) 
139
          {
140
            //case 'd': def_noten_laenge = 32 / value; break;
141
            case 'd': def_noten_laenge = value; break;
142
            case 'o': def_oktave = value; break;
143
            case 'b': def_bpm = value; break;
144
          }
145
        // folgende Leerzeichen ueberspringen
146
        while (rf(p) == ' ') p++;
147
        if (rf(p) == ',') p++;
148
      }
149
    p++;
150
    // Noten selbst analysieren
151
    while (rf(p)) 
152
      {
153
        uint8_t note = 63;
154
        uint16_t oktave = def_oktave;
155
        uint16_t noten_laenge = def_noten_laenge;
156
        uint16_t dauer_ms;
157
        uint8_t punkt_note = 0;
158
159
        // Leerzeichen ueberspringen
160
        while (rf(p) == ' ') p++;
161
        if (!rf(p)) return;
162
163
        // Notenlaenge bestimmen
164
        if (rf(p) >= '0' && rf(p) <= '9') 
165
          {
166
            uint16_t value = 0;
167
            while (rf(p) >= '0' && rf(p) <= '9') 
168
              {          
169
                value = value * 10 + (rf(p) - '0');
170
                p++;
171
              }
172
            noten_laenge = value;
173
          }
174
175
        // Note bestimmen
176
        switch (rf(p)) 
177
          {
178
            case 0: return;
179
            case 'C': case 'c': note = 0; break;
180
            case 'D': case 'd': note = 2; break;
181
            case 'E': case 'e': note = 4; break;
182
            case 'F': case 'f': note = 5; break;
183
            case 'G': case 'g': note = 7; break;
184
            case 'A': case 'a': note = 9; break;
185
            case 'H': case 'h': note = 11; break;
186
            case 'B': case 'b': note = 11; break;
187
            case 'P': case 'p': note = 63; break;
188
          }
189
        p++;
190
    
191
        // Halbnote hoeher
192
        if (rf(p) == '#') 
193
          {
194
            note++;
195
            p++;
196
          }
197
    
198
        // Halbnote tiefer(?)
199
        if (rf(p) == 'b') 
200
          {
201
            note--;
202
            p++;
203
          }
204
205
          // Punktnote=
206
          if (rf(p) == '.') 
207
            {
208
              // noten_laenge += noten_laenge / 2;
209
              punkt_note = 1;
210
              p++;
211
            }
212
213
          // Oktave ermitteln
214
          if (rf(p) >= '0' && rf(p) <= '9') 
215
            {
216
              oktave = (rf(p) - '0');
217
              p++;
218
            }
219
220
          // hier koennte auch ein Punkt sein...
221
          if (rf(p) == '.') 
222
            {
223
              // noten_laenge += noten_laenge / 2;
224
              punkt_note = 1;
225
              p++;
226
            }
227
228
          // nachfolgende Leerzeichen ueberspringen
229
          while (rf(p) == ' ') p++;
230
          // Komma ist Notentrenner
231
          if (rf(p) == ',') p++;
232
          // Tondauer berechnen (60s = 60000ms)
233
          dauer_ms = (((60000 / def_bpm) * def_noten_laenge) / noten_laenge);
234
          // war eine Punktnote dabei?
235
          if (punkt_note) dauer_ms += dauer_ms/2;
236
          if (note != 63) 
237
            {
238
              OCR0A = f(note, oktave);     // Tonfrequenz einstellen
239
              OCR0B = f(note, oktave);
240
              ctc_on();              // Ton einschalten
241
              my_delay_ms(dauer_ms);      // Ton fuer berechnete Dauer halten
242
              ctc_off();              // Ton ausschalten      
243
            } 
244
          else 
245
            {
246
              // Pause fuer berechnete Dauer
247
              ctc_off();        // Ton ausschalten
248
              my_delay_ms(dauer_ms);
249
            }
250
        }
251
  }
252
253
int main(void) 
254
  {
255
    uint8_t i = 0;
256
    // Taster 
257
    TASTER_PORT &= ~(1 << TASTER_PIN);    // Taster-Pin als Eingang
258
  
259
  
260
    // PCINT0 initialisieren  
261
    
262
  PCMSK2 |=  (1 << TASTER_INT);        // Taster-Pin maskieren
263
  PCICR |=  (1 << PCIE2);          // Port Change Interrupt frei
264
  
265
  sei();
266
    // Lautsprecher als Ausgang
267
    SPEAKER_DDR |= (1<<SPEAKER);
268
    while(1) 
269
      {
270
        if (i >= (sizeof(ma)/sizeof(ma[0]))) i = 0;
271
        play(i);
272
        // Sleep-Mode
273
        set_sleep_mode(SLEEP_MODE_PWR_DOWN);
274
        sleep_mode();
275
        i++;
276
      }
277
    return 0;
278
  }
Sorry, habe gerade erst gesehen, das prescaler nicht angepasst. Gibt es 
sonst einen Grund?
Vielleicht könnte jemand drüber schauen
achim

von Achim (Gast)


Lesenswert?

Hallo Peter
das ist das gesamte Programm zu dem RTTTL Player
achim

von Jürgen S. (jurs)


Lesenswert?

Achim Seeger schrieb:
> Vielleicht könnte jemand drüber schauen

Ich würde mal prüfen, ob Du überhaupt die beabsichtigte Melodie ausliest 
und nicht irgendwelchen Datenmüll.

Ich als Arduino-Programmierer verhaspele mich per default regelmäßig 
dabei, auf ein Array of PROGMEM-Konstanten über ein Array von 
PROGMEM-Pointern zuzugreifen und brauche dann stets serielles Debugging, 
um mir das auszubaldowern, wie die Zugriffe mit Pointern und pgm_read... 
in sich stimmig sind.

So auf Anhieb würde ich erstmal sagen, dass Deine Melodieanfänge im 
Programm nicht "array of char" sein sollen:
1
const char ma[] PROGMEM = "m4,  m1,  m2,  m3";
sondern dass da ein "array of char pointer" definiert werden sollte, und 
das nicht als String, sondern als Array of Pointer:
1
const char *ma[] PROGMEM = {m4,  m1,  m2,  m3};

: Bearbeitet durch User
von Achim (Gast)


Lesenswert?

Danke Jürgen, werde es probieren

von Achim S. (achims)


Lesenswert?

Habe die Zeile noch mal kontrolliert. War fehlerhaft übertragen. Habe es 
jetzt geändert und bekomme ein Fehlermeldung:

Error  1  variable 'ma' must be const in order to be put into read-only 
section by means of '__attribute__((progmem))'

Sorry, versteh nicht was ich machen soll.
achim

von Achim S. (achims)


Lesenswert?

Sorry, habe die Zeile und die übersetzung vergessen. Kommt sofort
1
const char *ma [] PROGMEM = {m4,  m1,  m2,  m3};
2
3
/*
4
\  Fehler 1 Variable 'ma' muss const sein, um mit Hilfe von '__attribute __ ((progmem))' 
5
E in Nur-Lese-Abschnitt gesetzt werden .c 63 13 Sound_V1_1
6
*/

Was sagt mir diese Zeile?
achim

von Jürgen S. (jurs)


Lesenswert?

Achim Seeger schrieb:
> Sorry, habe die Zeile und die übersetzung vergessen. Kommt sofort
>
>
1
> const char *ma [] PROGMEM = {m4,  m1,  m2,  m3};
2
> 
3
> /*
4
> \  Fehler 1 Variable 'ma' muss const sein, um mit Hilfe von '__attribute 
5
> __ ((progmem))'
6
> E in Nur-Lese-Abschnitt gesetzt werden .c 63 13 Sound_V1_1
7
> */
8
>
>
> Was sagt mir diese Zeile?


Die Fehlermeldung besagt, dass der Compiler den Code nicht fressen 
möchte.
Das ist ja gediegen!

Ich habe es selbst gerade mal mit der Arduino-IDE getestet:

Mit einer alten AVR-GCC Compilerversion (Arduino 1.0.5) wird der Code 
fehlerfrei compiliert.

Mit einer neuen AVR-GCC Compilerversion (Arduino 1.5.7) erzeugt der Code 
beim Compilieren die Fehlermeldung.

Mit ist bekannt, dass am AVR-GCC etwas an der PROGMEM-Verarbeitung von 
Flash-Konstanten geändert wurde, so dass es nun zwingend erforderlich 
ist, PROGMEM-Konstanten als "const" zu deklarieren.

Aber dass sich auf die altbekannte Art überhaupt keine Stringtabellen 
mehr vollständig im Flash-Speicher anlegen lassen, war mir neu. Ich 
konnte auch nicht über Google herausfinden, was da die neue Alternative 
sein soll. Mit ein bisschen Tüfteln bin ich auf diese Zeile gekommen, 
die der Compiler akzeptiert:
1
const int ma[] PROGMEM= {(int)m4, (int)m1, (int)m2, (int)m3};

Da String-Pointer auf 8-Bit AVRs ja im Endeffekt Integers sind, sollte 
es damit funktionieren. Ich habe allerdings nur getestet, dass sich der 
Code damit COMPILIEREN läßt. Das Funktionieren habe ich mangels Hardware 
NICHT getestet.

von Achim S. (achims)


Lesenswert?

Hallo Jürgen
habe es sofort versucht. Es lässt sich ohne Fehler compilieren. Leider 
keine Funktion
Sorry, wenn du schon gediegen nimmst, was bleibt mir noch zu sagen.
Vermute das einiges Profis hier mitlesen. Vielleicht gibt es ein 
klärendes wort dazu? Hallo ...
achim

von Jürgen S. (jurs)


Lesenswert?

Achim Seeger schrieb:
> Hallo Jürgen
> habe es sofort versucht. Es lässt sich ohne Fehler compilieren. Leider
> keine Funktion

Also ich habe das Programm mit meiner Änderung mal in die Arduino-IDE 
geladen und lasse mir in der Play-Funktion die zu spielenden Noten auf 
dem "Seriellen Monitor" ausgeben.

Debug-Code der dekodierten Noten auf Arduino:
1
          if (note != 63) 
2
            {
3
              Serial.print(note);Serial.print('\t');
4
              Serial.print(oktave);Serial.print('\t');
5
              Serial.print(f(note, oktave));Serial.print('\t');
6
              Serial.println(dauer_ms);
7
              /*
8
              OCR0A = f(note, oktave);     // Tonfrequenz einstellen
9
              OCR0B = f(note, oktave);
10
              ctc_on();              // Ton einschalten
11
              my_delay_ms(dauer_ms);      // Ton fuer berechnete Dauer halten
12
              ctc_off();              // Ton ausschalten      
13
              */
14
            }

Serielle Ausgabe der dekodierten Noten und der zu spielenden Frequenz 
beim Song "Yesterday":
1
Note  Oktave  Freq.  Dauer
2
7  5  2550  480
3
5  5  2864  240
4
5  5  2864  480
5
9  5  2271  240
6
11  5  2023  240
7
1  6  1804  240
8
2  6  1702  240
9
4  6  1516  480
10
5  6  1431  240
11
4  6  1516  480
12
2  6  1702  240
13
2  6  1702  480
14
2  6  1702  240
15
2  6  1702  240
16
0  6  1911  240
17
10  5  2144  240
18
9  5  2271  240
19
7  5  2550  240
20
10  5  2144  240
21
9  5  2271  240
22
9  5  2271  240
23
9  5  2271  480
24
7  5  2550  480
25
5  5  2864  480
26
9  5  2271  240
27
7  5  2550  240
28
7  5  2550  480
29
2  5  3400  240
30
5  5  2864  480

Also wenn Du mit der Hardware diese Noten/Frequenzen mit den 
Abspieldauern in Millisekunden ausgibst, sollte eigentlich etwas zu 
hören sein.

Wenn nicht, dann dürfte entweder etwas mit der eigentlichen 
Tongenerierung in Deinem Programm nicht stimmen. Oder es stimmt etwas 
nicht mit der Hardwareschaltung für die Tonausgabe.

von Achim S. (achims)


Lesenswert?

Hallo Jürgen
es könnte sein das der verwendete PC7 gar nicht für sowas geht. Mal 
sehen was ich an der Hardware schnell machen kann.
achim

von Jürgen S. (jurs)


Lesenswert?

Achim Seeger schrieb:
> Hallo Jürgen
> es könnte sein das der verwendete PC7 gar nicht für sowas geht. Mal
> sehen was ich an der Hardware schnell machen kann.

Ich muß mal sehen, ob ich irgendwo noch einen alten PC zur Entsorgung 
abgestellt rumstehen habe, wo ich mir schnell mal einen 
Kleinstlautsprecher zum Testen ausbauen kann. Dann könnte ich mal mit 
einem Atmega328 probieren, ob mit Deinem Code Töne ausgegeben werden.

Aber mal eine andere Frage:
So wie ich im Thread Beitrag "Einfache Tonerzeugung" sehe, 
spielst Du schon seit über zwei Jahren mit einfacher Piepstonausgabe auf 
8-Bit AVR Controllern herum. Hast Du in den zwei Jahren noch keine 
verlässliche Möglichkeit gefunden, "Sinustöne" bestimmter Piepsfrequenz 
an einem Pin auszugeben?

In dem Fall wäre mein Rat, sich mal "Arduino" näher anzusehen. Da gibt 
es für diverse Standardaufgaben entweder Funktionen in der Arduino 
Core-Library, oder in mitgelieferten Libraries, oder von Leuten aus der 
Arduino-Community, die eigene Libraries als Open Source anbieten. Zur 
Tonerzeugung ist sogar direkt im Arduino-Core eine Funktion dabei:
http://arduino.cc/en/pmwiki.php?n=Reference/Tone
Damit zauberst Du quasi mit Null Aufwand und ohne irgendwelche Register 
"zu Fuß" programmieren zu müssen, eine Audio-Tonfrequenz auf einen 
Ausgabepin.

Mit direkter Registerprogrammierung der AVR-Controller kenne ich mich 
selbst nur schlecht aus. Ich muß mal sehen, ob ich das in Deinem Sketch 
nachvollziehen kann, zumindest auf Atmega328. Aber vorher benötige ich 
erstmal einen Lautsprecher zum Testen.

Du müßtest auch darauf achten, dass die erzeugten Frequenzen wirklich 
genau erzeugt werden. Wenn Du beispielsweise statt 1804 oder 1702 Hertz 
andere Frequenzen erzeugst, die acht- oder sechzehnmal so hoch sind, 
dürftest Du wohl kein hörbares Audiosignal mehr erhalten.

von Achim S. (achims)


Lesenswert?

Hallo Jürgen
ist eigentlich eine einfache Sache. Im Jahre 2012 habe ich noch viel mit 
dem Nibo 2 gemacht. Dieser hat den Ausgang mit dem OPV drauf. Habe 
versucht was in Hardware und Bus dazu zu bauen und Erweiterungen zu 
machen. Der Hersteller nutzt seine eigenen Libs usw. und gibt keine oder 
sehr wenig Info. Dann noch alles open source. Irgendwann hatte ich keine 
Lust mehr, blöde Fragen zu stellen und keine Antworten zubekommen. Habe 
dann an dem I2C Bus weiter gemacht und einiges dazu gebaut und 
programmiert. Verwende jetzt den AT1284p auf einem eigenen Board und ca. 
20 zusätzliche Platinen. Alles in einem einheitlichen System mit 
gleichen Anschlüssen. Dadurch kann ich alles zusammenstellen wie ich 
möchte und ständig erweitern und umbauen und umstecken. Dazu zählen 
Netzteile, Anzeigen, Relais, Triax, Fernbedienung, 8 und 16 Bit Ein- und 
Ausgänge, die Kombinationen zwischen Bus und Port, Übertragung des Bus 
auf Entfernung bis hin zum Multitasking und der Kombination aus beiden 
Sachen. Zufällig habe ich auf dem PC7 einen Piezo Lautsprecher 
eingebaut. Diesen wollte ich zur Ausgabe eines Tones nutzen. Mit einer 
einfachen Art (delay) klappt es sehr gut. Vom Nibo kannte ich noch das 
RTTTL und woltte es auch so machen. Das klappt leider nicht. Dietr hat 
schon geschrieben, das der PC7 nicht da für geht. Da kein PWM. Wustte 
ich nicht. Muss mir wohlwas anderes überlegen.
achim

von bt (Gast)


Lesenswert?

Vielleicht erklärt hier mal jemand, wie sich das mit den PWM Ausgängen 
der Timer verhält..
Wenn der Timer 0 benutzt wird, dann kommt der Pieps an einem Pin raus, 
der auch als OC0 bezeichnet ist, wenn's der Timer1B ist, piepst's nur 
wenn der Speaker an einem Pin mit der Zusatzbezeichnung OC1B hängt.
In "doc2467.pdf" (von Atmel Seite downloadbar) ab Seite 82 geht's los..
oder etwas auf deutsch:
[[http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Z%C3%A4hler_des_AVR]]

und das mit den Titeladressarray geht bei mir so (im Studio 6)
1
/*****************************************************  TITEL STARTADRESSE
2
3
  ->  nr = Titelindex (Titelnummer-1) in der songs[] Liste
4
5
  <-  Startadresse des RTTTL Notenstrings im Flash
6
    Der Zeiger wird zur Titelanzeige mit show_titel() verwendet 
7
    und / oder an den RTTL Parser play_song() übergeben
8
9
**************************************************************************/
10
11
const char * PROGMEM const songs[] = {song0,song1,song2,song3,song4,song5,song6,\
12
          song7,song8,song9,songA,songB,songC,songD,songE,songF};
13
14
PGM_P audio_start_titel_P(uint8_t nr){
15
  if (nr >= (sizeof(songs)/sizeof(songs[0]))) nr =0;
16
  return (const char*)(pgm_read_word(&(songs[nr])));
17
}

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.