Forum: Mikrocontroller und Digitale Elektronik C ohne if() - in einzelnen Fällen möglich?


von Georg M. (g_m)


Lesenswert?

Der Zustand einiger voneinander unabhängiger Bits eines Bytes (uint8_t) 
wird überwacht und auswertet.
Ein vereinfachtes und extrem verständliches Beispiel dazu wäre:
Bit 3 == 1  ---> LED on
Bit 3 == 0  ---> LED off
1
uint8_t b1;
2
. . . . .
3
. . . . .
4
  if((b1 & 0x08) == 0x08)   // if b1 == xxxx1xxx
5
  {
6
    PORTA.OUT |= 0x08;      // set PA3 (LED on)
7
  }
8
  else                      // if b1 == xxxx0xxx
9
  {
10
    PORTA.OUT &= 0xF7;      // clear PA3 (LED off)
11
  }
12
. . . . .
Kann man dieses Beispiel irgendwie ohne if() umsetzen?
(ist nicht sehr wichtig, nur eine theoretische Frage)

von Dirk B. (dirkb2)


Lesenswert?

Du kanst den ?: Operator Missbrauchen.

von Schützt die OPAMP-Tiere! (Gast)


Lesenswert?

Falls der Port auch mal kurz auf 0 gehen darf:
immer mit &= clearen, dann geshiftetes ergebnis der if bedingung wieder 
"rein-Odern"...

von ChSch (Gast)


Lesenswert?

Ternärer Operator:
Bedingung ? Anweisung wahr : Anweisung falsch;
b1 & 0x08 ? PORTA.OUT |= 0x08 : PORTA.OUT &= 0xF7;

von Dirk B. (dirkb2)


Lesenswert?

Diese if-Anweisung kann der Compiler gut erkennen und entsprechend 
optimieren.
Z.B. mit Bit-Setz oder Lösch-Befehlen, sofern auf der Architektur 
vorhanden

von Ralf G. (ralg)


Lesenswert?

'switch/case'
Sieht manchmal schöner aus...

von Markus F. (mfro)


Lesenswert?

Bitwackler sollten das hier:

https://graphics.stanford.edu/~seander/bithacks.html

kennen...

von Rocket-Informatiker (Gast)


Lesenswert?


von Georg M. (g_m)


Lesenswert?

Schützt die OPAMP-Tiere! schrieb:
> Falls der Port auch mal kurz auf 0 gehen darf:
> immer mit &= clearen, dann geshiftetes ergebnis der if bedingung wieder
> "rein-Odern"...

Es wäre schön. Leider dürfen unbeteiligte Bits nicht angefasst werden.



Georg M. schrieb:
> wird auswertet

Naja...

von Mario M. (thelonging)


Lesenswert?

1
tmp = PORTA.OUT & 0xf7;
2
PORTA.OUT = tmp | b1 & 8;

von Docureader (Gast)


Lesenswert?

Bei komplizierteren Bitpermutationen:

__builtin_avr_insert_bits

https://gcc.gnu.org/onlinedocs/gcc/AVR-Built-in-Functions.html

von Erich (Gast)


Lesenswert?

Mario M. schrieb:
>
1
tmp = PORTA.OUT & 0xf7;
2
> PORTA.OUT = tmp | b1 & 8;

Das scheint mir gute Lösung zu sein.

Ein Compiler in wirklich hoher Optimierungsstufe sollte allerdings die 
Vorgabe-Lösung des TE im Idealfall exakt genauso hinkriegen! Vielleicht 
sogar codeidentisch.

Gruss

von Stefan F. (Gast)


Lesenswert?

((b1 & 0x08) == 0x08) && PORTA.OUT |= 0x08 || PORTA.OUT &= 0xF7;

Ist nur geraten, nicht getestet.

von Gerald K. (geku)


Lesenswert?

1
switch((b1 & 0x08) == 0x08) // if b1 == xxxx1xxx
2
{
3
    case 0:    PORTA.OUT &= 0xF7; // clear PA3 (LED off)
4
               break;
5
    default:   PORTA.OUT |= 0x08; // set PA3 (LED on)
6
}

: Bearbeitet durch User
von Ralf G. (ralg)


Lesenswert?

Gerald K. schrieb:
> ...
^^
Naja. Da würde ich 'if/else' bevorzugen.

von HildeK (Gast)


Lesenswert?

Mich würde interessieren, was der TO gegen if / else hat.
Klar, damit kann man unübersichtlich verschachteln, aber bei dem 
genannten Beispiel ist das ja nicht so.
Und andere Konstrukte, wie ?: wird der Compiler zum ebenso effizienten 
Code auflösen, ich vermute, dass auch die Variante von Gerald K. 
annähernd den gleichen Assemblercode ergibt.
Also, warum nicht if und else?

von Gerald K. (geku)


Lesenswert?

HildeK schrieb:
> Also, warum nicht if und else?

War nur eine theoretische Frage des TO's ohne praktischem Nutzen.

Georg M. schrieb:
> Kann man dieses Beispiel irgendwie ohne if() umsetzen?
> (ist nicht sehr wichtig, nur eine theoretische Frage)

von Hannes J. (Firma: _⌨_) (pnuebergang)


Lesenswert?

Man kann jedes if() durch ein while() mit einer Hilfsvariable ersetzen. 
Aufgabe formal erfüllt. Man kann sich auch ein Loch ins Knie bohren und 
La Paloma drauf pfeifen lassen. Ähnlich sinnvoll.

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Stefan ⛄ F. schrieb:
> ((b1 & 0x08) == 0x08) && PORTA.OUT |= 0x08 || PORTA.OUT &= 0xF7;
>
> Ist nur geraten, nicht getestet.

Sieht korrekt aus, ob short-logic hier bekannt/beliebt ist ...?
ABER, die Sequenze ist (eigentlich) gleich dem if/else des TO.

von EAF (Gast)


Lesenswert?

Aus meiner Sicht, gibts keinen Weg an if Konstrukten vorbei.
Klar kann man in manchen Fällen einen alternativen Weg finden.
Nur ist es dann lesbarer?
Daran entscheidet sich der Sinn in erster Linie.

Natürlich macht es Sinn möglichst flache Programme zu schreiben.
Möglichst geringe Schachtelungstiefen, einfache Bedingungen.
Eben genau, wegen der Lesbarkeit.

Ein Weg:
Viele kleine gut benannte Funktionen, statt wenige aufgeblähte.

von Freizeit Coder (Gast)


Lesenswert?

Wie wäre es mit einer Switch Case Anweisung?
Schaue hier :
https://www.c-howto.de/tutorial/verzweigungen/switch-case/

int a=2;

switch(a) {
  case 1: printf("a ist eins\n"); break;
  case 2: printf("a ist zwei\n"); break;
  case 3: printf("a ist drei\n"); break;
  default: printf("a ist irgendwas\n"); break;
}

von Erich (Gast)


Lesenswert?

Freizeit Coder schrieb:
> Wie wäre es mit einer Switch Case Anweisung?
> Schaue hier :
> https://www.c-howto.de/tutorial/verzweigungen/switch-case/
>
> int a=2;
>
> switch(a) {
>   case 1: printf("a ist eins\n"); break;
>   case 2: printf("a ist zwei\n"); break;
>   case 3: printf("a ist drei\n"); break;
>   default: printf("a ist irgendwas\n"); break;
> }

Hmm,
und was hat jetzt diese deine Erläuterung
zu tun mit
der Fragestellung (= erster Beitrag).

von MaWin (Gast)


Lesenswert?

Erich schrieb:
> Hmm,
> und was hat jetzt diese deine Erläuterung
> zu tun mit
> der Fragestellung (= erster Beitrag).

Das er das Programmieren erfunden hat. Alle anderen sind in seinen Augen 
Idioten. Er ist der Macker. Nur er. Ohne Helm und ohne Gurt.
Kot Er.

von A. S. (Gast)


Lesenswert?

Also: ein ?:, Ggf mit Komma statt {} kann viele ifs ersetzen.

Eine binäre Zuweisung aus einer binären Frage geht meist ohne jedes If 
oder dessen äquivalent


 && Und || erlauben viele if-äquivalente Konstrukt 
(Kurzschluss-Auswertung)

Switch/Case, for und while können immer als If missbraucht werden, als 
Else nur teilweise.

Weitere Möglichkeiten über funktionsptr-Arrays und und und.

Wenn Du einen der genannten Ansätze nicht Kennst, einfach fragen

von Hermann Kokoschka (Gast)


Lesenswert?

WAS GENAU soll dieser Unfug?
Langeweile des TO?

von Eggsbert (Gast)


Lesenswert?

Wenn AVR:
> von Docureader (Gast)  10.06.2022 16:28

PORTA.OUT = __builtin_avr_insert_bits(0xfffff2ff, b1, PORTA.OUT);
Wird in 4 Maschinen-Befehlen (in, lds, bst, out) ausgeführt.
Kürzer, schneller, eleganter und edler geht es nicht.
Man muss nur wissen wie.

von Eggsbert (Gast)


Lesenswert?

Uups, Korrektur:
PORTA.OUT = __builtin_avr_insert_bits(0xffff3fff, b1, PORTA.OUT);

von Stefan F. (Gast)


Lesenswert?

Eggsbert schrieb:
> Kürzer, schneller, eleganter und edler geht es nicht.

Von anderen AVR Modellen bin ich gewohnt, dass das Setzen/Löschen eines 
einzelnen Bits in jeweils eine einzige Instruktion übersetzt wird.

Auszug aus einem Assembler Listing:
1
    PORTB |= (1<<PB4);
2
  e4:  c4 9a         sbi  0x18, 4  ; 24
3
4
    PORTB &= ~(1<<PB5);
5
  e6:  c5 98         cbi  0x18, 5  ; 24

Das hat allerdings nichts mit der Frage des TO zu tun.

von Stefan F. (Gast)


Lesenswert?

Ich schrieb:
>> ((b1 & 0x08) == 0x08) && PORTA.OUT |= 0x08 || PORTA.OUT &= 0xF7;

Apollo M. schrieb:
> Sieht korrekt aus, ob short-logic hier bekannt/beliebt ist ...?

Bei mir ist es jedenfalls nicht beliebt. Aber wenn er schon so fragt ...

Ich kenne dieses Konstrukt eher von Shell Scripten, zum Beispiel:
1
wget http://whatever/data.zip || exit 1
2
unzip data.zip || exit 1
3
mv /target/folder/summary.csv /target/folder/summary.old || exit 1
4
copy data/summary.csv /target/folder || exit 1
5
echo "Download of new summary succeeded"

In diesem Fall bricht das Script bei jedem Fehler sauber ab, ohne 
Folgefehler zu produzieren. Insbesondere das Umbenennen von summary.csv 
nach summary.old soll nur stattfinden, wenn der Download und das 
Auspacken der ZIP Datei erfolgreich war.

von DerEinzigeBernd (Gast)


Lesenswert?

> Bei mir ist es jedenfalls nicht beliebt.
Short-Circuit evaluation ist elementarer Bestandteil von C und davon 
abgeleiteten Sprachen.

Um die zu umgehen, muss man reichlich sinnlosen und aufgeblähten Code 
schreiben.

von A. S. (Gast)


Lesenswert?

A. S. schrieb:
> Weitere Möglichkeiten über funktionsptr-Arrays und und und.

Oder ganz allgemein: reine Daten-Zweige sind auf zig weitere Arten 
möglich (Rückgabewert abhängig vom Argument). Die Wege für den 
kontrollfluas sind begrenzter und größtenteils schon gelistet (mir fällt 
so schnell kein weiterer ein, vielleicht über mehr experimentelle Sachen 
wie Exit, ljump, typeof in Makros, ...

von Rolf M. (rmagnus)


Lesenswert?

Gerald K. schrieb:
> HildeK schrieb:
>> Also, warum nicht if und else?
>
> War nur eine theoretische Frage des TO's ohne praktischem Nutzen.

Aber der Hintergrund der Frage wäre schon interessant zu wissen, auch im 
Bezug auf die Antworten. Geht es eher darum, zu vermeiden, dass der 
Computer eine Verzweigung ausführt? Dann wird die Antwort sehr 
kompliziert (oder sehr einfach, je nach Sichtweise). Oder ist es eher 
eine sprachliche Frage, also welche Sprachkonstrukte es gibt, die im 
Prinzip das gleich leisten können?
Oder gibt es keinen Hintergrund, und die Frage ist wirklich komplett aus 
der Luft gegriffen? Dann ist sie irgendwie sinnlos.

: Bearbeitet durch User
von Eggsbert (Gast)


Lesenswert?

>   if((b1 & 0x08) == 0x08)   // if b1 == xxxx1xxx
kann man kürzer schreiben:
    if(b1 & 8)
Ein Ausdruck ist dann wahr, wenn er ungleich 0 ist, man muss also nicht 
explizit mit 8 vergleichen, es reicht, wenn !=0.

Korrektur:
> Wird in 4 Maschinen-Befehlen (in, lds, bst, out) ausgeführt.
Es sind 5 Befehle: in, lds, bst, bld, out

> Von anderen AVR Modellen bin ich gewohnt, dass das Setzen/Löschen
> eines einzelnen Bits in jeweils eine einzige Instruktion übersetzt wird.
Schon, aber bei bst (Bit Store from Register to T) wird das Bit im 
Status-Flag T zwischengespeichert und mit bld (Bit Load from T to 
Register) ins Zielregister kopiert (eigentlich würde man es von store 
und load genau andersherum erwarten).

von Ralf G. (ralg)


Lesenswert?

Rolf M. schrieb:
> Aber der Hintergrund der Frage wäre schon interessant zu wissen, auch im
> Bezug auf die Antworten.

Georg M. schrieb:
> Der Zustand einiger voneinander unabhängiger Bits eines Bytes (uint8_t)
> wird überwacht und auswertet.

Da habe ich jetzt rausgelesen, normalerweise sind es mehr Bits als in 
dem Beispiel. Deshalb:

Ralf G. schrieb:
> 'switch/case'
> Sieht manchmal schöner aus...

Jedes mögliche Bitmuster bekommt seinen 'case-Zweig'. Das sieht für mich 
dann aufgeräumter aus als immer 'if-else-if-if-else'...

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Eggsbert schrieb:
> PORTA.OUT = __builtin_avr_insert_bits(0xfffff2ff, b1, PORTA.OUT);
> Wird in 4 Maschinen-Befehlen (in, lds, bst, out) ausgeführt.
> Kürzer, schneller, eleganter und edler geht es nicht.
> Man muss nur wissen wie.

Verstehe nur Bahnhof und blicke es nicht.
Kann das mal erklärt werden hins. 0xfffff2ff, ...
Wo kommt der Wert her? Warum ist der so lang?

Der Zweck wird von gnu genannt, aber wie der damit erfüllt wird kapiert 
ich auch nicht. Wie kann ich da über mehrere Ports an den Bits einfach 
rumfummeln?

von Erich (Gast)


Lesenswert?

Apollo M. schrieb:
> Eggsbert schrieb:
>> PORTA.OUT = __builtin_avr_insert_bits(0xfffff2ff, b1, PORTA.OUT);
>> Wird in 4 Maschinen-Befehlen (in, lds, bst, out) ausgeführt.
>> Kürzer, schneller, eleganter und edler geht es nicht.
>> Man muss nur wissen wie.
>
> Verstehe nur Bahnhof und blicke es nicht.
> Kann das mal erklärt werden hins. 0xfffff2ff, ...
> Wo kommt der Wert her? Warum ist der so lang?
>
> Der Zweck wird von gnu genannt, aber wie der damit erfüllt wird kapiert
> ich auch nicht. Wie kann ich da über mehrere Ports an den Bits einfach
> rumfummeln?


Mal abgesehen davon, daß das mit "..2FFF" falsch ist (und vom Beitrag 
Schreiber inzwischen  korrigiert),
braucht das NIEMAND verstehen, der nicht optimierten Assemblercode für 
genau diese Prozessor-Architektur erstellen wollen.
Alle anderen schreiben vernünftig lesbaren und kommentierten C-Code, den 
sie selbst verstehen und auch in 1/2 Jahr noch kampieren (dank der 
eigenen Kommentare).
Den Rest besorgt der C-Compiler mit Optimierungslevel 3 von 4 oder der 
höchsten.

Gruss

von MaWin (Gast)


Lesenswert?

EAF schrieb:
> Aus meiner Sicht, gibts keinen Weg an if Konstrukten vorbei

Schade eigentlich.

Damit bist du ungeeignet um hochoptimierte Assemblerprogramme zu 
erstellen.

Denn ein Sprung unterbricht auf vielen Prozessorarchitekturen die 
Pipeline und kostet mehr Takte als z.B. das hier angemessene

Mario M. schrieb:
> tmp = PORTA.OUT & 0xf7;
> PORTA.OUT = tmp | b1 & 8;

Komplette Programme ohne einen einzigen Sprung sind natürlich arg 
limitiert: sie laufen nur ein Mal ab und können nicht viele Dinge 
treiben. Aber es gibt sie, so auf dem Level der AWL einer SPS.

von EAF (Gast)


Lesenswert?

MaWin schrieb:
> Schade eigentlich.
>
> Damit bist du ungeeignet um hochoptimierte Assemblerprogramme zu
> erstellen.

Schwachkopf!

von vn nn (Gast)


Lesenswert?

HildeK schrieb:
> Mich würde interessieren, was der TO gegen if / else hat.

Abgesehen von "Code beliebig komplex schreiben" fällt mir auf die 
schnelle tatsächlich eine Prozessorplattform ein, die einerseits eine 
extrem schlechte Branch-Performance aufweist, gleichzeitig vom 
Hersteller aber jahrelang einen Compiler spendiert bekam der nicht fähig 
war, beispielsweise ein "if/else" zu einer (wesentlich performanteren) 
bedingten Zuweisung zu optimieren, wenn mans nicht extra als 
Ternäroperation hinschrieb.

von EAF (Gast)


Lesenswert?

vn nn schrieb:
> der nicht fähig
> war, beispielsweise ein "if/else" zu einer (wesentlich performanteren)
> bedingten Zuweisung zu optimieren, wenn mans nicht extra als
> Ternäroperation hinschrieb.

Naja...
Ist es doch so, dass das if() Statement für den Kontrollfluss zuständig 
ist, und der ?: Operator für Daten.
Optimierungen werden nicht vom Standard eingefordert.
Also eigentlich alles richtig.

Deiner Aussage nach sind die betreffenden Compiler "besser" geworden.
Also auch da alles richtig und gut so.

von vn nn (Gast)


Lesenswert?

EAF schrieb:
> Ist es doch so, dass das if() Statement für den Kontrollfluss zuständig
> ist, und der ?: Operator für Daten.

Was natürlich in sehr vielen Alltagssituationen aufs gleiche hinaus 
läuft, insbesondere bei komplexer Regelungstechnik statt Pins toggeln.

EAF schrieb:
> Optimierungen werden nicht vom Standard eingefordert.

Hat auch keiner behauptet, man geht im 21. Jahrhundert halt davon aus 
dass ein Compiler zumindest ansatzweise sinnvoll optimieren kann.

EAF schrieb:
> Also eigentlich alles richtig.

Natürlich. Es fordert ja auch kein Standard dass ich mir nicht von 
hinten durchs Knie ins Auge schießen kann, somit alles richtig.

EAF schrieb:
> Deiner Aussage nach sind die betreffenden Compiler "besser" geworden.

Ich wüsste nicht wo ich das geschrieben haben soll, ich kenn lediglich 
die aktuelle Situation nicht, nachdem ich schon vor einigen Jahren den 
Arbeitsgeber gewechselt habe.
Nachdem der Prozessorhersteller aber bis heute immer noch auf seine 
mistigen proprietären Compiler statt auf GCC oder LLVM setzt und immer 
noch damit kämpft, überhaupt mal den Standard einzuhalten, gehe ich 
nicht davon aus dass er übers simpelste hinausgehende Optimierungen 
hinbekommt.

EAF schrieb:
> Also auch da alles richtig und gut so.

Ja, alles gut, es gibt nichts zu sehen, Mindestmaß ist ja erfüllt, mehr 
Ansprüche hat ja eh keiner.

von c-hater (Gast)


Lesenswert?

vn nn schrieb:

> Abgesehen von "Code beliebig komplex schreiben" fällt mir auf die
> schnelle tatsächlich eine Prozessorplattform ein, die einerseits eine
> extrem schlechte Branch-Performance aufweist, gleichzeitig vom
> Hersteller aber jahrelang einen Compiler spendiert bekam der nicht fähig
> war, beispielsweise ein "if/else" zu einer (wesentlich performanteren)
> bedingten Zuweisung zu optimieren, wenn mans nicht extra als
> Ternäroperation hinschrieb.

Sowas kann im konkreten Fall sicher nicht das Problem sein. Denn: es 
handelt sich ganz offensichtlich ja nicht um eine simple Zuweisung mit 
Bedingung. Allerhöchstens dann, wenn die Zielarchitektur 
Bitinstruktionen kennt.

Damit dein Geschwalle also überhaupt irgendeinen praktischen Nutzen 
entfalten kann, braucht es eine Architektur sowohl mit Codecache als 
auch mit der der Fähigkeit zu Bitinstruktionen auf jedes beliebige Ziel.

Da wird die Luft doch schon arg dünne...

Und wenn es so eine Architektur gibt, der Compiler das aber nur für die 
ternäre Schreibweise korrekt umsetzt, dann bedeutet das nicht mehr und 
nicht weniger als: der Compiler taugt nix.

von Wilhelm M. (wimalopaan)


Lesenswert?

Eggsbert schrieb:
> Wenn AVR:
>> von Docureader (Gast)  10.06.2022 16:28
>
> PORTA.OUT = __builtin_avr_insert_bits(0xfffff2ff, b1, PORTA.OUT);
> Wird in 4 Maschinen-Befehlen (in, lds, bst, out) ausgeführt.
> Kürzer, schneller, eleganter und edler geht es nicht.
> Man muss nur wissen wie.

Naja, so RMW-Sequenzen müssen ggf. auch noch gegen Interrupts gesperrt 
werden.

Da es ja um AVR zu gehen scheint, könnte man auch vermuten, dass es sich 
dabei um die moderneren AVRs haben, bei denen man gar kein RMW braucht, 
sondern das über die CLR / SET-Register kürzer und atomar machen kann.

von Wilhelm M. (wimalopaan)


Lesenswert?

Georg M. schrieb:
> Kann man dieses Beispiel irgendwie ohne if() umsetzen?
> (ist nicht sehr wichtig, nur eine theoretische Frage)

Ja, z.B. mit for(...) oder while(...).

von Wilhelm M. (wimalopaan)


Lesenswert?

Georg M. schrieb:
> Kann man dieses Beispiel irgendwie ohne if() umsetzen?
> (ist nicht sehr wichtig, nur eine theoretische Frage)

LUT

von Ein Kommentar (Gast)


Lesenswert?

Ein extremes Beispiel findet sich in den Quelltexten des Apple 2 
Betriebssystems.

In dem Assemblercode finden sich abstruse and/or/xor Verknüpfungen, bei 
denen vollkommen undurchschaubare Ergebnisse übrig bleiben. Und auf 
dieses Kuddelmuddel werden dann weiter Tests gemacht - bei denen niemand 
mehr durchblickt.

Lieber vollkommen undurchschaubare Verknüpfungen als ein Sprungbefehl zu 
viel.

Der praktische Nutzen? BS und Anwendungsprogramm passen in 64 Kilobyte.

von dfIas (Gast)


Lesenswert?

Georg M. schrieb:
> Kann man dieses Beispiel irgendwie ohne if() umsetzen?
> (ist nicht sehr wichtig, nur eine theoretische Frage)
1
// Eingangsbits definieren (dabei auf Endianity achten!):
2
typedef struct
3
{
4
  uint8_t TasterGruen:1,
5
          TasterRot:1,
6
          TasterBlau:1,
7
          :5;            // unbenutze Bits
8
} tstTaster;
9
// Ausgangsbits definieren:
10
typedef struct
11
{
12
  uint8_t LEDGruen:1,
13
          :5,            // unbenutze Bits
14
          LEDRot:1,
15
          LEDGelb:1;
16
} tstLampen;
17
// Danach einfach zuweisen, den Rest erledigt der Compiler:
18
((tstLampen*) &PORT_OUT)->LEDRot = ((tstTaster*) &PORT_IN)->TasterRot;
Man kann das auch noch eleganter handhaben, indem man die Port-Pointer 
vorher festlegt, z. B.:
1
tstTaster *pTaster = (tstTaster*) &PORT_IN;
2
tstLampen *pLampen = (tstLampen*) &PORT_OUT;
3
// ...
4
pLampen->LEDRot = pTaster->TasterRot;
Ein "volatile" für den Eingangsport sollte für alle Fälle (wiederholter 
Zugriff auf die Ports) auch berücksichtigt werden.

von Docureader (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Da es ja um AVR zu gehen scheint, könnte man auch vermuten, dass es sich
> dabei um die moderneren AVRs haben, bei denen man gar kein RMW braucht,
> sondern das über die CLR / SET-Register kürzer und atomar machen kann.

Wenn nur ein toggle/xor gewünscht ist, könnte man das selbst bei älteren 
AVR (z.B. ATmega644) sehr effizient machen: Bei denen kann man durch 
Schreiben des PINx Registers die 1-bits im PORTx Register toggeln.
1
PINB = (1<<PB1);
2
//    ldi r18, 2
3
//    out PINB, r18
4
5
// Equivalent to:
6
// PORTB ^= (1<<PB1)
7
//    in  r18, PORTB
8
//    ori r18, 2       ; sbr r18, 1
9
//    out PORTB, r18

Als kleine Spezialität wird sbi nicht als RMW des Registers 
ausgeführt, sondern ist ein echter Bit-Befehl und führt direkt zu 
bit-xor im PORTx Register. Das ist vielleicht nicht jedem auf Anhieb 
offensichtlich...
1
PINB |= (1<<PB1);
2
//    sbi PINB, 1
3
4
// Equivalent to:
5
// PORTB ^= (1<<PB1)
6
//    in  r18, PORTB
7
//    ori r18, 2       ; sbr r18, 1
8
//    out PORTB, r18
9
10
// NOT equivalent to:
11
// PORTB ^= PINB | (1<<PB1)
12
//    in  r18, PINB
13
//    ori r18, 2       ; sbr r18, 1
14
//    in  r19, PORTB
15
//    or  r19, r18
16
//    out PORTB, r19

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
Noch kein Account? Hier anmelden.