Forum: Compiler & IDEs AVR/Delay.h Wie aufrufen?


von Izoard (Gast)


Angehängte Dateien:

Lesenswert?

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!

von Izoard (Gast)


Angehängte Dateien:

Lesenswert?

sorry! das ist der aktuelle Code!

von Joerg Wunsch (Gast)


Lesenswert?

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.

von Izoard (Gast)


Angehängte Dateien:

Lesenswert?

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

von Izoard (Gast)


Lesenswert?

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

von Joerg Wunsch (Gast)


Lesenswert?

> 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.

von Izoard (Gast)


Lesenswert?

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! :-(

von Joerg Wunsch (Gast)


Lesenswert?

-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)?

von Izoard (Gast)


Lesenswert?

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

von Joerg Wunsch (Gast)


Lesenswert?

> 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.

von Izoard (Gast)


Lesenswert?

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 ;-)

von Joerg Wunsch (Gast)


Lesenswert?

Aktuelle Compilerversion benutzt?

von Izoard (Gast)


Lesenswert?

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?

von Izoard (Gast)


Lesenswert?

stimmt!  mit der neusten Version funktioniert's ! Danke..

von Peter D. (peda)


Lesenswert?

@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

von Joerg Wunsch (Gast)


Lesenswert?

@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...)

von Izoard (Gast)


Lesenswert?

@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?

von Joerg Wunsch (Gast)


Lesenswert?

> 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. ;-)

von Izoard (Gast)


Angehängte Dateien:

Lesenswert?

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

von Joerg Wunsch (Gast)


Lesenswert?

> 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?

von Peter D. (peda)


Lesenswert?

@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

von Joerg Wunsch (Gast)


Lesenswert?

> 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...

von Stefan (Gast)


Lesenswert?

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

von Joerg Wunsch (Gast)


Lesenswert?

> 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? :-)

von Stefan (Gast)


Lesenswert?

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

von Joerg Wunsch (Gast)


Lesenswert?

> 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.

von Stefan (Gast)


Lesenswert?

> 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

von Joerg Wunsch (Gast)


Lesenswert?

> 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

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

@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
Noch kein Account? Hier anmelden.