mikrocontroller.net

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


Autor: Izoard (Gast)
Datum:
Angehängte Dateien:

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

Autor: Izoard (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
sorry! das ist der aktuelle Code!

Autor: Joerg Wunsch (Gast)
Datum:

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

Autor: Izoard (Gast)
Datum:
Angehängte Dateien:

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

Autor: Izoard (Gast)
Datum:

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

Autor: Joerg Wunsch (Gast)
Datum:

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

Autor: Izoard (Gast)
Datum:

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

Autor: Joerg Wunsch (Gast)
Datum:

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

Autor: Izoard (Gast)
Datum:

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

Autor: Joerg Wunsch (Gast)
Datum:

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

Autor: Izoard (Gast)
Datum:

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

Autor: Joerg Wunsch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Aktuelle Compilerversion benutzt?

Autor: Izoard (Gast)
Datum:

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

Autor: Izoard (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
stimmt!  mit der neusten Version funktioniert's ! Danke..

Autor: Peter Dannegger (peda)
Datum:

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

Autor: Joerg Wunsch (Gast)
Datum:

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

Autor: Izoard (Gast)
Datum:

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

Autor: Joerg Wunsch (Gast)
Datum:

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

Autor: Izoard (Gast)
Datum:
Angehängte Dateien:

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

Autor: Joerg Wunsch (Gast)
Datum:

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

Autor: Peter Dannegger (peda)
Datum:

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

Autor: Joerg Wunsch (Gast)
Datum:

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

Autor: Stefan (Gast)
Datum:

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

Autor: Joerg Wunsch (Gast)
Datum:

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

Autor: Stefan (Gast)
Datum:

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

Autor: Joerg Wunsch (Gast)
Datum:

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

Autor: Stefan (Gast)
Datum:

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

Autor: Joerg Wunsch (Gast)
Datum:

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

Autor: Peter Dannegger (peda)
Datum:
Angehängte Dateien:

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

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.