Forum: Compiler & IDEs Anfänger Verständnisfrage zu PORT, PIN und DDR


von Alexander G. (grossmann200)


Lesenswert?

Hallo,

arbeite mich gerade in die Welt der Mikrokontroller ein. Obwohl ich das 
Tutorial http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial zu 
rate gezogen habe, scheine ich noch etwas nicht verstanden zu haben.

Folgendes Verhalten will ich bei meinem Atmega8 programmieren:

Wenn auf PB0 +5V liegen, dann soll auf PB1 +5V ausgegeben werden.
Das entspricht doch der Aussage:

PBO ist als Eingang festzulegen und wenn dieser gleich 1 ist, dann soll 
der Ausgang PB1 ebenfalls zu 1 werden.

Ich dachte mir, dass durch folgenden gcc-code zu erreichen:
1
#include <avr/io.h>
2
3
int main (void) {
4
5
 DDRB &= ~(1<<PB0); //PBO auf 0 -> als Eingang
6
 DDRB |=  (1<<PB1); //PB1 auf 1 -> als Ausgang
7
8
 //PB0 und PB1 sicherheitshalber auf 0 zurücksetzen
9
 PORTB &= ~(1<<PB0);
10
 PORTB &= ~(1<<PB1);
11
12
if (PINB & (1<<PB0)) { //Wenn PB1 auf 1 steht, dann ist auch die Bedingung 1 (wahr)
13
  PORTB |= (1<<PB1); //Ausgang PB1 auf 1 setzen
14
  }
15
}

Jedoch liefert das Progamm nicht das gewünschte Ergebnis. Eine an PB1 
anliegenden Diode leuchtet SOFORT auch wenn das PB0-Beinchen mit nichts 
verbunden ist (messe ich daran die Spannung, so zeigt mir mein Voltmeter 
1,62V).

von Rolf Magnus (Gast)


Lesenswert?

Alexander G. schrieb:

> Wenn auf PB0 +5V liegen, dann soll auf PB1 +5V ausgegeben werden.
> Das entspricht doch der Aussage:
>
> PBO ist als Eingang festzulegen und wenn dieser gleich 1 ist, dann soll
> der Ausgang PB1 ebenfalls zu 1 werden.

Richtig.

> Ich dachte mir, dass durch folgenden gcc-code zu erreichen:
>
> #include <avr/io.h>
>
> int main (void) {
>
>  DDRB &= ~(1<<PB0); //PBO auf 0 -> als Eingang
>  DDRB |=  (1<<PB1); //PB1 auf 1 -> als Ausgang
>
>  //PB0 und PB1 sicherheitshalber auf 0 zurücksetzen
>  PORTB &= ~(1<<PB0);
>  PORTB &= ~(1<<PB1);
>
> if (PINB & (1<<PB0)) { //Wenn PB1 auf 1 steht, dann ist auch die Bedingung 1 
(wahr)
>   PORTB |= (1<<PB1); //Ausgang PB1 auf 1 setzen
>   }
> }
>
>
> Jedoch liefert das Progamm nicht das gewünschte Ergebnis. Eine an PB1
> anliegenden Diode leuchtet SOFORT auch wenn das PB0-Beinchen mit nichts
> verbunden ist (messe ich daran die Spannung, so zeigt mir
> mein Voltmeter 1,62V).

Wenn wirklich nichts am Eingang anliegt, nimmt er irgendeinen 
undefinierten Pegel an ("floating"), der vielleicht als high-Pegel oder 
vielleicht als low-Pegel erkannt wird. Also solltest du bei Eingängen 
immer definierte Pegel anlegen und sie nicht einfach in der Luft 
hängen lassen.
Ansonsten prüft dein Programm nach der Initialisierung ein einziges Mal, 
ob der Eingang 1 ist und schaltet dann entsprechend den Ausgang. Danach 
ist es "zu Ende".

von Schmitty (Gast)


Lesenswert?

Hallo Alexander,

dein Programm ist schon zu 80% richtig, hier eine korregierte Version:
1
#include <avr/io.h>
2
3
int main (void) {
4
5
 DDRB &= ~(1<<PB0); //PBO auf 0 -> als Eingang
6
 DDRB |=  (1<<PB1); //PB1 auf 1 -> als Ausgang
7
8
 //PB0 und PB1 sicherheitshalber auf 0 zurücksetzen
9
 PORTB &= ~(1<<PB0);
10
 PORTB &= ~(1<<PB1);
11
12
  while(1) {
13
    if (PINB & (1<<PB0)) { 
14
      PORTB |= (1<<PB1); //Ausgang PB1 auf 1 setzen
15
    }
16
    else {
17
      PORTB &= ~(1<<PB1); //Sonst: PortB aus!
18
    }
19
  }
20
21
}
Dein Programm endet direkt nach dem Vergleich und startet danach von 
ganz vorne. In meiner Version wird der Vergleich in einer Endlosschleife 
ausgeführt.
Dass Du an PB1 1.62V misst, kann verschiedene Ursachen haben:

*Wichtig:* Wenn der PB0 in der Luft hängt, kann das auch zufällig als 
"high" interpretiert werden. Suche hierzu mal nach den Stichworten 
"PullUp" und "PullDown"!

Was für einen Controller verwendest Du überhaupt? Manche Controller 
haben standardmäßig andere Funktionen für ihre Pins aktiviert, z.B. die 
JTAG-Funktion. Die muss möglicherweise abgestellt werden.

Zusatzfrage: Betreibst Du die LED mit einem passenden Vorwiderstand? ;)

von Alexander G. (grossmann200)


Lesenswert?

Hallo,
tolle Hinweise. Danke!
Auf http://www.rn-wissen.de/index.php/Pullup_Pulldown_Widerstand habe 
ich Infos zum Tipp mit dem Pullup/Pulldown-Widerständen gefunden.

==> Habe jetzt zwischen PB0 und GND einen 10kOhm Widerstand. Dadurch 
messe ich nun auch eine sauberen Pegel von 0V als Ausgangszustand.

Habe mich dann gewundert, warum bei folgendem Ablauf die LED nicht 
leuchten wollte:

- Controller anschalten, indem Spannung angelegt wird
- PB0 war noch offen und nach dem Einschalten mit +5V verbinden
-> Nix passierte. KLAR, denn bis ich PB0 auf +5V gelegt hatte, war der 
Controller schon längst am Programmende. ==> Deswegen die Endlosschleife 
wie es die Beiträge von Schmitty und Rolf auch empfehlen.

Um dies Gegenzuprüfen, nochmals mit altem Programm ohne Schleife:
- Controller aus
- PB0 auf +5V
- Controller an
-> Die LED an PB1 leuchtet wie erwartet.

Anm.: Ich spiele hier mit einem Atmega8 und habe die LED an einem 
Vorwiderstand (wie irgendwie auf www.mikrocontroller.net gelesen :-) )

Danke für die Kommentare -> Haben zum Ziel geführt. Danke!

von Martin e. C. (eduardo)


Lesenswert?

Du kannst die Pullup von Controller einschalten, dann brauchst du keine 
10kOhm Widerstand.

z.B
1
/* Pins auf Eingang */
2
  DDRB &= ~((1 << DDB0) | (1 << DDB1) | (1 << DDB2));
3
4
/* Interne Pull-Up Widerstände einschalten */
5
  PORTB |= ((1<<PB0)|(1<<PB1)|(1<<PB2));

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.