Forum: Compiler & IDEs Präprozessor kann nicht rechnen


von Dominc R. (derdingsder)


Lesenswert?

Hallo,

ich habe da ein kleines Problem mit dem avr-gcc.
Ich möchte eine delay Schleife die in Assembler geschreiben ist, mit
dem GCC compilieren. Der Startwert für das Zählregister soll aus der
Konstanten F_CPU berechnet werden, wie macht man das richtig?
wenn ich es so mache:

ldi  R18, (unsigned char)((F_CPU*0.00005-6)/4)

kommt folgender Fehler:

delay.S:26: Error: missing ')'
delay.S:26: Error: garbage at end of line

wenn ich das /4 durch *0.25 ersetze passiert genau das gleiche.
Warum kann der Präprozessor denn die Werte nicht einfach berechnen, und
den konstanten wert da einsetzen, wenn man das in einer C datei macht
klappt das doch auch?

ach ja: der gcc wird mit folgendem Befehl aufgerufen:
avr-gcc -c -mmcu=atmega16 -I. -x assembler-with-cpp -DF_CPU=7372800UL
-Wa,-adhlns=delay.lst,-gstabs,--listing-cont-lines=100 delay.S -o
delay.o

mfg
Dominic Rathje

von A.K. (Gast)


Lesenswert?

Der Präprozessor rechnet nur in seinen eigenen Statements, wie z.B. #if.
Alles andere ist in seiner ursprünglichen Anwendung überflüssig, weil's
da der Compiler macht.

Deine Aufgabe besteht also darin, das ganze so zu formulieren, dass es
der Assembler rechnen kann.

von Karsten (Gast)


Lesenswert?

Hallo Dominic,

mi fällt folgendes auf:

1.)Ein Präprozessor rechnet nie!
   Er ersetzt nur vorgegebene Ausdrücke im Code.

2.)Welchen Controller verwendest Du?
   Hat der wirklich das Register R18?

3.)Ich vermute, dass Du hier von in C-Code eingebetteten
Assembler-Anweisungen sprichts. Deshalb vermutet ich den Fehler ganz wo
anders.

Bitte stelle uns doch mal einen kompletten Auszug aus deimen Code zur
Verfügung damit wir mehr Informationen haben.

Karsten

von Lupin (Gast)


Lesenswert?

kann mir nicht vorstellen, dass der assembler den C cast "(unsigned
char)" versteht... nimm das weg, sollte besser gehen ;)

von A.K. (Gast)


Lesenswert?

"Ein Präprozessor rechnet nie!"

Doch. In
   #if (1+1) != 2
kann er rechnen.

von Dominc R. (derdingsder)


Lesenswert?

Hallo, danke für die Antworten.

also das ganze soll mal auf einem ATMega16 laufen.
das eigentliche Programm ist in C geschreiben, die delay routine in
Assembler.

die routine sieht folgendermaßen aus:

;50us Delay
.global delay50us
delay50us:

    ldi  R18, (unsigned char)((F_CPU*0.00005-6)/4)
delay50us_A:
  dec  R18
  nop
  nop
    brne delay50us_A
ret

die delay.h sieht folgendermaßen aus:

#ifndef ASM_FILE
extern void delay50us(void);
#else
.extern delay50us
#endif

das Makro ASM_FILE habe ich in den .S dateinen definiert, damit ich
diese .h datei überall einbinden kann.

in dem Hauptprogramm wird die Funktion einfach mit delay50us();
aufgerufen

Wenn ich aber die funktion mit Parameter aufrufe, und das zeug als
parameter mitgebe, funktioniert das einwandfrei. Das habe ich z.B. beim
Initialisieren vom UART so gemacht:

uart_init(115200);  //ist aus Komfortgründen nur ein Makro:
#define uart_init(br)  uart_init_func((( F_CPU / (16 * br) ) - 1));
und uart_init_func ist wiederum eine ASM Routine

Compiliert sieht das ganze das so aus:
  ce:  83 e0         ldi  r24, 0x03  ; 3
  d0:  90 e0         ldi  r25, 0x00  ; 0
  d2:  0e 94 e5 00   call  0x1ca <uart_init_func>
funktioniert also einwandfrei.

Wie muss man so einen Ausdruck denn Formulieren, damit der Assembler
das ausrechnet und einen konstanten Wert an der Stelle einsetzt?

von Karsten (Gast)


Lesenswert?

Ok, hätte mir den gcc-Aufruf mal genauer ansehen sollen.

Ist natürlich kein eingebetteter Code.

@A.K.: Kann sein habe ich so noch nie verwendet!

@Lupin: Das mit dem cast sieht mir auch verdächtig aus.

Karsten

von Dominc R. (derdingsder)


Lesenswert?

"kann mir nicht vorstellen, dass der assembler den C cast "(unsigned
char)" versteht... nimm das weg, sollte besser gehen ;)"

ohne den cast motzt er folgendes:

delay.S:26: Error: missing ')'
delay.S:26: Error: missing ')'
delay.S:26: Warning: constant out of 8-bit range: 7372800
delay.S:26: Error: garbage at end of line

ich hab das auch schon irgendwo so gesehen, find nur den link nicht
mehr, kann aber auch sein das ich da was verwechselt habe.

von peter dannegger (Gast)


Lesenswert?

Ein Assembler kennt keine Datentypen, keine float-Konstanten und keine
C-header Files.


C != Assembler


Peter

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Vielleicht nimmst du dir ja lieber die Funktionen aus
<util/delay.h>?

von Dominc R. (derdingsder)


Lesenswert?

Das Problem ist nur, dass ich die delay routine auch in Assembler
Dateien brauche, wie macht man denn dann eine routine die unabhängig
von der Taktfrequenz eine konstante Zeit verbraucht?

Oder gibt es nur die möglichkeit mit vielen #if F_CPU = ... für die
gängigsten Taktfrequenzen diese routinen getrennt zu implementieren ?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Hmm, wenn du das auch im Assembler brauchst, wird es schwierig.

Hardware-Timer kommt nicht in Frage?

Ja, die diversen #if F_CPU == ... könntest du sicher benutzen.
Dran denken, dass F_CPU dann als Integerzahl definiert sein
muss, der Präprozessor kann keine Gleitkomma-Rechnungen.

von peter dannegger (Gast)


Lesenswert?

Wenn es um CPU-Zeitvernichterschleifen geht, dann kann ja der Assembler
nicht zeitkritisch sein und ich würde alles nur in C machen.

Es fällt auch leichter, Assembler nach C umzuschreiben, solange man
dessen Funktion noch gut im Kopf hat.


50µs kann man auch durchaus mit nem freilaufenden Timer machen. Da ist
ein 1-wire Beispiel in C in der Codesammlung.


Peter

von Dominc R. (derdingsder)


Lesenswert?

Hallo, und danke für die zahlreichen Antworten

ich hab das jetzt mal so gemacht:

;void delay_us(uint16_t)
.global delay_us
delay_us:
  subi r24, 1    ;1
  sbci r25, 0    ;1
  nop
  brne delay_us    ;1 + 1
  ret

plus folgendes macro:
#define delayus(time_us) delay_us((F_CPU*0.000001*time_us-9)/4);


damit kann ich aus C heraus eine (fast) beliebige anzahl an µs
verzögern.

um das aus Assembler Dateien zu können würde ich jetzt gern ein macro
schreiben, das im prinzip folgendes macht:

ldi r24, irgend_ein_wert
ldi r25, irgend_ein_wert
call delay_us

aber mit .MACRO ... .ENDMACRO klappt das irgenwie nicht.
und mit #define motzt er rum wenn man mehrere zeilen hat.
wie definiert man denn nun so ein macro richtig, das der gcc das
versteht?

von Dominc R. (derdingsder)


Lesenswert?

So, ich glaub ich weiss jetzt wie man das macht:

  #define _L $

  #define delay50us(time_us)    \
    ldi r24, 90  _L\
    ldi r25, 0  _L\
    call delay_us

zumindest funktioniert es so

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.