Forum: Mikrocontroller und Digitale Elektronik Pin Change Interrupt - Controller hängt sich auf ab 40kHz - ATMega168


von Joshi (Gast)


Lesenswert?

Hallo,

ich habe das Problem dass sich der Controller ab einer Frequenz von 
ca.40kHz am Eingangspin aufhängt. Kann mir einer den Grund dafür 
erklären?

Vielen Dank

von Thomas B. (nichtessbar)


Lesenswert?

ohne dass du uns sagtst wie schnell der controller ist nicht...

und die Interruptroutine und deren Abarbeitungszeit wären auch nicht 
uninteressant...

von Peter D. (peda)


Lesenswert?

Joshi schrieb:
> Kann mir einer den Grund dafür
> erklären?

Ja.
Da ist ein Fehler in Deinem Programm.

Peter

von Joshi (Gast)


Lesenswert?

Der Controller läuft mit 8MHz und die Interruptroutine sieht 
folgendermaßen aus:
1
ISR(PCINT2_vect)
2
{
3
  PCINT_count++;
4
}

Alle 20ms wird dann der Counter abgefragt und wieder auf Null gesetzt.

Die Routine sieht folgendermaßen aus:
1
void read_PCINT(void)
2
{
3
  switch(PCINT_state)
4
  {
5
    case 0: 
6
    //disable PIN Change Interrupt
7
    PCICR &= ~(1 << PCIE2);
8
    
9
    //read the countet Interrupts
10
    PCINT_buffer[0] = PCINT_count;
11
            
12
    //set colour direction to red
13
    PORTC &= ~(1 << PC3);
14
    PORTC &= ~(1 << PC4);
15
16
    //restore counter value
17
    PCINT_count  = 0;
18
19
    //increase state
20
    PCINT_state++;
21
22
    //enable PIN Change Interrupt
23
    PCICR |= (1 << PCIE2);
24
    break;
25
26
    case 1:  
27
    //disable PIN Change Interrupt
28
    PCICR &= ~(1 << PCIE2);
29
    
30
    //read the countet Interrupts
31
    PCINT_buffer[1] = PCINT_count;
32
            
33
    //set colour direction to green
34
    PORTC |= (1 << PC3);
35
    PORTC &= ~(1 << PC4);
36
37
    //restore counter value
38
    PCINT_count  = 0;
39
40
    //increase state
41
    PCINT_state++;
42
43
    //enable PIN Change Interrupt
44
    PCICR |= (1 << PCIE2);
45
    break;
46
47
    case 2:      
48
    //disable PIN Change Interrupt
49
    PCICR &= ~(1 << PCIE2);
50
    
51
    //read the countet Interrupts
52
    PCINT_buffer[2] = PCINT_count;
53
            
54
    //set colour direction to blue
55
    PORTC &= ~(1 << PC3);
56
    PORTC |= (1 << PC4);
57
58
    //restore counter value
59
    PCINT_count  = 0;
60
61
    //increase state
62
    PCINT_state = 0;
63
64
    //enable PIN Change Interrupt
65
    PCICR |= (1 << PCIE2);
66
    break;
67
  }
68
}

von nicht "gast" (Gast)


Lesenswert?

lässt sich deutlich kürzer schreiben
1
void read_PCINT(void)
2
{
3
    //disable PIN Change Interrupt
4
    PCICR &= ~(1 << PCIE2);
5
    
6
    //read the countet Interrupts
7
    PCINT_buffer[PCINT_STATE] = PCINT_count;
8
9
    PORTC = (PORTC & ~(1<<PC3 | 1<<PC4)) | PCINT_STATE++; 
10
11
    //restore counter value
12
    PCINT_count  = 0;
13
14
    //enable PIN Change Interrupt
15
    PCICR |= (1 << PCIE2);
16
}

von nicht "gast" (Gast)


Lesenswert?

nicht "gast" schrieb:
> PORTC = (PORTC & ~(1<<PC3 | 1<<PC4)) | PCINT_STATE++;

PORTC = (PORTC & ~(1<<PC3 | 1<<PC4)) | PCINT_STATE++ << PC3;

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Hallo!

Joshi schrieb:
> Der Controller läuft mit 8MHz und die Interruptroutine sieht
> folgendermaßen aus:

Sicher, dass nicht das Fuse-Bit CKDIV8 auf 0 programmiert ist? In dem 
Fall würde dein Mikrocontroller nämlich mit 1 MHz laufen und den Fehler 
erklären.

1
> ISR(PCINT2_vect)
2
> {
3
>   PCINT_count++;
4
> }

Falls PCINT_count eine 16-Bit-Variable ist, braucht die Interruptroutine 
mehr als 50 Taktzyklen, wenn sie in C geschrieben ist.

Genaueres siehst du, wenn du dir den generierten Code disassemblieren 
lässt.

Mögliche Lösung: nimm Assembler, dann sind es 15 bis 17 Zyklen...

Zum PCI: Denk dran, dass der bei jedem Flankenwechsel ausgelöst wird, 
also beim Wechsel von 1 auf und und beim Wechsel von 0 auf 1. Falls dir 
eine Flanke reicht, nimm den INT0.

von Oliver J. (skriptkiddy)


Lesenswert?

Joshi schrieb:
> Alle 20ms wird dann der Counter abgefragt und wieder auf Null gesetzt.
Warum nimmst du keinen Timer und taktest den extern über dein Signal? Da 
kannst du dann ohne Interruptlast zählen.

Ich tippe mal darauf, dass der µC ab einer bestimmten Signalfrequenz 
ständig in der ISR hängt, weil bevor die abgearbeitet ist, das 
Interruptflag schon wieder gesetzt wird und gleich nach dem reti ein 
neuer Aufruf der ISR stattfindet.

Gruß Oliver

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.