Skip to content

Taste

starlightViewModes.switchTo

This content is not available in your language yet.

Tasten sind eine Eingabe des Benutzers auf einfachster Hardware-Ebene. Die Taste kann entweder gedrückt sein oder eben nicht. Diese binäre Zustandsoption ermöglicht das einfache Konvertieren in „Strom an“ oder „Strom aus“.

Theorie

Grundsätzlich gibt es zwei verschiedene Arten, Tasten zu verwenden:

  • Active Low Beschaltung => Pull-Up Widerstand
  • Active High Beschaltung => Pull-Down Widerstand

Diese beiden Arten müssen auf Code-Ebene unterschiedlich verarbeitet werden.

Active Low / Pull-Up

Bei der Active Low Beschaltung liegen 0V Spannung (low) am Eingang an, wenn die Taste gedrückt ist (active). Der Aufbau einer Active Low Beschaltung verwendet den Pull-Up Widerstand.

Active High / Pull-Down

Active High Beschaltungen funktionieren genau anders herum. Hierbei liegen die 5V Spannung (high) am Eingang an, wenn die Taste gedrückt ist (active). Der Aufbau einer Active High Beschaltung verwendet den Pull-Down Widerstand.

Aufbau

Active Low / Pull-Up

Am korrespondierendem PIN baut man einen Spannungsteiler auf, welcher auf der einen Seite einen 10K Widerstand mit 5V Versorgungsspannung und auf der anderen Seite eine an den Ground angeschlossene Taste anliegen hat.

Pull-Up Widerstand Ein Pull-Up Widerstand Aufbau, wenn die Taste geöffnet ist

Pull-Up Widerstand geschlossen Ein Pull-Up Widerstand Aufbau, wenn die Taste geschlossen ist

Active High / Pull-Down

Am korrespondierendem PIN liegt wieder ein Spannungsteiler an, welcher diesmal allerdings auf der Seite des 10K Widerstandes den Ground (GRN) hat und auf der anderen Seite befindet sich die Taste mit 5V Versorgungsspannung.

Pull-Down Widerstand Ein Pull-Down Widerstand Aufbau, wenn die Taste geöffnet ist

Pull-Down Widerstand geschlossen Ein Pull-Down Widerstand Aufbau, wenn die Taste geschlossen ist

Code

Ohne Interrupts

Pull-Up Beschaltung

#include <avr/io.h>
#include <util/delay.h>
void checkButton(void);
int main(void)
{
// Taste an Port B, Pin 0
// Port B, Pin 0 als Eingang konfigurieren
DDRB &= ~(1<<DDB0);
while (1)
{
checkButton();
}
}
void checkButton(void) {
// Überprüfen, ob die Taste gedrückt wird.
if (!(PINB & (1<<PINB0)))
{
// Taste wurde 1x gedrückt
}
// Prellen vermeiden
_delay_ms(70);
}

Pull-Down Beschaltung

#include <avr/io.h>
#include <util/delay.h>
void checkButton(void);
int main(void)
{
// Taste an Port B, Pin 0
// Port B, Pin 0 als Eingang konfigurieren
DDRB &= ~(1<<DDB0);
while (1)
{
checkButton();
}
}
void checkButton(void) {
// Überprüfen, ob die Taste gedrückt wird.
if (PINB & (1<<PINB0))
{
// Taste wurde 1x gedrückt
}
// Prellen vermeiden
_delay_ms(70);
}

Interner Pull-Up Widerstand

#include <avr/io.h>
#include <util/delay.h>
void checkButton(void);
int main(void)
{
// Taste an Port B, Pin 0
// Port B, Pin 0 als Eingang konfigurieren
DDRB &= ~(1<<DDB0);
// Port B, Pin 0 Spannung: 5V (internen Pull-Up Widerstand aktivieren)
PORTB |= (1<<PORTB0);
while (1)
{
checkButton();
}
}
void checkButton(void) {
// Überprüfen, ob die Taste gedrückt wird.
if (!(PINB & (1<<PINB0)))
{
// Taste wurde 1x gedrückt
}
// Prellen vermeiden
_delay_ms(70);
}

Mit Interrupts

Mit Interrupts hat man den Vorteil, dass man nicht in der while-Schleife ständig eine Methode aufrufen muss, welche die Tasten abfragt. Dieses Verhalten wird bei den Interrupts noch besser erklärt.

Direkt externe Interrupts

An Port D gibt es zwei PINs (2 und 3), welche über direkte externe Interrupts - Funktionalitäten verfügen. Das bedeutet, dass dort angeschlossene Tasten spezifisch mithilfe von bereits definierten Interrupts überprüft werden können. Dies erspart ein wenig komplexen Programmcode.

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
int main(void)
{
// Taste an Port D, Pin 2
// Port D, Pin 2 als Eingang konfigurieren
DDRD &= ~(1<<DDD2);
// Port D, Pin 2 Spannung: 5V (internen Pull-Up Widerstand aktivieren)
PORTD |= (1<<PORTD2);
// Interrupt
// direktes externe Interrupt an Port D, Pin 2 aktivieren
EIMSK |= (1<<INT0);
// Set Enable Interrupt
sei();
while (1)
{
}
}
ISR (INT0_vect) {
// Taste wurde 1x gedrückt
_delay_ms(70);
}

Gruppenbasierte externe Interrupts

Die gruppenbasierten externen Interrupts gelten immer für den gesamten Port. Aus diesem Grund muss man im Interrupt auch nochmals den richtigen PIN auf Tasteneingaben überprüfen, wie man unten, im Code, sehen kann.

Port BPort CPort D
PIN 0PCIE0, PCINT0PCIE1, PCINT8PCIE2, PCINT16
PIN 1PCIE0, PCINT1PCIE1, PCINT9PCIE2, PCINT17
PIN 2PCIE0, PCINT2PCIE1, PCINT10PCIE2, PCINT18
PIN 3PCIE0, PCINT3PCIE1, PCINT11PCIE2, PCINT19
PIN 4PCIE0, PCINT4PCIE1, PCINT12PCIE2, PCINT20
PIN 5PCIE0, PCINT5PCIE1, PCINT13PCIE2, PCINT21
PIN 6PCIE0, PCINT6PCIE1, PCINT14PCIE2, PCINT22
PIN 7PCIE0, PCINT7-PCIE2, PCINT23
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
int main(void)
{
// Taste an Port D, Pin 4
// Port D, Pin 4 als Eingang konfigurieren
DDRD &= ~(1<<DDD4);
// Port D, Pin 4 Spannung: 5V (internen Pull-Up Widerstand aktivieren)
PORTD |= (1<<PORTD4);
// Interrupt
// gruppenbasiertes externe Interrupt an Port D, Pin 4 aktivieren
PCICR |= (1<<PCIE2);
PCMSK2 |= (1<<PCINT20);
// Set Enable Interrupt
sei();
while (1)
{
}
}
ISR (PCINT2_vect) {
// notwendige Überprüfung des spezifischen PINs 4 auf Port D
// aufgrund der Verwendung von gruppenbasierten Interrupts
if(!(PIND & (1<<PIND4))){
// Taste wurde 1x gedrückt
}
_delay_ms(70);
}

Troubleshooting

Floating Point

Ohne Widerstand darf man keine 5V Versorgungsspannung auf der Taste anlegen:

Floating Point

Kurzschluss

Ebenso darf ein Spannungsteiler nicht einfach an den Ground (GND) angeschlossen werden, da dieser Ground sofort die Versorgungsspannung aufheben würde.

Kurzschluss