mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Abstand zweier Zahlen in 16-Bit (vgl. Galoisfeld)


Autor: Alexander I. (daedalus)
Datum:

Bewertung
0 lesenswert
nicht 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
if(SystemZeit>Timeout)
{
 // Timeout erreicht.
}
else
{
 // Timeout noch nicht abgelaufen.
}

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.

Autor: olykar (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jens S, (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wenn du einfach die abfrage machst
if(SystemZeit != Timeout)
 dann müsste es doch gehen oder?

Die Systemzeit fängt ja beim überlauf auch von 0 wieder an und dann geht 
das doch.

Autor: Martin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Alex,

vielleicht so etwas:

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

Das funktioniert aber nur bis zu Verzögerungszeiten von 32767 Schritten 
korrekt.

Gruß,
Martin

Autor: Alexander I. (daedalus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

es kann leider nicht auf "==" und "!=" zurückgegriffen werden, da die 
Tasks priorisiert sind und es so auch mal sein kann, dass einer erst 
einen Zyklus später dran kommt. Der µC hat noch ein paar mehr Aufgaben 
zu erledigen.

Der Vorschlag von Martin scheint mir eine Option zu sein.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
timeout = systemzeit;

...

if ( abs(systemzeit - timeout) > 0)
{
 ...
}

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du brauchst eine zusätzliche Variable:
startzeit = systemzeit;
// ...
if( (systemzeit - startzeit) > timeout ){
// timeout handler
}


Peter

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht 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.
if ( zeit soll beginnen )   Zeitstempel = SystemZeit;
...
if (   ( SystemZeit - Zeitstempel ) 
     > ( TimeOut                  )  )
{
...

Das funktioniert super.


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

Autor: Stefan Kleinwort (_sk_)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es gibt 2 Lösungsansätze:

1. Wenn Du Timeouts > 3,2s brauchst:
------------------------------------
Merk Dir beim Start des Timeouts einen Timestamp:
uint16_t Systemzeit;
uint16_t Timestamp;
uint16_t Timeout;
...
void set_timeout (uint16_t my_Timeout){
  sei();
  Timestamp = Systemzeit;
  cli();
  Timeout = my_Timeout;
}
Zum Test, ob der Timeout abgelaufen ist, rechnest Du dann:
  sei();
  my_Systemzeit = Systemzeit);
  cli();
  if (Timeout <= (Systemzeit - Timestamp){
    // Timeout erreicht
  }
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:
--------------------------------
uint16_t Systemzeit;
uint16_t Timeout;
...
void set_timeout (uint16_t my_Timeout){
  sei();
  Timeout = Systemzeit + my_Timeout;
  cli();
}
  sei();
  int16_t Timediff = Systemzeit - Timeout;
  cli();
  if ( Timediff >= 0){
    // Timeout erreicht
  }

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

Autor: Stefan Kleinwort (_sk_)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
oh Mann ... und ich gewinne den Preis für die langsamste Antwort ...

Autor: Jens S, (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 :)

Autor: Alexander I. (daedalus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank für die zahlreichen Rückmeldungenen. Ich denke ich werde die 
1. Variante von SK realisieren.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.