www.mikrocontroller.net

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


Autor: Alexander G. (grossmann200)
Datum:

Bewertung
0 lesenswert
nicht 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);
}
}
}

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Frank N. (betafrank)
Datum:

Bewertung
0 lesenswert
nicht 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....

Autor: Alexander G. (grossmann200)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Alexander G. (grossmann200)
Datum:

Bewertung
0 lesenswert
nicht 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 :-)

Autor: Alexander G. (grossmann200)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.