Hallo zusammen,
ich befasse mich gerade mit den Interrupts des ATTINY13 und stehe gerade
etwas auf dem Schlauch.
Simpler Versuchsaufbau:
-PB0: kann mit Taster gegen GND verbunden werden (INT0).
-PB1: LED gegen GND.
Simpler Code:
Eigentlich hätte ich folgendes erwartet:
-Taster nicht geschlossen: LED blinkt.
-Taster geschlossen: LED leuchtet dauerhaft.
Tatsächliches Verhalten:
-LED leuchtet immer dauerhaft,d.h. die Interruptroutine wird immer
ausgeführt, nur warum? Was habe ich da falsch definiert?
LG Stefan
Stefan Ott schrieb:> Problem gelöst, INT0 ne PCINTO ;-)> So funktioniert die Sache:
Aber nur auf den ersten Blick. Eigentlich funktioniert das überhaupt
nicht.
Stefan Ott schrieb:> MCUCR |=(0<<ISC01) | (0<<ISC00);
Das ist schonmal Quatsch. Eine Oder-Verküpfung mit 0 bewirkt gar nichts.
Funktioniert nur zufällig, da das Register nach dem Reset ohnehin 0 ist.
Siehe Tutorial: Bitmanipulation.
Stefan Ott schrieb:> Interrupt auslösen wenn INT0 = GND
Das macht er dann solange, wie der Taster gedrückt ist. D.h. wenn die
ISR fertig ist, wird sie sofort wieder aufgerufen, sodaß das Programm
dann so gut wie nichts anderes macht, als in der Interrupt-Routine zu
hängen. Das Hauptprogramm bekommt praktisch keine Rechenzeit mehr.
Das ist aber nicht der Sinn eines Interrupts.
Auch wird das Loslassen des Tasters gar nicht (sinnvoll) ausgewertet.
Für deine Anwendung macht das Sinn:
"Any logical change on INT0 generates an interrupt request."
Dann muss deine ISR so aussehen:
volatile char blink = 0;
ISR(INT0_vect)
{
if (PINB & (1 << PB1)) blink = 0; else blink = 1;
}
Und in der main:
int main(void)
{
.
.
.
while(1)
{
if (blink) Blinken(); else Dauerlicht();
}
}
Blinken() und Dauerlicht() muß dann entsprechend durch Code ersetzt bzw.
als Funktionen eingebaut werden.
Ist zwar immer noch ein wenig unelegant, da der Taster nicht entprellt
ist. Das tut hier aber nichts zur Sache.
Warum das Ganze so?
Wenn der Taster gedrückt wird, wird die ISR aufgerufen, da der Taster
nicht entprellt ist, mehrmals, aber nur solange bis er sich beruhigt
hat. Dann wird die ISR, solange die Taste gehalten wird, NICHT mehr
aufgerufen und der Controller werkelt im Hauptprogramm.
Das ist der Sinn eines Interrupts.
Hauptprogramm unterbrechen, KURZ was machen, Hauptprogramm läuft weiter.
Beim Loslassen des Tasters entsprechend umgekehrt.
Womit dann beide Tasterstellungen auch wirklich ausgewertet werden.
mfg.
Hi Thomas,
danke Dir. Das Beispiel war eigentlich nur zum testen für mich gedacht
warum in einem anderen Code nicht wie erwartet auf einen Interrupt
reagiert wurde.
Wenn ich auf Pegeländerungen reagiere will ist laut Datenblatt im
Register MCUCR auf ISC01=0 und ISC00=1 zu setzen.
Ist
Stefan Ott schrieb:> Ich habe mir das Beispiel> [http://www.mikrocontroller.net/articles/Bitmanipulation] nochmal zu> Gemüte geführt. Im Abschnitt "Bits setzen" habe ich das vom Beispiel
Dann bitte jetzt noch den Abschnitt "Bits löschen" lesen, denn
> ISC01=0
bedeutet, dass des Bit ISC01 gelöscht werden soll.
Stefan Ott schrieb:> Kann ich beide Codezeilen irgendwie> vernünftig zusammenfassen?
Geht bestimmt irgendwie, aber ob man dann noch mit einem Blick erkennen
kann, was diese Zeile bewirkt?
Ich würde es bei den zwei Zeilen belassen.
Stefan Ott schrieb:> Kann ich beide Codezeilen irgendwie> vernünftig zusammenfassen?
Da es sich um die Initialisierung handelt, die nur ein einziges mal pro
Einschalten der Betriebsspannung erfolgt und immer direkt nach dem Reset
erfolgt, kannst Du Dir die Bitmanipulation mit OR und ggf. AND sparen.
Es genügt hier völlig, die I/O-Register per direkter Zuweisung zu
setzen. Und dabei brauchst Du im Term nur die Einsbits zu nennen, der
Rest ist dann automatisch Null.
Die von Dir aus dem Tutorial abgeschriebenen Bitmanipulationen sind dann
wichtig, wenn weitere Zugriffe auf die I/O-Register erfolgen, bei denen
darauf geachtet werden muss, dass zuvor veränderte andere Bits des
betreffenden Registers unverändert bleiben. Beim Erstzugriff bei der
Initialisierung ist dies nicht nötig.
...
Hannes Lux schrieb:> Und dabei brauchst Du im Term nur die Einsbits zu nennen, der> Rest ist dann automatisch Null.
Das ist im hier vorliegenden Fall richtig, deshalb hat ja seine
ursprüngliche Version mit den veroderten Nullen auch funktioniert. Im
Allgemeinen halte ich es aber für besseren Stil, in
Initialisierungsroutinen alle Bits die man setzen möchte (sowohl 0 als
auch 1) auch aufzuschreiben. Es gibt ja schliesslich auch Register,
deren Bits zum Teil mit 1 vorbelegt sind.
Stefan Ott schrieb:> ich habe aber trotzdem wieder etwas dazu> gelernt und darum geht es mir hauptsächlich.
Richtig. Bitmanipulation gehört zum Alphabet der Programmierung. Ohne
dieses Wissen (in der jeweils benutzten Prog-Sprache) kann man
eigentlich nicht (auf kleinen Mikrocontrollern) programmieren. Aber man
muss es nicht immer und überall anwenden, sondern nur da, wo es auch
sinnvoll ist.
...
J.-u. G. schrieb:> Version mit den veroderten Nullen auch funktioniert.
VerORte Nullen blähen nur den Code auf und machen ihn nicht unbedingt
lesbarer.
J.-u. G. schrieb:> halte ich es aber für besseren Stil, in> Initialisierungsroutinen alle Bits die man setzen möchte (sowohl 0 als> auch 1) auch aufzuschreiben.
Auch das bläht nur den Code auf, blockiert Programmspeicher und belastet
den Lesen mit Selbstverständlichkeiten (müllt das Wesentliche zu).
Solcher Code liest sich dann wie das Kleingedruckte in Verträgen, man
wird mit soviel Selbstverständlichkeiten zugemüllt, dass man das
Wesentliche nicht mehr erkennt.
Wenn man das konsequent durchziehen will, dann muss man auch alle
I/O-Register, also auch die, die man nicht verändern will,
initialisieren, was bei kleinen Controllern wie dem Tiny13 schon einen
erheblichen Teil des Programmspeichers belegt.
Ich gehe davon aus, dass man beim Erstellen des Programmcodes für die
Initialisierung der I/O-Register ins Datenblatt schaut und dabei sieht,
welche Bits (Schalter) im jeweiligen Register vorhanden sind und welchen
Initial-Value sie haben.
Dies ist meine persönliche Meinung, die ich Niemandem aufdrängen will.
Ich halte mich daher jetzt hier aus einer weiteren Diskussion darüber
raus.
...
Hannes Lux schrieb:> Auch das bläht nur den Code auf, blockiert Programmspeicher und belastet> den Lesen mit Selbstverständlichkeiten (müllt das Wesentliche zu).> Solcher Code liest sich dann wie das Kleingedruckte in Verträgen, man> wird mit soviel Selbstverständlichkeiten zugemüllt, dass man das> Wesentliche nicht mehr erkennt.
Nunja, es geht doch nur um die eine oder andere Zuweisung, die sowieso
in irgendeiner Initialisierungsroutine verschwindet. Wenn es tatsächlich
mit dem Speicher knapp wird, und das Programm deshalb nicht mehr richtig
läuft, lässt man die Zeilen natürlich weg.
Hannes Lux schrieb:> Dies ist meine persönliche Meinung, die ich Niemandem aufdrängen will.
War auch nur meine Meinung. Letztendlich wird sich jeder für eine ihm
genehme Herangehensweise entscheiden.