C Code Frage: subtrahieren in Bitfeld

Gast #5359484
Lesenswert?

Hallo zusammen,

ich habe eine uint8_t counter variable, die ich als 4 separate 2bit 
counter nutzen möchte.
Ich stehe gerade etwas auf dem schlauch wie ich diese counter am besten 
herunterzählen kann.

Bit 0,1 -> Counter 0
Bit 2,3 -> Counter 1
Bit 4,5 -> Counter 2
Bit 6,7 -> Counter 3

jeden Counter möchte ich nun herunterzählen können um "-1", aber auch 
nicht kleiner als 0 werden (Überlauf).

Wie mache ich das am geschicktesten?

Viele Grüße,
C-Anfänger
Moderator #5360128
Lesenswert?

c-anfaenger schrieb:
> jeden Counter möchte ich nun herunterzählen können

Alle miteinander in einem Aufwasch?

Das geht bspw. so:

1
uint8_t counter;
2

3
counter = counter & counter<<1 & 0xaa | ~counter & counter>>1 & 0x55;

Mit diesem Ausdruck wird jeder der vier 2-Bit-Zähler dekrementiert,
falls sein aktueller Wert >0 ist. Ist der Wert 0, bleibt er unverändert.

Beispiel:

1
binär:        dezimal:
2

3
C3 C2 C1 C0   C3 C2 C1 C0
4
———————————   ———————————
5
10 11 00 01    2  3  0  1
6
01 10 00 00    1  2  0  0
7
00 01 00 00    0  1  0  0
8
00 00 00 00    0  0  0  0
Moderator #5360152
Lesenswert?

Walter T. schrieb:
> Hast Du Dir das gerade selbst mal eben hergeleitet oder ist das ein
> festes Rezept?

Ersteres. Rezepte kann ich mir leider schlecht merken ;-)

Die Herleitung ist aber nicht schwer:
1. Wertetabelle aufstellen
2. Daraus logische Terme ableiten und vereinfachen
3. Das Ganze noch etwas schöner machen

Hier ist noch eine leicht geänderte Variante, die die beiden
Maskierungsoperationen zu einer zusammenfasst:

1
  uint8_t counter;
2

3
  uint8_t tmp = counter & 0xaa;
4
  counter =  tmp & counter<<1 | tmp>>1 & ~counter;

Irgendwie habe ich das Gefühl, dass man das noch weiter vereinfachen
kann, evtl. unter Verwendung der XOR-Operationen, komme aber nicht
drauf.
Gast #5360647
Lesenswert?

>   uint8_t counter;
>
>   uint8_t tmp = counter & 0xaa;
>   counter =  tmp & counter<<1 | tmp>>1 & ~counter;
>
> Irgendwie habe ich das Gefühl, dass man das noch weiter vereinfachen
> kann, evtl. unter Verwendung der XOR-Operationen, komme aber nicht
> drauf.


das hilft mir schon mal sehr weiter!
Danke und Gruß!
Gast #5360755
Lesenswert?

Andreas R. schrieb:
> Wenn Du die Zähler gemeinsam dekrementierst, besser nur einen
> Zähler
> nehmen und 4x verwenden?  ;-)

es sind halt unabhängige Zähler, die zwar gleichzeitig runtergezählt 
werden aber zu anderen Zeiten gesetzt werden sollen.

Danke erstmal für die Hilfe, ich werde doch nur 2 4bit Zähler nutzen und 
nicht 4 2bit Zähler. Versuche das gerade entsprechend anzupassen!

Gruß,
Gast #5360826
Lesenswert?

c-anfaenger schrieb:
> ich werde doch nur 2 4bit Zähler nutzen und nicht 4 2bit Zähler.

Und warum? Hier RAM zu sparen bleibt blödsinn., Zumindest in 99.9%.

Weiter Idee zur Knobelaufgabe: wirklich subtrahiren.
1
tmp = (counter | counter>>1) & 0x55;
2
counter -= tmp;
3

4
//oder bei 4 Bit:
5

6
tmp = (counter | counter>>2) & 0x33;
7
tmp &= tmp>>1;
8
counter -= tmp;
Gast #5362033
Lesenswert?

ich habe inzwischen auch das herunterzählen hinbekommen, allerdings ist 
das mir hier zu peinlich den mehrzeiligen Code zu posten ;)

Also die Anwendung ist folgender:
Eine Art Event-System:
Es werden verschiedene Events ausgelöst und dabei jeweils ein Bit von 0 
auf 1  gekippt. Diese sollen nach kurzer Zeit wieder zurückgesetzt 
werden.
Da die Events zu unterschiedlichen Zeitpunkten ausgelöst werden, hat 
jedes Event einen eigenen Counter für das Zurücksetzen.
Das ganze findet in einer Smarthome-Bus Steuerung Anwendung, bei der ich 
einige Events haben möchte, da einfach für alles 8bit zu nehmen würde 
viel mehr Speicher fressen als notwendig.

gruß
Gast #5362069
Lesenswert?

c-anfaenger schrieb:
> ich habe inzwischen auch das herunterzählen hinbekommen, allerdings ist
> das mir hier zu peinlich den mehrzeiligen Code zu posten ;)

und warum nicht straight, mit Bitfeldern?
1
if(counter[n].A) {counter[n].A--;}

> ds einfach für alles 8bit zu nehmen würde
> viel mehr Speicher fressen als notwendig.

Das ist klar. Das ist aber normalerweise nicht die Frage. Es macht 
regelmäßig nur dann Sinn, den Code zu verunstalten, wenn es konkret an 
RAM mangelt. Denn hier hat Peter einfach Recht:

Peter D. schrieb:
> Wenn der MC dafür zu knapp an RAM ist, dann ist er auch zu knapp an
> Flash, um bei jeder Operation aufwendige AND/OR/Schiebe-Orgien
> auszuführen.


Und wenn RAM wirklich knapp sein sollte, dann sind Arrays von 2-4 Bit in 
einem Byte meist zweitbeste Lösung. Wenn es z.B. zu jedem Event-Timer 
noch 2-3 Bits gibt (z.B. enable, prio, ...), dann lieber diese in einem 
Byte gruppieren, um sie geschlossen und konsistent beackern zu können.
Gast #5362125
Lesenswert?

ich werde einen Atmega1284 nehmen, der hat ja 16KB SRAM.

Ich hatte überlegt alle Einstellungen um Events zu erkennen (z.B. auf 
dem genutzten RS485 Bus sendet 0x12345678 den Befehl 0x01 mit Wert 0x04, 
dann setze das Event-Bit auf 1 für Zeit 0x08) im RAM vorzuhalten um 
nicht permanent das EPROM abzufragen.
Somit sind durch die Settings schon ein paar KB RAM belegt.

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