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
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.
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
kann mir nicht vorstellen, dass der assembler den C cast "(unsigned char)" versteht... nimm das weg, sollte besser gehen ;)
"Ein Präprozessor rechnet nie!" Doch. In #if (1+1) != 2 kann er rechnen.
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?
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
"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.
Ein Assembler kennt keine Datentypen, keine float-Konstanten und keine C-header Files. C != Assembler Peter
Vielleicht nimmst du dir ja lieber die Funktionen aus <util/delay.h>?
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 ?
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.
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
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?
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.