Forum: Mikrocontroller und Digitale Elektronik Interrupt/taster


von Marcel R. (marcelr1588)


Lesenswert?

Guten Tag liebes Forum,

ich komme mal wieder nicht weiter und hoffe auf erneute Hilfe :D

Und zwar soll das Programm folgendes können:
Es soll 3 Modi geben die jeweils mit einem Tasterdruck ausgeführt werden 
soll.

Sprich, Lauflicht von links nach rechts
Tasterdruck > Lauflicht von recht nach links
Tasterdruck > Lauflicht aus

und dann wieder von vorne.


In meinem vorherigen Programm habe ich den Taster einbinden können, 
jedoch ohne Interrupt.

da sah die Funktion so aus:

while(1) {


     if (PIND & (1<<PD2))
   {
   lampen1an();
   }

   else
   {
   lampen2an();
   }


Hat auch super funktioniert.


Mein bisheriges Programm sieht jetzt so aus:

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

volatile unsigned int status = 0 ;

void init (void);
void mode1 (void);
void mode2 (void);
void mode3 (void);



ISR(INT0_vect)
{
   status++;
   if (status >=3)
   {
      status = 0;
   }
}



void main(void)
{
    init();
  while(1)
  {
      switch(status)
    {
       case 0: mode1(); break;
           case 1: mode2(); break;
       case 2: mode3(); break;
      }
    }
}







void init(void)
{
DDRD |= (1<<PD6);
DDRB |= (1<<PB2);
DDRB |= (1<<PB1);
DDRB |= (1<<PB0);
DDRD &= ~(1<<PD2);
PORTD |= (1<<PD2);
GIMSK = 0b01000000;
MCUCR = 0b00000001;
sei();
}


void mode1(void)
{
PORTD |= (1<<PD6);
_delay_ms(500);
PORTB |= (1<<PB0);
_delay_ms(500);
PORTB |= (1<<PB1);
_delay_ms(500);
PORTB |= (1<<PB2);
}

void mode2(void)
{
PORTB |= (1<<PB2);
_delay_ms(500);
PORTB |= (1<<PB1);
_delay_ms(500);
PORTB |= (1<<PB0);
_delay_ms(500);
PORTD |= (1<<PD2);
}


void mode3(void)
{
PORTD &= ~(1<<PD6);
PORTB &= ~(1<<PB2);
PORTB &= ~(1<<PB1);
PORTB &= ~(1<<PB0);
}



Die Frage wäre jetzt, wo genau ich den Taster mit einfüge?

Steh gerade richtig auf dem Schlauch.

Ich hoffe mir kann jemand helfen :)

von Stefan F. (Gast)


Lesenswert?

Marcel R. schrieb:
> Die Frage wäre jetzt, wo genau ich den Taster mit einfüge?

Dein Plan ist doch, dass der Tastendruck einen Interrupt auslöst. Die 
entsprechende ISR hast du bereits geschrieben.

Das wird aber nicht wie gewollt funktionieren, weil jeder Taster prellt. 
Beim Tastendruck wirst du mehrere Interrupts erhalten, so dass das 
Ergebnis ziemlich zufällig erscheint.

Du brauchst einen Timer, der nach erkanntem Tastendruck sicher stellt, 
dass weitere Impulse für eine gewisse Zeit (z.B. 20ms) ignoriert werden. 
Ich glaube, das ist für dich (noch) zu kompliziert.

Folgende Schaltung entprellt das Signal per Hardware:
1
             2,2kΩ           Taster
2
                                   _____
3
GND |---+----[===]-----------+------   --------o 5V
4
        |                    |
5
        +---||---+---[===]---+
6
                 |
7
       100nF     |    100Ω
8
                 |
9
                 o 
10
              I/O Pin PD2

von Marcel R. (marcelr1588)


Lesenswert?

Danke schonmal für die Antwort,

Die Schaltung zu bauen wäre kein Problem, Widerstände und Kondensatoren 
hab ich noch zur genüge :)

Kannst du mir dann noch mit dem Tasterproblem helfen?

Also wie bekomme ich es hin, das er weiß, wann er den Status wechseln 
soll mithilfe des Tasters?

von Peter D. (peda)


Lesenswert?

Taster mit Interrupt ist ne ganz schlechte Idee, da mechanische Kontakte 
prellen.
Da bietet sich eine Entprell-Lib an, die in einem festen Raster 
entprellt.

Das 2. Problem, wo wertet man das Ereignis aus, wenn die Routinen ganz 
lange dauern. Statt Warteschleifen bietet sich da eine Zeitsteuerung an, 
die neue Pattern aus eine Tabelle liest. Die gibt die Wartezeiten immer 
zum Main zurück, d.h. kann jederzeit abgebrochen werden.

Hier ein Beispiel für beides:
Beitrag "AVR Sleep Mode / Knight Rider"

von Stefan F. (Gast)


Lesenswert?

Marcel R. schrieb:
> Also wie bekomme ich es hin, das er weiß, wann er den Status wechseln
> soll mithilfe des Tasters?

Bei Tastendruck löst die Hardware einen Aufruf der ISR aus. Diese 
reagiert entsprechend. Das sieht in deinem Quelltext schon gut aus, mehr 
muss man da prinzipiell nicht machen.

So wie du fragst funktioniert es wohl nicht. Irgendwo wird sich ein 
kleiner Fehlerteufel versteckt haben.

Peter D. hat schon recht. Eine Entprellung per Software ist flexibler 
und billiger - also sinnvoller. Sobald du mehrere Tasten hast, muss man 
da schon etwas mehr Hirnschmalz rein stecken. Mit Interrupt-Routinen 
landet man da schnell in einer Sackgasse. Noch nicht, aber später wenn 
das Programm komplexer wird.

Probiere das trotzdem mal mit dem Kondensator aus. Wenn man die Vor- und 
Nachteile durch Fehler-Machen erlebt, prägen sie sich besser ein. Ich 
lerne im Hobby gerne auf diese Art (im Job geht das leider nicht so).

Eine andere Sache, auf die du sehr bald stoßen wirst ist, dass deine 
Lauflichter bis zum Ende durchlaufen, bevor sie die Richtung ändern. Das 
wirst du sicher auch verbessern wollen.

Aber eins nach dem Anderem. Bleibe erst einmal beim aktuellen Problem, 
dann erforsche unterschiedliche Methoden des Entprellens.

von Marcel R. (marcelr1588)


Lesenswert?

Danke euch beiden erstmal für die ganzen Infos.

@Stefan: Hatte das Programm noch gar nicht ausprobiert, da ich dachte es 
fehlt noch der Taster irgendwo.
Es funktioniert zwar so halb, weiß ehrlich gesagt nicht warum er den 
Taster erkennt :P


Da ich aber heute erst das zweite mal damit arbeite, verstehe ich nur 
ein Bruchteil und muss mich erst weiter einlesen.

Modus eins läuft, da die LEDS's schon in Modus zwei an waren, konnten 
sie bei Modus 2 natürlich nicht mehr angehen.

Dann hab ich den Modus 2 geändert:

void mode2(void)
{
PORTD &= ~(1<<PD6);
PORTB &= ~(1<<PB2);
PORTB &= ~(1<<PB1);
PORTB &= ~(1<<PB0);
_delay_ms(500);
PORTB |= (1<<PB2);
_delay_ms(500);
PORTB |= (1<<PB1);
_delay_ms(500);
PORTB |= (1<<PB0);
_delay_ms(500);
PORTD |= (1<<PD6);
}


Jetzt läuft es wie folgt:

Modus 1: Licht läuft einmal von links nach rechts und alle bleiben am 
Schluß an.

Modus 2:Licht läuft von rechts nach links, bleibt aber nicht an, sondern 
es fängt immer wieder von vorne an.

Modus 3: Licht geht aus.




Naja vll liegt es ja an einem von euren genannten Problemen.

So wird dann der Urlaub nächste Woche nicht langweilig.

von Stefan F. (Gast)


Lesenswert?

Marcel R. schrieb:
> Es funktioniert zwar so halb, weiß ehrlich gesagt nicht warum er den
> Taster erkennt :P

Weil du den entsprechenden Interrupt aktiviert hast. Die Verbindung 
zwischen I/O Pin und Aufruf der Interruptroutine hast du damit 
aktiviert:

> GIMSK = 0b01000000;
> MCUCR = 0b00000001;
> sei();

Anscheinend ist Dir nicht klar, was du programmiert/kopiert hast. Zieh 
Dir das mal rein: http://stefanfrings.de/mikrocontroller_buch/index.html

Im Mode 1 schaltest du die vier LEDs nacheinander ein. Sie bleiben 
danach alle an, weil du keinen Code hast, der sie wieder aus schaltet.

Im Mode 2 werden erst alle LEDs aus geschaltet, dann nacheinander ein. 
Hier ist die Wiederholung erkennbar, weil sie beim Beginn der Funktion 
aus geschaltet werden.

Also alles genau so, wie du es programmiert hast.

von Marcel R. (marcelr1588)


Lesenswert?

Ist alles selber geschrieben, nur nicht verstanden dann anscheinen :D

GIMSK = 0b01000000;   //für mich ist das das aktievieren des Interrupts 
INT0
MCUCR = 0b00000001;   // und das beim Ereignis sobald sich eine Flanke 
ändert
> sei();              // das war das allgemeine einschalten der Interrupts


kann sein das ich mich jetzt bei GIMSK/MCUCR vertan habe, habe das 
Datenblatt nicht mehr auf gerade.

hab nur gedacht, man müsste den Taster nochmal extra einfügen irgendwo.

von Stefan F. (Gast)


Lesenswert?

Marcel R. schrieb:
> hab nur gedacht, man müsste den Taster nochmal extra einfügen irgendwo.

Warum denn?

Der Taster löst den Interrupt aus, der Interrupt sorgt dafür, dass die 
ISR angesprungen wird. Da fehlt nichts.

von Marcel R. (marcelr1588)


Lesenswert?

Gute Frage warum :D
Naja ich hab bisher noch nie was mit programmieren zu tun gehabt, tu 
mich deshalb noch ein wenig schwer damit.

Aber es kann ja nur besser werden :)

Danke dir auf jedenfall für deine Hilfe/Zeit.

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.