Forum: Mikrocontroller und Digitale Elektronik Wo ist der Unterschied ?


von Aubacke (Gast)


Lesenswert?

Hallo zusammen,
ich programmiere auf einem dsPIC mit dem C30 Compiler und hier sind 
sowohl die Bits der SFRs als auch die Ports im Header File als Bitfeld 
maskiert, sodass man direkt auf ein einzelnes Bit zugreifen kann.

Nun möchte ich eben ein solches Bit während der Init auf einen 
bestimmten Wert setzen, nämlich dem invertierten (oder gegenteiligen) 
Wert dessen was an einem bestimmten Portpin anliegt --> also in etwa:

if (PORTAbits.RA15 == 1)
{
   INTCON2bits.INT4EP = 0;
}
else
{
   INTCON2bits.INT4EP = 1;
}

Um dies kürzer schreiben zu können, gibt es drei Varianten, von denen 
ich gerne wüsste wo der Unterschied liegt, alle funktionieren nämlich 
einwndfrei, dass Assembly ist allerdings unterschiedlich:

a) INTCON2bits.INT4EP = PORTAbits.RA15 ? 0 : 1;
b) INTCON2bits.INT4EP = !PORTAbits.RA15;
c) INTCON2bits.INT4EP = ~PORTAbits.RA15;

Sprich ist der Bitoperator (c) und logische Operator (b) bei einzelnen 
Bits gleichzusetzten ? Was ist der bessere Stil ? Was würdet ihr 
verwenden ?

Danke und Grüße...

von Oliver (Gast)


Lesenswert?

>Was würdet ihr verwenden ?

Möglichkeit #4:
1
INTCON2bits.INT4EP ^= 1;

Zu deiner Frage:

Der logische Negierungsoperator ! funktioniert zwar bei deiner 
Anwendung, das ist aber eher Zufall. Vom der Semantik her macht der 
eigeltich was anderes, und passt nicht zu der Aufgabenstellung.

Möglichkeit 1 und 3 sind Geschmachssache. Wenn der Compiler "weiß", das 
ein Bit nur die Werte 0 oder 1 haben kann, könnte da der selbe Code 
erzeugt werden, aber vermutlich weiß er das nicht, und dann ist eben 
eine Prüfung auf 0 bzw 1 etwas anderes, als ein binäres nicht.

Oliver

von Stephan Storm (Gast)


Lesenswert?

Hallo,

zunächst Mal zu deinem Vorschlag:

if (PORTAbits.RA15 == 1)
{
   INTCON2bits.INT4EP = 0;
}
else
{
   INTCON2bits.INT4EP = 1;
}

das ist im wesentlichen das gleiche wie

a) INTCON2bits.INT4EP = PORTAbits.RA15 ? 0 : 1;

da das ? eine if Anweisung darstellt. Das ist ganz normaler C-Syntax und 
du findest im Internet zahlreiche Erklärungen.
Beispiel:
if(bedingung)
{
 return 1;
}
else
{
 return 0;
}

ist in Kurzschreibweise: bedingung ? 0 : 1;
wie gesagt, eine C-Referenz hilft dir hier weiter.

b) INTCON2bits.INT4EP = !PORTAbits.RA15;
hier passiert folgendes: PORTAbits.RA15 ist der Zustand am 15. Pin des 
PortA. Dieser wird durch ! invertiert. Das ganze wird dann INT4EP 
zugewiesen. Bei ! handelt es sich um den logischen NICHT-Operator. D.h. 
wenn du eine Variable (z.B. int var) hast und diese invertierst (also 
!var). Dann bekommst du den Wert 1 wenn die Variable 0 war und 0 wenn 
die Variable nicht 0 war. Es handelt sich also nicht um ein Bitweises 
NICHT.

c) INTCON2bits.INT4EP = ~PORTAbits.RA15;
hier hast du nun ~. Das ist der Operator für Bitweises NICHT. D.h. bei 
einer Variable (int var=15) bewirkt ~var den Rückgabewert 4294967280. 
Zur Erläuterung: ein Integer ist 32-Bit breit. 15 entspricht also 
000000000000000000001111b. Nun wird jedes Bit einzeln invertiert:
111111111111111111110000b. Dieser Wert entspricht dezimal 4294967280.

b) und c) unterscheiden sich in deinem Fall natürlich nicht, da du 
Bitmasken verwendest.

Am sinnvollsten ist die Verwendung von b oder c, da du hier lediglich 2 
Anweisungen ausführts nämlich Invertierung und Zuweisung. Du braucht 
also genau zwei Takte um die Zeile abzuarbeiten. Bei a handelt es sich 
um einen Bedingten Sprung der je nachdem was ausgeführt wird 2-3 Takte 
in Anspruch nimmt. Dann muss noch der Rückgabewert in den Stack gelegt 
werden und zur nächsten Anweisung gesprungen werden. Das sind dann 
Pauschal 5-6 Takte. Wenn es dir auf Geschwindigkeit nicht ankommt ist es 
egal welche Variante du nimmst. Trotzdem sollte man natürlich so 
optimiert wie möglich Programmieren. b und c finde ich immer noch sehr 
gut lesbar und deswegen solltest du b oder c verwenden. Welches von 
beiden kannst du würfeln.

Ich hoffe es war Verständlich
Stephan

von tuppes (Gast)


Lesenswert?

> Möglichkeit #4:
> INTCON2bits.INT4EP ^= 1;

Passt leider nicht, denn INT4EP soll nicht invertiert werden, sondern 
soll mit dem Inversen von RA15 gefüllt werden, das ist was anderes.

Kann sein, dass das mit XOR irgendwie erledigt werden kann, aber warum 
um die Ecke denken? Möglichkeit c), das binäre Inverse, ist genau das, 
was der Frager will.

Hat auch den Vorteil, dass es genauso mit Bitmasken funktionieren würde, 
die breiter als 1 Bit sind.

a) und b) ersetzen die Bit-Operation durch eine boolsche. Auch wenn es 
hier dasselbe Ergebnis liefert: Die Daten werden uminterpretiert, und 
grundsätzlich kann man dabei (z.B. durch falsche Annahmen) Fehler 
machen. Darum würde ich das nicht empfehlen. Besser, weil klarer, ist, 
immer die Operationen zu verwenden, die zur Natur der Daten passen.

von Stephan Storm (Gast)


Lesenswert?

> a) und b) ersetzen die Bit-Operation durch eine boolsche. Auch wenn es
> hier dasselbe Ergebnis liefert: Die Daten werden uminterpretiert, und
> grundsätzlich kann man dabei (z.B. durch falsche Annahmen) Fehler
> machen. Darum würde ich das nicht empfehlen. Besser, weil klarer, ist,
> immer die Operationen zu verwenden, die zur Natur der Daten passen.

Dem Stimme ich natürlich zu. Das folgt dann dem Motto: Bierflasche mit 
einem öffner aufmachen führt zwar zum gleichen Ergebnis wie mit dem 
Feuerzeug, fliegt einem das Feuerzeug um die Ohren hat man aber ein 
Problem.

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.