"dtostrf" verdoppelt Werte

Persönliche Seite #813627
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.
Angehängte Dateien:
Persönliche Seite #813689
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.
Persönliche Seite #813697
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.
Persönliche Seite #813726
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.
Persönliche Seite #813736
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.
Persönliche Seite #813749
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
}

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren