Forum: Compiler & IDEs "dtostrf" verdoppelt Werte


von Robin T. (rotoe) Benutzerseite


Angehängte Dateien:

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.

von Stefan B. (stefan) Benutzerseite


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.

von Robin T. (rotoe) Benutzerseite


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.

von Stefan B. (stefan) Benutzerseite


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#Steuersignale_zwischen_ISR_und_Hauptprogramm

Nicht-Mosern

Bei mir kommt an der Stelle
1
../Robin.c:30: warning: assignment makes integer from pointer without a cast
2
../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.

von Robin T. (rotoe) Benutzerseite


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.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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

Beispiel:
1
{
2
  uint32_t tmp       = 2345;        // Hz
3
  uint32_t vorkomma  = tmp / 1000;  // 2345 / 1000 = 2
4
  uint32_t nachkomma = tmp % 1000;  // 2345 % 1000 = 345;
5
  uint8_t buffer[6];
6
7
  if (vorkomma > 99999)
8
  {
9
    // wg. Platz in buffer, ist anpassbar
10
    lcd_string(" OVERFLOW ");
11
  }
12
  else
13
  {
14
    ultoa(vorkomma, buffer, 10);
15
    lcd_string(buffer);
16
    lcd_string(",");
17
    ultoa(nachkomma, buffer, 10);
18
    // Nullen ergänzen auf 3 Stellen hinterm Komma
19
    // Bsp. 2,5 => 2,500
20
    while(strlen(buffer) < 3)
21
      strcat(buffer, "0");
22
    lcd_string(buffer);
23
    lcd_string(" kHz");
24
  }
25
}

von Robin T. (rotoe) Benutzerseite


Angehängte Dateien:

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.

von Stefan B. (stefan) Benutzerseite


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

von Robin T. (rotoe) Benutzerseite


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.

von Robin T. (rotoe) Benutzerseite


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.

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.