mikrocontroller.net

Forum: Compiler & IDEs "dtostrf" verdoppelt Werte


Autor: Robin Tönniges (rotoe) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hi Leute,

ich versuche mich an gcc ranzupirschen und stoße dabei auf einige kleine 
Hürden.

Momentan versuche ich einen Frequenzzähler zu programmieren. Der Zählt 
auch schon ganz schön aber ich wollte eine automatische Umschaltung von 
Hz nach kHz. Das funktioniert auch gut. Aber ich wollte "mehr". Nämlich 
eine Kommastelle bei kHz 123.456kHz. Das funktiioniert mit der Funktion 
"dtostrf" nur "teilweise".

Problem: Auf meinen LCD steht die eingespeiste Frequenz von zB. 1.500kHz 
und dann macht er manchmal 3.00kHz draus. Das wird schlimmer je höher 
ich in der Frequenz gehe. Manchmal verdoppelt er sogar mehrmals also 
erst z.B. 20.000kHz dann 40.000kHz dann 80.000kHz. Bei z.B. 500.000Hz 
passiert nichts da bleibt alles wie es soll.
Ich hänge mal meinen Programmcode an.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du machst IMHO viel zu viel in der Interruptroutine. Dadurch wird das 
Zeitfenster zu lang und du zählst zu lang Impulse. Dadurch wird der 
Frequenz zu hoch.

Ich würde:

1/ Messung und Anzeige so streng wie möglich trennen.
2/ Statt den Signaleingang in main() zu pollen, würde ich das in einem
   2. Interrupt machen lassen.
3/ Weshalb ist tmp vom Typ double, wenn du es doch ganzzahlig erhöhst?
4/ B und tmp werden von main() und ISR benutzt. Sie sollten volatile
   gekennzeichnet sein.
5/ Die Interrupts würde ich erst global einschalten, wenn alle
   Initialisierungen gelaufen sind (sei nach timer1_init)
6/ Einheit hat den falschen Typ (uint8_t statt uint8_t *). Da müsste der
   GCC gemosert haben.

Autor: Robin Tönniges (rotoe) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für die Antworten

> 1/ Messung und Anzeige so streng wie möglich trennen.
Ok. Ich versuchs

> 2/ Statt den Signaleingang in main() zu pollen, würde ich das in einem
>    2. Interrupt machen lassen.
Ok.

> 3/ Weshalb ist tmp vom Typ double, wenn du es doch ganzzahlig erhöhst?
Ich dachte damit kann ich mehr als nur 65535 speichern. Weil uint32_t 
macht er nicht dann zeigt er keine Zahlen mehr an.

> 4/ B und tmp werden von main() und ISR benutzt. Sie sollten volatile
>    gekennzeichnet sein.
Was heißt das? ^^

> 5/ Die Interrupts würde ich erst global einschalten, wenn alle
>    Initialisierungen gelaufen sind (sei nach timer1_init)
Ok.

> 6/ Einheit hat den falschen Typ (uint8_t statt uint8_t *). Da müsste der
>    GCC gemosert haben.
Hat nicht gemosert und angezeigt hat er Hz und kHz auch schön aber ich 
werds ändern.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
uint32_t tmp

65535 ist die Grenze bei uint16_t. Wenn du uint32_t tmp benutzt, kannst 
du bis 4294967295 zählen, aber dtostrf nicht benutzen. Die passende 
Umwandlungsfunktion ist ultoa(). Wie die Funktion aufzurufen ist, kannst 
du in stdlib.h herausfinden - die Reihenfolge und Bedeutung der 
Argumente ist anders als bei dstrtof. Auch das Setzen des Kommas ist 
etwas anders (Rechnen mit Ganzzahldivision / und Modulo %)

volatile

http://www.mikrocontroller.net/articles/Interrupt#...

Nicht-Mosern

Bei mir kommt an der Stelle

../Robin.c:30: warning: assignment makes integer from pointer without a cast
../Robin.c:34: warning: assignment makes integer from pointer without a cast


Wenn das bei deiner Toolchain nicht kommt, ist das ungünstig. Du 
verpasst Warnungen des GCC, die dir helfen, Programmierprobleme 
aufzudenken.

Wenn du GCC aus AVR Studio heraus bedienst, weiss ich nicht, wie man es 
schafft, diese Warnung zu unterdrücken.

Wenn du ohne AVR Studio mit einem Makefile arbeitst, solltest du das 
Makefile ändern. Wenn du das selbst nicht schaffst, zeig' das Makefile.

Autor: Robin Tönniges (rotoe) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> ../Robin.c:30: warning: assignment makes integer from pointer without a
> cast
> ../Robin.c:34: warning: assignment makes integer from pointer without a
> cast

Ok das hat er gesagt aber ich dachte wäre net schlimm weils ja 
funktioniertz hat^^

ultoa kenne ich. Habe es aber nicht benutzt weil es keine Kommazahlen 
gibt.
An Modula hab ich auch schon gedacht habe aber keinerlei Erfahrung damit 
und deshalb habe ich es bis jetzt gelassen. Werde es aber mal versuchen.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das Rechnen mit Modulo (Rest der Ganzzahldivision) ist nicht schlimm.

Beispiel:

{
  uint32_t tmp       = 2345;        // Hz
  uint32_t vorkomma  = tmp / 1000;  // 2345 / 1000 = 2
  uint32_t nachkomma = tmp % 1000;  // 2345 % 1000 = 345;
  uint8_t buffer[6];

  if (vorkomma > 99999)
  {
    // wg. Platz in buffer, ist anpassbar
    lcd_string(" OVERFLOW ");
  }
  else
  {
    ultoa(vorkomma, buffer, 10);
    lcd_string(buffer);
    lcd_string(",");
    ultoa(nachkomma, buffer, 10);
    // Nullen ergänzen auf 3 Stellen hinterm Komma
    // Bsp. 2,5 => 2,500
    while(strlen(buffer) < 3)
      strcat(buffer, "0");
    lcd_string(buffer);
    lcd_string(" kHz");
  }
}


Autor: Robin Tönniges (rotoe) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Habs kaputt verbessert :(
Hab mal ein paar Kommentare gemacht damit ich den Fehler dabei vlt. 
selbst finde aber nichts. Das LCD zeigt nichts mehr an bleibt einfach 
leer.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vorab:

Tja, den Einheit Fehler hast du nicht verbessert. Und bei der 
while-Schleife ist ein Klammerpaar nötig. Messung wird ohne das 
Klammerpaar nie aufgerufen!

Ich bin dabei das in den Simulator einzupassen. Mehr demnächst...

Autor: Robin Tönniges (rotoe) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Juhu. Dank deines Hinweises wegen der Klammern in der while Schliefe 
mißt er jetzt wieder und das auch noch bis über 100kHz. Leider fehlen 
jetzt noch die Kommazahlen.

Und wegen der Variable Einheit. Ich habe leider nicht ganz verstanden 
was ich da ändern soll.

Autor: Robin Tönniges (rotoe) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Habs jetzt hinbekommen das er bei der Variable "uint8_t Einheit" nicht 
mehr meckert. Hab sie in "static char* Einheit" geändert nd alles 
funktioniert.

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.