www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Drehzahlmesser / Frequenzmesser spinnt?


Autor: F. K. (digitalone)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen, nachdem ich schon öfter hier mitgelesen habe musste ich 
mich nun anmelden da ich bei der Programmierung eines Drehzahlmessers 
mit einem Atmega32 auf folgendes Problem gestossen bin und nicht weiter 
komme. So wie es aussieht zählt mein ICP Zähler die richtige Anzahl Tics 
macht jedoch bei der Umrechnung in 1/min Fehler. Das passiert jedoch 
erst ab einer gewissen Anzahl Tics nicht aber bei 56535 was ja auf ein 
int16 Überlauf hinweisen würde sondern erst bei höheren Werten.

Die Ausgegebenen Daten sehen z.B. so aus:

Tics   -     1/min
16696  -    7107
24695  -    4859
32695  -    3670
40700  -    2948
48700  -    2464
56702  -    2116
64698  -    1854
78998  -    15191  anstatt  1519
86992  -    13794  anstatt  1379

Hat jemand eine Idee woran das liegen kann? Habe ich irgendwas 
übersehen?

Vielen Dank im Voraus.

digitalone

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
F. K. schrieb:

> Das passiert jedoch
> erst ab einer gewissen Anzahl Tics nicht aber bei 56535 was ja auf ein
                                                    ^^
> int16 Überlauf hinweisen würde sondern erst bei höheren Werten.

uint16_t
65535
^^

int16_t
32767

Autor: F. K. (digitalone)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du hast Recht es müsste natürlich uint16_t Überlauf heißen aber das 
hilft jetzt leider nicht.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich seh auch kein ursächliches Problem

Aber ich würde erst mal:

  uint64_t drehzahl=0;

kein Grund das als uint64_t zumachen. Das ist nur Beschäftigungstherapie 
für den µC

   char temp2[6],temp3[6];
die sind ein wenig arg knapp. Bei solchen char-Felder: Nicht kleckern, 
klotzen. Auch wenn du nur mit maximal 5 stelligen Zahlen rechnest, es 
schadet nichts, diese Felder auf 10 oder 15 zu vergrößern. Und wenn dann 
eine Zahl doch einmal etwas größer wird, hat man ein wenig Reserve.


78998  -    15191  anstatt  1519
86992  -    13794  anstatt  1379

Das da ziemlich genau das 10-fache rauskommt, lässt mich nicht an einen 
Rechenfehler glauben, sondern an ein Anzeigeproblem, zb. Zahlen die 
nicht vollständig von der nächsten überschrieben werden. Aber so wie du 
das aufgebaut hast, kann es das eigentlich auch nicht sein.

Autor: F. K. (digitalone)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
uint64_t drehzahl=0; hatte ich auch schon auf 32 habe es nur testweise 
hochgesetzt. Die char hatte ich auch schon 20 lang - kein Unterschied.
Habe das ganze auch mal rechnen lassen mit 78998 als Festwert für Tics 
dann zeigt er richtig an. Deswegen bezweifel ich dass es an der Anzeige 
liegt. Bin nur erstmal beruhigt dass euch auf den ersten Blick auch 
nichts auffällt aber vielleicht kommt ja noch jmd. drauf.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
F. K. schrieb:

> 78998  -    15191  anstatt  1519
> 86992  -    13794  anstatt  1379
                  ^               ^

Da fehlt eine Stelle, also eventuell Bufferoverflow, wenn uint64_t 
drehzahl an ultoa() übergeben wird.

Ich würde versuchsweise temp2 größer machen, damit die abschliessende 
0 nicht verloren geht. Und ich würde auch mal drehzahl uint32_t 
machen.

> u64_drehzahl=((2000000/60)/u32_tics);

Hmm...

u64_drehzahl = ((uint64_t)2000000 / 60) / u32_tics;

Mit uint32_t:

drehzahl = (2000000UL / 60) / tics;

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
F. K. schrieb:

> Habe das ganze auch mal rechnen lassen mit 78998 als Festwert für Tics
> dann zeigt er richtig an. Deswegen bezweifel ich dass es an der Anzeige
> liegt.

Wird tics richtig berechnet?

>>    u32_tics = u16_zaehler - u16_zaehler_alt;

u32_tics = (uint32_t)u16_zaehler - u16_zaehler_alt;

Oder gemessen?

Was machst du, wenn u8_overflow_status == 1 ist? Du müsstest doch dann 
65536 auf u16_zaehler addieren!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich kann deine ganze Berechnung nicht nachvollziehen

78998  -    15191  anstatt  1519
86992  -    13794  anstatt  1379

mit der Berechnung
          drehzahl=((2000000/60)/tics);
und einem Taschenrechner kriege ich ganz andere Ergebnisse raus.

2000000/60 -> 33333

78998   ->   33333 / 78998  -> 0

Was'n jetzt los?
Zeigst du uns ein anderes Programm, als das was tatsächlich läuft?

Ganz abgesehen davon, dass tics als Differenz zweier unsigned 16 Bit 
Werte gar nicht 78998 sein kann! Bei 65535 ist in deinem Code Schluss.

**************************************
-> du hast den falschen Code gepostet!
**************************************

Autor: F. K. (digitalone)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
da ist mir beim zurückbauen meines Versuchscodes ein Fehler unterlaufen 
es muss natürlich heißen u64_drehzahl=((2000000*60)/u32_tics);
bzw. jetzt u32_drehzahl=((2000000*60)/u32_tics); alos MAL 60 nicht 
GETEILT durch 60.

Der Fehler ist natürlich weiterhin vorhanden.

Autor: F. K. (digitalone)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Ganz abgesehen davon, dass tics als Differenz zweier unsigned 16 Bit
> Werte gar nicht 78998 sein kann! Bei 65535 ist in deinem Code Schluss.
>
> **************************************
> -> du hast den falschen Code gepostet!
> **************************************

Das habe ich auch gedacht aber es funktioniert so da wird wohl intern 
mit overflow bit gerechnet werden!?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Habe das ganze auch mal rechnen lassen mit 78998 als Festwert für Tics
> dann zeigt er richtig an.

Dann würde ich mal ganz stark die Korrektheit der Ausgabe für ticks 
bezweifeln. Dort nach dem rechten sehen.
Zählerwerte ausgeben, Anzahl Overflows ausgeben, Berechnungen 
kontrollieren, etc.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
F. K. schrieb:
>> Ganz abgesehen davon, dass tics als Differenz zweier unsigned 16 Bit
>> Werte gar nicht 78998 sein kann! Bei 65535 ist in deinem Code Schluss.
>>
>> **************************************
>> -> du hast den falschen Code gepostet!
>> **************************************
>
> Das habe ich auch gedacht aber es funktioniert so da wird wohl intern
> mit overflow bit gerechnet werden!?

Nicht mit deinem geposteten Code.
Die Differenz zweier unsigned 16 Bit Zahlen kann nie größer als 65535 
sein. Wenn du was anderes schaffst, solltest du sofort einen Vertrag mit 
Las Vegas abschliessen, denn dann ist der Copperfield ein popeliger 
Trickbetrüger gegen dich.

Dieser Ausdruck hier
volatile uint16_t zaehler_alt=0,zaehler=0;

...

    tics = zaehler - zaehler_alt; 

kann nie größer als 65535 werden. Völlig unmöglich.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde vorschlagen.

Du stellst jetzt in deinem Code wieder die ursprüngliche Version her. So 
wie sie richtig ist und wie du denkst dass es sein müsste. drehzahl 
machst du als uint32_t und die beiden char-Felder setzt du größer. Dann 
kontrollierst du noch ob der Fehler immer noch da ist und notierst dir 
die Ausgaben.
An besten veränderst du auch die Ausgabe ganz leicht, so dass du sicher 
sein kannst, dass es genau dieser Code und kein anderer ist, der auf dem 
µC läuft.

Dann postest du Code und Zahlen


(Ich traue deinem Code nicht mehr. Sobald ich dich einmal dabei erwischt 
habe, dass der gepostete Code nicht dem entspricht der den Fehler zeigt, 
will ich es ganz genau wissen)

Autor: F. K. (digitalone)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Dieser Ausdruck hier
>
>
> volatile uint16_t zaehler_alt=0,zaehler=0;

>     tics = zaehler - zaehler_alt;
> 
>
> kann nie größer als 65535 werden. Völlig unmöglich.

Mhmm das hab ich mir vorher auch gedacht dachte dann durch das Programm 
eines besseren belehrt worden zu sein. Aber wenn das nicht funktioniert 
gilt es ja eigentlich nur den Fehler zu finden wie er auf die Werte über 
65535 kommt und wieso er in der Berechnung auf einmal so einen Sprung 
macht.

Autor: F. K. (digitalone)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Alles klar ich werde jetzt mal eben Pause machen und dann alles nochmal 
überarbeiten und reinstellen. Bis später.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eine Idee hab ich noch

Verändere das mal
    lcd_puts("tics=");
    ultoa (tics,temp3,10);
    set_cursor(6, 4);
    lcd_puts(temp3);
    lcd_puts("*");     // <- der ist neu

Ich vermute du hast gar keine 78998 Ticks. Du hast nur 7899 Ticks und 
die abschliessende 8 ist ein Überbleibsel von früher, welches nie 
gelöscht wurde. Der * soll das anzeigen, indem er klar macht, wo die 
Zahl wirklich aufhört.

Auf jeden Fall würde das alles erklären:
   7899 ist im möglichen Zahlenbereich
   Die Berechnung für 7899 ergibt tatsächlich 15191

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 78998  -    15191  anstatt  1519
> 86992  -    13794  anstatt  1379
steht da noch Müll von vorher auf dem Display und wird nicht 
überschrieben (die 1 bei 1519_1 bzw. die 4 bei 1379_4)?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lothar Miller schrieb:
>> 78998  -    15191  anstatt  1519
>> 86992  -    13794  anstatt  1379
> steht da noch Müll von vorher auf dem Display und wird nicht
> überschrieben (die 1 bei 1519_1 bzw. die 4 bei 1379_4)?

Bei den Drehzahlen nicht. Das hat er relativ geschickt gelöst. Aber bei 
den Ticks! Ich denke dort ist noch Müll von vorhergehenden Durchläufen.

Autor: Thilo M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier mal eine ältere (aber bewährte) Version von mir:
SIGNAL (SIG_INPUT_CAPTURE1)    // Frequenzmessung
{
  if (!(Status &(1<<ST_ICP)))
  {
     starttime = ICR1;
     ICP_OVF = 0;
     Status |= _BV(ST_ICP);
     return;
  }
  else
  {
     stoptime = ICR1;
     Frequenz = (ICP_OVF * 65536) + stoptime - starttime;// Zählerstand ermitteln
     Frequenz = (16000000/Frequenz);  // SYSCLK*16MHz 
     Status &= ~_BV(ST_ICP);    // Frequenz berechnen
    TIFR |= _BV(ICF1);
  }
}

Vielleicht kannst du was 'rauslesen. ;-)

Autor: F. K. (digitalone)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Verändere das mal
>
>
>     lcd_puts("tics=");
>     ultoa (tics,temp3,10);
>     set_cursor(6, 4);
>     lcd_puts(temp3);
>     lcd_puts("*");     // <- der ist neu
> 
>
> Ich vermute du hast gar keine 78998 Ticks. Du hast nur 7899 Ticks und
> die abschliessende 8 ist ein Überbleibsel von früher, welches nie
> gelöscht wurde. Der * soll das anzeigen, indem er klar macht, wo die
> Zahl wirklich aufhört.
>
> Auf jeden Fall würde das alles erklären:
>    7899 ist im möglichen Zahlenbereich
>    Die Berechnung für 7899 ergibt tatsächlich 15191

Das war der entscheidende Tip!!! Danke

Jetzt muss ich es nurnoch hinbekommen dass er mir zuverlässig im Falle 
eines Überlaufes zu den tics overflow_status*65536 hinzuaddiert. Zurzeit 
springt er mir leider noch hin und her zwischen mit und ohne 65536...

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.