Hallo, da jeder mal klein angefangen haben muss, traue ich mich nun doch mal hier zu fragen. Ich möchte an meinem ATmega8 über PD6 zwei LED im Wechsel an- bzw. ausschalten. Die LEDs sind mit PB0 und PB1 verbunden. Ziel der Übung, ich will verstehen, wie man Mikrocontroller programmiert. Ich habe vom meinem Programm erwartet, dass bereits beim Einschalten in der Endlosschleife die zweite Bedingung ausgeführt wird und die LED an PB1 leuchtet ... macht sie jedoch nicht (heul). Wenn ich jedoch PD6 mit dem Pluspol verbinde, scheint die erste Bedingung zu funktionieren, denn die LED an PB0 leuchtet (yipee) ... allerdings leuchtet auch die LED an PB1, was sie doch eigentlich nicht sollte (heul). Was habe ich falsch verstanden??? Vorab: allen, die mir helfen das Geheimnis der Mikrocontroller zu verstehen, schon jetzt: HERZLICHEN DANK!!! Hier mein Kunststück: #include <avr/io.h> void main(void) { DDRB = DDRB | (1 << 0); // Nulltes Bit Port B erhält Wert 1 (=Ausgang) DDRB = DDRB | (1 << 1); // Zusätzlich erstes Bit als Ausgang DDRD = DDRD | (0 << 6); //Sechster Pin von Port D als Eingang; PORTD = PORTD & (0<<6); //internen Pull-Up an PD6 de-aktivieren PIND = PIND | (0<<6); //Zunächst mal PinD6 auf low (=0) setzen. while (1) // Endlosschleife { /// ERSTE BEDINGUNG /// if (PIND & (1 << 6)) //Wahr, Wenn vom PortD, dass Pin6 auf 1 (=high) { PORTB = PORTB | (1 << 0); //Nulltes Bit Portes B wird Wert 1 -> LED an PORTB = PORTB | (0 << 1); //Bit 1 Port B auf 0 -> LED aus } /// ZWEITE BEDINGUNG /// if (PIND & (0 << 6)) //Wahr, wenn vom PortD, dass Pin6 auf 0 (=low) { PORTB = PORTB | (0 << 0); PORTB = PORTB | (1 << 1); } } }
@ Alexander Grossmann >Was habe ich falsch verstanden??? Einige Detail der C Programmierung. >void main(void) >{ >DDRB = DDRB | (1 << 0); // Nulltes Bit Port B erhält Wert 1 (=Ausgang) >DDRB = DDRB | (1 << 1); // Zusätzlich erstes Bit als Ausgang >DDRD = DDRD | (0 << 6); //Sechster Pin von Port D als Eingang; Das ist Quark. Wenn du eine Null um 6 Stellen nach links schiebst, ist es immer ncoh null. Besser so. >DDRD = DDRD | (1 << 6); Ausserdem solltest du nomal das Datenblatt lesen. Eine 1 im DDRx schaltet eine Pin auf AUSGANG! Nach dem Reset sind ale Pins schon Eingang. Was du ggf. willst/brauchst sind interen Pull-ups. Dazu muss im DDRx eine 0 stehen (Eingang) und im PORTx eine 1. Also so DDRD &= ~(1<< 6); // Pin auf Eingang (nur als Beispiel, ist schon nach dem Reset so) PORTD |= (1 << 6); //Sechster Pin von Port D als Eingang, Pull-Up aktiv; >PORTD = PORTD & (0<<6); //internen Pull-Up an PD6 de-aktivieren >PIND = PIND | (0<<6); //Zunächst mal PinD6 auf low (=0) setzen. Dito. >while (1) // Endlosschleife >{ >/// ERSTE BEDINGUNG /// >if (PIND & (1 << 6)) //Wahr, Wenn vom PortD, dass Pin6 auf 1 (=high) >{ >PORTB = PORTB | (1 << 0); //Nulltes Bit Portes B wird Wert 1 -> LED an >PORTB = PORTB | (0 << 1); //Bit 1 Port B auf 0 -> LED aus Dito. >} >/// ZWEITE BEDINGUNG /// >if (PIND & (0 << 6)) //Wahr, wenn vom PortD, dass Pin6 auf 0 (=low) >{ >PORTB = PORTB | (0 << 0); Dito. >PORTB = PORTB | (1 << 1); >} >} >} Schau dir nochmal das Datenblatt und das AVR-GCC Tutorial an. http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial MfG Falk
> DDRD = DDRD | (0 << 6); //Sechster Pin von Port D als Eingang; > PORTD = PORTD & (0<<6); //internen Pull-Up an PD6 de-aktivieren > PIND = PIND | (0<<6); //Zunächst mal PinD6 auf low (=0) setzen. kann raus da (0<<6) dasselbe wie eine um 6 Stellen nach links geschobene 0 ist, also 0000000 und letztlich 0 bleibt. Später im Text: >if (PIND & (0 << 6)) ist deshalb auch immer 0, denn irgendwas&0 ist 0! Habs daher mal durch else ersetzt: > if (PIND & (1 << 6)) //Wahr, Wenn vom PortD, dass Pin6 auf 1 (=high) > { > PORTB = PORTB | (1 << 0); //Nulltes Bit Portes B wird Wert 1 -> LED an > PORTB = PORTB | (0 << 1); //Bit 1 Port B auf 0 -> LED aus > } > else > { > PORTB = PORTB | (0 << 0); > PORTB = PORTB | (1 << 1); > } Die Eingänge vom AVR sind sehr hochohmig. Wenn Du nicht mit internem Pullup-Widerstand (Taster schaltet gegen Masse) arbeiten willst, brauchst Du einen Pulldown-Widerstand (z.B. 4,7kohm) und der Taster schaltet gegen V+. Wobei > PORTB = PORTB | (0 << 1); //Bit 1 Port B auf 0 -> LED aus und > PORTB = PORTB | (0 << 0); durch PORTB = PORTB & ~(1<<1); und PORTB = PORTB & ~(1 << 0); ersetzt werden müssen. Mit einer Oder-Verknüpfung kannst Du ja nicht löschen....
Hallo Falk, Mensch, das war ja eine schnelle Antwort - Danke! Die Ports B möchte ich ja auch als Ausgang, da an PB0 und PB1 die LEDs hängen. Ich dachte dies mit DDRB = DDRB | (1 << 0); DDRB = DDRB | (1 << 1); auch zu tun. Setzte ich hiermit den die beiden Pins nicht auf 1 (=Ausgang). Den PD6 will ich als Eingang. Dann muss ich doch den Pin auf 0 setzen? Ich hoffte dies mit "DDRD = DDRD | (0 << 6);" zu erreichen (ist halt doppelt, da nach dem Reset schon als Eingang festgelegt). Soweit stimmen wir doch überein. Ich verstehe jedoch nicht, auch nach dem Lesen von Tutorial und Datenblatt, warum "DDRD &= ~(1<< 6);" und "DDRD = DDRD | (0 << 6);" nicht zum selben Ergebnis führen: Meine Verständnis zu DDRD = DDRD | (0 << 6); Bit 7 6 5 4 3 2 1 0 Ur-Zustand 0 0 0 0 0 0 0 0 0 << 6 0 0 0 0 0 0 0 0 Oder verknpft. mit Ur-Z. 0 0 0 0 0 0 0 0 ->PD6 ist 0 = Eingang Meine Verständnis zu DDRD &= ~(1<< 6); Bit 7 6 5 4 3 2 1 0 Ur-Zustand 0 0 0 0 0 0 0 0 1 << 6 0 1 0 0 0 0 0 0 Negieren 1 0 1 1 1 1 1 1 Und verknpft. mit Ur-Z. 0 0 0 0 0 0 0 0 ->PD6 ist 0 = Eingang Ist doch identisch? Ich glaube bei dieser Bitoperation jedoch was falsch zu verstehen.
@ Alexander Grossmann >Mensch, das war ja eine schnelle Antwort - Danke! Speedy Gonzales ist ne lahme Schnecke! ;-) >Die Ports B möchte ich ja auch als Ausgang, da an PB0 und PB1 die LEDs >hängen. Ich dachte dies mit >DDRB = DDRB | (1 << 0); >DDRB = DDRB | (1 << 1); >auch zu tun. Setzte ich hiermit den die beiden Pins nicht auf 1 >(=Ausgang). Deine Wortwahl ist ungünstig. Du stellst die beiden Pins PB0 und PB1 auf Ausgang. >Den PD6 will ich als Eingang. Dann muss ich doch den Pin auf 0 setzen? NEIN! Du muss den Pin auf Eingang schalten. Deine Wortwahl ist auch hier ungünstig bis falsch. >Ich hoffte dies mit "DDRD = DDRD | (0 << 6);" zu erreichen (ist halt >doppelt, da nach dem Reset schon als Eingang festgelegt). Soweit stimmen Nein. Siehe mein erstes Posting. >wir doch überein. Ich verstehe jedoch nicht, auch nach dem Lesen von >Tutorial und Datenblatt, warum "DDRD &= ~(1<< 6);" und "DDRD = DDRD | (0 ><< 6);" nicht zum selben Ergebnis führen: Weil du eine Null schieben kannst wie du willst, es bleibt null. Wenn du eine 1 um 6 (binäre) Stellen nach links schiebst passiert das 1 << 6 = 0x40 wenn du das nun invertierst (mit dem ~ Operator) kommt raus ~0x40 = 0xBF = 0b1011111 Also alle Bits sind 1 ausser Bit #6. Wenn du das nun mit einem beliebigen Wert UND verknüpfst, wird Bit #6 definiv gelöscht (auf Null gesetzt). >Ist doch identisch? Ich glaube bei dieser Bitoperation jedoch was falsch >zu verstehen. So ist es. Nochmal anschauen. MfG Falk
Hallo Frank, hallo Falk, Frank, ich habe deine Änderungen übernommen und jetzt funktioniert es wie gewünscht. SUPER!!! Gestehe, jedoch noch nicht 100%ig verstanden zu haben, warum dies nun so funktioniert und welche Denkfehler ich hatte. Ich geh' jetzt mal ne' Runde raus, bekomme wieder einen klaren Kopf und werde es mir mit Tutorial und Datenblatt nochmals schrittweise zu Gemüte führen. Beste Grüße Der Alexander ... in der Hoffnung irgendwann mal einen cooles Mikrocontoller-Projekt zu verwirklichen :-)
Hab's jetzt endlich gerafft. Wichtig war insbesondere ein klares Verständnis über die Bitoperationen - in meinem Fall, dass man ein Bit nicht durch eine Oder-Verknüpfung mit (0 << 1) o.ä. löscht. Damit ist meine Problem eigentlich gelöst und dieser Thread kann geschlossen werden. Nochmals danke! Grüße
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.