Archiv verlassen und diese Seite im Standarddesign anzeigen : Interrupt als Eingangsabfrage
Hallo.
Aktuell beschäftige ich mich mit Interrupts als I/O-Eingangsabfrage/Einganbgsüberwachung.
Hier habe ich beim ATTiny84 mehrere Möglichkeiten; INT0, PCINT0-11
Wo ist denn der grundsätzliche Unterschied zw. INT0 und PCINT10, beides auf PB2 (Pin5) ?
Wird doch beides mit MCUCR und GICR konfiguriert und eingeschaltet?
Searcher
18.06.2019, 22:06
Wo ist denn der grundsätzliche Unterschied zw. INT0 und PCINT10, beides auf PB2 (Pin5) ?
INT0 kann auf verschiedene Arten ausgelöst werden. zB steigende oder fallende Flanke und andere. Konfiguriert wird das im MCUCR mit den ISC00 und ISC01 Bits.
PCINT10 wird bei steigender und bei fallender Flanke ausgelöst. Das kann nicht konfiguriert werden, sondern ist so festgelegt. Damit PCINT10 funktioniert, muß er im PCMSK1 Register mit dem PCINT10 Bit selektiert werden. Der I/O Pin kann dann über das PCIF1 Flag im GIFR Register den Pin Change Interrupt 1 auslösen. PCINT10 selbst hat keinen Interruptvektor sondern springt durch das Selektieren im PCMSK1 über den Pin Change Interrupt 1 (Interruptvektor 4) in die ISR.
Beide, Pin Change Interrupt 1 und INT0, müssen im GIMSK Register zugelassen (enabled) werden.
Wird doch beides mit MCUCR und GICR konfiguriert und eingeschaltet?
Nein. Im MCUCR wird nur die Auslösebedingung für den INT0 festgelegt. Ein GICR gibt es im ATTiny84 nicht. Im GIFR wird nicht konfiguriert sondern eventuell die Interrupt Flags abgefragt oder gelöscht.
Gruß
Searcher
Danke für deine Ausführungen - muss ich erst einmal verarbeiten..."
Mir scheint, bei Abfrage mehrerer I/O-Eingänge, die Nutzung der PCINT0-11 einfacher zu sein.
PCINT10 wird bei steigender und bei fallender Flanke ausgelöst. Das kann nicht konfiguriert werden, sondern ist so festgelegt.
Hmm? Das bedeutet, dass grundsätzlich 2 Interrupts bei einem Tastendruck kommen? Der 2te müsste irgendwie abgefangen/ingnoriert werden.
PCINT10 selbst hat keinen Interruptvektor sondern springt durch das Selektieren im PCMSK1 über den Pin Change Interrupt 1 (Interruptvektor 4) in die ISR.
...ist mir gerade zu hoch.
Laut Datenblatt stehen nur PCINT0 und PCINT1 als Interrupt-Vektor zur Verfügung.
Ist es das was du meinst?
Datenblatt-Ungenauigkeit oder PCINT2-11 über einen "Umwege" zu einer Interruptauslösung?
Hmm? Das bedeutet, dass grundsätzlich 2 Interrupts bei einem Tastendruck kommen? Der 2te müsste irgendwie abgefangen/ingnoriert werden.
Es sind noch mehr. Jedes Prellen erzeugt weitere und je älter der Taster wird, desto mehr. Daher wird das gerne anders gemacht. Es gibt einen zentralen Timerinterrupt, z.B. alle 10ms, und da werden alle Tasten abgefragt. Da wird dann entprellt und falls man möchte zwischen langem und kurzen Tastendruck unterschieden. In diesem Interrupt kann man dann auch alle weiteren regelmäßigen Dinge machen, mit dem ADC die Spannung oder eine Temperatur überwachen, einen Drehenkoder auswerten und diverse SW-Timer z.B. für blinkende LEDs erzeugen.
MfG Klebwax
Jedes Prellen erzeugt weitere und je älter der Taster wird, desto mehr.
Natürlich entprellte Tasten und Schalteingänge vorausgesetzt.
Es gibt einen zentralen Timerinterrupt
Wie passend, damit habe ich mich letzte Woche beschäftigt.
ADC die Spannung
ADC-Spannungsingänge werte ich via Bit-Schwellwert in einer Variable aus. Allerdings erst nach gezielter Werteabfrage.
Auf Interrupts bin ich hier noch gar nicht gekommen...
Natürlich entprellte Tasten und Schalteingänge vorausgesetzt.
Warum Tasten entprellen, wenn man einen µC hat der das erledigen kann.
MfG Klebwax
Software-Entprellung...allerdigs erst nach Abfrage.
Searcher
19.06.2019, 12:21
Das bedeutet, dass grundsätzlich 2 Interrupts bei einem Tastendruck kommen? Der 2te müsste irgendwie abgefangen/ingnoriert werden.
Je nach Programm. Klebwax hatte darauf ja schon geantwortet. Wenn der zweite Interrupt ignoriert werden soll: Man weiß ja normal, welche Flanke ausgewertet werden soll. In der, durch irgendeine der beiden Flanken ausgelösten ISR (es ist ja die gleiche ISR) fragt man zB das PIN-Register Bit des entsprechenden PINs ab um den Pegel des PINs zu bestimmen. Ist es gesetzt war es die steigende Flanke. Ist es rückgesetzt war es die fallende Flanke und man kann entsprechende Aktionen vorsehen.
Laut Datenblatt stehen nur PCINT0 und PCINT1 als Interrupt-Vektor zur Verfügung. Ist es das was du meinst?
Ja, für alle zwölf PCINT stehen nur zwei Interruptvektoren zur Verfügung. Mich hatten zu Anfang auch die Namen verwirrt. Man darf nicht die, in der Interruptvektor Tabelle genannten Sourcenamen mit den Namen am I/O Pin bzw Bitnamen in den PCMSK Registern verwechseln/vermischen. Es gibt nur zwei Interruptvektoren für alle zwölf PCINT-auslösefähigen PINs im ATtiny84. Das sind die PCINT0 und PCINT1 Interrupts.
Welche von den zwölf Pins einen PCINT auslösen können bestimmt man durch Setzten des entsprechenden Bits in den PCMSK Registern. Ist dort kein Bit gesetzt, findet auch kein PCINT0 oder PCINT1 statt. Die Interrupts PCINT0 bzw PCINT1 sind den PCMSK Registern fest zugeordnet. Laut Datenblatt können PA0 bis PA7 Pins mit ihren PCINT0 bis PCINT7 Bits im PCMSK0 Register nur den PCINT0 Interrupt auslösen. Die andern Pins mit ihren Bits im PCMSK1 nur den PCINT1.
Es können also durch Setzen mehrerer Bits in einem PCMSK Register mehrere PINs den gleichen Interrupt auslösen. Welcher Pin das war, könnte man dann in der ISR zB durch Zustandsabfragen der in Frage kommenden PINs feststellen.
Datenblatt-Ungenauigkeit oder PCINT2-11 über einen "Umwege" zu einer Interruptauslösung?
Datenblatt Ungenauigkeit würd ich das nicht nennen, eher unglückliche Namensgebung. Umweg? Naja, ist halt so vom Hersteller entworfen. Wenn man die richtige Anwendung noch dafür erfindet oder sogar schon hat, wär man für diese Lösung bestimmt noch dankbar :-)
Gruß
Searcher
Pinchanges verwende Ich im Prinzip nicht so gerne.
Eben weil man im Nachgang feststellen muss welcher Eingang denn nun den Interrupt getriggert hat und welche Flanke es war.
Ich lass eigentlich bei jedem Projekt einen Timer mitlaufen.
In seinem Timer Overflow Interrupt lasse ich dann einfach einen oder mehere Countdown Zähler runterzählen.
Die Anfangswerte werden im Hauptprogramm gesetzt und erst wenn der Counter wieder 0 erreicht hat wird nachgeschaut ob sich was geändert hat.
Beispiel:
Im Hauptprogramm wurde festgestellt, das eine Taste ihren Zustand geändert hat.
Dann wird der zugehörige Countdown Zähler mit einem Wert vorbelegt.
Die Timer Overflow Interrupt routine zählt diesen Zähler dann runter.
Wenn der wieder 0 erreicht hat wird geguckt, ob sich der Tastendruck bestätigt hat ( = Aktion auslösen ), oder ob die Taste nur geprellt hat.
Die entprell Zeiten lassen sich somit einfach durch verändern des Countdown Initial Wertes einstellen.
In der gleichen Timer Overflow Interrupt Routine lassen sich dann auch noch weitere Counter für andere Aufgaben realisieren.
Z.B. einen Countdowncounter für ein Display refresh usw.
Nur mal so zum Verständnis;
Diese Methode verbindet eine Timer-Interruptabfrage aller Eingänge kombiniert mit einer Entprellung >>> Toll!
Ich stelle mir das ALS ANFÄNGER so vor;
1. Zustand aller aktiven I/O-Eingänge wird in Variablen gespeichert.
2. Timer löst nach 10ms einen Timer-Interrupt aus
3. Wieder werden alle Eingangszustände ab gefragt und nmit den gespeicherten verglichen
4.1. keine Statusänderung, wird ab 2. wiederholt
4.2. Statusänderung erkannt
5. der betroffene Eingang wird noch 5-10 mal im 10ms Takt abgefragt
6. bestätigt sich die Statusänderung, wird eine entsprechende Variable (Eingang X==1) weiter verarbeitet
Das war übrigens mein gestriger Gedanke, eine "Listenabfrage" mit dem INT0, bis die verlockung winkte, dass jeder Eingang seinen eigenen Interrupt hat.
Dann war mein erster Gedanke doch nicht sooooo schlecht.
- - - Aktualisiert - - -
Zur Verdeutlichung meiner möglichen Abfrage-Struktur;
// PORTs setzen
//Gesamtes Register auslesen
uint8_t ZustandPA = PORTA;
uint8_t ZustandPB = PORTB;
//einzelne PORTs auslesen
uint8_t ZustandPA4 = PORT & (1<<PA4);
uint8_t ZustandPB5 = PORT & (1<<PB5);
// beliebig erweiterbar
//INT0 oder TIM1_COMPA_vect Interrupt wird ausgelöst ...
if ((PORTA != ZustandPA) || (PORTB != (ZustandPB)); // wenn sich irgend etwas an den Eingängen verändert
{
if ((PINA & (1<<PA4)) != ZustandPA4; {...mach was...} // wenn ungleich, dann mach was
if ((PINB & (1<<PB5)) != ZustandPB5; {...mach was...} // wenn ungleich, dann mach was
// beliebig erweiterbar
}
Hallo - die lange Wartezeit da ua. Urlaub und Krankheit dazwischen kam.
Habe jetzt mal ein kleines C-Prog (ATtiny84) mit Eingabe-Interrupt versucht.
Funktioniert nicht - LED ist dauerhaft aus.
Könnt ihr mir auf die schnelle Helfen?
int main(void)
{
...
//Interrupt-Routine wird defeniert
GIMSK = (1<<PCIE0); // Bank0 wird eingeschaltet (PA0-PA7) // BANK1 beinhaltet PB0-PB3
PCMSK0 = (1<<PCINT4)|(1<<PCINT5); // PCINT4(PA4) und PCINT5(PA5) könnte Interrupt auslösen
sei(); // Interrupt´s werden gestartet und laufen im Hintergrund
while(1) // alternativ SLEEP-Mode
...
}
ISR (PCINT0_vect) // Interrupt, aus Bank0, wird ausgelöst
{
//vorerst ohne Tastenentprellung und altem Tastenzustands-Vergleich
if ((PINA & (1<<PINA4)) == 1) // wenn EIN-Taster=1
{
LEDein;
}
if ((PINA & (1<<PINA5)) == 1) // wenn AUS-Taster=1
{
LEDaus;
}}
Searcher
24.07.2019, 20:45
if ((PINA & (1<<PINA4)) == 1)
Hallo,
Du vergleichst die bitweise Verknüfung mit 1. Kann aber nur eins werden, wenn PA0 (PINA0) = 1 und (1<<PINA4) gleich 1 ist. (1<<PINA4) ist aber niemals 1 sondern 16.
In C bin ich nicht so fit aber vermutlich könnte es so klappen:
if ((PINA & (1<<PINA4)) == (1<<PINA4))
Gruß
Searcher
PS Code ließt sich besser wenn in Code Tags eingeschlossen:
if ((PINA & (1<<PINA4)) == (1<<PINA4))[/CODE ] Ohne die Leerzeichen in den Klammern wird das [CODE]if ((PINA & (1<<PINA4)) == (1<<PINA4))
021aet04
24.07.2019, 22:41
Eine if Abfrage ist automatisch eine Abfrage auf ungleich 0.
Somit reicht es wenn du PINA und PINA4 mittels "und" verknüpfst.
if (PINA & (1<<PA4))
PINA ist der gesamte Port
PA4 (und die anderen Bezeichnungen) ist in den Libs definiert (PA4 => 4)
Der Ausdruck "(1<<PA4)" bedeutet also das du die "1" um 4 Stellen nach links schiebst => 0001 0000
Das ergibt dann:
als Beispiel wenn PINA = 0xff
PINA: 1111 1111
PA4: & 0001 0000
-------------------
Ergebnis: 0001 0000
If wird somit ausgeführt weil das Ergebnis nicht "0" ist, sondern 16.
Für solche Dinge ist der Simulator nicht schlecht geeignet. Du kannst es Schritt für Schritt abarbeiten lassen (oder mit Debugger) und schauen was passiert.
MfG Hannes
Dank euch vielmals für eure Mühe.
Leider war keiner der folgenden plausiblen Versuche erfolgreich;
if ((PINA & (1<<PA4)) != 0)
if ((PINA & (1<<PA4)) == 16)
if (PINA & (1<<PA4))
Daher vermute ich den Fehler innerhalb Interrupt-Einstellung;
GIMSK = (1<<PCIE0); // Bank0 wird eingeschaltet (PA0-PA7) // BANK1 beinhaltet PB0-PB3
PCMSK0 = (1<<PCINT4)|(1<<PCINT5); // PCINT4(PA4) und PCINT5(PA5) könnte Interrupt auslösen
sei(); // Interrupt´s werden gestartet und laufen im Hintergrund
//...
ISR (PCINT0_vect) // Interrupt, aus Bank0, wird ausgelöst
{
//tu was
}
Seht ihr hier ein Fehler?
Vor allem bin ich mir mit dem GIMSK-Register sehr unsicher.
021aet04
25.07.2019, 12:26
Ich habe mir die Register nicht angeschaut, kann ich erst wenn ich wieder Zuhause bin.
Aber was mir noch einfällt, wie hast du die Tasten angeschlossen? Gegen + oder 0V?
Du fragst ab ob der Eingang high ist, meist werden aber Pullups verwendet und wenn die Taste gedrückt wird ist es dann low.
Dann hast du folgendes Problem.
Keine Taste gedrückt: Es werden beide If ausgeführt, zuerst ein und gleich darauf aus.
Eine Taste gedrückt: Die jeweilige If Abfrage wird übersprungen, wenn du aber heruntergehst wird sofort wieder abgeschalten (siehe keine Taste gedrückt) .
MfG Hannes
Ich verwende Taster/Schalter, die auf Vcc liegen, mit Pulldown-Widerständen.
Dh., beim Tasten/Schalten, liegt am Schaltausgang Vcc an.
Daher mein Gedankenfehler;
if ((PINA & (1<<PA4)) == 1)
- - - Aktualisiert - - -
OH-MANN ... blöder als man(n) denken kann... (ich brauche H I T Z E F R E I !)
LEDein; // Falsch!
LEDaus; // Falsch!
kann nicht ohne Klammer funktionieren;
LEDein(); // Richtig!
LEDaus(); // Richtig!
funktioniert ausgezeichnet!
021aet04
26.07.2019, 21:30
Hauptsache ist ja das es funktioniert, mir ist es aber auch nicht aufgefallen.
MfG Hannes
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.