Zustände schalten mit Interrupt

Gast #3369876
Lesenswert?

Hallo mikrocontroller.net Gemeinde!

Da ich in Sachen yC-Programmierung noch ziemlich grün hinter den Ohren 
bin und mich bestehende Forumeinträge nicht weitergebracht haben, hier 
meine erste Frage:

Mit meinem Atmega8 will ich 3 LEDs mit einem Taster durchschalten 
können. Sprich bei jedem Tastendruck in den nächsten Zustand schalten. 
Das soll per Interrupt realisiert werden.
Was hab ich bei meinem Code vergessen? Die Ausgänge flackern wild hin 
und her... :(
Vielen Dank für eure Mühe.
Gruß Michi

Hier mein Code:

1
#define F_CPU 3686000UL
2
#include <util/delay.h>
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5

6
int i=0;
7

8
ISR(INT0_vect)
9
{
10
  _delay_ms(20);
11
  i++;
12
  
13
}
14

15
void eins() 
16
{
17
  PORTD=0b10000000;
18
}
19

20
void zwei()
21
{
22
  PORTD=0b01000000;
23
}
24

25
void drei()
26
{
27
  PORTD=0b00100000;
28
}
29

30
int main(void)
31
{
32
  
33
  DDRD=0b11100000;
34
        PORTD |= ( 1<<PD2 );  //pull up aktivieren
35
  
36
  GICR = ( 1<<INT0 );
37
  MCUCR = ( 0<<ISC01 | 0<<ISC00 );
38
  GIMSK = ( 1<< INT0 );
39

40
  sei();
41
  
42
  
43
  while(1)
44
    {
45
    
46
    if (i==0) 
47
    {  
48
      eins();  
49
    }
50
    else if (i==1)
51
    {
52
      zwei();
53
    }
54
    else if (i==2)
55
    {
56
      drei();
57
    }
58
    else
59
      i=0;
60
  }
61
}
#3369879
Lesenswert?

Michi R. schrieb:

> Mit meinem Atmega8 will ich 3 LEDs mit einem Taster durchschalten
> können. Sprich bei jedem Tastendruck in den nächsten Zustand schalten.
> Das soll per Interrupt realisiert werden.

Warum?
Taster und externer Interrupt sind eine blöde Idee, auch wenn das immer 
wieder propagiert wird.
Entprellung
die Konmfortroutinen vom PeDa sind alles was man braucht um Tasten 
zuverlässig auszuwerten.
#3369885
Lesenswert?

>
1
>   MCUCR = ( 0<<ISC01 | 0<<ISC00 );
2
>

so, so.
Und du denkst also, dass du innerhalb von 20 Millisekunden eine Taste 
drücken und wieder loslassen kannst.

Der Interrupt kommt, solange der Pin auf Low-Pegel ist und auch auf 
Low-Pegel bleibt! Bei dir: solange die Taste gedrückt ist, kommt ein 
Interrupt nach dem anderen.
Gast #3369894
Lesenswert?

;) So ists besser:

MCUCR = ( 1<<ISC01 | 0<<ISC00 );

Macht aber noch immer nicht, was es soll...
Ich dachte, für diese einfache Anwendung tuts auch ein externer 
Interrupt mit Taster! Bei der "Komfortroutine" blick ich ehrlich gesagt 
nicht wirklich durch...
#3369896
Lesenswert?

Michi R. schrieb:
> ;) So ists besser:
>
> MCUCR = ( 1<<ISC01 | 0<<ISC00 );
>
> Macht aber noch immer nicht, was es soll...
> Ich dachte, für diese einfache Anwendung tuts auch ein externer
> Interrupt mit Taster!

Wie du siehst, ist das eben nicht einfach.

Einfach wäre ein Pollen in der Hauptschleife mit Vergleich ob sich der 
zustand des Input-Pins verändert hat.

> Bei der "Komfortroutine" blick ich ehrlich gesagt
> nicht wirklich durch...

Das macht nichts. Dazu funktionieren sie zu gut.

PS: Welchen Prozessor hast du wirklich? Ein Mega 8 hat kein Register 
namens GIMSK
Gast #3369898
Lesenswert?

Grrr. Bekomm ich doch gleich die volle Breitseite.

Karl Heinz Buchegger schrieb:
> PS: Welchen Prozessor hast du wirklich? Ein Mega 8 hat kein Register
> namens GIMSK

Ich hab nen Atmega8! Komisch, dass er da nicht rummeckert. ;)

Karl Heinz Buchegger schrieb:
> Gratuliere, du hast dir soeben den notwendigen Pullup Widerstand am Pin
> 2 abgeschaltet.

Wie gesagt, bin ziemlicher Anfänger! Umso dankbarer bin ich für deine 
Korrektur.
#3370035
Lesenswert?

Michi R. schrieb:
> Grrr. Bekomm ich doch gleich die volle Breitseite.
>
> Karl Heinz Buchegger schrieb:
>> PS: Welchen Prozessor hast du wirklich? Ein Mega 8 hat kein Register
>> namens GIMSK
>
> Ich hab nen Atmega8! Komisch, dass er da nicht rummeckert. ;)

Ist in der Tat interessant.
Könnte ein Hinweis darauf sein, dass deine Projekteinstellungen nicht 
korrekt sind.
Nichts desto trotz: ein Mega 8 hat laut Datenblatt kein GIMSK Register. 
Atmel wird ja wohl wissen, wie die Dinger heißen
Gast #3370530
Lesenswert?

Wenn auch sehr unprofessionell geschrieben, so läuft das Programm 
tadellos:
Danke für die Vorschläge.
1
#define F_CPU 3686000UL
2
#include <util/delay.h>
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include <avr/sleep.h>
6
int i=0;
7

8
ISR(INT0_vect)
9
{
10
   _delay_ms(750);
11
  i++;
12
}
13

14
void eins() 
15
{
16
   PORTD &= ~((1<<PD5) | (1<<PD6));
17
   PORTD |= (1<<PD7);
18
}
19

20
void zwei()
21
{
22
  PORTD &= ~((1<<PD7) | (1<<PD5));
23
  PORTD |= (1<<PD6);
24
}
25

26
void drei()
27
{
28
  PORTD &= ~((1<<PD6) | (1<<PD7));
29
  PORTD |= (1<<PD5);
30
}
31

32
void nichts()
33
{
34
  PORTD &= ~((1<<PD6) | (1<<PD7) | (1<<PD5));
35
}
36

37
int main(void)
38
{
39
  DDRD=0b11100000;
40
        PORTD |= ( 1<<PD2 );    //pull up aktivieren
41
  
42
  GICR = ( 1<<INT0 );
43
  MCUCR = ( (1<<SE) | (1<<SM1) | (0<<ISC01) | (0<<ISC00) );
44

45
  sei();
46
  
47
  
48
  while(1)
49
    {
50
    
51
    if (i==0) 
52
    {  
53
      eins();  
54
    }
55
    else if (i==1)
56
    {
57
      zwei();
58
    }
59
    else if (i==2)
60
    {
61
      drei();
62
    }
63
    else if (i==3)
64
    {
65
      nichts();
66
      set_sleep_mode(SLEEP_MODE_PWR_DOWN);
67
      sleep_mode();
68
    }  
69
    else if (i>=4)
70
      i=0;
71
  }
72
}
#3370535
Lesenswert?

Michi R. schrieb:
> Wenn auch sehr unprofessionell geschrieben

In der Tat

> ISR(INT0_vect)
> {
>    _delay_ms(750);
>   i++;
> }

sowas ist Murks.

Auf der einen Seite benutzt du einen Interrupt, damit nur ja alles 
möglichst schnell reagiert (was eigentlich völlig sinnlos ist, denn für 
deinen µC bewegst du dich sowieso in Zeitlupe), auf der anderen Seite 
vertrödelst du dann genau hier die Zeit, damit dann ja alles, was der µC 
nebenher zu machen hätte (in einem richtigen Programm) zum Stillstand 
kommt.

So ist das Murks. Offen und ehrlich gesagt.
Einen durchgerosteten Kotflügel am Auto kann man auch mit Klebeband 
reparieren. Hält sogar eine Zeit lang. Murks ist es trotzdem.
Gast #3370550
Lesenswert?

Es sei Dir gestattet, daß Du es nicht besser kannst (Deine Aussage), daß 
Du aber lernen willst (auch Deine Aussgae) kann hier keiner erkennen. Du 
willst nur die LED leuchten sehen, auch wenn Du den größtmöglichen Murks 
ablieferst.

Lernen und Denken geht aber etwas anders.
Gast #3370583
Lesenswert?

> Du willst nur die LED leuchten sehen, auch wenn Du den größtmöglichen Murks
> ablieferst.

Es tut mir wirklich leid, dass mir das Freude bereitet. Wo ist denn das 
Problem, wenn ich mich langsam an die Sache rantasten möchte?

> Lernen und Denken geht aber etwas anders.

Gerne informiere ich dich über jeden einzelnen meiner Lernfortschritte.


kbuchegg, die Entprellung werde ich umgehend implementieren.

> Du aber lernen willst (auch Deine Aussgae) kann hier keiner erkennen.
---> jetzt aber! ;-)
#3370591
Lesenswert?

Wobei. Das muss ich heute am Abend direkt mal ausprobieren.
Meiner Meinung nach und ohne das jetzt laufen gelassen zu haben, dürfte 
diese Interrupt Lösung nicht funktionieren.
Das ist ein Level-Interrupt. Sobald die ISR betreten wird, wird das 
zugehörige Interrupt Flag erneut gesetzt, weil ja die Taste noch immer 
gedrückt ist, der Level also immer noch anliegt. Der delay_ms ändert 
daran nichts. Er sorgt mit seinen 750ms lediglich dafür, dass ich als 
Benutzer eine Chance habe, die Taste wieder loszulassen, ohne dass 
gleich alles Amok läuft. Aber die Schaltstufe um lediglich 1 zu erhöhen 
dürfte mir damit nicht gelingen. Mit einmal kurz drauf drücken erhöht 
sich die Stufe um mindestens 2. Das kann ich als Benutzer gar nicht 
verhindern.
Denke ich jetzt mal. Aber wie gesagt: das will ich tatsächlich mal 
ausprobieren, wie das jetzt wirklich ist. Denn da bin ich mir jetzt auch 
unsicher. Ich hab da noch im Hinterkopf, dass die Level Interrupts ein 
bisschen anders funktionieren als die anderen.
#3370603
Lesenswert?

Michi R. schrieb:
> Wie gesagt, bei mir läufts.
>
> Ich dachte, das Flag ist "geschützt", solange die ISR läuft?

Nö.
Keines der Interrupt Request Flags ist in irgendeiner Art und Weise 
geschützt. Sobald die ISR ausgelöst wird, werden sie wieder gelöscht.
Wobei beim INTF0 Flag in der Doku steht
1
This flag is always cleared when INT0 is configured
2
as a level interrupt.
Von daher verhält sich das in dem Fall ein wenig anders.


Edit: Du redest vom globalen Interrupt Flag.
Aber der komplette Interrupt Mechanismus ist ein wenig komplexer als nur 
dieses 1 Flag. Es muss ja auch einen Mechanismus geben, der das 
Auftreten eines Ereignisses registriert und festhält, während die CPU 
gerade in einer ISR einen ganz anderen Interrupt bearbeitet. Das 
Auftreten dieses 2-ten Interrupt Ereignisses soll ja deswegen nicht 
verloren gehen.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren