www.mikrocontroller.net

Forum: Compiler & IDEs Präprozessor kann nicht rechnen


Autor: Dominc Rathje (derdingsder)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Lupin (Gast)
Datum:

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

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"Ein Präprozessor rechnet nie!"

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

Autor: Dominc Rathje (derdingsder)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Karsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Dominc Rathje (derdingsder)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: peter dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ein Assembler kennt keine Datentypen, keine float-Konstanten und keine
C-header Files.


C != Assembler


Peter

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

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

Autor: Dominc Rathje (derdingsder)
Datum:

Bewertung
0 lesenswert
nicht 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 ?

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: peter dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Dominc Rathje (derdingsder)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Dominc Rathje (derdingsder)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.