Hallo zusammen, zunächst mal möchte ich mich bei allen Beitragsschreibern bedanken durch die ich die Grundlagen, der Mikrokontrolliererei lernen konnte. Bisher fand ich hier auf alle meine Fragen gute Antworten! Nun muss ich aber selbst etwas posten, weil mir das Verhalten meines Programms große Fragen aufwirft. Ich möchte den Zustand eines Schalters an PD0 auslesen. Port D ist auf Eingang geschaltet und ich habe die internen Pull-Up-Widerstände aktiviert. An allen Eingängen hängen Taster. Es passt auch alles. Ich hab's nachgemessen und an Port D liegt echt überall Vcc an, wenn kein Schalter gedrückt ist. Wenn ein Taster gedrückt wird, wird der entsprechende Pin auf GND gezogen - wie ich es wollte. Nun möchte ich zunächst ohne Entprellen oder sonstiges eine Aktion ausführen, wenn ein Schalter gedrückt wurde - einfach zu Lernzwecken. Dazu habe ich in meinem C-Programm quasi in einer Endlosschleife eine if-Abfrage konstruiert, die so aussieht: if (PIND == ~(1<<PD0)){ // restlicher Code - irrelevant für diese Zwecke } Das Argument der if-Abfrage gibt aber nie true. Eigentlich sollte es ja true sein, wenn der Taster an PD0 gedrückt wurde, oder? 1<<PD0 ergibt ja in Binärschreibweise sowas wie 0b00000001. ~(1<<PD0) wäre dann entsprechend 0b11111110, also das, was an PIND anliegen sollte, wenn der Taster an PD0 gedrückt ist. Das funktioniert aber nicht. Wenn ich die if-Abfrage aber folgendermaßen formuliere, geht es: if (PIND == 0xFE){ // restlicher Code - irrelevant für diese Zwecke } 0xFE ist ja das gleiche wie ~(1<<PD0), nur in hexadezimaler Schreibweise. Wieso geht jetzt die Variante mit hexadezimaler Schreibweise und die mit Binärschreibweise nicht? Interessanterweise funktioniert die if-Abfrage übrigens, wenn ich sowas mache wie: if (PIND == (1<<PD0)){ // restlicher Code - irrelevant für diese Zwecke } Die gibt mir true, wenn alle Schalter bis auf den an PD0 gedrückt ist. Liegt es also am ~-Operator? Vielen Dank schonmal im Voraus für sachdienliche Hinweise, die zur Ergreifung des Übeltäters führen!
Du solltest nicht das gesamte Byte des Porteingangs vergleichen, dich interessiert ja jeweils nur 1 Bit! Mit einem bitweisen AND kannst du das interessante Bit isolieren und so unabhängig voneinander prüfen. Das sieht dann so aus: if ((PIND & (1<<PD3)) == 0) { // Taster an PD3 wurde gedrückt ... }
Steffen S. schrieb: > if (PIND == ~(1<<PD0)){ > // restlicher Code - irrelevant für diese Zwecke > } > Liegt es also am ~-Operator? ja so ist es, überlegt doch mal genau was nach dem compiler rechts neben dem == steht. Du willst nur ein Bit von den Port nutzen und das machen alles andere mit einer und (&) verknüpfung - warum du nicht?
Ach, und ~(1<<PD0) ist natürlich äquivalent zu 0xFE. Bist du dir sicher, dass du richtig getestet hast? Vielleicht ist dein Compiler etwas kaputt? Optimierung an?
greg schrieb: > Ach, und ~(1<<PD0) ist natürlich äquivalent zu 0xFE. Nö... das ist höchstwarscheinlich equivalent zu 0xFFFE und damit ungleich von 0x00FE welches der Port wohl anehmen wird nachdem der (unsigned) Port auf int und die (signed) invertierte Variable erweitert worden sind.
greg schrieb: > Du solltest nicht das gesamte Byte des Porteingangs vergleichen, dich > interessiert ja jeweils nur 1 Bit! Mit einem bitweisen AND kannst du das > interessante Bit isolieren und so unabhängig voneinander prüfen. Das > sieht dann so aus: > > if ((PIND & (1<<PD3)) == 0) { > // Taster an PD3 wurde gedrückt > ... > } Das stimmt natürlich. Ich dachte, das hätte ich probiert, aber scheinbar wohl doch nicht. Komme heute abend wieder zum Testen. Vielen Dank einstweilen!
Steffen S. schrieb: Und um die eigentliche Frage zu beantworten: > 1<<PD0 ergibt ja in Binärschreibweise sowas wie 0b00000001. richtig > ~(1<<PD0) wäre dann entsprechend 0b11111110, falsch Du vergisst Datentypen und das in C die Grundeinheit ein int ist. ~(1<<PD0) ist kein 8 Bit Wert, sondern ein 16 Bit Wert. Nämlich 0xFFFE Und dein Port Eingang wird sich schwer tun, diese Wert jemals annehmen zu können. > Wenn ich die if-Abfrage aber folgendermaßen formuliere, geht es: > > if (PIND == 0xFE){ Auch klar. Denn 0xFE ist nicht dasselbe wie 0xFFFE > 0xFE ist ja das gleiche wie ~(1<<PD0), nur in hexadezimaler > Schreibweise. Leider eben nicht. Die kleinste Einheit, in der in C gerechnet wird, ist immer int (auf dem AVR: 16 Bit). Nur dann wenn der Compiler beweisen kann, dass er bei Verzicht auf die oberen 8 Bit auf das gleiche Ergebnis kommt, kann er die Operation als reine Byteoperation formulieren. Aber ~0x01 ist NICHT 0xFE sondern 0xFFFE. Und da machen jetzt die oberen 8 Bit den Unterschied. > Liegt es also am ~-Operator? Wie schon gesagt: Eingänge fragt man immer so ab, dass man sich das interessante Bit freimaskiert und das dann abfragt und nicht indem man Annahmen trifft, wie wohl die restlichen Bits am Port sein mögen.
Hi, natürlich sind die Hinweise " mach's mit & " richtig. Allerdings könnte man auf den ersten Blick denken, dass das if (PIND == ~(1<<PD0)){ // restlicher Code - irrelevant für diese Zwecke } Konstrukt auch gehen müsste. 1<<PD0 = 0b00000001 ~(1<<PD0) = 0b11111110 und wenn ich nun an Port D die erste Taste drücke, dann sollte doch dort 0b11111110 anliegen. Damit sollte 0b11111110 == 0b11111110 sein, und die Bedingung erfüllt sein. Der Compiler wird Dir aber aus ~(1<<PD0) nicht 0b11111110 machen, sondern er wird 0b1111111111111110 - also 16 Bit - machen. Und schon klappt der Vergleich nicht mehr. Man könnte nun mal folgendes probieren. if (PIND == (char)(~(1<<PD0))){ // restlicher Code - irrelevant für diese Zwecke } Aber wie gesagt - mach's besser mit if (PIND & ~(1<<PD0)){
Ok - Karl heinz Buchegger war schneller. ( Ich muss mal lernen schneller zu tuppen, damit ich auch mal gewinne ;-) )
... tippen, nicht tuppen. Kommt vom schnellen tippen :-)
NurEinGast schrieb: > Ok - Karl heinz Buchegger war schneller. No. Läubi wars Ich schreib zu viel :-)
Ah stimmt. int vs. char kann eine ganz schön fiese Falle sein. :) Wie auch immer, mach es per Maskierung, dann gibt es solche Probleme gar nicht erst.
Läubi .. schrieb: > greg schrieb: >> Ach, und ~(1<<PD0) ist natürlich äquivalent zu 0xFE. > Nö... das ist höchstwarscheinlich equivalent zu 0xFFFE und damit > ungleich von 0x00FE welches der Port wohl anehmen wird nachdem der > (unsigned) Port auf int und die (signed) invertierte Variable erweitert > worden sind. Sowas hab ich mir auch schon gedacht. Deshalb habe ich auch folgendes Konstrukt getestet: PIND == ~(uint8_t)(1<<PD0) Das ging aber auch nicht. Ich dachte, wenn ich 1<<PD0, was evtl. ein int ist, auf uint8_t caste und dann bitweise negiere, bekomme ich das gewünschte Ergebnis. Aber verstehe ich das richtig, dass der Ausdruck 1<<PD0 16bit lang ist?
Steffen S. schrieb: > Sowas hab ich mir auch schon gedacht. Deshalb habe ich auch folgendes > Konstrukt getestet: > > PIND == ~(uint8_t)(1<<PD0) Hier hast du schlecht getestet. Denn selbst wenn (uint8_t)(1<<PD0) ein 8 Bit Wert ist, der ~ macht dir daraus wieder 16 Bit. Reihenfolge der Operationen!
> PIND == ~(uint8_t)(1<<PD0)
PIND == (uint8_t)(~(1<<PDO))
Vielen Dank für die ausführliche Antwort, Karl-Heinz! Daumen hoch Wieder was gelernt. Auch allen anderen Helfern vielen Dank für die schnellen Antworten! Oh, ich sehe gerade, dass ich demnächst auch lernen sollte, C-Code in die entsprechenden Tags zu packen. Werde versuchen, daran zu denken!
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.