Abstand zweier Zahlen in 16-Bit (vgl. Galoisfeld)

#1064111
Lesenswert?

Hallo,

ich habe ein Problem, das sicherlich schonmal gelöst wurde. Folgendes:

Ein µC hat eine Timer-gesteuerte Endlosschleife die in 100µs-Zyklen 
arbeitet. Dabei verfügt der Knirps auch über eine 16-Bit Systemzeit die 
alle 100µs um 1 inkrementiert und bei 65535 wieder bei 0 anfängt, 
abgebildet in einem uint16.

Das ermöglicht mir einen Zeitraum von 6,55 Sekunden abzuprüfen, was 
ausreichend ist.

Auf dem µC läuft auch ein kleines serielles Protokoll. Selbiges muß auch 
Timeouts beherrschen um z.B. den Zusammenhang der hereintröpfelnden 
Bytes zu erkennen.

Jetzt ergibt sich folgendes Problem:
Zum Zeitpunkt 65530 wird eine Funktion aufgerufen. Diese setzt einen 
Timeout von 10 Zyklen, also bei 65540! Da wir hier aber nur 16 Bit 
haben, wird der Wert "5" abgespeichert. Soweit so gut.

Im Zeitpunkt 65534 findet eine Überprüfung statt, ob der Timeout schon 
erreicht wurde ... in einem unendlichen Zahlenraum würde das problemlos 
mit der Abfrage
1
if(SystemZeit>Timeout)
2
{
3
 // Timeout erreicht.
4
}
5
else
6
{
7
 // Timeout noch nicht abgelaufen.
8
}

funktionieren ... In diesem speziellen Fall ergibt sich aber das 
Problem, dass Timeout=5 ist und SystemZeit=65534! Obwohl ja der Timeout 
noch nicht abgelaufen ist, trifft die If-Bedingung fehlerhafterweise zu.

Im Endeffekt handelt es sich dabei doch nur um den Abstand in positiver 
Zählweise in einem endlichen Zahlenraum (Galois Feld)? Ich kann mir 
nicht vorstellen, dass ich hier auf weiter Flur allein bin mit dieser 
Problematik. Gibt's da eine geschmeidige Standardlösung für?

Achso und bevor der Vorschlag kommt: ein Long oder ähnlicher Typecast 
kann ich mir aufgrund sehr begrenzter Ressourcen nicht leisten. Ich 
werde auch mehrere von einander unabhängige Timeouts brauchen, d.h. ein 
"vertrimmen" der SystemZeit wie man es halt grade bräuchte (z.B. 
rücksetzen auf 0) ist auch nicht drin...

Vielen Dank.
Gast #1064120
Lesenswert?

Hallo,

Frage: wann wird die "Systemzeit > Timeout"- Bedingung abgefragt? Ist es 
sichergestellt, dass nach jedem Interrupt ausgeführt wird, dann würde 
ich "Systemzeit == Timeout" abfragen, der Übertrag wird dann 
uninteressant.
mfG Oswald
Gast #1064137
Lesenswert?

Also wenn mich nicht alles täuscht, hast du den Preis für die simplste 
Frage gewonnen =)

Ich würde den Timeout einfach als Countdown speichern. Also z. B. 5 
Zyklen eine 5 speichern und in jedem Zyklus um ein decrementieren. Dann 
auf 0 überprüfen.
Gast #1064142
Lesenswert?

>if (systemzeit - timeout > 0) {
>   // Timeout erreicht


Das ist ncihit ganz korrekt.

Ich mache solche Abfragen immer so:
SystemZeit sei der Zeitstempel, der im Zeitraster um eins erhöht wird.
1
if ( zeit soll beginnen )   Zeitstempel = SystemZeit;
2
...
3
if (   ( SystemZeit - Zeitstempel ) 
4
     > ( TimeOut                  )  )
5
{
6
...

Das funktioniert super.


Du brauchst somit für jedes zeitliche Ereignis eine ZeitStempel-Variable 
und kann denselbsen Systemzeit für alle verwenden...
#1064145
Lesenswert?

Es gibt 2 Lösungsansätze:

1. Wenn Du Timeouts > 3,2s brauchst:
------------------------------------
Merk Dir beim Start des Timeouts einen Timestamp:
1
uint16_t Systemzeit;
2
uint16_t Timestamp;
3
uint16_t Timeout;
4
...
5
void set_timeout (uint16_t my_Timeout){
6
  sei();
7
  Timestamp = Systemzeit;
8
  cli();
9
  Timeout = my_Timeout;
10
}
Zum Test, ob der Timeout abgelaufen ist, rechnest Du dann:
1
  sei();
2
  my_Systemzeit = Systemzeit);
3
  cli();
4
  if (Timeout <= (Systemzeit - Timestamp){
5
    // Timeout erreicht
6
  }
Angenommen, beim Start ist die Systemzeit 00FFh:
Dann ist 10 Ticks später die Systemzeit 109h.
Die Rechnung 109h - 000ffh ergibt im 16-Bit-Zahlenraum 0Ah (10dez).

Angenommen, beim Start ist die Systemzeit 0ffffh:
Dann ist 10 Ticks später die Systemzeit 09h.
Die Rechnung 09h - 0ffffh ergibt im 16-Bit-Zahlenraum 0Ah (10dez).

Bei der Berechnung wird ein Überlauf also durch die 16-Bit-Begrenzung 
abgeschnitten, das Ergebnis ist automatisch immer, wie von Dir 
gewünscht.

Nachteil an dieser Methode:
Du musst mit 2 16-Bit-Variablen arbeiten (und den Speicherplatz 
vorhalten).


2. Wenn 3,2s Timeout ausreichen:
--------------------------------
1
uint16_t Systemzeit;
2
uint16_t Timeout;
3
...
4
void set_timeout (uint16_t my_Timeout){
5
  sei();
6
  Timeout = Systemzeit + my_Timeout;
7
  cli();
8
}
1
  sei();
2
  int16_t Timediff = Systemzeit - Timeout;
3
  cli();
4
  if ( Timediff >= 0){
5
    // Timeout erreicht
6
  }

Nicht vergessen:
Ich gehe mal davon aus, dass die Systemzeit im IR hochgezählt wird. Weil 
Zugriffe auf die Systemzeit nicht atomar sind (2 8-Bit Zugriffe), muss 
in main() per sei() / cli() der IR kurzfristig gesperrt werden.

Viele Grüße, Stefan
Gast #1064158
Lesenswert?

Re: Abstand zweier Zahlen in 16-Bit (vgl. Galoisfeld)
Autor: Klaus (Gast)
Datum: 01.12.2008 11:20

Also wenn mich nicht alles täuscht, hast du den Preis für die simplste
Frage gewonnen =)

Ich würde den Timeout einfach als Countdown speichern. Also z. B. 5
Zyklen eine 5 speichern und in jedem Zyklus um ein decrementieren. Dann
auf 0 überprüfen.



also da gibts wirklich noch simplere fragen, ich fand die frage super, 
aber deine antwort würde ich mit zu den schlechtesten zählen. Wenn man 
die Zeit aus einem Timerregister liest und quasi mit Ticks arbeitet 
bringt deine Variante nichts.





Autor: Stefan Kleinwort (sk)
Datum: 01.12.2008 11:28

oh Mann ... und ich gewinne den Preis für die langsamste Antwort ...


Dafür war es auch eine sehr schöne und ausführliche Antwort die doch 
alle Fragen gut klärt :)

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