Forum: Mikrocontroller und Digitale Elektronik Problem mit externem Inerrupt


von Wayne I. (mustang)


Angehängte Dateien:

Lesenswert?

Hallo Gemeinde,

ich kämpfe hier gerade mit dem externen Interrupt des Atmega 32.

Initialisiert ist er folgendermaßen:

void init_interrupt0()
{
  DDRD &= ~ (1 << PD2);       //als Eingang deklarieren
  PORTD |=(1<<PD2);        //Pullup aktivieren
  GICR |= (1<<INT0);        //externen Interrupt 0 freigeben
  MCUCSR |=(1<<ISC01);      //Interrupt auf fallende Flanke
}

in der Interruptroutine steht folgendes:

ISR(INT0_vect)
{
  weiter =1;            //Boolsche Variable auf 1 setzen = 
Bestätigungsbedingung
}

Die globale Interruptfreigabe ( sei () ) erflogt im Hauptprogramm.

Angeschlossen daran ist ein entprellter Taster. Entrellung siehe 
Anahang.

Ich möchte eigentlich, dass der Interrupt genau einmal bei der Fallenden 
Flanke ausgelöst wird. Sollte ja laut Datenblatt so initalisiert werden. 
Tut er aber nicht, stattdessen löst er permanent Inerrupts aus, solange 
ich den Taster gedrück halte.
Was mache ich falsch. Wäre cool, wenn mir jemand weiterhelfen könnte.

von Spera (Gast)


Lesenswert?

Ist die weiter-Variable als volatile deklariert?

von wt (Gast)


Lesenswert?

wie lange prellt denn der Schalter?

von Wayne I. (mustang)


Lesenswert?

wt schrieb:
> wie lange prellt denn der Schalter?

gar nicht, da ja der Taster im moment des drückens den Kondensator 
schlagartig gegen Masse entlädt und somit auch dieses Potential an dem 
Interrupt eingang anliegt.
Diese Schaltung hat sich eigentlich bewährt die hab ich auf einem 
unserer experimentierboards in der Schule gesehen. Zwar an einem 8051 
aber das sollte ja keinen Unterschied machen.

Spera schrieb:
> Ist die weiter-Variable als volatile deklariert?

Ja, die "weiter- Variable" ist als volatile deklariert.

von Spera (Gast)


Lesenswert?

Und setzt du sie in der while Schleife auch wieder zurück?^^

Wäre besser, wenn du gleich den ganzen Source Code postest.

Grüße

von Spera (Gast)


Lesenswert?

Ich hab mir gerade die Schaltung angeschaut.
Wieso hast du einen externen Pull-up Widerstand, wenn du sowieso den 
internen nutzt?

Grüße

von Wayne I. (mustang)


Lesenswert?

Der komplette Code ist noch ziemlich lang und SEHR unübersichtlich.

Das ganze soll folgende Anwendung erfüllen:

Ich möchte über 2 Taster (1x Inerrupt / 1x Polling) und ein LCD Display 
die Ladeart und den Ladestrom eines Akkus einstellen.
Dazu ist die Taste die die Kapazität bzw. die Ladeart verändert im 
Pollingbetrieb geschalten und die OK Tast, die das ganze dann übernimmt 
im Interruptbetrieb, wofür die Variable weiter verantwortlich ist.

Hier mal die betreffenden Zeilen:
1
volatile bool weiter=0;          //OK Taste auswahlmenü
2
3
//*********************************************************************************************************************************
4
// Externen Interrupt 0 initialisieren
5
//**********************************************************************************************************************************
6
7
void init_interrupt0()
8
{
9
  DDRD &= ~ (1 << PD2);       //als Eingang deklarieren
10
  PORTD |=(1<<PD2);        //Pullup aktivieren
11
  GICR |= (1<<INT0);        //externen Interrupt 0 freigeben
12
  MCUCSR |=(1<<ISC01);      //Interrupt auf fallende Flanke
13
}
14
15
//************************************  END ****************************************************************************************
16
17
18
ISR(INT0_vect)
19
{
20
  weiter =1;            //Boolsche Variable auf 1 setzen = Bestätigungsbedingung
21
}
22
23
unsigned int AkkuSetting(char Akku)
24
{  
25
  weiter=0;
26
  char wahl =0;
27
  int Kapazitat=100;
28
  weiter=0;
29
  LcdClear();
30
  LcdGotoXY(3,1);
31
  LcdStr( FONT_1X," Akku ");
32
  LcdGotoXY(9,1);
33
  LcdStr( FONT_1X,dtostrf(Akku,1,0,string) );
34
  LcdUpdate();
35
36
  
37
  while (weiter <1)
38
  {
39
    if (wahl == 0)
40
    {
41
      LcdGotoXY(1,3);
42
      LcdStrINV( FONT_1X," Schnelladen ");
43
      LcdGotoXY(1,4);
44
      LcdStr( FONT_1X," 14h Laden ");
45
      LcdGotoXY(1,5);
46
      LcdStr( FONT_1X," Kapazitaet ");
47
      LcdUpdate();
48
    }
49
50
    if (wahl ==1)
51
    {
52
      LcdGotoXY(1,3);
53
      LcdStr( FONT_1X," Schnelladen ");
54
      LcdGotoXY(1,4);
55
      LcdStrINV( FONT_1X," 14h Laden ");
56
      LcdGotoXY(1,5);
57
      LcdStr( FONT_1X," Kapazitaet ");
58
      LcdUpdate();
59
  
60
    }
61
62
    if (wahl==2)
63
    {
64
      LcdGotoXY(1,3);
65
      LcdStr( FONT_1X," Schnelladen ");
66
      LcdGotoXY(1,4);
67
      LcdStr( FONT_1X," 14h Laden ");
68
      LcdGotoXY(1,5);
69
      LcdStrINV( FONT_1X," Kapazitaet ");
70
      LcdUpdate();
71
    }
72
  
73
    while (!(PIND& (1<<PD3))&&(weiter<0x01));    //Abwarten bis Taster gedrückt
74
    while ( PIND & (1 << PD3)&&(weiter<0x01));   //Abwarten bis Taster wieder gelöst oder Interrupt (OK Taste betätigt)
75
  
76
    wahl++;
77
78
    if (wahl==3)
79
    {
80
      wahl=0;
81
    }
82
  }
83
  wahl= wahl-1;
84
  LcdClear();
85
  LcdGotoXY(3,1);
86
  LcdStr( FONT_1X," Akku ");
87
  LcdGotoXY(9,1);
88
  LcdStr( FONT_1X,dtostrf(Akku,1,0,string) );
89
  LcdGotoXY(1,3);
90
  LcdStr( FONT_1X,"Kapazitaet?" );
91
  LcdUpdate();
92
  weiter =0;
93
  
94
  
95
  while (weiter<1)
96
  {
97
    LcdGotoXY(5,5);
98
    LcdStr( FONT_1X,dtostrf(Kapazitat,1,0,string));
99
    LcdGotoXY(10,5);
100
    LcdStr( FONT_1X,"mA/h" );
101
    LcdUpdate();
102
103
    while (!(PIND&(1<<PD3))&&(weiter0x01));
104
    while ( (PIND & (1 << PD3))&&(weiter<0x01)) ;
105
    
106
    Kapazitat = Kapazitat +100;
107
108
    if (Kapazitat ==3100)
109
    {
110
      Kapazitat =100;
111
      LcdGotoXY(8,5);
112
      LcdStr( FONT_1X," ");
113
    }
114
115
      
116
  }
117
118
  weiter=0;
119
  Kapazitat = Kapazitat -100;
120
         //Auswerten der Eingaben
121
122
  if (wahl==0)
123
  {
124
    Kapazitat = Kapazitat *2/3;
125
  }
126
127
  if (wahl==1)
128
  {
129
    Kapazitat = Kapazitat / 10;
130
  }
131
132
  if (wahl ==2)
133
  {
134
    Kapazitat = Kapazitat *2/3;
135
  }
136
137
  LcdClear();
138
  LcdGotoXY(3,1);
139
  LcdStr( FONT_1X," Akku ");
140
  LcdGotoXY(9,1);
141
  LcdStr( FONT_1X,dtostrf(Akku,1,0,string) );
142
143
  LcdGotoXY(1,3);
144
  LcdStr( FONT_1X,dtostrf(Kapazitat,1,0,string) );
145
  LcdUpdate();
146
        
147
  
148
  
149
  return Kapazitat;  
150
}

von Wayne I. (mustang)


Lesenswert?

Spera schrieb:
> Ich hab mir gerade die Schaltung angeschaut.
> Wieso hast du einen externen Pull-up Widerstand, wenn du sowieso den
> internen nutzt?

Berechtigte Frage!
Habe das ganze gerade so aus einem Schaltplan unseres Schulboards 
übernommen. Aber es ändert auch nichts, wenn ich den externen Pullup 
Widerstand ziehe und nur den internen verwende.

Ist der Interrupt überhaupt richtig initalisiert?
Gruß

von Spera (Gast)


Lesenswert?

Ist das der ganze Code?
Weil ich sehe keine main Funktion.

Grüße

von Spera (Gast)


Lesenswert?

Lass die Schaltung so wie sie ist und lass den internen Pullup 
Widerstand weg, indem du PORTD |=(1<<PD2); rauslöscht.

von Wayne I. (mustang)


Lesenswert?

Nein das ist nicht der komplette Code, jedoch greift der Interrupt nur 
auf diese Funktion zu. Also "weiter" wird nur in Akku Settings 
verwendet.

Das Problem ist eben, sobald ich den Interrupt auslöse, springt es mir 
wie gewünscht aus der while schleife wo ich die Ladeart (schnelladen, 
14h Laden, Kapazität) einstelle raus.
"weiter" wird ja danach wieder auf 0 gesetzt. Jedoch muss zeitgleich ein 
Interrupt kommen der Weiter sofort wieder auf 1 setzt und in die nächste 
while schleife (Eingabe der Kapazität) gar nicht mehr hineingesprungen 
wird, da die Bedingung zum beenden der while schleife bereits erreicht 
ist.

Ich hab mir vorhin mal den Spaß gemacht und anstatt einer Bool Variable 
ein int genommen. und deren wert in der Interruptroutine hochzählen 
lassen. Nach 1 Tastendruck stand die irgendwo zwichen 20000 und 40000 
also Taktzyklen. und das bei einem 8MHz Quarz.
Für mich sieht das so aus also ob der permanent interrupts bringt so 
lange der Taster gedrückt bleibt. Ich kann jedoch mit dem Datenblatt 
kein Indiz finden was ich falsch initalisiert habe.

Das deaktiviern von PORTD |=(1<<PD2); ändert auch nichts.

von Hannes L. (hannes)


Lesenswert?

> Ich hab mir vorhin mal den Spaß gemacht und anstatt einer Bool Variable
> ein int genommen. und deren wert in der Interruptroutine hochzählen
> lassen. Nach 1 Tastendruck stand die irgendwo zwichen 20000 und 40000
> also Taktzyklen. und das bei einem 8MHz Quarz.
> Für mich sieht das so aus also ob der permanent interrupts bringt so
> lange der Taster gedrückt bleibt. Ich kann jedoch mit dem Datenblatt
> kein Indiz finden was ich falsch initalisiert habe.

Schau Die mal PeDas Entprellung in Software (im Timer-Interrupt) an, 
sie enthält auch eine Flankenerkennung. Duch die Vierfachabfrage ist sie 
auch sehr störfest und kommt mit den labrigsten Tastern zurecht. Taster 
am ext.-Interrupt macht man eigentlich nur, wenn man damit den AVR aus 
dem Power-Down-Sleep holen will. Das eigentliche Tastenauslesen macht 
nach dem Wecken dann wieder der Timer-Int.

...

von Spera (Gast)


Lesenswert?

Genau. Für die Tastenabfrage würde ich auch einen Timer und keinen 
Interrupt verwenden.
Trotzdem würde ich dir raten, an deiner Stelle ein neues kleines Projekt 
zu machen, wo du versuchst, jeweils mit Interrupt und dannach mit Timer 
eine Taste abzufragen.
Wenn es dort funktioniert, kannst du es auch bei deinem großen Projekt 
verwenden.

Grüße

von Stefan E. (sternst)


Lesenswert?

Dirk K. schrieb:

> Ich hab mir vorhin mal den Spaß gemacht und anstatt einer Bool Variable
> ein int genommen. und deren wert in der Interruptroutine hochzählen
> lassen. Nach 1 Tastendruck stand die irgendwo zwichen 20000 und 40000

Weil du den Interrupt nicht auf Flanke konfiguriert hast.
Du setzt ISC01 im falschen Register.

von Spera (Gast)


Lesenswert?

Stimmt auch.
Du musst es im MCUCR Register setzen.
So wie du es jetzt hast, triggert der Interrupt solange, wie der INT0 
auf Low ist.

von Wayne I. (mustang)


Lesenswert?

Danke euch, das war es...
Wenn ich den ISC01 im MCUCR setze, dann geht es auch wie es soll. Weiß 
auch nicht woher ich noch ein S im MCUCR hatte. Komisch nur, dass der 
Kompiler nicht gemeckert hat.

Aber jetzt noch mal was grundlegendes. Tasterabfrage über Timer. Wie ist 
dabei die generelle Vorgehensweiße und welchen Vorteil bringt es mir im 
gegensatz zu dem externen Interrupt?

von Stefan E. (sternst)


Lesenswert?

Dirk K. schrieb:

> auch nicht woher ich noch ein S im MCUCR hatte. Komisch nur, dass der
> Kompiler nicht gemeckert hat.

Warum sollte er. MCUSR gibt es ja auch.

> Aber jetzt noch mal was grundlegendes. Tasterabfrage über Timer. Wie ist
> dabei die generelle Vorgehensweiße und welchen Vorteil bringt es mir im
> gegensatz zu dem externen Interrupt?

Och nö, das wurde hier doch schon mehrfach bis zum Erbrechen und bis in 
das letzte Detail "ausdiskutiert". Wiki und Suche liefern massenhaft 
Infos.

von Wayne I. (mustang)


Lesenswert?

Stefan Ernst schrieb:
> Och nö, das wurde hier doch schon mehrfach bis zum Erbrechen und bis in
>
> das letzte Detail "ausdiskutiert". Wiki und Suche liefern massenhaft
>
> Infos.

alles klar, dann les ich mich da mal schlau. Danke mal dafür

Stefan Ernst schrieb:
> Warum sollte er. MCUSR gibt es ja auch.

klingt logisch!

Vielen Dank nochmals für euere Hilfe.

von Hannes L. (hannes)


Lesenswert?

Dirk K. schrieb u.A.:

> Aber jetzt noch mal was grundlegendes. Tasterabfrage über Timer. Wie ist
> dabei die generelle Vorgehensweiße und welchen Vorteil bringt es mir im
> gegensatz zu dem externen Interrupt?

Ich habe nicht umsonst in meinem Beitrag weiter oben
Beitrag "Re: Problem mit externem Inerrupt"
das Wort Entprellung als Link eingesetzt... ;-)
Da ist das nämlich alles beschrieben bzw. da gibt es weiterführende 
Links. Brauchste nur zu lesen und zu verstehen. In der Codesammlung 
unter dem Suchbegriff "bulletproof" findest Du auch eine umfangreiche 
Diskussion, in der alle Fragen, die Dir einfallen könnten bereits 
gestellt und erschöpfend beantwortet wurden.

...

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.