Forum: Mikrocontroller und Digitale Elektronik Taster - LED Beispiel


von Da H. (darko91)


Lesenswert?

Hallo Zusammen,
Ich hab vor kurzem angefangen, auf dem Arduino UNO reines C zu 
programmieren.
Ein einfaches Blinky/Lauflicht habe ich zusammen bekommen, es scheitert 
aber am Taster Beispiel (Taster AN, LED8 leuchtet, Taster AUS, LED7 
leuchtet).
Compilieren funktioniert, Programm auf den ATMega328p drauf laden 
ebenso.
Es leuchtet lediglich die LED7, auch wenn ich den Taster betätige.
Leider verstehe ich nicht, woran das Problem liegt bei folgendem 
Programmcode:
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <stdio.h>
4
#include <stdint.h>
5
#include <avr/interrupt.h>
6
#include <inttypes.h>
7
8
uint8_t a;
9
10
int main (void)
11
{            
12
  DDRD |= (1<<7) | (1<<6);     // 7. und 8. PIN vom Port D als Ausgang
13
  DDRC &= ~(1<<0);    // 1. PIN vom Port C als Eingang
14
  PORTC |= (1<<0);    // internen Pull-up einschalten
15
  a = PINC & ~(1<<0);
16
17
  if(a != 0)      // wenn Taster gedrückt
18
  {
19
    PORTD|=(1<<7);    // LED8 geht an
20
  }
21
  else        // wenn Taster nicht gedrückt
22
  {
23
    PORTD|= (1<<6);    // LED geht an
24
  }
25
}
Bitte um eine kleine Hilfe.
PS: Bin Anfänger, daher bitte nicht allzu viel von mir erwarten :)

: Bearbeitet durch User
von Karol B. (johnpatcher)


Lesenswert?

Es fehlt eine Hauptschleife, siehe [1]. In der Arduino Welt macht das 
die "loop()" Funktion für dich. In reinem C musst du etwas wie 
"while(1);" notieren. Vermutlich startet dein Programm deshalb einfach 
immer wieder von vorne.

Außerdem schaltest du die LEDs nicht wieder ab, d.h. sie würden ohnehin 
immer leuchten.

Weiterhin bietet das Forum rudimentäre Formatierungsmöglichkeiten für 
Quellcode. Diese solltest du nutzen, um das ganze ansehlicher zu 
gestalten.

Mit freundlichen Grüßen,
Karol Babioch

[1]: 
https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Grunds.C3.A4tzlicher_Programmaufbau_eines_.C2.B5C-Programms

: Bearbeitet durch User
von Da H. (darko91)


Lesenswert?

Karol Babioch schrieb:
> Es fehlt eine Hauptschleife, siehe [1]. In der Arduino Welt macht
> das
> die "loop()" Funktion für dich. In reinem C musst du etwas wie
> "while(1);" notieren. Vermutlich startet dein Programm deshalb einfach
> immer wieder von vorne.
>
> Außerdem schaltest du die LEDs nicht wieder ab, d.h. sie würden ohnehin
> immer leuchten.
>
> Weiterhin bietet das Forum rudimentäre Formatierungsmöglichkeiten für
> Quellcode. Diese solltest du nutzen, um das ganze ansehlicher zu
> gestalten.
>
> Mit freundlichen Grüßen,
> Karol Babioch
>
> [1]:
> https://www.mikrocontroller.net/articles/AVR-GCC-T...

Stimmt, die Endlosschleife hab ich aus versehen weg gelassen.
Funktioniert aber trotzdem nicht. Jetzt leuchtet die LED8 
ununterbrochen.
Die Definition des Tasters passt?
1
uint8_t a;
2
3
int main (void)
4
{            
5
  DDRD |= (1<<7) | (1<<6); // 7. und 8. PIN vom Port D als Ausgang
6
  DDRC &= ~(1<<0);    // 1. PIN vom Port C als Eingang
7
  PORTC |= (1<<0);    // internen Pull-up einschalten
8
  a = PINC & ~(1<<0);
9
10
  while(1)
11
  {
12
    if(a != 0)        // wenn Taster gedrückt
13
    {
14
      PORTD|=(1<<7);    // LED8 geht an
15
      PORTD&= ~(1<<6);
16
    }
17
    else          // wenn Taster nicht gedrückt
18
    {
19
      PORTD|= (1<<6);    // LED geht an  
20
      PORTD&= ~(1<<7);  
21
    }
22
  }    
23
}

von holger (Gast)


Lesenswert?

>Stimmt, die Endlosschleife hab ich aus versehen weg gelassen.

Dann wäre es wohl noch sinnvoll die Tasterabfrage auch
in diese Endlosschleife zu legen.

von Da H. (darko91)


Lesenswert?

holger schrieb:
>>Stimmt, die Endlosschleife hab ich aus versehen weg gelassen.
>
> Dann wäre es wohl noch sinnvoll die Tasterabfrage auch
> in diese Endlosschleife zu legen.

Hab's versucht, geht trotzdem nicht.
Wie müsste ich den Code ändern? Glaub das wäre am schnellsten, bevor ich 
noch 100 mal rum probiere :)

von Karol B. (johnpatcher)


Lesenswert?

Darko Jen schrieb:
> Hab's versucht, geht trotzdem nicht.

Das ist keine brauchbare Fehlerbeschreibung.

Darko Jen schrieb:
> Wie müsste ich den Code ändern? Glaub das wäre am schnellsten, bevor ich
> noch 100 mal rum probiere :)

Lernen tust du es aber nur, wenn du es noch 100 mal probierst. Konkret 
geht es um die Zeile "a = PINC & ~(1<<0);". Diesen willst du ja 
kontinuierlich in der Schleife einlesen, nicht einmalig während der 
Initialisierung.

Übrigens: Wo kommst du Verneinung von (1<<0) her? Du möchtest du PC0 
abfragen, und nicht PC1:7? Durch deine Verundung jedenfalls wird das Bit 
0 immer als 0 eingelesen werden.


Mit freundlichen Grüßen,
Karol Babioch

von holger (Gast)


Lesenswert?


von Da H. (darko91)


Lesenswert?

Karol Babioch schrieb:
> Darko Jen schrieb:
>> Hab's versucht, geht trotzdem nicht.
>
> Das ist keine brauchbare Fehlerbeschreibung.
>
> Darko Jen schrieb:
>> Wie müsste ich den Code ändern? Glaub das wäre am schnellsten, bevor ich
>> noch 100 mal rum probiere :)
>
> Lernen tust du es aber nur, wenn du es noch 100 mal probierst. Konkret
> geht es um die Zeile "a = PINC & ~(1<<0);". Diesen willst du ja
> kontinuierlich in der Schleife einlesen, nicht einmalig während der
> Initialisierung.
>
> Übrigens: Wo kommst du Verneinung von (1<<0) her? Du möchtest du PC0
> abfragen, und nicht PC1:7? Durch deine Verundung jedenfalls wird das Bit
> 0 immer als 0 eingelesen werden.
>
> Mit freundlichen Grüßen,
> Karol Babioch

Soweit ich weiß wird die ODER-Verknüpfung verwendet, wenn es um einen 
Ausgang geht, eine UND-Verknüpfung mit einer Negierung des Pins, wenn es 
um einen Eingang geht. Daher habe ich mir gedacht, ich lass das "~" 
drinnen.
Hab nun die Zeile in der Schleife eingefügt und die Verneinung 
weggelassen und es funktioniert noch immer nicht, ich gebe schon langsam 
auf.

PS: gerade merke ich, dass die Abfrage am Taster garnicht funktioniert, 
da ich dasselbe Ergebnis erhalte, wenn ich den Taster raus nehme. (LED8 
leuchtet permanent).
Was genau muss ich noch ändern/hinzufügen? Das AVR GCC Tutorial hab ich 
schon gelesen und das beantwortet nicht meine frage. Sitze schon seit 2 
Abenden daneben
1
int main (void)
2
{            
3
  DDRD |= (1<<7) | (1<<6); // 7. und 8. PIN vom Port D als Ausgang
4
  DDRC &= ~(1<<0);    // 1. PIN vom Port C als Eingang
5
  PORTC |= (1<<0);    // internen Pull-up einschalten
6
7
  while(1)
8
  {
9
    a = PINC & (1<<0);
10
    if (a != 0)      // wenn Taster gedrückt
11
    {
12
      PORTD|=(1<<7);    // LED8 geht an
13
      PORTD&= ~(1<<6);
14
    }
15
    else          // wenn Taster nicht gedrückt
16
    {
17
      PORTD|= (1<<6);    // LED geht an  
18
      PORTD&= ~(1<<7);  
19
    }
20
  }    
21
}

von Karol B. (johnpatcher)


Lesenswert?

Darko Jen schrieb:
> Soweit ich weiß wird die ODER-Verknüpfung verwendet, wenn es um einen
> Ausgang geht, eine UND-Verknüpfung mit einer Negierung des Pins, wenn es
> um einen Eingang geht. Daher habe ich mir gedacht, ich lass das "~"
> drinnen.

Du kannst das doch kurz mit Zettel und Stift durchgehen. Mit lustig 
herum raten, bzw. der blinden Übernahme von Tutorials ohne es 
durchzuspielen, wird dich kaum zum Erfolg bringen.

Die Negierung mit Verundung setzt man typischerweise dann ein, wenn man 
ein Bit "löschen" will, ohne die anderen Bits des Ports zu ändern.

Du willst aber Bit 0 von PINC auswerten, d.h. du musst alle anderen Bits 
ignorieren. Das geschieht mit einer Verundung einer Bitmaske, die nur an 
Bit 0 eine 1 stehen hat.

Das Ergebnis dieser Verundung kannst du dann auswerten. Ist das Ergebnis 
0, so war das Bit nicht gesetzt, ist das Ergebnis ungleich 0 (bzw. in 
dem Fall sogar 1, weil Bit 0), so war das Bit gesetzt.

Darko Jen schrieb:
> und es funktioniert noch immer nicht

Nach wie vor eine schlechte Fehlerbeschreibung. Die halbe Miete des 
Debuggings ist es, das Fehlverhalten ordentlich auszuformulieren. Dabei 
wird einem selbst oft schon klar, was ggf. verkehrt läuft.

Darko Jen schrieb:
> ich gebe schon langsam
> auf.

Dann bist du aber nicht besonders geduldig ;). Manchmal dauern eben 
selbst solche Trivialitäten etwas. Die Zeit muss man sich eben nehmen. 
Glaub mir, dass es ein sehr befriedigendes Gefühl ist, wenn man so etwas 
selbst gelöst bekommt, und nicht per Copy & Paste Code von anderen 
übernimmt.

Übrigens: Wie ist denn dein Taster beschaltet? Da du den internen 
Pull-Up aktivierst, nehme ich an, dass das Ganze auf Active Low hinaus 
läuft? Dann wäre der Button aber aktiv, wenn a gleich 0 ist, d.h. 
zumindest die Kommentare der einzelnen Verzweigungen sind falsch.

Und wo wird in deiner aktuellsten Version a definiert? Gibt es 
Fehlermeldungen des Compilers, die du stillschweigend ignorierst?

Mit freundlichen Grüßen,
Karol Babioch

von Kasperl (Gast)


Lesenswert?

Schaltet der Taster gegen Masse?

von holger (Gast)


Lesenswert?

>PS: gerade merke ich, dass die Abfrage am Taster garnicht funktioniert,
>da ich dasselbe Ergebnis erhalte, wenn ich den Taster raus nehme. (LED8
>leuchtet permanent).

Dann schaltest du mit dem Taster vermutlich gegen VCC.
er muss aber gegen GND schalten damit der Code funktioniert.

>Schaltet der Taster gegen Masse?

Da ist noch jemand meiner Meinung;)

von Da H. (darko91)


Angehängte Dateien:

Lesenswert?

> Dann bist du aber nicht besonders geduldig ;). Manchmal dauern eben
> selbst solche Trivialitäten etwas. Die Zeit muss man sich eben nehmen.
> Glaub mir, dass es ein sehr befriedigendes Gefühl ist, wenn man so etwas
> selbst gelöst bekommt, und nicht per Copy & Paste Code von anderen
> übernimmt.

Ich kann es kaum glauben, dass es so schwer ist, kein einfaches 
Tasterbeispiel zu schaffen, daher der Verlust der Geduld :) werde aber 
natürlich nicht aufgeben, ehe ich es nicht fertig habe. Hätte ich ein 
Beispiel vor mir liegen, würde ich dieses im Kopf durchsteppen, bis ich 
jede Zeile kapiere.

> Übrigens: Wie ist denn dein Taster beschaltet? Da du den internen
> Pull-Up aktivierst, nehme ich an, dass das Ganze auf Active Low hinaus
> läuft? Dann wäre der Button aber aktiv, wenn a gleich 0 ist, d.h.
> zumindest die Kommentare der einzelnen Verzweigungen sind falsch.

Den Taster habe ich folgendermaßen beschaltet: siehe Bild

> Du willst aber Bit 0 von PINC auswerten, d.h. du musst alle anderen Bits
> ignorieren. Das geschieht mit einer Verundung einer Bitmaske, die nur an
> Bit 0 eine 1 stehen hat.
>
> Das Ergebnis dieser Verundung kannst du dann auswerten. Ist das Ergebnis
> 0, so war das Bit nicht gesetzt, ist das Ergebnis ungleich 0 (bzw. in
> dem Fall sogar 1, weil Bit 0), so war das Bit gesetzt.

Nun gut, jetzt verstehe ich, warum ich die Verneinung nicht brauche - 
logisch.
1
 a = PINC & (1<<0)
 sagt ja aus, dass sich a entsprechend der Änderung des PINC0 ändert
Durch
1
 if (a != 0)
 erfolgt eine Abfrage, ob der PORTC (0-6) ungleich 0 ist. Da die Pins 
PINC1 - PINC5 nirgends definiert sind, bleiben diese doch 0, oder? Bzw. 
da diese weder als Eingang, noch als Ausgang definiert sind, bleiben die 
auf Low?
Daher hängt es nur vom PINC0 ab, ob hier der Taster High oder Low ist. 
Bei High leuchtet die LED8, bei Low leuchtet die LED7.
-> das wäre mein logischer Gedanke gewesen. Anscheinend irre ich mich 
aber

> Und wo wird in deiner aktuellsten Version a definiert? Gibt es
> Fehlermeldungen des Compilers, die du stillschweigend ignorierst?
ganz oben, vor der while-Schleife wird a gleich 0 gesetzt.


PS: mit der IDE vom Arduino klappt das Button-Beispiel beim selben 
Aufbau  perfekt!

Der ganze Code, wodurch LED8 permanent leuchtet
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <stdio.h>
4
#include <stdint.h>
5
#include <avr/interrupt.h>
6
#include <inttypes.h>
7
8
uint8_t a = 0;
9
10
int main (void)
11
{            
12
  DDRD |= (1<<7) | (1<<6); // 7. und 8. PIN vom Port D als Ausgang
13
  DDRC &= ~(1<<0);    // 1. PIN vom Port C als Eingang
14
  PORTC |= (1<<0);    // internen Pull-up einschalten
15
16
  while(1)
17
  {
18
    a = PINC & (1<<0);    // a entweder HIGH oder LOW, je nach PINC0
19
    if (a != 0)        // wenn Taster gedrückt
20
    {
21
      PORTD|=(1<<7);    // LED8 geht an
22
      PORTD&= ~(1<<6);  // LED7 geht aus
23
    }
24
    
25
    else          // wenn Taster nicht gedrückt
26
    {
27
      PORTD|= (1<<6);    // LED7 geht an  
28
      PORTD&= ~(1<<7);  // LED8 geht aus
29
    }
30
  }    
31
}

sollte ich mich bei meinen Sätzen irren, bitte bescheid geben - wie 
gesagt, bin ziemlich neu in der µC-Welt :)

von holger (Gast)


Lesenswert?

>Den Taster habe ich folgendermaßen beschaltet: siehe Bild

Ja, scheisse baust du da. Dein Taster schaltet nicht gegen GND.
Nimm den Widerstand da weg. Die rote Leitung zum Taster weg und
eine schwarze Leitung zum Taster. Das sollte es dann gewesen sein.

von AMK (Gast)


Lesenswert?

1
/* Fuehre Aktion aus, wenn Bit Nr. 1 (das "zweite" Bit) in PINC gesetzt (1) ist */
2
if ( PINC & (1<<PINC1) ) {
3
  /* Aktion */
4
}
5
 
6
/* Fuehre Aktion aus, wenn Bit Nr. 2 (das "dritte" Bit) in PINB geloescht (0) ist */
7
if ( !(PINB & (1<<PINB2)) ) {
8
  /* Aktion */
9
}

http://www.mikrocontroller.net/articles/Bitmanipulation#Bits_pr.C3.BCfen
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Eing.C3.A4nge_.28Wie_kommen_Signale_in_den_.C2.B5C.29

und auch mal das lesen:
http://www.mikrocontroller.net/articles/AVR-Tutorial:_Tasten

von 123 (Gast)


Lesenswert?

Darko Jen schrieb:
> Da die Pins
> PINC1 - PINC5 nirgends definiert sind, bleiben diese doch 0, oder? Bzw.
> da diese weder als Eingang, noch als Ausgang definiert sind, bleiben die
> auf Low?

Nein. Dein Arduino hat interne Pullups, die die Eingänge auf High 
ziehen.

Darko Jen schrieb:
> Den Taster habe ich folgendermaßen beschaltet: siehe Bild

In dem Fall hast du einen Pulldown. Da der µC jedoch einen internen 
Pullup hat, dürfte das recht wackelig sein(Der Pullup lieht im Bereich 
von 10-25k, genaueres im Datenblatt). Tausch am Taster/Widerstand mal 
VCC und GND. Dann solltest du noch die Tasterabfrage umdrehen(wenn der 
Taster gedrückt ist, liefert er logisch 0).

von Da H. (darko91)


Lesenswert?

holger schrieb:
>>Den Taster habe ich folgendermaßen beschaltet: siehe Bild
>
> Ja, scheisse baust du da. Dein Taster schaltet nicht gegen GND.
> Nimm den Widerstand da weg. Die rote Leitung zum Taster weg und
> eine schwarze Leitung zum Taster. Das sollte es dann gewesen sein.

Leider nein, ich erhalte dasselbe Ergebnis

PS: Den Plan hab ich von arduino.cc, wobei das mit der IDE klappt.

von Da H. (darko91)


Lesenswert?

123 schrieb:
> Darko Jen schrieb:
>> Da die Pins
>> PINC1 - PINC5 nirgends definiert sind, bleiben diese doch 0, oder? Bzw.
>> da diese weder als Eingang, noch als Ausgang definiert sind, bleiben die
>> auf Low?
>
> Nein. Dein Arduino hat interne Pullups, die die Eingänge auf High
> ziehen.
>
> Darko Jen schrieb:
>> Den Taster habe ich folgendermaßen beschaltet: siehe Bild
>
> In dem Fall hast du einen Pulldown. Da der µC jedoch einen internen
> Pullup hat, dürfte das recht wackelig sein(Der Pullup lieht im Bereich
> von 10-25k, genaueres im Datenblatt). Tausch am Taster/Widerstand mal
> VCC und GND. Dann solltest du noch die Tasterabfrage umdrehen(wenn der
> Taster gedrückt ist, liefert er logisch 0).

Getan! Nun liefert er logisch 0 und die LED7 leuchtet (sollte auch so 
sein, da der Taster nicht gedrückt ist)
Wenn ich den Taster nun drücke, merke ich keinen unterschied. Es 
leuchtet permanent die LED7 (Ergebins also konstant logisch 0)

von chris (Gast)


Lesenswert?

und an welchem Pin hängt denn jetzt dein Taster?
laut deinem Bild an D8, das wäre dann PB0, wenn dieser Plan hier stimmt:
http://arduino-info.wikispaces.com/file/view/ATMEGA328-900.jpg/421493080/ATMEGA328-900.jpg

PC0 = A0

du sollst nicht von irgendeiner Arduino-Seite Bilder hier hochladen, 
sondern DEINEN Aufbau zeigen. Mach halt einfach ein Foto.

von holger (Gast)


Lesenswert?

>Leider nein, ich erhalte dasselbe Ergebnis

Tut mir leid, aber ich bin jetzt raus.
Du bist nicht dazu in der Lage einen simplen Taster
vom Portpin gegen GND zu schalten. Nimm dein
Multimeter und pieps mal durch ob der überhaupt
so schaltet wie du es dir vorstellst. Spannung
am Portpin messen. Das wars dann von mir.

von Da H. (darko91)


Lesenswert?

Liebe Leute,

Ich bedanke mich bei jedem einzelnen von Euch!! Es funktioniert

Zum einen hat der Code nicht gestimmt. danke @karol
Zum anderen habe ich aus versehen PORTC und PORTB vertauscht!! Danke 
@chris

Den Widerstand vor dem Taster habe ich komplett raus gemacht, da der 
Pull-up Widerstand ohnehin aktiviert ist.

Der Taster war ebenso nicht auf GND. habe nun links oben am Taster GND 
angeschlossen und rechts unten PINC0 (bei einer verbindung rechts oben 
mit PINC0 bleibt LED8 konstant auf HIGH). Wenn zusätzlich noch Vcc am 
Taster dran kommt, dann leuchtet zwar die LED7, wenn der Taster aus ist, 
jedoch GARNICHTS, wenn der Taster betätigt wird. hierbei danke @holger, 
hattest Recht

usw...
Die restlichen Infos waren ebenso hilfreich (Schaltplan, etc.)

Hier der endgültige Code, der endlich passt, jedoch bin ich gerade 
dabei, es zu verstehen, warum es umgekehrt funktioniert als gewollt 
(Taster gedrückt, LED8 aus, Taster aus, LED8 an)... es steht doch 
"if(a!=0)" da, sprich: wenn das Bit von PINC0 gesetzt ist, soll die LED8 
leuchten..komisch, wahrscheinlich zu spät für mich :)
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <stdio.h>
4
#include <stdint.h>
5
#include <avr/interrupt.h>
6
#include <inttypes.h>
7
8
uint8_t a = 0;
9
10
int main (void)
11
{            
12
  DDRD |= (1<<7) | (1<<6); // 7. und 8. PIN vom Port D als Ausgang
13
  DDRB &= ~(1<<0);      // 1. PIN vom Port C als Eingang
14
  PORTB |= (1<<0);      // internen Pull-up einschalten
15
16
  while(1)
17
  {
18
    a = PINB & (1<<0);  // a entweder HIGH oder LOW, je nach PINC0
19
    if (a != 0)         // Taster nicht gedrückt...
20
    {
21
      PORTD|=(1<<7);    // LED8 geht an
22
      PORTD&= ~(1<<6);  // LED7 geht aus
23
    }
24
    
25
    else                 // Taster gedrückt
26
    {
27
      PORTD|= (1<<6);    // LED7 geht an  
28
      PORTD&= ~(1<<7);   // LED8 geht aus
29
    }
30
  }    
31
}

von Karol B. (johnpatcher)


Lesenswert?

Darko Jen schrieb:
> Hier der endgültige Code, der endlich passt, jedoch bin ich gerade
> dabei, es zu verstehen, warum es umgekehrt funktioniert als gewollt
> (Taster gedrückt, LED8 aus, Taster aus, LED8 an)...

Weil dein Taster gegen GND schaltet. Per Pull-Up ziehst du die Spannung 
im Ausgangszustand gegen Vcc, d.h. logisch 1. Wennn du den Taster 
drückst, dann fällt die Spannung auf 0 Volt ab (logisch 0). Deine 
if-Abfrage ist also genau verkehrt herum.

Mit freundlichen Grüßen,
Karol Babioch

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.