Zähler mit Grenzwerten effizient implementieren

OP (Firma: privat) #1026859
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
Gast #1026971
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!
#1026988
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.
OP (Firma: privat) #1026996
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:
1
 if ( dcf77_accuracy ) dcf77_accuracy--;
2
     234a:       80 91 b5 01     lds     r24, 0x01B5
3
     234e:       88 23           and     r24, r24
4
     2350:       29 f0           breq    .+10    ; 0x235c <__vector_3+0x$
5
     2352:       80 91 b5 01     lds     r24, 0x01B5
6
     2356:       81 50           subi    r24, 0x01       ; 1
7
     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!?!?
Gast #1027004
Lesenswert?

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

In Assembler selbst sind beide Teilaufgaben mit je vier Instruktionen 
erledigt:
1
LimitedIncrement:
2
    cpi   t, MAXVALUE
3
    breq  LimitedIncrementEnd
4
    inc   t  
5
LimitedIncrementEnd:
6
    ret
7

8

9
LimitedDecrement:
10
    cpi   t, MINVALUE
11
    breq  LimitedDecrementEnd
12
    dec   t  
13
LimitedDecrementEnd:
14
    ret

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

4
LimitedIncrement:
5
    cpse  t, max
6
    inc   t  
7
LimitedIncrementEnd:
8
    ret
9

10

11
LimitedDecrement:
12
    cpse  t, min
13
    dec   t  
14
LimitedDecrementEnd:
15
    ret
OP (Firma: privat) #1027011
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
Gast #1027037
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

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