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
:
Verschoben durch Moderator
1 | struct sCounter; |
2 | {
|
3 | uint8_t C0 :2; |
4 | uint8_t C1 :2; |
5 | uint8_t C2 :2; |
6 | uint8_t C3 :2; |
7 | };
|
8 | |
9 | struct sCounter Counter4; |
10 | |
11 | ...
|
12 | |
13 | if(Counter.C3 > 0) {Counter.C3--;} |
14 | ...
|
c-anfaenger schrieb: > Wie mache ich das am geschicktesten? Man nimmt 4 Byte. 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.
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 |
:
Bearbeitet durch Moderator
Yalu X. schrieb: > uint8_t counter; > > counter = counter & counter<<1 & 0xaa | ~counter & counter>>1 & 0x55; Hast Du Dir das gerade selbst mal eben hergeleitet oder ist das ein festes Rezept?
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.
Yalu X. schrieb: > 1. Wertetabelle aufstellen Achja... ein Schritt, den ich regelmäßig vergesse: Vor dem Programmieren einen Schritt weg vom Monitor machen und auf einem Blatt Papier kritzeln...
Wenn Du die Zähler gemeinsam dekrementierst, besser nur einen Zähler nehmen und 4x verwenden? ;-)
> 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ß!
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ß,
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; |
Achim S. schrieb: > Und warum? Hier RAM zu sparen bleibt blödsinn., Zumindest in 99.9%. Das würde mich auch mal interessieren, was die Anwendung ist.
Peter D. schrieb: > Das würde mich auch mal interessieren, was die Anwendung ist. Vielleicht so etwas Ähnliches wie die vertical Counters in deiner Entprellroutine? Nur dass die Counters hier horizontal sind, nur 1 statt 2 Bytes belegen und damit in der Anzahl auf 4 beschränkt sind.
Achim S. schrieb: > counter -= (counter>15?16:0)+!!(counter&15); Der Preis für den geheimnisvollsten und nichtssagensten Code geht an Achim S.
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ß
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.
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.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.