Forum: Mikrocontroller und Digitale Elektronik Taster abfrage in C


von Dario (Gast)


Lesenswert?

Hi

Ich habe diesen Code geschrieben:
1
#include <avr/io.h>
2
3
int main(void)
4
{
5
    DDRA = (1 << DDA0) | (1 << DDA1) | (1 << DDA2) | (0 << DDA3) | (0 << DDA4) | (0 << DDA5) | (0 << DDA6) | (0 << DDA7);
6
  
7
    while(1)
8
    {
9
10
11
        if ( PINA & (1 << PINA3) ) {
12
          PORTA = (1 << PA0);
13
        }
14
        
15
        if ( PINA & (0 << PINA3))  {
16
          PORTA = (0 << PA0);
17
        }
18
  
19
20
    }
21
}
Die LED bleibt angeschaltet, wenn ich den Taster drücke.
Wenn ich den Code so abändere:
1
#include <avr/io.h>
2
3
#include <avr/io.h>
4
5
int main(void)
6
{
7
    DDRA = (1 << DDA0) | (1 << DDA1) | (1 << DDA2) | (0 << DDA3) | (0 << DDA4) | (0 << DDA5) | (0 << DDA6) | (0 << DDA7);
8
  
9
    while(1)
10
    {
11
12
13
        if ( PINA & (1 << PINA3) ) {
14
          PORTA = (1 << PA0);
15
        }
16
        
17
        if (!( PINA & (0 << PINA3) )) {
18
          PORTA = (0 << PA0);
19
        }
20
  
21
22
    }
23
}
Funktioniert es. Warum ist das so?

lgd

von Peter II (Gast)


Lesenswert?

Dario schrieb:
> Funktioniert es. Warum ist das so?

weil (0 << PINA3)

zu 99.99% Unsinn ist und keinen sinn ergibt. Denn ist es 0

  if ( PINA & (0 << PINA3))  {

und wenn man eine 0 mit irgendetwas verundet kommt immer 0 raus.

Auch das ist fehlerhaft:

>  PORTA = (0 << PA0);
auch wenn es hier funktioniert. Es macht aber viel mehr als ein Pin zu 
löschen und führt später Problemen.

von Dario (Gast)


Lesenswert?

Der 2. Code muss natürlich:
#include <avr/io.h>

int main(void)
{
    DDRA = (1 << DDA0) | (1 << DDA1) | (1 << DDA2) | (0 << DDA3) | (0 << 
DDA4) | (0 << DDA5) | (0 << DDA6) | (0 << DDA7);

    while(1)
    {


        if ( PINA & (1 << PINA3) ) {
          PORTA = (1 << PA0);
        }

        if (!( PINA & (1 << PINA3) )) {
          PORTA = (0 << PA0);
        }


    }
}
lauten.

von Der kleine Nils (Gast)


Lesenswert?

Das Problem ist, dass du die Logik hinter der Schiebeoperation nicht 
verstanden hast.

Schau mal in diesen Artikel

http://www.mikrocontroller.net/articles/Bitmanipulation

in den Abschnitt "Standard C"

von Der kleine Nils (Gast)


Lesenswert?

Der kleine Nils schrieb:
> in den Abschnitt "Standard C"

sollte natürlich heissen "jeweils in die Abschnitte Standard C"

von Dario (Gast)


Lesenswert?

Ich verstehe das Problem immer noch nicht. Was ist denn bei meinem Code 
falsch?

von Max H. (hartl192)


Lesenswert?

Dario schrieb:
> PORTA = (0 << PA0);
Das ist das gleiche wie PORTA=0;

Dario schrieb:
> !( PINA & (0 << PINA3)
Das ist immer TRUE

von Thomas E. (thomase)


Lesenswert?

Dario schrieb:
> Der 2. Code muss natürlich:
> #include <avr/io.h>
>
> int main(void)
> {
>     DDRA = (1 << DDA0) | (1 << DDA1) | (1 << DDA2) | (0 << DDA3) | (0 <<
> DDA4) | (0 << DDA5) | (0 << DDA6) | (0 << DDA7);
>
>     while(1)
>     {
>         if ( PINA & (1 << PINA3) ) {
>           PORTA = (1 << PA0);
>         }
>         if (!( PINA & (1 << PINA3) )) {
>           PORTA = (0 << PA0);
>         }
>     }
> }
> lauten.

Das funktioniert auch nicht. Und wenn doch, dann spätestens wenn an der 
Nordseeküste die nächste Flut einsetzt, nicht mehr. Es sei denn, du hast 
an PA3 einen Pullup gelötet.
1
#include <avr/io.h>
2
 
3
int main(void)
4
{
5
     DDRA = (1 << DDA0) | (1 << DDA1) | (1 << DDA2);
6
     PORTA |= (1 << 3);
7
     while(1)
8
     {
9
         if ( PINA & (1 << PINA3) ) 
10
         {
11
         //  PORTA = (1 << PA0);
12
             PORTA |= (1 << PA0);
13
         }
14
         if (!( PINA & (1 << PINA3) ))
15
         {
16
           //PORTA = (0 << PA0);
17
           PORTA &= ~(1 << 0);
18
         }
19
     }
20
}

Das ist aber immer noch nichts Dolles. Das lässt sich auch mit einem 
Taster alleine lösen. Ganz ohne Controller.
Für den nächsten Schritt, einmal Drücken EIN, nochmal Drücken AUS, muß 
dein Taster entprellt werden. Aber verinnerliche erstmal das Thema 
Bitmanipulation.

mfg.

von Dario (Gast)


Lesenswert?

Ich habe einen 10k Pullup Wiederstand an PA3.

von Thomas E. (thomase)


Lesenswert?

Dario schrieb:
> Ich habe einen 10k Pullup Wiederstand an PA3.
Wohl eher einen Widerstand. Dann hat sich das mit der Flut erledigt.
Der Widerstand ist aber unnötig, da der Controller Pullups eingebaut hat 
und der entsprechende mit
1
PORTA |= (1 << 3);
aktiviert wird.

Guck dir die letzte Zeile in meiner Version an und vergleiche sie mit 
deiner auskommentierten darüber. Wenn das nur Stirnrunzeln bei dir 
verursacht:

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Ausg.C3.A4nge

mfg.

von Karl H. (kbuchegg)


Lesenswert?

Dario schrieb:
> Ich verstehe das Problem immer noch nicht.


Es gibt einen fundemantalen Unterschied zwischen

1
     1 << PA_irgendwas

und

1
     0 << PA_irgendwas


0 um eine ANzahl Bits nach links geschoeben, ist immer noch 0!

Das ist dasselbe wie in der Mathe
1
  1 * 1   = 1
2
  1 * 2   = 2
3
  1 * 3   = 3
4
  1 * 4   = 4
5
  ...
ABER
1
  0 * 1   = 0
2
  0 * 2   = 0
3
  0 * 3   = 0
4
  0 * 4   = 0
5
  ...

egal womit du 0 multiplizierst, das Ergebnis ist immer (in allen Fällen) 
0. Im Falle das du 1 multiplzierst kriegst du jeweils ein anderes 
Ergebnis. Aber nicht bei 0., Die Ergebnisse sind alle gleich, nämlich 0

Nimm den binären Wert 1 her
1
   0000 0001

und verschieb den um 5 Stellen nach links
1
   0000 0001   << 5
2
3
-> 0010 0000

das Ergebnis ist ein binärer Wert, der genau an der Bitposition 5 ein 
1-Bit hat. Genau darauf zielt man ja mit 1 << xxx ab: einen Wert zu 
kriegen, der genau an der Bitposition xxx ein 1 Bit aufweist.

Aber:
Das funktioniert, wenn man eine 1 schiebt.
Aber bei einer 0, so wie in 0 << PA0, ergibt die Operation keinen Sinn. 
Denn eine binäre 0 kannst du nach links schieben so oft du willst
1
   0000 0000   << 5
das Ergebnis ist wieder einfach nur
1
   0000 0000


Daher ist
1
   PORTA = (0 << PA0);
in allen Belangen völlig gleichwertig zu
1
   PORTA = 0;

Dass du da in deinem Ausdruck PA0 drinnen stehen hast, ist zwar nett, 
aber komplett irrelevant, weil es nichts bewirkt. De Facto hast du 
einfach nur an PORTA eine 0 zugewiesen.

von Dario (Gast)


Lesenswert?

Danke für die tolle Erklärung!
Um das zu verinnerlichen wollte ich so eine LED zum Blinken bringen. 
Aber ich
finde den Fehler nicht :(
#include <avr/io.h>
#include <util/delay.h>

#define F_CPU 1000000

int main(void)
{
  DDRA = 0;
  DDRA |= (1 << 0) | (1 << 1) | (1 << 2);

    while(1)
    {
    PORTA |= (1 << 0);
    _delay_ms(1000)
    PORTA &= ~(1 << 0);
    }
}

von Felix P. (fixxl)


Lesenswert?

Die Zeit vom Ausschalten zum Wiedereinschalten ist so kurz, dass du sie 
mit den Augen nie wahrnehmen kannst. Es fehlt noch ein Delay.

von Jens H. (jens_h19)


Lesenswert?

Dario schrieb:
> while(1)
>     {
>     PORTA |= (1 << 0);
>     _delay_ms(1000)
>     PORTA &= ~(1 << 0);
>     }

vielleicht so:

    while(1)
    {
    PORTA |= (1 << 0);
    _delay_ms(1000);
    PORTA &= ~(1 << 0);
    _delay_ms(1000);
    }

bei dir fehlt ein ';' und die LED geht so schnell wieder an, dass du 
nichts siehst

von Dario (Gast)


Lesenswert?

#include <avr/io.h>
#include <util/delay.h>

#define F_CPU 1000000

int main(void)
{
  DDRA = 0;
  DDRA |= (1 << 0) | (1 << 1) | (1 << 2);

    while(1)
    {
    PORTA |= (1 << 0);
    _delay_ms(1000);
    PORTA &= ~(1 << 0);
    }
}
Das ; bei _delay_ms hat gefehlt. Es blinkt trotzdem nicht :(

von Thomas E. (thomase)


Lesenswert?

Dario schrieb:
> Danke für die tolle Erklärung!
> Um das zu verinnerlichen wollte ich so eine LED zum Blinken bringen.
> Aber ich
> finde den Fehler nicht :(
> #include <avr/io.h>
> #include <util/delay.h>
>
> #define F_CPU 1000000
>
> int main(void)
> {
>   DDRA = 0;
>   DDRA |= (1 << 0) | (1 << 1) | (1 << 2);
>
>     while(1)
>     {
>     PORTA |= (1 << 0);
>     _delay_ms(1000)
>     PORTA &= ~(1 << 0);
>     }
> }

1
     while(1)
2
     {
3
       PORTA |= (1 << 0);
4
       _delay_ms(1000);
5
       PORTA &= ~(1 << 0);
6
       //du mußt dir hier auch eine Sekunde gönnen
7
       _delay_ms(1000);
8
     }

mfg.

von Dario (Gast)


Lesenswert?

Danke :)

von ich (Gast)


Lesenswert?

oder auch noch einfacher:
> while(1)
>      {
>        PORTA ^= (1 << 0);
>        _delay_ms(1000);
>      }

von Dario (Gast)


Lesenswert?

Ich stand gerade ein bisschen aufm Schlauch.

von Dario (Gast)


Lesenswert?

Ich habe mein Ziel erreicht:
1
#include <avr/io.h>
2
3
#define F_CPU 1000000
4
5
int main(void)
6
{
7
  DDRA = 0;
8
  DDRA |= (1 << 0) | (1 << 1) | (1 << 2);
9
  
10
    while(1)
11
    {
12
    if ( PINA & (1 << PA3)) {
13
      PORTA |= (1 << PA0);
14
    }
15
    if ( PINA | (1 << PA3)) {
16
      PORTA &= ~(1 << PA0);
17
    }
18
      
19
    }
20
}

von Peter II (Gast)


Lesenswert?

Dario schrieb:
> Ich habe mein Ziel erreicht:

was war das ziel? fehlerhafter Code?


>  if ( PINA | (1 << PA3)) {

ist zumindest schon mal nicht richtig.

von Karl H. (kbuchegg)


Lesenswert?

Dario schrieb:
> Ich habe mein Ziel erreicht:

Nope

>
1
>
2
>     if ( PINA | (1 << PA3)) {
3
>
4
>

ganz sicher nicht.

Was ist denn so schwer dran

Abfrage, ob ein Pin auf 1 ist
1
  if( PINx & ( 1 << PinNr ) )
2
     ...

Abfrage ob der Pin auf 0 ist
1
  if( !( PINx & ( 1 << PinNr ) ) )


Oder in deinem speziellen Fall
1
    if ( PINA & (1 << PA3)) {
2
      PORTA |= (1 << PA0);
3
    }
4
    else {
5
      PORTA &= ~(1 << PA0);
6
    }
... da stellt sich dann die Fragestellung gar nichgt mehr. Denn wenn der 
Pin nicht auf 1 war (erstes if), dann ist automatisch klar, dass er auf 
0 sein muss. Eine andere Möglichkeit existiert gar nicht mehr. Der Pin 
ist entweder 1 oder er ist 0. Sobald klar ist, dass er nicht 1 ist, MUSS 
er 0 sein.

von Max H. (hartl192)


Lesenswert?

Dario schrieb:
> PINA | (1 << PA3))
Das ist immer TRUE

von Dario (Gast)


Lesenswert?

Okay

#include <avr/io.h>

#define F_CPU 1000000

int main(void)
{
  DDRA = 0;
  DDRA |= (1 << 0) | (1 << 1) | (1 << 2);

    while(1)
    {
    if ( PINA & (1 << 3)) {
      PORTA |= (1 << PA0);
    }
    if (!( PINA & (1 << 3)) ){
      PORTA &= ~(1 << PA0);
    }
    }
}
oder
#include <avr/io.h>

#define F_CPU 1000000

int main(void)
{
  DDRA = 0;
  DDRA |= (1 << 0) | (1 << 1) | (1 << 2);

    while(1)
    {
    if ( PINA & (1 << 3)) {
      PORTA |= (1 << PA0);
    }
    else{
      PORTA &= ~(1 << PA0);
    }
    }
}
Jetzt müsste es richtig sein. Wie kann ich den Code in ein Codefenster 
schreiben?(so wie Ihr)

von Max H. (hartl192)


Lesenswert?

Dario schrieb:
> Wie kann ich den Code in ein Codefenster
> schreiben?(so wie Ihr)
[c*]C-Code[/c]
Nur ohne das '*'

@Mod: Sry, falls ich den oberen Beitrag aus Versehen gemeldet habe. Ich 
habe beim Zitieren vllt. den falschen Button angeklickt.

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.