Tick counter / Überlauf verarbeiten

Gast #3660525
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
Gast #3660567
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.
Gast #3661024
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 ????
Gast #3661041
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.
Gast #3661069
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)
Gast #3661073
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?
Gast #3661095
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?
Gast #3661108
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...
Gast #3661115
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.
#3661127
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!
Gast #3661130
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) ...
Gast #3661277
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.
Gast #3661325
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.
Gast #3661332
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.
Gast #3661374
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...
Gast #3661382
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

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