Ich möchte die Include Datei Avr/delay.h einbinden. Und danach das Delay mit verschiedenen Parametern aufrufen können! Nur klappte es irgendwie nicht! Es wird zwar ein Delay aufgerufen, jedoch kann man mit den Übergabewerten die Verzögerungszeit nicht beeinflussen! Wisst ihr, was ich falsch mache? Vielen Dank!
Nun, diverse Dinge. Erstens, im Prinzip müßte das gehen. Aber: > void _delay_loop_2(unsigned int); Überflüssig, wahrscheinlich nicht schädlich. Die Funktion ist bereits ausreichend in der Header-Datei deklariert. > outp (0xff,DDRB); // Port B als Ausgang outp() ist `deprecated'. Schreibe besser DDRB = 0xff; > bPortD = 0xFE; // Variable initialisieren Es ist relativ unsinning, dafür eine extra Variable zu verplempern, noch dazu eine globale. Speicherzugriffe brauchen meiner Erinnerung nach wenigstens zwei Zyklen und müssen außerdem umständlich über ein Adreßregister vorbereitet werden, Portzugriffe brauchen nur einen Zyklus. Da beim AVR der Inhalt des Ausgabelatches garantiert rücklesbar ist (Lesen von PORTB, zum Lesen der Eingabepins muß PINB gelesen werden -- andere Microcontroller machen das nicht so), kann man sich ruhig auf PORTB verlassen. Die Empfehlung eines Atmel-Menschen auf der avr-gcc Liste neulich war sogar, daß man sich ein unbenutztes Portregister suchen solle, wenn man innerhalb einer Interruptroutine ein permanentes Register haben möchte, um sich zwischen den Aufrufen der Routine einen Wert zu merken. ;-) (Vorsicht aber, nicht jedes Portregister ist gleich schnell, das lohnt nur bei solchen, die durch direkte IN/OUT Befehle erreichbar sind.) > _delay_loop_2(120); Nun, _delay_loop_2() ist mit 4 Takten pro Durchlauf ausgewiesen. Bei angenommenen 4 MHz Oszillatorfrequenz wäre also der übergebene Wert die direkte Verzögerung in µs. Dein Aufruf würde 120 µs Verzögerung bewirken, der gesamte Durchlauf 8 * 120 µs =~ 1 ms. Du mußt ziemlich schnelle Augen haben, wenn Du das noch wahrnehmen kannst. :-) Ich würde den Wert erstmal für einen Test verhundertfachen, also 12000. Das wären dann 100 ms Gesamtdurchlaufzeit (oder 400 ms bei 1 MHz Takt), immer noch recht flott. Denk dran, daß be 65535 Schluß ist, es ist ein 16-Bit-Wert.
So, habe den Fehler gefunden: Der Compiler versteht den Befehl "static inline void" nicht!!! Sobald ich nur void _delay_loop_2 (unsigned int) in der Include Datei definiere, funktioniert die Routine! Und noch eine Frage zum Compiler! Kennt er den Befehl "lsl" nicht??? Im Anhang noch die Delay - Include Datei
Vielen Dank für die Analys meines codes ;-) Wenn im Include File das Delay mit "static inline void _delay_loop_2 (unsigned int)" kann ich _delay_loop_2 (65535) oder _delay_loop_2 (1) aufrufen, die Verzögerung bleibt genau gleich! Jedoch sobald ich das "static inline void" weglasse funktioniert die Parameterübergabe! -> Wieso ist das so? und die übersetzung von: bPortD = (bPortD<<1)|(bPortD>>7); könnte doch ganz einfach mit einem lsl Befehl realisiert werden! Liegt das an der Optimierungsangabe im Makefile? Die übersetzung von
> Der Compiler versteht den Befehl "static inline void" nicht!!! [Nebenbei: Deine Frage- und Ausrufezeichentasten prellen, laß sie bei Gelegenheit mal reparieren. ;-)] Natürlich versteht er den, sonst würde das nicht im Headerfile so stehen. ;-) Allerdings gibt es einen offenen Bugreport, das Ganze funktioniert derzeit nicht, wenn die Optimierung ausgeschaltet wird (-O0), weil der Compiler dann keine inline-Funktionen anlegen will. Außerdem könnte es noch sein, daß Deine redundante (nicht-inline) Deklaration ggf. im Weg ist, habe ich nicht analysiert. > Kennt er den Befehl "lsl" nicht??? Das ist kein C-Befehl. Der Prozessor selbst kennt sowas, dafür müßtest Du aber auf inline assembler zurückgreifen. Würde ich einem Anfänger nicht empfehlen. > und die übersetzung von: > bPortD = (bPortD<<1)|(bPortD>>7); > könnte doch ganz einfach mit einem lsl Befehl realisiert werden! Eher wohl mit einem ROL, aber ganz so intelligent ist der Compiler wohl leider nicht. Wie gesagt, Optimierung auf jeden Fall einschalten (also mindestens -O1), damit die inline-Funktionen funktionieren. Hatte ich vorhin vergessen: "int main(void)" ist OK, aber am Ende fehlt dann ein "return 0;", der Schönheit halber. Durch die vorangehende Endlosschleife wird das vom Compiler sowieso wegoptimiert.
Vielen Dank Ich habe die Optimierung auf opt=s. Was empfiehlst du? Was gibt es für verschiedene Optimierungsstufen? Wo sind diese Beschrieben? Beherrsche Englisch noch nicht soo gut! :-(
-Os sollte genügen, wichtig ist halt nur, daß überhaupt optimiert wird. Fehlendes -O oder -O0 wäre das. Nö, sollte tun. Schau doch mal den Disassembler-Output an, gibt's da nicht sogar 'ne Datei (.lss oder sowas)?
also wenn ich beim makefile opt = 0s oder -0s schreibe, gibt es mir eine Fehlermeldung beim kompilieren ;-( Wo sind die verschiedenen Optimierungs levels beschrieben? Die Datei .lss hab ich schon angeschaut! Dort sehe ich, dass beim static inline void -> kein Parameter übergeben wird... Danke
> opt = 0s oder -0s (OPT wird übrigens groß geschrieben.) Ja klar, wenn Du Dir das Makefile ansiehst wirst Du feststellen, daß der Makro OPT ja für den Teil nach dem -O benutzt wird, also gehören dort exakt die aufgeführten Werte (0, 1, s, 2 oder 3) hinein. Im Prinzip wäre auch gar kein Wert zulässig, das entspricht dann der 1 (weil -O äquivalent zu -O1 ist). > Wo sind die verschiedenen Optimierungs levels beschrieben? Im gcc-Manual. Sollte bei Dir lokal installiert sein, oder ist im Web zu finden (http://gcc.gnu.org/ wenn ich mich recht entsinne). > Die Datei .lss hab ich schon angeschaut! Dort sehe ich, dass beim > static inline void -> kein Parameter übergeben wird... Ja klar, bei inline wird ja gar nichts ,,übergeben'', der entsprechende Code wird stattdessen an Ort und Stelle eingebaut. Das ist ja gerade der Sinn von inline. /* 16-bit count, 4 cycles/loop */ static inline void _delay_loop_2(unsigned int __count) { 7a: 88 e7 ldi r24, 0x78 ; 120 7c: 90 e0 ldi r25, 0x00 ; 0 asm volatile ( 7e: 01 97 sbiw r24, 0x01 ; 1 80: f1 f7 brne .-4 ; 0x7e 82: f2 cf rjmp .-28 ; 0x68 Das sieht mir eigentlich korrekt aus.
also, jetz habe ich alle 4 verschiedene Optimierungs Modi durchgespielt! Und es gibt mir immer diesen Code: /* 16-bit count, 4 cycles/loop */ static inline void _delay_loop_2(unsigned int __count) { asm volatile ( 78: 31 97 sbiw r30, 0x01 ; 1 7a: f1 f7 brne .-4 ; 0x78 7c: f4 cf rjmp .-24 ; 0x66 Es wird also kein Wert geladen! Das makefile habe ich auch gerade mal neu vom WinAVR Ordner in mein Verzeichnis kopiert! PS: Vielen Dank für die schnellen Antworten und für die Geduld ;-)
Also ich hab das gesamte WinAVR Packet! Es ist nicht mehr das neuste! Muss ich jetzt alles neu installieren? Oder kann man nur den Compiler updaten? -> Wie?
@Izoard, vielleicht gefällt es Dir auch besser diesen ganzen unsäglichen programmzerhackenden, ressourcenfressenden Delay-Krempel komplett über Bord zu schmeißen, z.B. so: http://www.mikrocontroller.net/forum/read-4-49709.html Peter
@Izoard Ja, ich konnte mich beim Anblick des von Dir geposteten Assemblerstücks dan dran erinnern, daß es da mal einen Compilerbug gab. @Peter Im Prinzip hast Du Recht, gerade für längere Delays sind die Timer natürlich die Waffe der Wahl. Andererseits braucht natürlich gerade ein Anfänger erstmal eine übersichtliche Methode, da finde ich die schon OK, außerdem wüßte das Lauflicht mit den freiwerdenden CPU-Zyklen sowieso nicht viel anzufangen. ;-) (Außer power save, aber das artet auch gleich wieder in Handbuch lesen aus...)
@Peter Vielen Dank für den Hinweis mit einem Sheduler zu Arbeiten! @Joerg Habe noch eine Grundsätzliche Frage, Der Compiler übersetzt ja: bPortD = bPortD<<3; nicht mit 3 Shift Befehlen! Kennt der Compiler nicht alle Befehle des Atmels? Setzt er aus wenigen Befehlen alle anderen Befehle (z.B. lsl) zusammen? Oder wie muss ich das verstehen?
> Der Compiler übersetzt ja: bPortD = bPortD<<3; nicht mit 3 Shift > Befehlen! Hmm, hier schon: lds r24,dPortD lsl r24 lsl r24 lsl r24 sts dPortD,r24 > Kennt der Compiler nicht alle Befehle des Atmels? Er kennt alle die, die ihm sein Programmierer beigebracht hat. ;-)
Ist schon interessant! Die im Anhang kompilierte C- Source wird so übersetzt: (der Befehl bPortD = bPortD<<3 wird einfach ignoriert) oder mach ich da was falsch? 00000052 <main>: #include <avr/io.h> int main(void) { 52: cf e5 ldi r28, 0x5F ; 95 54: d2 e0 ldi r29, 0x02 ; 2 56: de bf out 0x3e, r29 ; 62 58: cd bf out 0x3d, r28 ; 61 unsigned char bPortD; bPortD = bPortD<<3; /*outp(0xff, DDRB); //Port B = Output outp(0x00, DDRD); //Port D = Input for(;;) //loop { outp(inp(PIND), PORTB); }*/ } 5a: 00 c0 rjmp .+0 ; 0x5c 0000005c <_exit>: 5c: ff cf rjmp .-2 ; 0x5c
> Die im Anhang kompilierte C- Source ... Bitte!, laß inp() und outp() sein. Sie bringen Dir außer häßlichem C-Code rein gar nichts. Schreibe einfach: PORTB = PIND; und gut is'. > (der Befehl bPortD = bPortD<<3 wird einfach ignoriert) Ja. > oder mach ich da was falsch? Du benutzt das Ergebnis in bPortD anschließend nicht mehr, wofür soll sich der Compiler also die Mühe machen, es dann überhaupt zu berechnen?
@Joerg, "außerdem wüßte das Lauflicht mit den freiwerdenden CPU-Zyklen sowieso nicht viel anzufangen." wie wärs denn mit einem 2. völlig unabhängigen Lauflicht ? Oder ein Lauflicht rast dem anderen ein bischen schneller hinterher und überholt es immer wieder. Peter
> Oder ein Lauflicht rast dem anderen ein bischen schneller hinterher > und überholt es immer wieder. Ja klar, kann er ja als Anregungen für die Weiterführung seines Bastelspaßes benutzen. ;-) Aber laß ihn doch mal nicht den zweiten Schritt vor dem ersten tun...
Endlich spricht es mal jemand aus: gcc ist einfach .... faul! Daraus ergeben sich natürlich Fragen über Fragen: 1. ist das der erste Schritt zu künstlicher Intelligenz? 2. if (frage1) ist gcc schon intelligenter als der Programmierer? 3. if (frage2) kommen daher die Fehlermeldungen auf meinem Schirm? murks.c:4: error: main declared but complete nonsens murks.c.4: error: parse error before "return" Stefan
> if (frage1) ist gcc schon intelligenter als der Programmierer? Nein, insbesondere nicht als sein eigener Programmierer. ;-) > murks.c:4: error: main declared but complete nonsens > murks.c.4: error: parse error before "return" Was hast Du ihm denn da zum Fraß vorgeworfen? :-)
hmmmmm ... merkwürdig, seit Deinem Posting kommt der Fehler nicht mehr. Kontrolliert gcc etwa den Browser? Stecken gcc und Mozilla unter einer Decke? Aber Spass beiseite: es ist garnicht so einfach, ein Testprogramm zu schreiben, dass gcc nicht komplett wegoptimiert :-) Stefan
> merkwürdig, seit Deinem Posting kommt der Fehler nicht mehr. Hmm, haste irgendwo ein Schrottzeichen drin gehabt oder sowas? Diese Fehlermeldung find' ich jedenfalls lustig, die habe ich in mehr als 10 Jahren gcc noch nie gesehen. ;-) > Stecken gcc und Mozilla unter einer Decke? Vielleicht. Nur: ich benutze emacs-w3m für dieses Forum. :) Na gut, der Emacs ist genauso wie der gcc mal von Richard Stallmann gezimmert worden, das würde es natürlich erklären... > Aber Spass beiseite: es ist garnicht so einfach, ein Testprogramm zu > schreiben, dass gcc nicht komplett wegoptimiert :-) Das ist allerdings wahr. Nimm doch das demo.c aus der avr-libc Doku, die an- und abschwellende LED (mit PWM). Benutzt sogar schon einen Interrupt, da ich das Konzept der Interrupts in einem Microcontroller für so essentiell halte, daß ich der Meinung war, daß selbst die Helloworld-Applikation das schon haben sollte.
> Das ist allerdings wahr. Nimm doch das demo.c aus der avr-libc Doku, > die an- und abschwellende LED (mit PWM). Benutzt sogar schon einen Naja, ein Problem habe ich damit nicht wirklich, war nur am Anfang ein ziemlicher Aha-Effekt, als im Assemblercode garnichts drin stand. Ich schaue eigendlich ziemlich gerne in den erzeugten Assemblercode. Wenn man mit dem Compiler etwas rumspielt, lernt man dabei Tricks, sein Programm in C und trotzdem effektiv zu schreiben. > Interrupt, da ich das Konzept der Interrupts in einem Microcontroller > für so essentiell halte, daß ich der Meinung war, daß selbst die > Helloworld-Applikation das schon haben sollte. Wie wahr wie wahr. Ich habe mal ein Praktikum gemacht, wo sie Steuerungen für Bagger bauten. Der Chef hatte ein Problem mit Interrupts, deshalb baute die ganze Abteilung Regelkreise ohne einen einzigen Timer oder IR. Die Hauptaufgabe war, die if .. else Konstrukte möglichst exakt gleich lang zu machen. Seitdem bin ich bei Baggern immer etwas vorsichtig. Stefan
> Ich habe mal ein Praktikum gemacht, wo sie Steuerungen für Bagger > bauten. Der Chef hatte ein Problem mit Interrupts, deshalb baute die > ganze Abteilung Regelkreise ohne einen einzigen Timer oder IR. Aua! :-o
@Joerg, "Ja klar, kann er ja als Anregungen für die Weiterführung seines Bastelspaßes benutzen. ;-) Aber laß ihn doch mal nicht den zweiten Schritt vor dem ersten tun..." Genau das ist ja das geniale am Scheduler, man kann nachträglich weitere Funktionen hinzufügen, ohne den bisherigen Code zu ändern oder diese Erweiterungen bereits zu Beginn einplanen zu müssen. Anbei mal das Lauflicht mit Scheduler gelöst. Es sind 2 Lauflichter, die aufeinander zu gehen, d.h. entgegengesetzt drehen. Zusätzlich ist ein kleiner Zeitversatz drin. Sieht ganz lustig aus. Der Fantasie sind da keine Grenzen gesetzt. Ich habs auf dem ATMega16 gemacht, damit ich einen kompletten Byte-Port für die LEDs habe und ich beim ATMega8 nicht immer den seriellen Port zum Bootloader umstecken muß. Ein AT90S2313 ist natürlich vollkommen ausreichend. Bloß dann müßte ich die original STK500-Programmiersoftware nehmen und die ist nun wirklich schnarchlahm. Die restlichen Files sind aus dem Beispiel in der Codesammlung zu entnehmen. Peter
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.