Forum: Compiler & IDEs Tabelle mir Präprozessor erzeugen?


von risu (Gast)


Lesenswert?

Hallo,

um mit dem 16-Bit Timer (ATmega48) bestimmte Frequenzen erzeugen zu 
können, möchte ich eine Tabelle mit Werten für OCR1A im EEPROM ablegen, 
die folgendermaßen aussehen soll (hier auf 4 Elemente verkürzt; 
tatsächlich soll die Tabelle etwa 100 16-Bit-Werte umfassen):
1
uint16_t const OCR[] __attribute__ ((section(".eeprom"))) = {1250, 1176, 1111, 1053};

Die Elemente des Arrays gehorchen der Formel F_CPU/(2*f), wobei f mit 
400 beginnt und in Schritten von 25 ansteigt.

Kann ich diese Tabelle vom Präprozessor oder Compiler erzeugen lassen? 
Die Tabelle soll zur "compile time" entstehen und nicht auf dem Atmega 
berechnet werden. Bisher erzeuge ich die Tabelle in Excel, exportiere 
sie als Text, bearbeite sie, und kopiere sie dann in meine Quelldatei.

Gruß
 risu

von (prx) A. K. (prx)


Lesenswert?

Implizite Schleife ist im Präprozessor nicht drin, aber rechnen kann er 
schon (bzw. dann der Compiler). Also ={F(1),F(2),F(3),...} mit 
entsprechendem Makro F(x).

Wird das zu viel, kann man den Quellcode der Tabelle von einem Programm 
auf der Entwicklungsmaschine erzeugen lassen.

Wenn dir das auch nicht passt, kannst du zuätzlich den M4-Präprozessor 
vorschalten. Der kann Schleifen, auch wenn's etwas komisch aussieht.

von risu (Gast)


Lesenswert?

Danke, hatte gehofft, dass es einen Trick gibt für eine Schleife!

von Peter D. (peda)


Lesenswert?

risu wrote:
> um mit dem 16-Bit Timer (ATmega48) bestimmte Frequenzen erzeugen zu
> können, möchte ich eine Tabelle mit Werten für OCR1A im EEPROM ablegen,

Konstanten legt man besser im Flash ab, da ist mehr Platz und das Lesen 
geht schneller.

Nur wenn die Werte zur Compilezeit noch unbekannt sind oder später 
geändert werden müssen, nimmt man den EEPROM.



Peter

von 900ss (900ss)


Lesenswert?

So geht es auch. Du sparst dir das ausrechnen der einzelnen Werte 
sondern mußt nur die Tabelle mit den Frequenzen erstellen. Die 
Frequenzen lassen sich ja im Kopf errechnen ;-)

1
#define FREQUENZEN L(400), \
2
                   L(425), \
3
                   L(450), \
4
                   L(475)
5
6
7
8
#define L(f)   (F_CPU/(2*f))
9
uint16_t const OCR[] __attribute__ ((section(".eeprom"))) =
10
  {
11
      FREQUENZEN
12
  };
13
#undef L

Edit: nochmal angepaßt, damit es auch im EEPROM liegt. Im Flash geht es 
aber auch.

von risu (Gast)


Lesenswert?

Danke, 900ss D. ! Nachdem sich eine "Präprozessor-Schleife" als nicht 
machbar herausgestellt hat, ist das sicher die beste Lösung.

Gruß
 risu

von (prx) A. K. (prx)


Lesenswert?

@900ss: Weshalb der Umweg über Makro?

@risu: Schleife geht nicht, dies aber schon:
 #define F(n) ...
 #define FF(n) F(n+0),F(n+1),...,F(n+9)
und dann
 ... { FF(0),FF(10),... };
was auf 10xFF statt 100xF rausläuft.

von 900ss (900ss)


Lesenswert?

A. K. wrote:
> @900ss: Weshalb der Umweg über Makro?

Geht natürlich auch ohne das Makro in diesem Fall.
Aber diese Lösung nutze ich als "Standard" oft, da auch mehrspaltige 
Tabellen so zu nutzen sind. Und ich habe es deshalb hier so übernommen.
Es lassen sich noch viele andere schöne Sachen damit machen.
Im Beispiel brauchst Du nur die "Tabelle" STATES ändern und der erzeugte 
Enumerator und auch die Funktion GetStatusText() passen automatisch.
1
#define STATES     L(STATE1, 1), \
2
                   L(STATE2, 4), \
3
                   L(STATE3, 7), \
4
                   L(STATE4, 8)
5
6
#define L(a,b)   ( a = b )
7
enum eStates
8
{
9
  STATES
10
};
11
#undef L
12
13
static u08 *GetStatusText( u08 id )
14
{
15
    switch(id)
16
    {
17
    #define L(id,value) case id: return #id;
18
       STATES
19
    #undef L
20
       default:return "not defined";
21
    }
22
}

Solche Konstrukte sind allerdings sehr grenzwertig, da sie schon 
schlecht "lesbar" sind.
Außerdem muß man aufpassen, dass die "Tabelle" STATES nicht zu ang wird, 
da ja der Präprozessor dieses als eine lange Zeile sieht. D.h. die max. 
mögliche Zeilenlänge ist die begrenzende Größe und dass ist von Compiler 
zu Compiler unterschiedlich, wenn ich nicht irre.

Die Idee stammt übrigens nicht von mir. Hat mir mal ein Kollege so 
gezeigt.

von risu (Gast)


Lesenswert?

Für alle Kommentare vielen Dank!

von StinkyWinky (Gast)


Lesenswert?

Ich bin der Meinung, es sollte so heissen:
1
#define STATES     L(STATE1, 1) \
2
                   L(STATE2, 4) \
3
                   L(STATE3, 7) \
4
                   L(STATE4, 8)
5
6
#define L(a,b)   a = b,
7
enum eStates
8
{
9
  STATES
10
};
11
#undef L
12
13
static u08 *GetStatusText( u08 id )
14
{
15
  switch(id)
16
  {
17
    #define L(id,value) case id: return #id;
18
      STATES
19
    #undef L
20
      default:return "not defined";
21
  }
22
}

Den Originalcode von 900ss D kann ich sonst nicht compilieren.

von 900ss (900ss)


Lesenswert?

Hmmm... ja, habe es so aus dem Kopf hingeschrieben und nicht getestet. 
Hatte gerade keinen Source "in der Hand", wo ich es abschreiben konnte.
Sorry an alle, die ich verwirrt habe.

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.