Forum: Mikrocontroller und Digitale Elektronik PCINT Interruptroutine


von Karl H. (Gast)


Lesenswert?

Nabend,
ich lasse am Arduino Uno (Atmega328p) mittels PCINT eine Interrupt 
Routine durchlaufen. Initialisiert habe ich die Pins mit
1
  PCICR = ((1 << PCIE1) | (1 << PCIE2));
2
  PCMSK1 = ((1 << PCINT12) | (1 << PCINT13));
3
  PCMSK2 = (1 << PCINT20);

Die ISR lautet dann
1
ISR(PCINT1_vect){
2
...
3
uart_string("ISR PCINT1");
4
...
5
}

solange ich die Taste gedrückt halte, die an PC0 (PCINT8) angeschlossen 
ist, läuft die ISR immer wieder durch. Lasse ich die Taste los und 
drücke sie wieder, passiert nichts.

Eigentlich sollte die ISR doch nur auf Flankenwechsel reagieren, also 
wenn ich gedrückt halte nur einmal durchlaufen und beim loslassen wieder 
und beim erneuten drücken auch wieder usw.

Oder habe ich da was missverstanden?

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Karl H. schrieb:
> solange ich die Taste gedrückt halte, die an PC0 (PCINT8) angeschlossen
> ist, läuft die ISR immer wieder durch. Lasse ich die Taste los und
> drücke sie wieder, passiert nichts.
>
> Oder habe ich da was missverstanden?

 Ja.
 Wo hast du in deiner Init Routine irgendetwas am PCINT8 gesetzt ?
 Richtig wäre es so:
1
  DDRC &= ~(1 << PC0);
2
  PORTC |=  (1 << PC0);
3
  PCICR = (1 << PCIE1);
4
  PCMSK1 = (1 << PCINT8);

 Und ein Taster (NO) zwischen PC.0 und GND.

 Wieso deine ISR überhaupt angesprungen wird, ist mir unklar. Auf jeden
 Fall wird die ISR nicht mit PC.0 getriggert.
 Wo du deinen Taster angeschlossen hast...

von Karl M. (Gast)


Lesenswert?

Guten Morgen,

ich rufe keine komplexen Funktionen in einer ISR auf.
1
uart_string("ISR PCINT1");
Dies kann zum blockierter/ verzögerter Abarbeitung führen.

von Karl H. (Gast)


Lesenswert?

Karl M. schrieb:
> ich rufe keine komplexen Funktionen in einer ISR auf.

Das habe ich auch nur gemacht, um zu sehen, ob ich in die ISR 
reinspringe. Sobald das alles zuverlässig funktioniert, wird diese 
Funktion wieder entfernt.


Habe aber trotzdem noch einmal ein paar fragen, da mir das alles 
merkwürdig vorkommt.
1
/* -- Keypad -- */
2
#define row1_high      PORTC |= (1 << DDC0)
3
#define row1_low      PORTC &= ~(1 << DDC0)
4
#define row2_high      PORTC |= (1 << DDC1)
5
#define row2_low      PORTC &= ~(1 << DDC1)
6
#define row3_high      PORTC |= (1 << DDC2)
7
#define row3_low      PORTC &= ~(1 << DDC2)
8
#define row4_high      PORTC |= (1 << DDC3)
9
#define row4_low      PORTC &= ~(1 << DDC3)
10
#define column1_not_active  !(PINC & (1<<PINC4))
11
#define column2_not_active  !(PINC & (1<<PINC5))
12
#define column3_not_active  !(PIND & (1<<PIND4))
13
/* -- -- */

1
  PCICR = ((1 << PCIE1) | (1 << PCIE2));
2
  PCMSK1 = ((1 << PCINT12) | (1 << PCINT13));
3
  PCMSK2 = (1 << PCINT20);
4
  
5
  // Keypad
6
  // row
7
  DDRC |= ((1 << DDC0) | (1 << DDC1) | (1 << DDC2) | (1 << DDC3)); // output
8
  PORTC &= ~((1 << DDC0) | (1 << DDC1) | (1 << DDC2) | (1 << DDC3)); // low
9
10
  // column
11
  DDRC &= ~((1 << DDC4) | (1 << DDC5)); // input
12
  DDRD &= ~(1 << DDD4); // input
13
  PORTC |= ((1 << DDC4) | (1 << DDC5)); // Pullup an
14
  PORTD |= (1 << DDD4); // Pullup an
15
16
  sei(); // Global Interrupts activate
17
  PORTC &= ((1 << DDC0) | (1 << DDC1) | (1 << DDC2) | (1 << DDC3)); // all rows low
18
  while (1){}


ISR:
1
ISR(PCINT1_vect){
2
  usart_transmit_string("ISR 1\r\n");
3
  // row 1
4
  row1_low;
5
  while ( PINC & (1<<DDC0) )  {}
6
  if ( column1_not_active ) key_press[0][0]=1; else key_press[0][0]=0;
7
  if ( column2_not_active ) key_press[0][1]=1; else key_press[0][1]=0;
8
  row1_high;
9
  
10
  // row 2
11
  row2_low;
12
  while ( PINC & (1<<DDC1) )  {}
13
  if ( column1_not_active ) key_press[1][0]=1; else key_press[1][0]=0;
14
  if ( column2_not_active ) key_press[1][1]=1; else key_press[1][1]=0;
15
  row2_high;
16
  
17
  // row 3
18
  row3_low;
19
  while ( PINC & (1<<DDC2) )  {}
20
  if ( column1_not_active ) key_press[2][0]=1; else key_press[2][0]=0;
21
  if ( column2_not_active ) key_press[2][1]=1; else key_press[2][1]=0;
22
  row3_high;
23
  
24
  // row 4
25
  row4_low;
26
  while ( PINC & (1<<DDC3) )  {}
27
  if ( column1_not_active ) key_press[3][0]=1; else key_press[3][0]=0;
28
  if ( column2_not_active ) key_press[3][1]=1; else key_press[3][1]=0;
29
  row4_high;
30
31
  memcpy(key_mask, key_press, sizeof(key_press));
32
  for(unsigned int i=0; i<=3; i++){
33
    for(unsigned int k=0; k<=2; k++){
34
      if((key_press[i][k]==1) && (key_mask[i][k]!=key_mask_old[i][k])){
35
        usart_transmit_string("\r\n KEY: ");
36
        usart_transmit_char(key_num[i][k]);
37
      }
38
    }
39
  }
40
  memcpy(key_mask_old, key_mask, sizeof(key_mask));
41
  PORTC &= ~((1 << DDC0) | (1 << DDC1) | (1 << DDC2) | (1 << DDC3)); // all rows low
42
}


Da ich die internen pullups aktiviert habe, muss ich eigentlich alle 
Ausgänge (die für die Tastatur verwendet werden) auf high setzen und 
dann spalte 1 auf low schalten, reihen überprüfen, spalte 1 high, spalte 
2 low usw.
Aber dann springe ich gar nicht in die ISR rein. Wenn ich allerdings 
alle auf low schalte, funktioniert das.
Da macht das für mich aber keinen Sinn mehr. Ich schalte alle auf low, 
schalte reihe1 auf low (was ja schon ist) und überprüfe, reihe1->high, 
reihe2->low (was ja auch schon ist)...
Oder funktioniert das mit den internen pullups für die ISR nicht? aber 
warum nicht?

von Karl M. (Gast)


Lesenswert?

Hallo,

ich habe diese Routine von Peter Dannegger Peda für eine Tastenmatrix 
3x4 Problem im Einsatz.

Beitrag "Re: Tastenmatrix 3x4 Problem"

Kein PCINT sondern Pollen ist angesagt !

Wenn Du das Scan-Schemata verstanden hast, bekommst Du eine Idee, wie 
man allg. Tastenmatrix abfragen kann.

von Falk B. (falk)


Lesenswert?

@ Karl M. (Gast)

>Kein PCINT sondern Pollen ist angesagt !

Stimmt, es ist mit verstärktem Pollenflug zu rechnen!! Ganz schlimm für 
Allergiker! ;-)

von Karl H. (Gast)


Lesenswert?

Karl M. schrieb:
> Kein PCINT sondern Pollen ist angesagt !

ich denke, du meintest Prellen? Dann müsste ich ja immer abfragen, ob 
eine Taste gedrückt wurde. Ich wollte eigentlich das Haupt-Programm ohne 
direkte Tastenabfrage machen. Durch PCINT kann ich das Haupt-Programm so 
durchlaufen lassen und bekomme trotzdem den Tastendruck mit.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Karl H. schrieb:
> Karl M. schrieb:
>> Kein PCINT sondern Pollen ist angesagt !
>
> ich denke, du meintest Prellen?

 LOL.
 Wenn sich Fachleute unterhalten, verstehen die Normaluser kein
 einziges Wort.

von Karl H. (Gast)


Lesenswert?

Egal, ob Pollen richtig oder falsch verstanden (habe ich auch falsch 
verstanden).
Trotzdem muss ich so im Hauptprogramm immer aktiv nachfragen, ob eine 
Taste gedrückt wurde. Das möchte ich ja vermeiden.

von Hosenmatz (Gast)


Lesenswert?

Karl H. schrieb:
> Egal, ob Pollen richtig oder falsch verstanden (habe ich auch falsch
> verstanden).
> Trotzdem muss ich so im Hauptprogramm immer aktiv nachfragen, ob eine
> Taste gedrückt wurde. Das möchte ich ja vermeiden.

Ich will nicht sagen, dass diese Absicht grundsätzlich zu kritisieren 
wäre, aber warum willst Du im Hauptprogramm nicht aktiv nachfragen, ob 
eine Taste gedrückt wurde?

Mal so gesehen:
Abgesehen von der Entprellung und anderen Kleinigkeiten, die "man" im 
allgemeinen anders erledigt, wird "man" in der Mehrzahl der Fälle genau 
das tun: Im Hauptprogramm aktiv nachfragen, ob eine Taste gedrückt 
wurde.
Das ist einfach und braucht weder viel Zeit noch viel Resourcen.

von Einer K. (Gast)


Lesenswert?

Karl H. schrieb:
> Das möchte ich ja vermeiden.
Warum?
Ist dir ein Sturm von Interrupts (beim prellen) lieber?


Du könntest die Tastatur auch in einem Timer Interrupt abfragen. Den 
Timer, oder irgendeine Zeit, brauchst du sowieso um prellen zu erkennen.

von Karl H. (Gast)


Lesenswert?

Ich wollte nicht andauernd nach der Taste abfragen, da ich den 
Kontroller, wenn der nichts zu tun hat schlafen legen wollte.
Auch war/bin ich mir nicht sicher gewesen, ob ich, wenn ich eine Taste 
drücke, die Funktion aufgerufen wird.
evtl könnte ja auch passieren, dass ich die Taste kurz nach dem 
Funktionsaufruf drücke und vor dem Funktionsaufruf wieder losgelassen 
habe. Dadurch würde der Tastendruck ja verloren gehen.

von Michael L. (michaelx)


Lesenswert?

Marc V. schrieb:
> Karl H. schrieb:
>> Karl M. schrieb:
>>> Kein PCINT sondern Pollen ist angesagt !
>>
>> ich denke, du meintest Prellen?
>
>  LOL.
>  Wenn sich Fachleute unterhalten, verstehen die Normaluser kein
>  einziges Wort.

Ist doch ganz einfach: Wegen dem Prellen muss man pollen.

Das Pollen muss aber nicht im Hauptprogramm gemacht werden, dazu kann 
man auch einen Timerinterrupt nehmen, der z.B. alle 10 ms den Zustand 
der Taste abfragt, und wenn sich über 50ms bzw. 5 Interrupts der Zustand 
nicht geändert hat, dann hat man die Flanke für "Taste gedrückt" bzw. 
"Taste losgelassen" erkannt. Dieses Ereignis schreibt die ISR in eine 
Speicherzelle, und das Hauptprogramm reagiert darauf, wenn es grad 
passt.

von Einer K. (Gast)


Lesenswert?

Karl H. schrieb:
> Ich wollte nicht andauernd nach der Taste abfragen, da ich den
> Kontroller, wenn der nichts zu tun hat schlafen legen wollte.

Gute Idee.
PCint ist dafür gut geeignet.
Aber nur zum wecken.

Danach pollen.

Karl H. schrieb:
> evtl könnte ja auch passieren, dass ich die Taste kurz nach dem
> Funktionsaufruf drücke und vor dem Funktionsaufruf wieder losgelassen
> habe. Dadurch würde der Tastendruck ja verloren gehen.

Hei hei hei ....
Wie viele Tausend Tastendrücke pro Sekunde möchtest du denn auswerten 
können?

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Michael L. schrieb:
> Marc V. schrieb:
>> Karl H. schrieb:
>>> Karl M. schrieb:
>>>> Kein PCINT sondern Pollen ist angesagt !
>>>
>>> ich denke, du meintest Prellen?
>>
>>  LOL.
>>  Wenn sich Fachleute unterhalten, verstehen die Normaluser kein
>>  einziges Wort.
>
> Ist doch ganz einfach: Wegen dem Prellen muss man pollen.

 Aber dann kriegt man doch Heuschnupfen, oder ?

 Und die gehen mit Prellen auch nicht weg, oder ?

: Bearbeitet durch User
von Michael L. (michaelx)


Lesenswert?

Marc V. schrieb:
>  Aber dann kriegt man doch Heuschnupfen, oder ?
>
>  Und die gehen mit Prellen auch nicht weg, oder ?

Kommt noch irgendwas sinnvolles von dir?

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Michael L. schrieb:
> Kommt noch irgendwas sinnvolles von dir?

 Bei so etwas in der ISR ?
1
ISR(PCINT1_vect){
2
  usart_transmit_string("ISR 1\r\n");
3
  // row 1
4
  row1_low;
5
  while ( PINC & (1<<DDC0) )  {}

 Bei solch einem Unsinn kann nichts sinvolles kommen...

 P.S.
 Und sich dann beschweren:

Karl H. schrieb:
> Aber dann springe ich gar nicht in die ISR rein. Wenn ich allerdings
> alle auf low schalte, funktioniert das.

: Bearbeitet durch User
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.