Forum: Mikrocontroller und Digitale Elektronik PIN abfragen und LEDs zum leuchten bringen


von Alexander G. (grossmann200)


Lesenswert?

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);
}
}
}

von Falk (Gast)


Lesenswert?

@ 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

von Frank N. (betafrank)


Lesenswert?

> 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....

von Alexander G. (grossmann200)


Lesenswert?

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.

von Falk (Gast)


Lesenswert?

@ 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

von Alexander G. (grossmann200)


Lesenswert?

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 :-)

von Alexander G. (grossmann200)


Lesenswert?

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