Forum: Mikrocontroller und Digitale Elektronik attiny: Nach Interrupt Pin abfragen—wie geht das?


von Stefan R. (Gast)


Lesenswert?

Hallo alle zusammen,

ich stecke mit der ganzen AVR-Programmiererei in C immer noch in den 
Anfängen fest. Leider gibt weder das Manual für den atTiny45 noch die 
Suche im Internet eine klare Antwort:

Ich lasse bei Pin Change (PCINT0) einen Interrupt auslösen, und habe 
einer entsprechende ISR. Konfiguriert habe ich:

--->Any logical change on INT0 generates an interrupt request.

Aber wie kann ich in der ISR nun herausbekommen, ob steigende oder 
fallende Flanke anlag?

Bei dem folgenden Programmbeispiel würde die Abfrage natürlich keinen 
Sinn ergeben, aber dieses kurze Beispiel ist mein Ausgangscode für 
weitere Programme.

Gruss,
Stefan
1
#define F_CPU 8000000                    // clock 1.2MHz, internal oscillator
2
3
#include <avr/io.h>
4
#include <util/delay.h>
5
#include <avr/interrupt.h>
6
7
#define LED PB4
8
9
int main(void) {
10
11
12
GIMSK = _BV (PCIE);                                  // Pin Change Interrupt Enable
13
PCMSK = _BV (PCINT0);            // Enable external interrupts PCINT0
14
MCUCR = _BV (ISC00);            // PCINT0 is triggered on any change
15
sei();                        // int - Global enable interrupts
16
DDRB |= (1 << LED);            // Set direction register output
17
18
    for (;;) {                  // loop (endless)
19
      asm("NOP");
20
    }
21
22
return 0;
23
}
24
25
ISR (PCINT0_vect)               // Interrupt on PCINT0 vector
26
{ 
27
28
PORTB ^= (1 << 4);               // Toggle LED
29
_delay_ms (1);
30
PORTB ^= (1 << 4);               // Toggle LED
31
}

von STK500-Besitzer (Gast)


Lesenswert?

Du musst dir den vorherigen Port-Zustand merken und mit dem aktuellen 
vergleichen.
Um die Änderung zu finden, brauchst du nur die XOR-Funktion anwenden.

von Jack (Gast)


Lesenswert?

Stefan R. schrieb:
> _delay_ms (1);

Das ist etwas kurz ums zu sehen.

: Bearbeitet durch Admin
von Stefan R. (Gast)


Lesenswert?

Ja, ich weiss, das ist zu kurz. Ich habe auch eine Version, wo ich eine 
längere Zeit habe. Aber das ist ja auch nicht der springende Punkt. So 
eine Abfrage habe ich schon versucht zu basteln, aber es funktionierte 
nicht, weil ich:

1. nicht sicher bin, ob in dem Moment, wo ich in der ISR bin, der Pin 
überhaupt noch auf dem gleichen Wert wie beim Auslösen des Interrupts 
steht und

2. keine Ahnung habe, wie so eine Abfrage aussehen müsste.

Vielleicht hat ja eine eine Idee, wie man besipielsweise in das hier ein 
entsprechende Abfrage einbauen könnte:

ISR (PCINT0_vect)               // Interrupt on PCINT0 vector
{
wenn Flanke hoch ging,
dann Lampe (PORTB4) an,
ansonsten Lampe aus

}

von STK500-Besitzer (Gast)


Lesenswert?

Stefan R. schrieb:
> 1. nicht sicher bin, ob in dem Moment, wo ich in der ISR bin, der Pin
> überhaupt noch auf dem gleichen Wert wie beim Auslösen des Interrupts
> steht und

Dann müsste das Signal schon relativ hochfrequent sein.

Stefan R. schrieb:
> 2. keine Ahnung habe, wie so eine Abfrage aussehen müsste.
>
> Vielleicht hat ja eine eine Idee, wie man besipielsweise in das hier ein
> entsprechende Abfrage einbauen könnte:
>
> ISR (PCINT0_vect)               // Interrupt on PCINT0 vector
> {
> wenn Flanke hoch ging,
> dann Lampe (PORTB4) an,
> ansonsten Lampe aus
>
> }

am Anfang deines Programms (bzw. zu dem Zeitpunkt, an dem es für dich 
interessant wird) speicherst du den Portzustand in einer Variablen.
Dann schaltest du die PCINT-Geschichte ein.
Wird der Interrupt nun ausgelöst, vergleichst du Bitweise die Variable 
mit dem aktuellen Portzustand (den du dir auch in einer Variablen 
zwischenspeichern kannst/solltest).
Eine steigende Flanke erkennst du daran, dass das Bit in der ersten 
Variablen 0 ist und beim aktuellen Portzustand 1.
Am Ende der ISR überträgst du dann noch den Portzustand in die 
Vergleichsvariable, da diese ab jetzt den letzten Portzustand 
wiedergibt.

Am Ende der I

: Bearbeitet durch Admin
von STK500-Besitzer (Gast)


Lesenswert?

da fehlt noch was...

Sollte heissen:
Am Ende der ISR überträgst du noch den "aktuellen" Portzustand in die 
Vergleichsvariable, da diese den vorhergehenden Portzustand wiedergibt.

von Stefan R. (Gast)


Lesenswert?

OK, das habe ich verstanden. Aber: wie könnte so der Code aussehen, der 
den Zusatnd des Ports abfragt?

Ich habe die ISR umgeschrieben. Immer wenn ein Flankenwechsel gemeldet 
wird, soll nachgeschaut werden, ob die Flanke oben oder unten ist. Ob 
ich einen vorigen Zustand vorliegen habe, ist da ja zunächst mal 
unerheblich.

Wenn Level high ist, dann Lampe an, wenn Level nach Interrupt low ist, 
dann Lampe aus.

Man muss es an der LED sehen können, denn wenn ich sie direkt an den 
Eingang halte, wo PWM ankommt, leuchtet sie auch leicht.

Meine ISR funktioniert allerdings nicht:
1
ISR (PCINT0_vect)               // Interrupt on PCINT0 vector
2
{ 
3
  if (PORTB&(1<<1)){
4
    PORTB |=(1<<PB4);
5
  } else {
6
    PORTB &= ~(1<<PB4);
7
  }
8
}

von STK500-Besitzer (Gast)


Lesenswert?

1
#define F_CPU 8000000                    // clock 1.2MHz, internal oscillator
2
3
#include <avr/io.h>
4
#include <util/delay.h>
5
#include <avr/interrupt.h>
6
7
#define LED PB4
8
9
int main(void) {
10
11
volatile unsigned char hilfsvar;
12
13
hilfsvar = PINB;         // vollständigen Eingangszustand von Port B
14
                         // sichern
15
GIMSK = (1<<PCIE);       // Pin Change Interrupt Enable
16
PCMSK = (1<<PCINT0);     // Enable external interrupts PCINT0
17
MCUCR = (1<<ISC00);      // PCINT0 is triggered on any change
18
19
sei();                   // Global enable interrupts
20
DDRB |= (1 << LED);      // Set direction register output
21
22
    while(1);            // loop (endless)
23
24
return 0;
25
}
26
27
ISR (PCINT0_vect)               // Interrupt on PCINT0 vector
28
{ unsigned char hilfsvar2;
29
hilfsvar2 = PINB ^ hilfsvar;    // XOR-Operation auf aktuellen
30
                               // und vorherigen Portzustand anwenden
31
if (hilfsvar2 & 1)
32
{
33
   PORTB |=(1<<PB4);
34
}
35
else PORTB &= ~(1<<PB4);
36
}

von External (Gast)


Lesenswert?

Das ISC00 Bit hat nichts mit dem Pin Change Interrupt z tun, nur mit 
Ext. Interrupt 0

Um den Zustand auf einem PIN abzufragen muß Du das PINB Register 
abfragen
IF .. PINB ..

von Stefan R. (Gast)


Lesenswert?

OK, das wäre ja dann mit einer Sicherung des Zustandes. Aber es muss 
doch auch ohne gehen, indem ich einfach frage: in welchem Zustand ist 
PORTB, Bit 1? Und zwar genau dann, wenn ein Interrupt ausgeführt wird.

von STK500-Besitzer (Gast)


Lesenswert?

etwas Blödsinn habe ich auch geschrieben: Die XOR-Operation zeigt jeden 
Wechsel mit "1" an, nicht nur die steigenden Flanken.
Dafür kann man damit herausfinden, welcher Kanal eine Flanke hatte...

von STK500-Besitzer (Gast)


Lesenswert?

Stefan R. schrieb:
> OK, das wäre ja dann mit einer Sicherung des Zustandes. Aber es muss
> doch auch ohne gehen, indem ich einfach frage: in welchem Zustand ist
> PORTB, Bit 1? Und zwar genau dann, wenn ein Interrupt ausgeführt wird.

Und wenn ein Port die ganze Zeit auf "1" gesetzt ist? Dann würdest du 
nach deiner Definition das auch als Flanke werten.

: Bearbeitet durch Admin
von Stefan R. (Gast)


Lesenswert?

Naja, dann würde ja aber auch kein Interrupt ausgelöst werden, wenn ich 
das richtig verstehe. Also noch einmal Entschuldigung: ich habe wirklich 
verdammt wenig Ahnung. So wenig, dass ich das PINB-Register nicht kannte 
und jetzt erst einmal nachlesen muss ;-)

von Thomas E. (thomase)


Lesenswert?

Stefan R. schrieb:
> OK, das wäre ja dann mit einer Sicherung des Zustandes.
Das ist völliger Unsinn.
Der vorherige Zustand ist das Gegenteil vom jetzigen. Immer.

STK500-Besitzer schrieb:
> Eine steigende Flanke erkennst du daran, dass das Bit in der ersten
> Variablen 0 ist und beim aktuellen Portzustand 1.
Wenn der Zustand 1 ist, war er vorher 0. Sonst wäre der Interrupt nicht 
ausgelöst worden.

Da muß man sich gar nichts merken.
Der Pin-Change-Interrupt wird ausgelöst, wenn sich der Zustand ändert. 
Und zwar immer und nur dann. Da wird nichts eingetsellt.
Die Level-Einstellungen sind für INT0 und INT1.

mfg.

: Bearbeitet durch Admin
von STK500-Besitzer (Gast)


Lesenswert?

Stefan R. schrieb:
> Naja, dann würde ja aber auch kein Interrupt ausgelöst werden, wenn ich
> das richtig verstehe. Also noch einmal Entschuldigung: ich habe wirklich
> verdammt wenig Ahnung. So wenig, dass ich das PINB-Register nicht kannte
> und jetzt erst einmal nachlesen muss ;-)

Willst du nur einen Pin auswerten? PCINT ist für eine Gruppe von Pins 
gedacht...

: Bearbeitet durch Admin
von Stefan R. (Gast)


Lesenswert?

So, jetzt geht's offensichtlich so, wie ich es wollte, danke Deiner 
Hilfe und dem Hinweis, darauf, dass es auf die Register PINx. ein wenig 
peinlich ist mir das nun schon :-) Danke!
1
ISR (PCINT0_vect)               // Interrupt on PCINT0 vector
2
{ 
3
  if (PINB&1){
4
    PORTB |=(1<<PB4);
5
  } else {
6
    PORTB &= ~(1<<PB4);
7
  }
8
}

von Rolf Magnus (Gast)


Lesenswert?

Stefan R. schrieb:
> Naja, dann würde ja aber auch kein Interrupt ausgelöst werden, wenn ich
> das richtig verstehe.

Wenn du nur für genau einen PIN den Interrupt aktivierst, ja. Aber der 
PCINT kann ja auch von mehr als einem Pins ausgelöst werden. Und wenn du 
das machst, mußt du nicht nur erkennen, welche Flanke, sondern auch 
welcher Pin den Interrupt ausgelöst hat.

: Bearbeitet durch Admin
von Thomas E. (thomase)


Lesenswert?

STK500-Besitzer schrieb:
> Willst du nur einen Pin auswerten? PCINT ist für eine Gruppe von Pins
> gedacht...
Warum denn nicht? PCINT ist nicht für eine Gruppe von Interrupts 
gedacht, sondern verwendet eine ISR für bis zu 8 Pins.
Dabei ist der Nachteil gegenüber INT0/1, daß man noch nach der 
Interruptquelle suchen muß. Je nach Maskierung gibt es dabei 1 - 8 
Möglichkeiten.

mfg.

von slow (Gast)


Lesenswert?

Praktisch gedacht:

Um eine Lampe oder LED einzuschalten (Trägheit des Betrachters), braucht 
es wahrlich keinen Interrupt mit Flankenerkennung. Das ist alles ganz 
locker mit Polling zu erschlagen.

Die ganzen Ratschläge sind eher akademischer Natur, praktischen Nutzen 
haben sie nicht, eher im Gegenteil, sie komplizieren alles nur unnötig.

von STK500-Besitzer (Gast)


Lesenswert?

Thomas Eckmann schrieb:
> STK500-Besitzer schrieb:
>> Willst du nur einen Pin auswerten? PCINT ist für eine Gruppe von Pins
>> gedacht...
> Warum denn nicht? PCINT ist nicht für eine Gruppe von Interrupts
> gedacht, sondern verwendet eine ISR für bis zu 8 Pins.
> Dabei ist der Nachteil gegenüber INT0/1, daß man noch nach der
> Interruptquelle suchen muß. Je nach Maskierung gibt es dabei 1 - 8
> Möglichkeiten.
>
> mfg.

Das ist mir schon klar. Wenn man aber nur einen Pin auswerten will, kann 
man sich das ganze Gehampel sparen, indem man einen dedizierten 
Interrupt-Pin benutzt und da die gewünschte Flanke einstellt.

von Thomas E. (thomase)


Lesenswert?

slow schrieb:
> Das ist alles ganz locker mit Polling zu erschlagen.
Noch lockerer macht man das mit dem Pin-Change-Interrupt.

slow schrieb:
> braucht es wahrlich keinen Interrupt mit Flankenerkennung.
Das ist in diesem Zusammhang in der Tat nur Gesülze.

mfg.

von Rolf Magnus (Gast)


Lesenswert?

Thomas Eckmann schrieb:
> STK500-Besitzer schrieb:
>> Willst du nur einen Pin auswerten? PCINT ist für eine Gruppe von Pins
>> gedacht...
> Warum denn nicht? PCINT ist nicht für eine Gruppe von Interrupts
> gedacht, sondern verwendet eine ISR für bis zu 8 Pins.

Es ist aber schlecht, mal so ganz pauschal zu behaupten, sich den 
vorherigen Zustand zu merken, sei Unsinn. Normalerweise muß man das ja 
sehr wohl tun. Es gibt aber einen Spezialfall, für den man es sich 
sparen kann. Dir ist das klar, aber dem TE nicht. Und auch wenn er im 
Moment vielleicht nur einen Pin braucht, fragt er spätestens dann wieder 
hier nach, wenn der zweite Pin dazukommt und er sich daran erinnert, daß 
es ja Unsinn ist, sich den alten Zustand zu merken. Deshalb ist es 
besser, ihm das gleich richtig zu erklären.

von Stefan R. (Gast)


Lesenswert?

Also, ich will nicht nur eine Lampe ein- oder ausschalten. Ich bekomme 
von einem RC-Empfänger alle 20ms einen Impuls von 1-2ms Länge. Je 
nachdem, wie lang der ist möchte ich mittels PWM an einem der Ausgänge 
über einen MOSFET eine Glühkerze für einen Verbrenungsmotor dimmen.

Das ganze vorhin ist einer der Schritte auf dem Weg dorthin. Auf dem 
Arduino läuft die ganze Anwendung schon, allerdings ist der für ein 
Flugzeug zu schwer, zu gross und zu teuer.

von Thomas E. (thomase)


Lesenswert?

Stefan R. schrieb:
> Ich bekomme von einem RC-Empfänger alle 20ms einen Impuls von 1-2ms
> Länge. Je nachdem, wie lang der ist
Dann vergiss' das mit dem Pin-Change und guck' dir mal bei den Timern 
die Input Capture Unit an. Das ist genau dafür gemacht.

mfg.

: Bearbeitet durch Admin
von STK500-Besitzer (Gast)


Lesenswert?

Stefan R. schrieb:
> Also, ich will nicht nur eine Lampe ein- oder ausschalten. Ich bekomme
> von einem RC-Empfänger alle 20ms einen Impuls von 1-2ms Länge. Je
> nachdem, wie lang der ist möchte ich mittels PWM an einem der Ausgänge
> über einen MOSFET eine Glühkerze für einen Verbrenungsmotor dimmen.
>
> Das ganze vorhin ist einer der Schritte auf dem Weg dorthin. Auf dem
> Arduino läuft die ganze Anwendung schon, allerdings ist der für ein
> Flugzeug zu schwer, zu gross und zu teuer.

Wieso wusste ich nur, dass es sich mal wieder um die 
Modellbau-Problematik handelt? ;)
In der Codesammlunbg hat jemand schon etwas derartiges gepostet. Auch 
mit einer Servoansteuerung allerdings als Quasi-Polling, da er im 
20µs-Intervall die Portpins abfragt und die Flanke selber feststellt.
Da hatte ich auch die "Idee" mit dem XOR her...
Wenn es nur um einen Pin geht, kann man für den Zweck noch viel besser 
die Input-Capture-Einheit benutzen.
Die PCINT-Geschichte wollte ich schon lange mal in Angriff nehmen... 
sollte langsam mal losgehen...

: Bearbeitet durch Admin
von External (Gast)


Lesenswert?

Stefan R. schrieb:

> Anfängen fest. Leider gibt weder das Manual für den atTiny45 noch die
> Suche im Internet eine klare Antwort:

Input Capture auf'm ATtiny45 ???

: Bearbeitet durch Admin
von Thomas E. (thomase)


Lesenswert?

External schrieb:
> Input Capture auf'm ATtiny45 ???
Hast Recht.

mfg.

von STK500-Besitzer (Gast)


Lesenswert?

n

External schrieb:
> Stefan R. schrieb:
>
>> Anfängen fest. Leider gibt weder das Manual für den atTiny45 noch die
>> Suche im Internet eine klare Antwort:
>
> Input Capture auf'm ATtiny45 ???

Ja, nee, der nun nicht. Man kann sich den Controller aber auch nach den 
durch die Anwendung vorgegeben Anforderungen aussuchen...
Das nächste bei dieser Aufgabe ist dann ja eh die Timer-Geschichte...

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