Forum: Compiler & IDEs Pin Change Interrupt Mega 644P - Bin ich echt zu doof?


von Mos K. (moscito)


Lesenswert?

Moin zusammen,

hab da ein echt komisches Phänomen.
Versuche mich gerade mit dem Pin Change Interrupt und habe natürlich das 
Datenblatt vorher gelesen.

Bei diesem einfachen Code funktioniert der Pin Change Interrupt nur, 
wenn ich in der Main vor der Hauptschleife das blink Unterprogramm 
aufrufe.
Lasse ich die Zeile mit dem Casus Knaxus weg, blinkt nichts ?!

Sieht irgendwie so aus, als würde der Compiler die blink Funktion 
wegoptimieren.

Es handelt sich hierbei um das Crumb644-Net und den WinAVR Portable 
(20090313).

Ich raffs nicht mehr ... Hat von Euch jemand einen Tipp?


Danke !



1
/*
2
* Chip type           : ATMEGA 644
3
* Clock frequency     : External clock 20 Mhz 
4
5
*/
6
7
// ************************************************************************************************ 
8
// Include Dateien laden
9
// ************************************************************************************************ 
10
#include  <avr\io.h>  //AVR Register und Konstantendefinitionen
11
#include  <avr\interrupt.h> //AVR Interrupt Vektoren
12
#include  <util\delay.h>
13
14
//Funktionsprototypen
15
void blink(void);
16
 
17
int main(void)
18
{
19
  DDRD &= ~(1 << PD6);          //Pin D6 als Eingang
20
  DDRB = 0xFF;            //Port B komplett als Ausgang
21
  PCMSK3 |= (1 << PCINT30);      //Pin D6 für Pin Change Interrupt in Maske 3 setzen
22
  PCICR  |= (1 << PCIE3);      //Pin Change Interrupt Control Register - PCIE3 setzen für PCINT30
23
24
  //blink();              // ************ CASUS KNAXUS ***************
25
  sei();                //Interrupts enablen
26
  
27
  while(1)
28
    {
29
      
30
                    //Dauerloop
31
32
    }    
33
}//Main
34
35
ISR(PCINT0_vect)            //Interrupt Service Routine
36
{
37
  cli();                //Interrupts disablen
38
  blink();              //Einmal kurz blinken
39
  sei();                //Interrupts wieder enablen
40
} //ISR
41
42
 void blink (void)            //Blinkroutine
43
 {
44
  PORTB |= (1<<PB6);          
45
   _delay_ms(100);
46
  PORTB &= ~(1<<PB6);
47
 } //toggle

von Oliver (Gast)


Lesenswert?

Mos Kito schrieb:
> Sieht irgendwie so aus, als würde der Compiler die blink Funktion
> wegoptimieren.

Mit Sicherheit nicht.

Ich habe jetzt das Datenblatt nicht hier, aber prüfe nochmals nach, ob 
du die richtige ISR zum freigegeben Interrupt hast. Wenn nicht, startet 
das Programm bei jedem Interrupt von vorne, und blinkt dann natürlich, 
wenn blink() in main steht.

Oliver

von Justus S. (jussa)


Lesenswert?

- wirf das cli und sei aus der ISR
- benutz die richtige ISR zu deinem Interrupt

von Werner B. (werner-b)


Lesenswert?

Unabhängig vom Problem:
Verwende "/" in den Includes.
1. Portabel zwischen Win und *nix
2. Wirst du generell weniger Problem damit haben (z.B. im AVR Studio 4).
z.B.
1
#include  <avr/io.h>  //AVR Register und Konstantendefinitionen

Für das einfache Testprogramm mag es OK sein, aber generell sind 
_delay_xxx in ISR mit extremer Vorsicht zu genießen.

von Mos K. (moscito)


Lesenswert?

Zuerst mal Danke für Eure Antworten.

@Justus:
Der Rauswurf von cli und sei hat erwartungsgemäß nichts gebracht.
Was meinst Du mit "die richtige ISR"?

@All
Wenn ich die blink() Funktion vor dem Loop einmal aufrufe blinkt es nach 
dem Reset natürlich einmal und danach funktioniert auch der Interrupt 
wunderbar. Lasse ich den Aufruf weg, geht auch der Interrupt nicht.
Das ist es ja, was mich verblüfft...

von Justus S. (jussa)


Lesenswert?

Mos Kito schrieb:
> @Justus:
> Der Rauswurf von cli und sei hat erwartungsgemäß nichts gebracht.

hat aber in der ISR nichts zu suchen, das macht die schon von alleine...

> Was meinst Du mit "die richtige ISR"?

PCINT0_vect
und
PCMSK3 |= (1 << PCINT30);
passen nicht wirklich zusammen...

von Oliver (Gast)


Lesenswert?

Mos Kito schrieb:
> danach funktioniert auch der Interrupt
> wunderbar

Nö. Wenn du die falsche ISR hast, erzeugt dir jeder Interrupt ein Reset, 
und es blinkt auch.

Und wenn dein Kommentar
>//Pin Change Interrupt Control Register - PCIE3 setzen für PCINT30

richtig ist, ist ISR(PCINT0_vect) wohl die falsche ISR.

Oliver

von Mos K. (moscito)


Lesenswert?

Ja krass!

Kaum verwende ich den PCINT3_vect statt dem PCINT0_vect - schon geht's.

Eigentlich logisch ...

Super! Vielen Dank!!!!


@Justus:
Verstehe ich das richtig? Während die Interrupt Service Routine 
durchlaufen wird sind die Interrupts automatisch disabled?
Das war nämlich meine Sorge - ein Interrupt im Interrupt...

von Oliver (Gast)


Lesenswert?

Bei den AVR's ist das so.

Oliver

von Mos K. (moscito)


Lesenswert?

Gut zu wissen. Danke!!

von ... (Gast)


Lesenswert?

Oliver schrieb:
> Bei den AVR's ist das so.

Das hat nichts mit dem AVR zu tun sondern mit der avr-libc. In älteren 
Versionen gabs dafür extra zwei unterschiedliche Makros für 
ISR-Routinen, eimal mit ausgeschalteten, einmal mit eingeschalteten 
Interrupts. In aktuellen Versionen gibt es dafür einen zusätzlichen 
Parameter im 'ISR'-Makro.
1
ISR(PCINT3_vect) {}               // default, interrupts disabled
2
ISR(PCINT3_vect, ISR_BLOCK) {}    // interrupts disabled
3
ISR(PCINT3_vect, ISR_NOBLOCK) {}  // interrupts enabled

von Mos Kito (Gast)


Lesenswert?

Sehr gute Info ... Gast.

Habe gerade die Attribute in meiner interrupt.h gefunden.

So einfach kann es sein, wenn man es weiß.


Thx!

von Peter D. (peda)


Lesenswert?

... schrieb:
> Das hat nichts mit dem AVR zu tun sondern mit der avr-libc.

Mit dem AVR hat das schon was zu tun, der hat nämlich keine 
Interruptprioritäten.

Bei einem MC mit Prioritäten (z.B. 8051) kann ein Interrupt durch einen 
mit höherer Priorität unterbrochen werden. Er kann sich sogar selbst 
unterbrechen, wenn man im Handler die Priorität hochsetzt. Die Anzahl 
der Instanzen ist aber durch die Anzahl der Prioritätsstufen begrenzt, 
also kann es keinen Stacküberlauf geben.

Im Gegensatz dazu kann beim AVR das
1
ISR(PCINT3_vect, ISR_NOBLOCK) {}  // interrupts enabled
zu einem Stacküberlauf führen und ist daher mit äußerster Vorsicht zu 
verwenden.


Peter

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.