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
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
Du hast Recht es müsste natürlich uint16_t Überlauf heißen aber das hilft jetzt leider nicht.
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.
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.
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;
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!
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! **************************************
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.
> 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!?
> 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.
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
1 | volatile uint16_t zaehler_alt=0,zaehler=0; |
2 | |
3 | ...
|
4 | |
5 | tics = zaehler - zaehler_alt; |
kann nie größer als 65535 werden. Völlig unmöglich.
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)
> Dieser Ausdruck hier > >
1 | > volatile uint16_t zaehler_alt=0,zaehler=0; |
2 | |
3 | > tics = zaehler - zaehler_alt; |
4 | >
|
> > 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.
Alles klar ich werde jetzt mal eben Pause machen und dann alles nochmal überarbeiten und reinstellen. Bis später.
Eine Idee hab ich noch Verändere das mal
1 | lcd_puts("tics="); |
2 | ultoa (tics,temp3,10); |
3 | set_cursor(6, 4); |
4 | lcd_puts(temp3); |
5 | 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
> 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)?
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.
Hier mal eine ältere (aber bewährte) Version von mir:
1 | SIGNAL (SIG_INPUT_CAPTURE1) // Frequenzmessung |
2 | {
|
3 | if (!(Status &(1<<ST_ICP))) |
4 | {
|
5 | starttime = ICR1; |
6 | ICP_OVF = 0; |
7 | Status |= _BV(ST_ICP); |
8 | return; |
9 | }
|
10 | else
|
11 | {
|
12 | stoptime = ICR1; |
13 | Frequenz = (ICP_OVF * 65536) + stoptime - starttime;// Zählerstand ermitteln |
14 | Frequenz = (16000000/Frequenz); // SYSCLK*16MHz |
15 | Status &= ~_BV(ST_ICP); // Frequenz berechnen |
16 | TIFR |= _BV(ICF1); |
17 | }
|
18 | }
|
Vielleicht kannst du was 'rauslesen. ;-)
> Verändere das mal > >
1 | > lcd_puts("tics="); |
2 | > ultoa (tics,temp3,10); |
3 | > set_cursor(6, 4); |
4 | > lcd_puts(temp3); |
5 | > lcd_puts("*"); // <- der ist neu |
6 | >
|
> > 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...
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.