Forum: Mikrocontroller und Digitale Elektronik AVR: Bit-Abfragen und -Zuweisungen an einzelnem Port


von Bernd H. (berndy)


Lesenswert?

Hallo liebes Forum,


ich habe ein Problem für das ich eure Hilfe brauche.

Auf einem ATMEGA16 möchte ich einen einzelnen Port (B) als Ein- UND 
Ausgang verwenden, sprich PIN0 ist Eingang und PIN1 ist Ausgang.
Das geht auch relativ einfach mit dem Befehl "DDRB = 0bXXXXXX01".

Das Problem ist nun, wie kann ich einen einzelnen Eingang ABFRAGEN?
Kann man nur ein ganzes Byte abfragen ( [...]  if(PORTB == 0b00000010){ 
... }  [...] ) oder ist auch ein einzelnes Bit möglich?

Beim Googeln habe ich leider keine Lösung für dieses Problem gefunden.


Vielen Dank schon mal für eure Hilfe!

Berndy

von Falk B. (falk)


Lesenswert?


von Karl H. (kbuchegg)


Lesenswert?

Bernd Hauegg schrieb:

> Das geht auch relativ einfach mit dem Befehl "DDRB = 0bXXXXXX01".
>
> Das Problem ist nun, wie kann ich einen einzelnen Eingang ABFRAGEN?
> Kann man nur ein ganzes Byte abfragen ( [...]  if(PORTB == 0b00000010){
> ... }  [...] ) oder ist auch ein einzelnes Bit möglich?

Zunächst mal willst du nicht den PORTB abfragen, sondern den PINB.

PORTx      die Ausgangsbits
PINx       die Eingangsbits

und das andere, was dir noch fehlt, sind die Möglichkeiten die du hast, 
mittels Bitoperationen das gelesene Byte so zu manipulieren, dass dir am 
Ende nur dieses 1 Bit übrig bleibt, welches dich interessiert.

D.h. du liest nach wie vor den kompletten PINB als 1 Byte ein.
Aber danach bearbeitest du dieses Byte so, dass alle Bits, die dich 
NICHT interessieren, definitiv und ganz sicher auf 0 gesetzt werden. 
Dann bleibt nur dieses eine Bit übrig und der Wert des so manipulierten 
Bytes ist dann entweder 0 (dann ist auch das Bit 0) oder das Byte ist 
nicht 0 (dann ist dieses eine Bit auf 1)

Bitmanipulation


> "DDRB = 0bXXXXXX01".
und mit genau denselben Methoden willst du auch das DDRB bearbeiten. 
Nicht indem du ihm als ganzes einen Wert zuweist, sondern indem du 
gezielt nur das eine Bit 0 auf 1 setzt.
Denn mit einer einfachen Zuweisung veränderst du ALLE 8 Bit. Das kannst 
du nicht verhindern. Aber du kannst den momentanen Wert des Bytes in 
DDRB nehmen, dort gezielt mit einer Oder-Operation das 1 Bit zuätzlich 
setzen und dann das so manipulierte Byte wieder insd DDRB 
zurückschreiben. Der Effekt ist, dass bereits bestehende Bits in DDRB 
(die du so verschämt mit XXXXXX bezeichnet hast) garantiert nicht 
verändert werden. Und genau das willst du haben! Du möchtest dich davon 
befreien, dass du dir merken musst, wie die restlichen XXXXXX Bits 
gerade stehen, wenn du das Bit 0 auf 1 setzen willst. Denn solche Dinge 
sind ansonsten sehr fehleranfällig. Heute weißt du noch, dass du bei

   DDRB = 0b00000001;

die höherwertigen Bits alle auf Eingang gestellt werden und das das auch 
gut so ist. Aber wenn deine Programme größer werden und du an einem Port 
3 LED und 5 Taster hast, dann weißt du nicht mehr so schnell, welche DDR 
Bits jetzt 1 und welche 0 sein müssen.


> Beim Googeln habe ich leider keine Lösung für dieses Problem gefunden.
Fang mit dem >>>AVR-GCC-Tutorial<<< als deine erste Anlaufstelle an. 
Dort finden sich solche Dinge, die dir für den Anfang den Weg 
erleichtern.
1
#include <avr/io.h>
2
3
#define TASTER   PB1
4
#define LED      PB0
5
6
int main()
7
{
8
  DDRB |= ( 1 << LED );       // den Pin mit der Led auf Ausgang
9
                              // setzen, indem im DDRB dafür ein 1 Bit
10
                              // eingetragen wird
11
12
  DDRB &= ~( 1 << TASTER );   // den Pin mit dem Taster auf Eingang setzen
13
                              // indem im DDRB dafür ein 0 Bit eingetragen wird
14
15
  PORTB |= ( 1 << TASTER );   // den Pullupwiderstand einschalten, indem am PORTB
16
                              // das Bit für den Eingang auf 1 gesetzt wird.
17
18
  while( 1 ) {
19
    if( PINB & ( 1 << TASTER ) )     // ist das Bit an dem der Taster hängt
20
                                     // auf 1?
21
      PORTB |= ( 1 << LED );         // Ja: Das Ausgangsbit an dem die LED hängt
22
                                     //     auf 1 setzen
23
    else
24
      PORTB &= ~( 1 << LED );        // Nein: Das Ausgangsbit an dem die LED
25
                                     //     hängt auf 0 setzen
26
  }
27
}

von Sepp (Gast)


Lesenswert?

Vorsicht!

Beim Einlesen PINB verwenden! PORTB steuert nur die Ausgänge! Man kann 
PORTB zurücklesen, bekommt aber nur den Wert der aktuell eingestellten 
Ausgänge wieder!
PINB hingegen liefert den Eingangswert.
Einzelne Bits kann man nicht lesen, nur die ganzen 8 Bit des Ports B.
Wenn Du einzelen Bits brauchst --> Bitmanipulation

z.B. bei Dir:
1
char Bit_Status
2
3
int main(void)
4
{
5
....
6
Bit_Status = ((PINB & (1<<PIN0)) != 0); //Bit_Status hält den Zustand Pin0
7
....
8
}

von Rolf Magnus (Gast)


Lesenswert?

Sepp schrieb:
> Einzelne Bits kann man nicht lesen, nur die ganzen 8 Bit des Ports B.

Man kann z.B. auf Assembler-Ebene zumindest mit den SKIP-Befehlen auch 
einzelne  Bits abfragen, aber scheint hier wohl um C zu gehen. Der 
Compiler nutzt ggf. solche Befehle intern, aber auf C-Ebene schreibt man 
trotzdem immer den Zugriff auf das ganze Byte hin.

von Sepp (Gast)


Lesenswert?

>Man kann z.B. auf Assembler-Ebene zumindest mit den SKIP-Befehlen auch
>einzelne  Bits abfragen, aber scheint hier wohl um C zu gehen.

das ist schon richtig, aber wenn man eine Zuweisung zu einer Variablen 
machen will geht's nicht mehr.

P.S.:

....
if (PINB & (1<<PIN0))
  {
  }
....

wird der Compiler in EINEM Befehl (ala "Skip if bit 0 is set") 
abarbeiten! Auch wenn die Zeile nach mehr gerneriertem (Assembler-)Code 
aussieht.

von Bernd H. (berndy)


Lesenswert?

Hallo,


vielen Dank für eure tollen Antworten! Die Beitrage haben sich wunderbar 
ergänzt.

Besonders gut — und wichtig — waren die theoretischen Grundlagen mit dem 
Artikel von Karl Heinz Buchegger.

Die Abfrage selbst hat mit dem Code von Sepp (Gast) hervorragend 
funktioniert:
1
char Bit_Status
2
int main(void)
3
{
4
  ....
5
  Bit_Status = ((PINB & (1<<PIN0)) != 0); //Bit_Status hält den Zustand Pin0
6
  ....
7
}


Vielen Dank auch an Falk Brunner und Rolf Magnus für ihre Beiträge!


Herzliche Grüße

Bernd Hauegg

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.