www.mikrocontroller.net

Forum: Compiler & IDEs #define fuer _delay_loop_2


Autor: Tom M. (tomm) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

Ich steh auf dem Schlauch, oder so... ;)

Wenn ich in meinem Source Code meine Wartefunktion so definiere, stimmt 
die Wartezeit:
void delay_1ms( uint8_t ms ) {
   while (ms--)
      _delay_loop_2( 4000 );    // 4 cycles per iteration
}

Für meinen atmega168 mit 16Mhz hab ich überschlagen:
4 Mio Iterationen - 1 s
4 k   Iterationen - 1 ms

Gut. Um ein bisschen portabler zu schreiben, packe ich die Formel in ein 
#define statement und ... meine Funktion tut nicht mehr, die Wartezeit 
wird viel zu lang:
// delay loop iterations for 1ms
#define ONEMS 1 / 4 * F_CPU / 1000
und
void delay_1ms( uint8_t ms ) { 
   while (ms--)
      _delay_loop_2( (uint16_t) ONEMS );    // 4 cycles per iteration
}


Was mach ich falsch?

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tom M. schrieb:
> Was mach ich falsch?

Du benutzt nicht die fix-und-fertige Funktion aus der AVR-Libc...

Autor: Rupert (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ganz davon ab resultiert 1/4 bei Integer-Werten in 0, wodurch ONEMS 0 
wird...

Autor: Tom M. (tomm) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Du benutzt nicht die fix-und-fertige Funktion aus der AVR-Libc...

Oooch ;) -- ist ja immerhin util/delay_basic.h aus der arv-libc.
F_CPU ist mit 16e6 definiert.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und warum nicht <util/delay.h>?
Ansonsten wird 1/4 tatsächlich 0.

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

Bewertung
0 lesenswert
nicht lesenswert
Was spricht dagegen?
void delay_1ms( uint8_t ms ) { 
   while (ms--)
      _delay_ms(1);
}

_delay_ms ist weiter nichts als ein Wrapper um _delay_loop_2, der
aus F_CPU und dem angegebenen Wert die für _delay_loop_2 notwendige
Zyklenanzahl berechnet -- also letztlich exakt das, was du willst
(wenn ich dich richtig verstanden habe).

Autor: Tom M. (tomm) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch schrieb:

> _delay_ms ist weiter nichts als ein Wrapper um _delay_loop_2, der
> aus F_CPU und dem angegebenen Wert die für _delay_loop_2 notwendige
> Zyklenanzahl berechnet -- also letztlich exakt das, was du willst

Das ist richtig. Da _delay_ms aber mit float Zahlen rumhantiert, will 
ich  diesen "teuren" Aufruf/Code wegoptimieren.

Das Resultat meiner Rechnerei im #define sei also Null, versteh ich noch 
nicht, weshalb das so ist.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
_delay_ms hantiert nicht mit Floats herum und ist auch nicht teuer.

Dein #define ist null, weil 1/4 nunmal null ist.

Autor: Rupert (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es entscheidet sich erst bei dem Aufruf der Funktion, von welchem Typ 
ONEMS ist. In deinem Fall ist es ein Integer, kann somit nur ganzzahlig 
werden. 1/4 ergibt nach Adam Riese 0.25, somit also 0.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ne, 1/4 ist 0, egal wo es benutzt wird.

Autor: Rupert (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nicht wenn es ein Float oder Double ist ;)

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
#include <stdio.h>

#define ONEMS \
  (1 / 4)

void print_float(float f) {
  printf("== %f\n", f);
}

int main() {
  print_float(ONEMS);
}

Ausgabe:
== 0.000000

Autor: Rupert (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
#include <stdio.h>

#define ONEMS 1/4*16000000/1000
int main() {
    printf("%f\n",(float)ONEMS);
    printf("%d\n",(int)ONEMS);
}

Ergebnis:
4000.000000
0

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

Bewertung
0 lesenswert
nicht lesenswert
Tom M. schrieb:

> Das ist richtig. Da _delay_ms aber mit float Zahlen rumhantiert, will
> ich  diesen "teuren" Aufruf/Code wegoptimieren.

"teuer" ist das nur für den Compiler.  Der macht daraus dann den
gewünschten Integerwert.

Die Intention hinter den Gleitkommazahlen war einfach, dass auf
deinem Quarz ja nicht drauf steht: 7372800 Hz, sondern: 7,3728 MHz.
Damit kannst du schreiben:
#define F_CPU 7.3728E6

ohne dir erst überlegen zu müssen, wie viele Nullen du jetzt anhängst.
Außerdem kannst du halt auch bei _delay_ms schreiben:
_delay_ms(0.8);
_delay_ms(2.2);

Das empfinde ich als die durchaus natürliche Denkweise eines
Ingenieurs.  Solche Aufrufe werden oft genug benutzt, um bestimmte
Timing-Werte aus einem Datenblatt zu realisieren, und da stehen sie
auch als Gleitkommazahlen -- weil man das am besten lesen kann.

Die Umrechnung in das, was der Controller kann, sollte man halt dann
dem Computer überlassen können.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
(a) das hat nix mit dem Funktionsaufruf zu tun, sondern mit dem 
cast-Operator.

(b) dein Define ist falsch, der cast bezieht sich nur auf die 1.

Beispiel:
#include <stdio.h>

#define ONEMS \
  (1 / 4)

void print_float(float f) {
  printf("== %f\n", f);
}

int main() {
  print_float((int)ONEMS);
  print_float((float)ONEMS);
}

Ausgabe:
== 0.000000
== 0.000000

1/4 ist 0, egal wie und wo es verwendet wird.

Autor: Tom M. (tomm) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab jetzt auf _delay_ms() umgestellt und siehe da, mein Code a) 
funktioniert b) ist nicht wesentlich grösser. Schön. :)

Ich meine mich gerade zu erinnern, dass man dem Compiler mit einem 
Suffix mitteilen sollte, wenn man mit nicht-integer Zahlen hantiert, 
sowas wie:
#define ONEMS 1L / 4 * F_CPU / 1000

1L (long?)... Muss gleich mal K&R rauskramen...

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tom M. schrieb:
> Hab jetzt auf _delay_ms() umgestellt und siehe da, mein Code a)
> funktioniert b) ist nicht wesentlich grösser. Schön. :)
Endlich :->

> Ich meine mich gerade zu erinnern, dass man dem Compiler mit einem
> Suffix mitteilen sollte, wenn man mit nicht-integer Zahlen hantiert,
> sowas wie:
Es würde schon helfen, wenn du endlich ein paar verdammte Klammern 
setzen würdest:
/* FALSCH!!!!!111einself */
#define ONEMS 1L / 4 * F_CPU / 1000

/* Besser, aber immer noch 0 */
#define ONEMS (1L / 4 * F_CPU / 1000)

/* 'Korrekt': */
#define (ONEMS 1.0 / 4.0 * F_CPU / 1000.0)


Probier mal aus:
#define X 5 + 9

printf("== %u\n", 10 * X);
Und? Gibt nicht 14*10=140 aus, gell? Komisch.

Autor: Tom M. (tomm) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Es würde schon helfen, wenn du endlich ein paar verdammte Klammern
> setzen würdest:

Hast ja recht, die Klammern... :)


> Und? Gibt nicht 14*10=140 aus, gell? Komisch.

Nee, da nicht: Der Präprozessor tauscht den Text aus, und dann greift 
das altbekannte "Punkt-vor-Strich". Mein Cast war allerdings total übel, 
oder die Klammern ham gefehlt, oder beides. ;)


Danke euch allen, schönen Abend noch. :)

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.