mikrocontroller.net

Forum: Compiler & IDEs Zähler mit Grenzwerten effizient implementieren


Autor: Klaus W. (Firma: privat) (texmex)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!!

Ich habe ein ganz einfaches Problem:

Ein Zähler soll Werte zwischen 0 und 255 annehmen können. Also eine 8 
Bit Variable.

Natürlich kann diese einfach in-/dekrementiert werden.

Aber gibt es einen Trick effizient den Über- bzw. Unterlauf zu 
verhindern?

Jedesmal mit if zu prüfen produziert so schrecklich viel Assembler 
Code...

Vielleicht eine arithmetische Lösung?


Viele Grüße,
Klaus

Autor: Detlev T. (detlevt)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Warum nimmst du nicht einfach eine 16-Bit-Variable, die in- und 
dekrementiert wird? Wenn dann das High-Byte ungleich null ist, gab es 
einen Überlauf.

Subtraktion des High-Bytes vom Lowbyte, ohne if-Abfrage, müsste dann das 
leisten, was du willst.

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was willst du denn tun?
soll durch +1 rechnen die variable bei 255 stehen bleiben?

icrgendwei versteh ich dich nicht

Autor: Klaus W. (Firma: privat) (texmex)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Matthias Lipinsky wrote:
> Was willst du denn tun?
> soll durch +1 rechnen die variable bei 255 stehen bleiben?
>
> icrgendwei versteh ich dich nicht

Ja, genau.

In Assembler würde ich halt einfach das Carry-Flag wegwerfen...

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>In Assembler würde ich halt einfach das Carry-Flag wegwerfen...
Das stimmt nicht. Wenn du das Carrayflag wegwirst, dann schmeist du die 
Info weg, dass er übergelaufen ist..


>Jedesmal mit if zu prüfen produziert so schrecklich viel Assembler
>Code...
Poste den vielen Code doch mal!

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@texmex: Was soll das den bringen? Dann folgt auf 255 die 0. Wenn du bei 
255 stehen bleiben willst, dann musst du nach add +1 das C Flag wieder 
abziehen.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So übel finde ich den Code übrigens nicht.

Aus
  if (++i == 0) i = 255;
wird
  subi r17,lo8(-(1))
  brne .L2
  ldi r17,lo8(-1)
.L2:

Ok, ein bischen unsauber ist der Quellcode schon, denn er setzt zwingend 
voraus, dass die Variable als 8bit Byte implementiert ist und nicht etwa 
in 9 Bits. Ist heutzutage aber recht verbreitet.

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
einfacher gehts auch nicht

Autor: Klaus W. (Firma: privat) (texmex)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Matthias Lipinsky wrote:
>>In Assembler würde ich halt einfach das Carry-Flag wegwerfen...
> Das stimmt nicht. Wenn du das Carrayflag wegwirst, dann schmeist du die
> Info weg, dass er übergelaufen ist..
>
>
>>Jedesmal mit if zu prüfen produziert so schrecklich viel Assembler
>>Code...
> Poste den vielen Code doch mal!

Naja, beim Dekrementieren z.B. so:
 if ( dcf77_accuracy ) dcf77_accuracy--;
     234a:       80 91 b5 01     lds     r24, 0x01B5
     234e:       88 23           and     r24, r24
     2350:       29 f0           breq    .+10    ; 0x235c <__vector_3+0x$
     2352:       80 91 b5 01     lds     r24, 0x01B5
     2356:       81 50           subi    r24, 0x01       ; 1
     2358:       80 93 b5 01     sts     0x01B5, r24

Aber wenn ich mir das gerade so ansehe, liegt das wohl eher daran, dass 
die Variable erst direkt aus dem Ram geladen wird und nicht in einem 
Register steht!?!?

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@lippy: Doch:
  ldi r0,1
  add r,r0
  sbci r,0
ist zwar nicht kürzer, aber schneller.

@texmex: Speicher ist eines, aber dann auch noch volatile...

Autor: Klaus W. (Firma: privat) (texmex)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. wrote:
> @texmex: Was soll das den bringen? Dann folgt auf 255 die 0. Wenn du bei
> 255 stehen bleiben willst, dann musst du nach add +1 das C Flag wieder
> abziehen.

Hm, stimmt.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Jedesmal mit if zu prüfen produziert so schrecklich viel Assembler
>Code...

In Assembler selbst sind beide Teilaufgaben mit je vier Instruktionen 
erledigt:
LimitedIncrement:
    cpi   t, MAXVALUE
    breq  LimitedIncrementEnd
    inc   t  
LimitedIncrementEnd:
    ret


LimitedDecrement:
    cpi   t, MINVALUE
    breq  LimitedDecrementEnd
    dec   t  
LimitedDecrementEnd:
    ret

Wenn Du es noch kompakter haben willst und zwei Register freizustellen 
bereit bist, kannst Du auch die cpse-Instruktion verwenden:
; (Register min und max irgendwo im Initialisierungsteil 
; des Programms mit MINVALUE resp. MAXVALUE laden)

LimitedIncrement:
    cpse  t, max
    inc   t  
LimitedIncrementEnd:
    ret


LimitedDecrement:
    cpse  t, min
    dec   t  
LimitedDecrementEnd:
    ret

Autor: Klaus W. (Firma: privat) (texmex)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. wrote:
> @lippy: Doch:
>   ldi r0,1
>   add r,r0
>   sbci r,0
> ist zwar nicht kürzer, aber schneller.
>
> @texmex: Speicher ist eines, aber dann auch noch volatile...

Ah, verstehe! Deshalb wird das dann anschließend gleich nochmal aus dem 
Ram geladen.
Wäre es denn evtl. sinnvoll die volatile Variable am Anfang der 
Interrupt Routine in eine lokale Variable zu kopieren (die dann 
vermutlich in einem Register landet), wenn sie häufiger modifiziert 
wird?

Oder macht man "sowas" ganz anders?


viele Grüße,
Klaus

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oh, das ist ja das GCC-Forum hier (ups, erst jetzt gesehn). Sollte Dich 
Assemblercode nicht interessieren: Sorry!

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus W. wrote:

> Oder macht man "sowas" ganz anders?

Nö, genau so. Standardproblem von volatile.

Autor: Klaus W. (Firma: privat) (texmex)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gast wrote:
> Oh, das ist ja das GCC-Forum hier (ups, erst jetzt gesehn). Sollte Dich
> Assemblercode nicht interessieren: Sorry!

Nun, das eine schliesst das andere ja nicht aus :-).

Autor: Klaus W. (Firma: privat) (texmex)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. wrote:
> Klaus W. wrote:
>
>> Oder macht man "sowas" ganz anders?
>
> Nö, genau so. Standardproblem von volatile.

Mir kam da grade die Speicherklasse "register" in den Sinn. Tatsächlich 
findet sich in 
http://www.nongnu.org/avr-libc/user-manual/FAQ.htm...
ein entsprechender Hinweis.
Aber das bietet wohl auch so allerlei Fallstricke....

Autor: IRQ (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Ich habe ein ganz einfaches Problem:
No Problem for me !

> Ein Zähler soll Werte zwischen 0 und 255 annehmen können. Also eine 8
> Bit Variable.
All right.

> Natürlich kann diese einfach in-/dekrementiert werden.
Lets go.

> Aber gibt es einen Trick effizient den Über- bzw. Unterlauf zu
> verhindern?
Yes, sir !

> Jedesmal mit if zu prüfen produziert so schrecklich viel Assembler
> Code...
Yeah, thats true.

> Vielleicht eine arithmetische Lösung?
CPU boardmittel !

Also, hier die ultimative Lösung:

Du programmierst einen Timer und setzt das Kompareflag ! Dann Vergleicht 
die CPU und erzeugt einen Interrupt, unhabhängig vom Programm und alles 
ist bestens ! 100% Effe ;-)

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.