Forum: Mikrocontroller und Digitale Elektronik Problem mit Tachoprogramm tiny2313


von F. P. (pl504)


Lesenswert?

So, jetzt muß ich Euch Experten nochmal bemühen. Habe mir ein 
Tachoprogramm gebaut, das wird mit zwei Low-Flanken pro Raddrehung an 
ICP1 befeuert und zeigt die Geschwindigkeit auf einem LCD an.

Folgendes Problem:
Sporadisch springt die Anzeige kurz auf 4 oder 5 km/h, wenn Impulse 
reinkommen.

Wo liegt der Fehler?
1
// -------------------------------------------------------------------
2
// Projekt : Tacho-Test, 2 Impulse pro Raddrehung
3
// Taktrate: 8 MHz
4
// Prozessor: ATtiny2313
5
// -------------------------------------------------------------------
6
7
#include <avr/io.h>
8
#include <avr/interrupt.h>
9
#include <stdlib.h>      // für itoa
10
#include <util/delay.h>
11
#include "lcd-routines.h"
12
13
#define FAKTOR 384750    // Zählrate/(Impulse pro Drehung) * 3,6 * (Radumfang in m)
14
15
volatile uint8_t impulse = 0, ende = 0, status = 0;
16
volatile uint16_t zahl1 = 0, zahl2 = 0xFFFF;
17
18
19
int main(void) {
20
    char puffer[4];
21
    uint32_t ergebnis = 0;
22
23
// Init
24
    PORTD |= (1<<PD6);              // Pullup ein für Impulszähler
25
26
    TCCR1B = (1<<ICNC1 | 3<<CS10);  // Rauschfilter, Teiler 64 = 125 kHz Zählrate
27
    TIMSK = (1<<ICIE1) | (1<<TOIE1);// Interrupt für Überlauf und ICP1
28
29
    lcd_init();
30
    lcd_setcursor(2, 1);
31
    lcd_string("0 km/h");
32
    sei();
33
34
    while(1) {
35
        if(ende) {                  // Berechnung von v, wenn Messung abgeschlossen
36
            ergebnis = impulse;
37
            ergebnis = (ergebnis << 16) + zahl2 - zahl1;
38
            if(!ergebnis)           // Division 0 abfangen
39
                ergebnis = 0xFFFF;
40
            ergebnis = (FAKTOR + (ergebnis >> 1)) / ergebnis; // clever runden
41
            ende = 0;
42
        }
43
// Begrenzung
44
        if(impulse > 2)
45
            ergebnis = 0;
46
        if(ergebnis > 199)
47
            ergebnis = 199;
48
49
        _delay_ms(250);             // Anzeige wird 4x pro Sekunde aktualisiert
50
51
// Ausgabe
52
        utoa((uint16_t)ergebnis, puffer, 10);
53
        if(ergebnis < 10) {         // einstellig (0...9 km/h)
54
            lcd_setcursor(0, 1);
55
            lcd_string("  ");
56
        }
57
        else if(ergebnis < 100) {   // zweistellig (10...99 km/h)
58
            lcd_setcursor(0, 1);
59
            lcd_string(" ");
60
        }
61
        else                        // dreistellig (100...199 km/h)
62
            lcd_setcursor(0, 1);
63
        lcd_string(puffer);
64
    }
65
}
66
67
ISR(TIMER1_OVF_vect) {
68
    if(impulse < 3)
69
        impulse++;
70
}
71
72
ISR(TIMER1_CAPT_vect) {
73
    if(!ende) {
74
        if(!status) {
75
            zahl1 = ICR1;
76
            impulse = 0;
77
            status = 1;
78
        }
79
        else {
80
            zahl2 = ICR1;
81
            ende = 1;       // Messung beendet
82
            status = 0;
83
        }
84
    }
85
}

von Karl H. (kbuchegg)


Lesenswert?

Hmm

Deine Einrechnung der Overflows
1
            ergebnis = impulse;
2
            ergebnis = (ergebnis << 16) + zahl2 - zahl1;

ist falsch.
Wenn zahl2 kleiner als zahl1 ist (es also mindestens 1 Overflow gab), 
dann zählst du einen Overflow zu viel.

(Annahme: es gab genau einen Overflow)
Der springende Punkt ist, dass durch die Differenzbildung Ende - Anfang 
mittels unsigned Rechnung, du 1 Overflow nicht berücksichtigen 
musst/brauchst. Solange deine Timerwerte so sind, dass du nicht mehr als 
65535 Timerticks zählen musst, kommt durch die unsigned Subtraktion 
IMMER das richtige Tick-Differenz-Ergebnis raus, selbst wenn da 1 
Overflow dazwischen lag.

Ich hab jetzt die Zahlen nicht kontrolliert und nachgerechnet. Aber 
durch den einen zuviel gezählten Overflow, kriegst du eine zu lange Zeit 
als Messergebnis und dadurch eine zu geringe Geschwindigkeit.
Frage: kann es dir überhaupt passieren, dass dein Messergebnis den Wert 
65535 übersteigt? Jetzt rein rechnerisch. Oder anders gefragt: Wie 
schnell (bzw. langsam) müsstest du fahren, damit Endzeitpunkt - 
Startzeitpunkt überhaupt größer als 65535 werden kann?
Denn wenn da jetzt 0.5km/h raus kommen, dann kannst du dir die ganze 
Overflow Berücksichtung in der Berechnung komplett sparen. Du benutzt 
den Overflow dann nur noch dazu um den Stillstand zu detektieren, alles 
an Geschwindigkeit kleiner als 0.5km/ definierst du als Stillstand und 
zeigst am Tacho 0 an. Aber wie gesagt: ich hab die Rechnerei nicht 
gemacht und nicht nachgesehen, was da für Zahlen raus kommen.

: Bearbeitet durch User
von Max H. (hartl192)


Lesenswert?

Karl Heinz schrieb:
> selbst wenn da 1
> Overflow dazwischen lag.
Das mit dem Overflow habe ich vorgestern hier erklärt:
Beitrag "Re: Capture Mode mit PIC18F46k80"

von F. P. (pl504)


Lesenswert?

Karl Heinz schrieb:
> Deine Einrechnung der Overflows
>
1
>             ergebnis = impulse;
2
>             ergebnis = (ergebnis << 16) + zahl2 - zahl1;
3
>
>
> ist falsch.
> Wenn zahl2 kleiner als zahl1 ist (es also mindestens 1 Overflow gab),
> dann zählst du einen Overflow zu viel.
>
> (Annahme: es gab genau einen Overflow)
> Der springende Punkt ist, dass durch die Differenzbildung Ende - Anfang
> mittels unsigned Rechnung, du 1 Overflow nicht berücksichtigen
> musst/brauchst. Solange deine Timerwerte so sind, dass du nicht mehr als
> 65535 Timerticks zählen musst, kommt durch die unsigned Subtraktion
> IMMER das richtige Tick-Differenz-Ergebnis raus, selbst wenn da 1
> Overflow dazwischen lag.
kopfkratz
Habe jetzt die Berücksichtigung der Überläufe rausgenommen. Damit haut 
es hin. Kann es nur noch nicht zu 100 % nachvollziehen. 
Mindestgeschwindigkeit liegt dann bei ca. 7 km/h, das ist OK.

Angenommen, es gab 2 Überläufe und zahl2 = 4, zahl1 = 100:
ergebnis = 131072 + 4 - 100 = 130976
Klingt für mich plausibel. Oder muß man "(ergebnis <<16) + zahl2" in 
Klammern setzen, damit der Compiler nicht fälschlicherweise erst "zahl2 
- zahl1" (vorzeichenlos) rechnet?

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.