Pin Change Interrupt - Controller hängt sich auf ab 40kHz - ATMega168

Gast #2712035
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
}
Gast #2712043
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
}
(Firma: guloshop.de) #2712065
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.
#2712098
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

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