AT Mega 88 Interrupt

Gast #3242898
Lesenswert?

Hallo,

ich möchte über einen Tastendruck (fallende Flanke) den Interrupt INT1 
auslösen.

passen die Registereinstellungen?
1
 //Interrupt INT1 auf fallende Flanke definiert
2
  EICRA = 0x08;
3
  EIMSK = 0x02;
das ist dann der Interrupt Aufruf:
1
ISR (INT1_vect)
2
{
3
  ChargeCurrent_Write_Speed();
4
  ChargeVoltage_Write();
5
  InputCurrent_Write();
6
}
Muss ich noch irgendwas einstellen?? Es tut sich nichts wenn ich auf die 
Taste drücke es wird kein Interrupt ausgelöst...
#3242901
Lesenswert?

sei(); eingegeben? Aktiviert die Interrupts global.

sonst sind die Interrupts nicht aktiviert!

Zeig ansonsten mal bitte deinen ganzen Code, dann kann man besser 
helfen.

Ersetze die Konstanten wie z.B. 0x12 usw. in Zukunft durch so etwas wie 
z.B. (1 << INTF0) oder was du da gerade machst. Man sieht es viel besser 
was passiert.
Gast #3242915
Lesenswert?

Johannes O. schrieb:
> sei(); eingegeben? Aktiviert die Interrupts global.
>
> sonst sind die Interrupts nicht aktiviert!
>
> Zeig ansonsten mal bitte deinen ganzen Code, dann kann man besser
> helfen.
>
> Ersetze die Konstanten wie z.B. 0x12 usw. in Zukunft durch so etwas wie
> z.B. (1 << INTF0) oder was du da gerade machst. Man sieht es viel besser
> was passiert.

hier ist die Anpassung:
 //Interrupt INT1 auf fallende Flanke definiert
  EICRA = (1 << ISC11);
  EIMSK = (1 << INT1);

ISR (INT1_vect)
{
  ChargeCurrent_Write_Speed();
  ChargeVoltage_Write();
  InputCurrent_Write();
}

geht leider aber immer noch nicht.

Muss ich noch was definieren ? Habe ich was übersehen?
Gast #3242932
Lesenswert?

Johannes O. schrieb:
> Bitte mal den GANZEN Code. Hast du sei() drin?


das ist der gesamte relevante code:
1
//Interrupt INT1 auf fallende Flanke definiert
2
  EICRA = (1 << ISC11);
3
  EIMSK = (1 << INT1);
4

5

6
ISR (INT1_vect)
7
{  __enable_interrupt;
8
  ChargeCurrent_Write_Speed();
9
  ChargeVoltage_Write();
10
  InputCurrent_Write();
11
}
Passt das soweit mit den Registern?
#3242937
Lesenswert?

Amateur schrieb:
> Johannes O. schrieb:
>> Bitte mal den GANZEN Code. Hast du sei() drin?
>
>
> das ist der gesamte relevante code:

glaub ich kaum.

>
> //Interrupt INT1 auf fallende Flanke definiert
>   EICRA = (1 << ISC11);
>   EIMSK = (1 << INT1);
>
>
> ISR (INT1_vect)
> {  __enable_interrupt;

in der ISR die Interrupts freigeben?
Das kann aber nicht dein Ernst sein.

Zeig halt mal alles oder bau dir ein abgespecktes Beispiel, wenn dir der 
Code insgesamt als zu viel vorkommt.

Ein einfaches Beispiel, bei dem der Interrupt eine LED einschaltet und 
sonst nichts im Programm ist, reicht ja schon um die Funktionsgruppe 
'externer Interrupt' zu testen, zu debuggen und in Betrieb zu nehmen. 
Das was man dann daran lernt wendet man aufs eigentliche Programm an.
#3242940
Lesenswert?

Amateur schrieb:
> Johannes O. schrieb:
>> Bitte mal den GANZEN Code. Hast du sei() drin?
>
>
> das ist der gesamte relevante code:
Den ganzen Code. Nicht was du für relevant hältst.
Wie oft denn noch?
>
> //Interrupt INT1 auf fallende Flanke definiert
>   EICRA = (1 << ISC11);
>   EIMSK = (1 << INT1);
>
>
> ISR (INT1_vect)
> {  __enable_interrupt;
Was ist denn das für ein Unsinn?

>   ChargeCurrent_Write_Speed();
>   ChargeVoltage_Write();
>   InputCurrent_Write();
> }
>
> Passt das soweit mit den Registern?

mfg.
Gast #3242960
Lesenswert?

1
#ifndef _DEFINITIONEN_H_
2
#define _DEFINITIONEN_H_
3

4
// ***** Anfang allgemeine Includes
5
#include <avr/io.h>    // ATmega88 Definitionen
6
//#include <inavr.h>    // IAR Definitionen
7
#include <stdio.h>    // Standard I/O Definitionen
8
// ***** Ende allgemeine Includes
9

10

11
// ***** Beginn Systemkonfiguration
12

13
// ***** Ende Systemkonfiguration
14

15

16
// ***** Anfang Direktiven
17
#ifndef setbit                                         // Bit setzen durch ODER-Maskierung
18
#define setbit(p,n) (p|=(1<<n))
19
#endif
20

21
#ifndef clearbit                                       // Bit rücksetzen durch UND-Maskierung
22
#define clearbit(p,n) (p&=~(1<<n))
23
#endif
24
// ***** Ende Direktiven
25

26

27
// ***** Beginn diverses
28
#define ON            1               // Definition On
29
#define OFF           0               // Definition Off
30
#define SW_VERSION    0x01
31

32

33
#define __no_operation() __asm__ volatile ("nop")
34
#define __enable_interrupt() __asm__ volatile ("sei")
35
#define __disable_interrupt() __asm__ volatile ("cli")
36
#define __watchdog_reset() __asm__ volatile ("wdr")
37

38
#endif /*_DEFINITIONEN_H_*/
1
 //Interrupt INT1 auf fallende Flanke definiert
2
  EICRA = (1 << ISC11);
3
  EIMSK = (1 << INT1);
4

5
__enable_interrupt;
6
ISR (INT1_vect)
7
{
8

9
  PORTC |= ( 1 << PC0);
10

11
}

Was fehlt noch was damit diese "einfache" InterruptFunktion aufgerufen 
wird?
#3242999
Lesenswert?

Den Port C auf Ausgang schalten.


Sag mal wird das eine Verarsche?
Was ist denn bitte an
1
....
2

3
int main()
4
{
5
  DDRC |= ( 1 << PC0 );
6

7
  DDRD &= ( 1 << PD3 );
8
  PORTD |= ( 1 << PD3 );
9

10
  EICRA = (1 << ISC11);
11
  EIMSK = (1 << INT1);
12

13
  __enable_interrupt;
14

15
  PORTC &= ~( 1 << PC0 );
16

17
  while( 1 )
18
    ;
19
}
das große Problem? Jeder der schon mal eine LED ein/ausgeschaltet hat, 
muss doch die restlichen Zutaten für ein simples Testprogramm im Schlaf 
runterbeten können.
Gast #3243905
Lesenswert?

Hallo hier ist der Quellcode der soweit auch funktioniert beim betätigen 
der Taste wird der Interrupt ausgelöst und die LED leuchtet.

Jetzt möchte ich aber aus dem Interrupt raus und die LED ausmachen. Wie 
setze ich das um?
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#define __enable_interrupt() __asm__ volatile ("sei")
4
#define __disable_interrupt() __asm__ volatile ("cli")
5

6

7

8

9
int main(void)
10
{
11
 
12
    DDRB = 0x06;
13
    PORTB = 0;
14
    
15
  
16
    DDRC = 0x3F;
17
    PORTC = 0;
18
    
19
    
20
    DDRD = 0x00;
21
    PORTD = 0x1F;
22
    
23
   
24
    
25
    //Interrupt INT1 
26
    __enable_interrupt();
27
    EICRA = (1 << ISC11);
28
    EIMSK = (1 << INT1);
29
   
30
   
31
    while(1)
32
    {
33
        
34
    }
35
}
36

37

38
ISR (INT1_vect)
39
{
40
  PORTB |= ( 1 << PB2);
41
  __disable_interrupt();
42
  
43
}


P.S bitte nicht gleich "steinigen" wenn es zu einfach ist .....
#3243908
Lesenswert?

Amateur schrieb:

> Jetzt möchte ich aber aus dem Interrupt raus und die LED ausmachen. Wie
> setze ich das um?

Du willst nicht 'aus dem Interrupt raus'.
Du willst dir im Interrupt in einer globalen Variablen (die volatile 
sein muss) vermerken, dass die LED auzuschalten ist.

Und die Hauptschleife sieht sich diese globale Variable an und wenn dort 
der 'Befehl' zum ausmachen der LED auftaucht, dann macht sie das und 
setzt den 'Befehl' wieder zurück.


> P.S bitte nicht gleich "steinigen" wenn es zu einfach ist .....

Es geht nicht um "einfach".
Es geht darum, dass diese Taktik der Problem-Präsentation in 
homöopathischen Dosen einfach nur nervt. Speziell wenn schon x-mal nach 
komplettem Code nachgefragt wurde und du dann immer noch nicht 
reagierst.
#3243913
Lesenswert?

Das hier
1
ISR (INT1_vect)
2
{
3
  PORTB |= ( 1 << PB2);
4
  __disable_interrupt();
5
  
6
}
(gemeint ist der _disable_interrupt) bringt dir genau gar nichts.
Denn der Code ist hier in einer ISR.
* während des Betretens der ISR werden die Interrupts abgeschaltet. d.h. 
alleine dadurch, dass das eine ISR ist, ist damit implizit verknüpft, 
dass vor deinem Code ein __disable_interrupt() gemacht wird
* beim Verlassen der ISR werden Interrupts automatisch wieder 
zugelassen. D.h. alleine dadurch, dass das eine ISR ist, ist damit 
implizit verknüpft, dass am Ende der Funktion, als allerletztes (also 
nachdem alle Aufräumarbeiten der Funktion gemacht wurden) als Teil der 
Returns ein __enable_interrupt() durchgeführt wird. Tatsächlich ist es 
so, dass es für diesen Fall eine spezielle Prozessorinstruktion gibt, 
die beides gleichzeitig macht: Return und Interrupts freigeben. Weil es 
eben wichtig ist, das hier die zeitliche Reihenfolge stimmt.

Fazit:
1) dein __disable_interrupt() bringt überhaupt nichts
2) vergreifst du dich innerhalb einer ISR an dieser Freigabe, dann 
kannst du maximal auf die Schnauze fallen (wenn du nicht exakt und 100% 
weißt was du tust).
Gast #3243915
Lesenswert?

Kurz nachdem du die LED eingeschaltet hast, bist du doch schon wieder 
aus dem Interrupt raus.
Warum hast du eigentlich
1
 __disable_interrupt();
in der Interruptroutine stehen?
Und ganz abgesehen davon, warum ersetzt du
1
cli();
2
durch
3
 __disable_interrupt();
und
1
sei();
2
durch
3
 __enable_interrupt();

Ist dir cli(); und sei(); zu kurz? :-)

LED ausschalten:
Fallende Flanke auswerten und dann mit
1
PORTB &= ~(1 << PB2);
die LED wieder ausmachen.
Gast #3243934
Lesenswert?

hilmar schrieb:
> Kurz nachdem du die LED eingeschaltet hast, bist du doch schon
> wieder
> aus dem Interrupt raus.
> Warum hast du eigentlich __disable_interrupt();
> in der Interruptroutine stehen?
> Und ganz abgesehen davon, warum ersetzt ducli();
> durch
>  __disable_interrupt();
> undsei();
> durch
>  __enable_interrupt();

>
> Ist dir cli(); und sei(); zu kurz? :-)
hat der Compiler(AVR-Studio 6.1) erst nicht genommen jetzt komischer 
weise schon
>
> LED ausschalten:
> Fallende Flanke auswerten und dann mitPORTB &= ~(1 << PB2);
> die LED wieder ausmachen.


wie werte ich denn die fallende Flanke aus?
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3

4

5

6
volatile unsigned int Merker;
7

8
int main(void)
9
{
10
 
11
    DDRB = 0x06;
12
    PORTB = 0;
13
    
14
  
15
    DDRC = 0x3F;
16
    PORTC = 0;
17
    
18
    
19
    DDRD = 0x00;
20
    PORTD = 0x1F;
21
  
22
  Merker;
23
    
24
   
25
    
26
    //Interrupt INT1 
27
    sei();
28
  
29
    EICRA = (1 << ISC11);
30
    EIMSK = (1 << INT1);
31
   
32
   
33
    while(1)
34
    {
35
        
36
    }
37
}
38

39

40
ISR (INT1_vect)
41
{
42
  PORTB |= ( 1 << PB2);
43
  
44
  Merker = PORTB &= ~ ( 1 << PB2);
45
}
Gast #3243963
Lesenswert?

Du mußt in deiner Interrupt-Routine umschalten von steigender auf 
fallende Flanke und umgedreht. Also immer abwechselnd. Dafür hast du ja 
den Marker eingeführt. Das Bit ISC11=1 und ISC10=0 sagt dem Interrupt, 
daß er die fallende Flanke auswerten soll (so wie du es jetzt hast). 
Wenn du ISC11 auch auf 1 setzt, wird die steigende Flanke ausgewertet. 
Und das mußt du immer umschalten. Das heißt, erst fallende Flanke und 
beim nächten Interrupt steigende Flanke usw.

Du kannst auch nur die fallende Flanke auswerten und dann in der 
Interrupt-Routine die LED einmal ein- und das nächste Mal ausschalten.

Bei deinen Versuchen wirst du bestimmt merken, daß du manchmal mehrmals 
drücken mußt, damit was passiert. Dann kommt das Thema Entprellung zum 
Tragen. Aber dazu wurde hier im Forum schon eine ganze Menge 
geschrieben.
#3243979
Lesenswert?

1
ISR (INT1_vect)
2
{
3
  PORTB |= ( 1 << PB2);
4
  
5
  Merker = PORTB &= ~ ( 1 << PB2);
6
}

du schaltest die LED ein und gleich darauf wieder aus?
(oder umgekehrt, je nachdem wie die LED angeschlossen ist)

Wenn du nicht sehr gute Augen hast, dann wirst du das nicht wirklich 
feststellen können. Eigentlich, das kann nur Superman.

Gemeint war das ganze zb so
1
...
2

3
#define LED_ON   0x01
4

5
volatile uint8_t Command;
6

7
int main()
8
{
9

10
  ....
11

12
  while( 1 )
13
  {
14

15
    if( Command == LED_ON )
16
    {
17
      Command = 0;
18
      _delay_ms( 1000 );
19
      PORTB &= ~(1 << PB0);   // und wieder aus
20
    }
21
  }
22
}
23

24
ISR( .... )
25
{
26
  PORTB |= (1 << PB0);   // LED ein ....
27
  Command = LED_ON;      // Hauptschleife benachrichtigen, dass die LED brennt
28
}

der delay_ms da drinnen ist natürlich nicht der Weisheit letzter 
Schluss. Er dient nur dazu, dass die LED eine gewisse wahrnehmbare Zeit 
leuchtet. Um mit externen Interrupts zu experimentieren reicht das, mehr 
aber auch nicht. Zumal man Tasten sowieso anders auswertet und nicht mit 
externen Interrupts. Aber so wie ich das im Moment noch verstehe, geht 
es nicht im eigentlichen Sinn um Tasten (die Taste ist nur Mittel zum 
Test-Zweck) sondern darum, dass irgendein Signal einen Interrupt 
auslösen soll.


Edit: Ach ja. Weil ich es gesehen habe.
Gewöhn dir diese int-Rundumschläge gleich wieder ab. Es ist sinnlos, 
wenn du den µC in 16-Bit Arithmetik treibst, wenn es 8 Bit auch tun. UNd 
an dieser Stelle ist das sogar ziemlich wichtig, weil der µC einen 8-Bit 
Wert atomar (in einem Rutsch ohne Unterbrechung) auswerten kann, einen 
16 Bit Wert aber nicht.
Gast #3244388
Lesenswert?

Karl Heinz Buchegger schrieb:
> ISR (INT1_vect)
> {
>   PORTB |= ( 1 << PB2);
>
>   Merker = PORTB &= ~ ( 1 << PB2);
> }
>
> du schaltest die LED ein und gleich darauf wieder aus?
> (oder umgekehrt, je nachdem wie die LED angeschlossen ist)
>
> Wenn du nicht sehr gute Augen hast, dann wirst du das nicht wirklich
> feststellen können. Eigentlich, das kann nur Superman.
>
> Gemeint war das ganze zb so
> ...
>
> #define LED_ON   0x01
>
> volatile uint8_t Command;
>
> int main()
> {
>
>   ....
>
>   while( 1 )
>   {
>
>     if( Command == LED_ON )
>     {
>       Command = 0;
>       _delay_ms( 1000 );
>       PORTB &= ~(1 << PB0);   // und wieder aus
>     }
>   }
> }
>
> ISR( .... )
> {
>   PORTB |= (1 << PB0);   // LED ein ....
>   Command = LED_ON;      // Hauptschleife benachrichtigen, dass die LED
> brennt
> }
>
> der delay_ms da drinnen ist natürlich nicht der Weisheit letzter
> Schluss. Er dient nur dazu, dass die LED eine gewisse wahrnehmbare Zeit
> leuchtet. Um mit externen Interrupts zu experimentieren reicht das, mehr
> aber auch nicht. Zumal man Tasten sowieso anders auswertet und nicht mit
> externen Interrupts. Aber so wie ich das im Moment noch verstehe, geht
> es nicht im eigentlichen Sinn um Tasten (die Taste ist nur Mittel zum
> Test-Zweck) sondern darum, dass irgendein Signal einen Interrupt
> auslösen soll.
>
> Edit: Ach ja. Weil ich es gesehen habe.
> Gewöhn dir diese int-Rundumschläge gleich wieder ab. Es ist sinnlos,
> wenn du den µC in 16-Bit Arithmetik treibst, wenn es 8 Bit auch tun. UNd
> an dieser Stelle ist das sogar ziemlich wichtig, weil der µC einen 8-Bit
> Wert atomar (in einem Rutsch ohne Unterbrechung) auswerten kann, einen
> 16 Bit Wert aber nicht.

okay super Danke! Funktioniert soweit.

Jetzt möchte ich gerne das bei Tastendruck die Anweisungen in der 
Interruptroutine dauerhaft in eine Schleife ausgeführt wird.

Finde aber keinen Ansatz ...
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4

5
// Prototyp
6
void schnellladen (void);
7

8
 volatile uint8_t Merker;
9
 #define Zustand 0x01
10

11
int main()
12
{
13
    DDRB = 0x06;
14
    PORTB = 0;
15
    
16
    
17
    DDRC = 0x3F;
18
    PORTC = 0;
19
    
20
    
21
    DDRD = 0x00;
22
    PORTD = 0x1F;
23
           
24
    
25
    //Interrupt INT1
26
    sei();
27
    
28
    EICRA = (1 << ISC11);
29
    EIMSK = (1 << INT1);
30
  
31

32
  while( 1 )
33
  {
34

35
    schnellladen();
36
  }
37
}
38

39
ISR( INT1_vect )
40
{
41
  Merker = Zustand;
42
}
43

44
void schnellladen (void)
45
{
46
while ( Merker == Zustand)
47
  {
48
    Merker = 0;
49
    ChargeCurrent_Write_Speed()
50
    ChargeVoltage_Write();
51
    InputCurrent_Write()
52
  }
53
}
Gast #3244404
Lesenswert?

> Jetzt möchte ich gerne das bei Tastendruck die Anweisungen in der
> Interruptroutine dauerhaft in eine Schleife ausgeführt wird.

Also immer wieder
> Merker = Zustand;
bis zum Sanktnimmerleinstag...

Grundsatz: So wenig wie möglich im Interrupt machen und alles andere 
außerhalb. Flags setzen (so wie du es machst) ist ok. Und dann außerhalb 
auf die Flags reagieren.

Also was soll wiederholt werden?
#3244639
Lesenswert?

Amateur schrieb:
>> Ist dir cli(); und sei(); zu kurz? :-)
> hat der Compiler(AVR-Studio 6.1) erst nicht genommen jetzt komischer
> weise schon
Das ist nicht komisch. Ein Compiler ist das humorloseste, was es gibt.
Die beiden sind in "interrupt.h" definiert. Und die muß natürlich auch 
included sein.

War sie aber vorher nicht:
> // ***** Anfang allgemeine Includes
> #include <avr/io.h>    // ATmega88 Definitionen
> //#include <inavr.h>    // IAR Definitionen
> #include <stdio.h>    // Standard I/O Definitionen
> // ***** Ende allgemeine Includes

Wenn der Compiler etwas nicht kennt, was er kennen sollte, bastelt man 
sich keine Würgeraunds. Damit kann man sich ganz üble Probleme schaffen.

mfg.
#3244647
Lesenswert?

Amateur schrieb:

> void schnellladen (void)
> {
> while ( Merker == Zustand)
>   {
>     Merker = 0;
>     ChargeCurrent_Write_Speed()
>     ChargeVoltage_Write();
>     InputCurrent_Write()
>   }
> }


Nicht
while ( Merker == Zustand )

in deinem Fall dann eben einfach
1
  if ( Merker == Zustand )
2
    ChargeCurrent_Write_Speed()
3
    ChargeVoltage_Write();
4
    InputCurrent_Write()
5
  }
die Schleife drummherum besorgt dann sowieso die Hauptschleife in main.

Du musst dir dann halt nur überlegen, wann 'Merker' wieder auf 0 
zurückgesetzt werden soll. Also: Wann genau sollen die Texte wieder 
verschwinden bzw. nicht mehr upgedatet werden? Was ist die Bedingung 
dafür? Könnte es sein, dass dieses genau dann der Fall ist, wenn die 
Akkus voll sind? Dann kommt dann eben dort das Rücksetzen dieses Flags 
dazu, wo dieses festgestellt wird.

PS: Nenn das nicht Merker. Das ist ein selten dämlicher Name, der genau 
gar nichts aussagt. Was ist seine Funktion? Und nach der benennst du 
ihn. Zb ShowValues oder ChargeAkku oder .... Benenne Variablen nach 
ihrer logischen Funktion und nicht danach, wie sie intern implementiert 
sind.

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