Forum: Mikrocontroller und Digitale Elektronik Tick counter / Überlauf verarbeiten


von Simon (Gast)


Lesenswert?

Ich habe aus dem Microchip TCP Stack (Tick.c) gesehen wie die ein Tick 
count generieren.


Die verwenden hierfür gleich 6 Bytes um auch möglichst Lange Zeiten 
berechnen zu können.

Ich incrementiere eine 16Bit variable per Timer Interrupt alle 10ms.

Ich möchte die vergangene Zeit anhand einer differenz bestimmen.

z.B.

zeit vergangen = (tick anfang) - (tick jetzt)

Frage:

Wie handled man hier den Überlauf der tick Variable?




Tick.c von Microchip.


http://read.pudn.com/downloads197/sourcecode/embed/928883/MicrochipTCP/TCPIP%20Stack/Tick.c__.htm

von Simon (Gast)


Lesenswert?

Ich glaube ich bin bischen weiter gekommen.

Es gibt keinen Überlauf, so einfach scheint das zu sein.

Nach meiner Theorie läuft der 16Bit Timer bis zu seinem overflow
interrupt, dann wird eine Variable erhöht.

Wenn dieser Interrupt jede sekunde einmal eintritt und wir eine 32Bit 
Variable aufzählen. somit hätte ich das selbe wie die UNIX Zeit.
http://de.wikipedia.org/wiki/Unixzeit

und für kleinere Messungen nehmen die einfach den Timerwert selbst.
Der hat dann wohl eine auflösung von 1sekunde/16bit was doch schon 
ordentlich ist.

von Simon (Gast)


Lesenswert?

ok so klar ist es doch noch nicht.


Im TCP Stack wird immer wieder auf den TickCount zurück gegriffen

z.B.
1
if (TickGet() - AutoIPClient.eventTime > TICK_SECOND * 60)
2
       AutoIPClient.smAUTOIPState = SM_AUTOIP_CHECK_ADDRESS;
3
break;
1
 ((WORD*)vTickReading)[0] = TMR1;
2
3
DWORD TickGet(void)
4
{
5
  GetTickCopy();
6
  return *((DWORD*)&vTickReading[0]);
7
}



Hier wird ganz klar ein Timer Register direkt verwendet und bis zum 
Überlaufen gezählt.


Wie ist das möglich das man denoch die Zeit ermitteln kann auch wenn es 
zu einem Überlauf kam?


Wenn der Timer läuft (mehrach überläuft) dann starte ich z.B. mit einem 
Wert 100.


zeit = (startzeit) - (jetzt)
zeit = 100 - 400 = 300


und bei
zeit = 100 - 5 = 95 ????

von Daniel V. (danvet)


Lesenswert?

Simon schrieb:
> ok so klar ist es doch noch nicht.
>
> zeit = (startzeit) - (jetzt)
> zeit = 100 - 400 = 300

????

>
>
> und bei
> zeit = 100 - 5 = 95 ????

!!!!

Du bist nah dran.
Du mustt halt innerhalb des Timerintervalls mindestens einmal den Tick 
abfragen, dann.... kannst du den Überlauf berechnen, nämlich... da 
kommst du drauf.

von Easylife (Gast)


Lesenswert?

Simon schrieb:
> zeit = (startzeit) - (jetzt)
> zeit = 100 - 400 = 300
>
> und bei
> zeit = 100 - 5 = 95 ????

zeit = (jetzt) - (startzeit)
denn
zeit = 100 - 400 = -300

Wenn beide Zeitstempel unsigned sind, ist ein Überlauf kein Problem, 
man kann die Zeitstempel trotzdem voneinander abziehen, und es kommt das 
richtige Ergebnis raus.

Mehrfachüberläufe führen zu Fehlern.

von Dieter F. (Gast)


Lesenswert?

Simon schrieb:
> Die verwenden hierfür gleich 6 Bytes um auch möglichst Lange Zeiten
> berechnen zu können.
>
> Ich incrementiere eine 16Bit variable per Timer Interrupt alle 10ms.
>
> Ich möchte die vergangene Zeit anhand einer differenz bestimmen.

Wie Du geschrieben hast, "die" verwenden 48 Bit und Du verwendest 16 
Bit. D.h. Du kannst nicht ganz so lange Zählen (Inkrementieren) wie 
"die" ...

Bei Deiner Tick-Einheit von 10 mS also max. bis ca. 10 Minuten 55 
Sekunden (vorausgesetzt Du hast eine 16-Bit Integer-Varaibale OHNE 
Vorzeichen benutzt).

Willst Du weiter zählen musst Du

- entweder die Tick-Variable größer definieren
- oder einen mehrstufigen Zähler ("Ober-Tick" der alle x Ticks 
inkrementiert wird) einrichten
- oder die Tick-Einheit erhöhen

Auch solltest Du Deine Berechnung mal überdenken

Simon schrieb:
> zeit = (startzeit) - (jetzt)
> zeit = 100 - 400 = 300
>
> und bei
> zeit = 100 - 5 = 95 ????

Üblicherweise zieht man von der aktuellen Zeit die Startzeit ab (wenn 
inkrementiert wird).

100 - 400 ergeben nicht 300 sondern -300 (zumindest wenn man beim 
Ergebnis das Vorzeichen berücksichtigt)

von Dieter F. (Gast)


Lesenswert?

Easylife schrieb:
> Wenn beide Zeitstempel unsigned sind, ist ein Überlauf kein Problem,
> man kann die Zeitstempel trotzdem voneinander abziehen, und es kommt das
> richtige Ergebnis raus.

Interessant, was passiert bei Startzeit 1 und akt. Zeit 1 wenn 1 
Überlauf erfolgt ist?

von Simon (Gast)


Lesenswert?

Also erstmal zur 48Bit länge, wenn man den source durchsieht werden
bei einem GetTick tatsächlich nur die unteren 2 Byte direkt aus dem TMR1
register gelesen.

Die anderen Bytes sind für größere Zeiten gedacht die liest Microchip 
dann so aus:
1
DWORD TickGetDiv256(void)   
2
{   
3
    DWORD_VAL ret;   
4
   
5
    GetTickCopy();   
6
    ret.v[0] = vTickReading[1]; // Note: This copy must be done one    
7
    ret.v[1] = vTickReading[2]; // byte at a time to prevent misaligned    
8
    ret.v[2] = vTickReading[3]; // memory reads, which will reset the PIC.   
9
    ret.v[3] = vTickReading[4];   
10
       
11
    return ret.Val;   
12
}


Also es ist tatsächlich so das hier nur ein 16Bit wert verwendet wird.

Kann mir da jemand erklären wie genau das trotz überlauf funzt?

von Easylife (Gast)


Lesenswert?

Dieter Frohnapfel schrieb:
> Interessant, was passiert bei Startzeit 1 und akt. Zeit 1 wenn 1
> Überlauf erfolgt ist?

Das ist dann ja schon genau der 2. Überlauf.

von Easylife (Gast)


Lesenswert?

Easylife schrieb:
> Dieter Frohnapfel schrieb:
>> Interessant, was passiert bei Startzeit 1 und akt. Zeit 1 wenn 1
>> Überlauf erfolgt ist?
>
> Das ist dann ja schon genau der 2. Überlauf.

Bzw. mit Überlauf meine ich ein Überlauf über 0.
Die gemessene Zeit darf natürlich nie länger sein, als der Zähler fassen 
kann...

von Simon (Gast)


Lesenswert?

Hier mal ein Beispiel:
1
    if(TickGet() - DHCPClient.dwTimer < TICK_SECOND) ...


Hier sieht man wie schnell der Tick am ende ist (16Bit Timer)
1
#define GetSystemClock()    (80000000ul)      // Hz
2
#define GetInstructionClock()  (GetSystemClock()/1)  // Normally GetSystemClock()/4 for PIC18, GetSystemClock()/2 for PIC24/dsPIC, and GetSystemClock()/1 for PIC32.  Might need changing if using Doze modes.
3
#define GetPeripheralClock()  (GetSystemClock()/1)  // Normally GetSystemClock()/4 for PIC18, GetSystemClock()/2 for PIC24/dsPIC, and GetSystemClock()/1 for PIC32.  Divisor may be different if using a PIC32 since it's configurable.
4
5
#define TICKS_PER_SECOND    ((GetPeripheralClock()+128ull)/256ull)  // Internal core clock drives timer with 1:256 prescaler
6
7
// Represents one second in Ticks
8
#define TICK_SECOND        ((QWORD)TICKS_PER_SECOND)



Ich komme da denoch nicht drauf was bei einem überlauf geschieht.

ich könnte ja GetTick() genau dann aufrufen wenn der TMR1 bei 0xFFFE 
steht.

von Karl H. (kbuchegg)


Lesenswert?

Dieter Frohnapfel schrieb:

> 100 - 400 ergeben nicht 300 sondern -300 (zumindest wenn man beim
> Ergebnis das Vorzeichen berücksichtigt)

Ein unsigned Wert hat aber per Definition kein Vorzeichen.

von Karl H. (kbuchegg)


Lesenswert?

Simon schrieb:

> Ich komme da denoch nicht drauf was bei einem überlauf geschieht.

Rechne es dir beispielhaft mal binär mit einem 4 BIt Zähler durch.

Wieviel ergibt 2 - 13
1
   2       0010
2
- 13     - 1101
3
        --------
4
           ????

Das Ergebnis ist zwar -11, aber durch die Art und Weise, wie negative 
Zahlen im 2-er Komplement dargestellt werden und der einfachen Tatsache, 
dass es bei unsigned kein Vorzeichen gibt (und somit 2-er Komplement 
irrelevant ist) sowie der Beschränkung auf ein 4 Bit Ergebnis sodass der 
Unterlauf daher nicht zum tragen kommt, kommt da tatsächlich 5 ( binär: 
0101) raus.

Und das ist genau die ANzahl der Schritte, die man machen muss um bei 13 
beginnend weiterzuzählen, um dann bei 16 den Überlauf nach 0 zu haben 
und bei 2 zu landen.

> ich könnte ja GetTick() genau dann aufrufen wenn der TMR1 bei 0xFFFE
> steht.

Du brauchst ÜBERHAUPT nichts tun!
Solange deine Zeitdauer sich in 16 Bit darstellen lässt, subtrahierst du 
einfach die unsigned 16 Bit Endzeit von der unsigned 16 Bit Startzeit. 
Und zwar ohne dich um den Überlauf kümmern zu müssen. ---- solange die 
Zeitdauer nicht länger als 65535 ist. Denn länger kannst du mit 16 Bit 
nicht darstellen.

Probiers mit kleinen Zahlen und in binärer Rechnerei aus!

: Bearbeitet durch User
von Simon (Gast)


Lesenswert?

Karl Heinz schrieb:
> Dieter Frohnapfel schrieb:
>
>> 100 - 400 ergeben nicht 300 sondern -300 (zumindest wenn man beim
>> Ergebnis das Vorzeichen berücksichtigt)
>
> Ein unsigned Wert hat aber per Definition kein Vorzeichen.


ja das Beispiel habe ich einfach nur verkackt vorhin.
1
if( 400    -  300  < 1000)
2
if(TickGet() - DHCPClient.dwTimer < TICK_SECOND) ...

TickGet würde hier also 400 wiedergeben, und der Start war bei 300.

Nur was geschieht wenn ich bei 65534 und
1
DHCPClient.dwTimer = GetTick(); //TMR1 hat hier 65534
2
///... hier irgendwas tun ....
3
//..... überlauf geschieht und TMR1 beginnt bei 10
4
if( 10    -  65534  < 1000)
5
if(TickGet() - DHCPClient.dwTimer < TICK_SECOND) ...

von Simon (Gast)


Lesenswert?

Karl Heinz, vielen Dank für deine ausführliche Antwort,
war gerade am Tippen bevor ich deine Antwort gelesen habe.

Ich denk das mal ebend in ruhe durch...

von Simon (Gast)


Lesenswert?

oooooooooooh man!!!

ok, jetzt ist alles geklärt.

Danke dir :-)

von Dieter F. (Gast)


Lesenswert?

Karl Heinz schrieb:
> Du brauchst ÜBERHAUPT nichts tun!
> Solange deine Zeitdauer sich in 16 Bit darstellen lässt, subtrahierst du
> einfach die unsigned 16 Bit Endzeit von der unsigned 16 Bit Startzeit.
> Und zwar ohne dich um den Überlauf kümmern zu müssen. ---- solange die
> Zeitdauer nicht länger als 65535 ist. Denn länger kannst du mit 16 Bit
> nicht darstellen.
>
> Probiers mit kleinen Zahlen und in binärer Rechnerei aus!

Jein (und, ja - ich weiß das ein unsigned Wert kein Vorzeichen hat, 
danke), das sehe ich etwas anders.

Wie will er denn sicherstellen, dass die gemessene Zeitdauer nicht > 
65535 war? Dem Ergebnis der Subtraktion kann er das nicht entnehmen.

Das geht nur, wenn bei Überlauf des Zählers mindestens ein Flag gesetzt 
(oder besser ein Überlauf-Zähler inkrementiert) wird (und bei der 
Berechnung wieder zurückgesetzt wird), damit das bei der Berechnung 
berücksichtigt werden kann.

von c-hater (Gast)


Lesenswert?

Dieter Frohnapfel schrieb:

> Wie will er denn sicherstellen, dass die gemessene Zeitdauer nicht >
> 65535 war?

Kannst du nicht lesen? Genau das hat Karl-Heinz doch eindeutig und 
völlig unmißverständlich als Vorbedingung definiert. Du selbst hast den 
entsprechenden Satz auch noch zitiert.

> Dem Ergebnis der Subtraktion kann er das nicht entnehmen.

Natürlich nicht. Einen größeren Zählumfang kann man nunmal nur mit mehr 
Zählbits erreichen, das ist eine Tatsache, die so logisch ist, daß es 
kein weiteres Wort wert ist, nichtmal in einer Diskussion auf dem Niveau 
dieses Forums...

Aber natürlich kann man den Überlauftrick auch bei jedem beliebigen (wie 
auch immer erweiterten) größeren Zählumfang ganz genauso anwenden, mit 
einer kleinen Modifikation sogar für Zählumfänge mit Bitzahlen, die 
nicht ganzzahlig in die ALU-Verarbeitung passen. Der Trick ist dann die 
Maskierung des MSB, was sehr "billig" zu haben ist.

von Dieter F. (Gast)


Lesenswert?

c-hater schrieb:
> Kannst du nicht lesen?

Ich schon - und ich kann sogar (wenn auch noch als Anfänger in C) 
programmieren. Auch bin ich nicht zu feige, meinen Namen zu nennen.

Mögliche Fehler(-Situationen) sollten immer abgefangen werden. Ob der 
Prozessor intuitiv die Vorbedingung erfasst wage ich zu bezweifeln.

c-hater schrieb:
> Du selbst hast den entsprechenden Satz auch noch zitiert

Aber ich habe den Satz nicht nur zitiert sondern die Möglichkeiten und 
Restriktionen weiter oben im Post (wer lesen kann wird es bemerkt haben) 
beschrieben.

von c-hater (Gast)


Lesenswert?

Dieter Frohnapfel schrieb:

> Ich schon - und ich kann sogar (wenn auch noch als Anfänger in C)
> programmieren. Auch bin ich nicht zu feige, meinen Namen zu nennen.

Ich auch nicht. Mein wahrer Name ist c-hater. Den habe ich selbst 
gewählt. Das ist viel wahrhaftiger, als das anzugeben, was meine 
Erzeuger vor mehr als einem halben Jahrhundert als Bezeichner für das 
schreiende Bündel ausgewählt haben, was sie da 9 Monate zuvor produziert 
hatten.

Übrigens kenne einige Leute hier durchaus auch meinen sog. "bürgerlichen 
Namen".  Teilweise, weil ich selber es so wollte, teilweise, weil sie 
clever genug waren, es ihn auch alleine herauszufinden. Das ist nämlich 
garnicht so schwierig. Wenn man halbwegs intelligent ist...

Du aber kennst ihn nicht. Mehr gibt es dazu eigentlich nicht zu sagen...

> Mögliche Fehler(-Situationen) sollten immer abgefangen werden.

Natürlich, ganz meine Meinung.

> Ob der Prozessor intuitiv die Vorbedingung erfasst wage ich zu
> bezweifeln.

Zu Recht. Natürlich wird der Prozessor nicht die Einhaltung der dieser 
Vorbedingung überwachen können. Es ist der verdammte Job des 
Programmierers, sicherzustellen, daß niemals die Grenzen des verwendeten 
Datentyps überschritten werden und wenn doch, dann nur in einer genau 
kontrollierten Weise.

Und genau das ist, was hier passiert und zu desen Verständnis dir wohl 
einfach noch die Erfahrung fehlt. Denn: es ist bei vielen Algorithmen 
völlig normal, zum Zwecke höherer Effizienz ganz bewußt die Grenzen des 
Datentyps zu verletzen. Schau dir einfach mal nur das weite Feld der 
Krypto-Algorithmen (im weitesten Sinne, angefangen bei CRC) an.

Mich selber interessiert das eher weniger, denn ich programmiere all 
das, was wirklich schnell und effizient passieren soll in einer Sprache, 
die nicht wirklich Datentypen kennt: Asm.

Deswegen bin ich es absolut gewohnt, bei jeden Schritt z.B. darüber 
nachzudenken, ob die Bitzahl reicht oder ob der Scheiß auch negativ 
werden könnte. Das ist eine Erfahrung, die auch überaus nützlich ist, 
wenn man denselben Scheiß in einer höheren Sprache programmiert...
Oder auch mit anderen ALU-Word-Breiten...

Das ist, was dir fehlt: Der Überblick über's Ganze. Du beherschst, wenn 
du so weiter machst wie bisher, irgendwann bestenfalls einen Compiler 
einer Sprache und produzierst damit dann dauernd suboptimalen Code.

Willst du wirklich SO enden? Von diesen Schmalspurlern gibt es doch 
wirklich schon mehr als genug...

von Dieter F. (Gast)


Lesenswert?

c-hater schrieb:
> Zu Recht. Natürlich wird der Prozessor nicht die Einhaltung der dieser
> Vorbedingung überwachen können. Es ist der verdammte Job des
> Programmierers, sicherzustellen, daß niemals die Grenzen des verwendeten
> Datentyps überschritten werden und wenn doch, dann nur in einer genau
> kontrollierten Weise.

Schön, dass wir einer Meinung sind.

Oh, ich habe aus Spass mal Google genutzt:

http://www.henning-thielemann.de/CHater.html

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.