Hallo, ich möchte mit einem Button einen Interrupt auslösen. Bisher habe
ich immer in der while schleife abgefragt
1
int main(){
2
while(1){
3
...
4
if(PINB&(1<<PINB4)){
5
PORTB |= (1<<PB0); // LED an
6
_delay_ms(1000);
7
}
8
else{
9
PORTB &= ~(1<<PB0); // LED aus
10
}
11
...
12
}
13
}
Jetzt ist es ja so, dass die while schleife immer durchläuft und nur
wenn ich im richtigen zeitpunkt den Taster gedrückt halte, die LED
angeht.
Kann man das auch so machen, dass eine Routine aufgerufen wird, sobald
ich den Taster drücke und dort dann drinn steht:
1
PORTB |= (1<<PB0); // LED an
2
_delay_ms(1000);
so könnte ich das dann aus der hauptschleife raus nehmen.
Peter schrieb:> Jetzt ist es ja so, dass die while schleife immer durchläuft und nur> wenn ich im richtigen zeitpunkt den Taster gedrückt halte, die LED> angeht.
damit hast du erkannt, dass delay nur Probleme verursacht und fast nie
sinnvoll ist.
Taster an Interrupts zu hängen ist der nächste Fehler ;)
Und delay in Interrupts ist eine noch viel schlimmere Todsünde.
Lies dir mal diesen Artikel durch:
http://www.mikrocontroller.net/articles/Entprellung
Insbesondere den Abschnitt "Timer-Verfahren (nach Peter Dannegger)"
lg
Chris
Sers,
natürlich könntest du das ganze außerhalb der main in eine extra
"methode" funktion oder wie man es sonst noch nennen will, packen.
Vergiss aber nicht, die Funktion auch noch als Prototyp festzulegen, da
du sonst einen Fehler bekommst.
Hab die Übung ausm lehrbuch (stark ähnlich) übrigens schon hinter mir,
und kann mir auch vorstellen, was bei dir danach noch kommt.
Mfg,
tommyProg
chris schrieb:> Peter schrieb:>> Jetzt ist es ja so, dass die while schleife immer durchläuft und nur>> wenn ich im richtigen zeitpunkt den Taster gedrückt halte, die LED>> angeht.>> damit hast du erkannt, dass delay nur Probleme verursacht und fast nie> sinnvoll ist.
Mag sein, aber lass ihn das noch ausprobieren, und ihn stück für Stück
machen.
> Taster an Interrupts zu hängen ist der nächste Fehler ;)
Hehe, ich weiß noch wo ich das gemacht hatte.
Du hast nicht recht, es ist kein Fehler, aber man soll es nicht machen,
weil es technisch katastrophal ist.
In einer Übung ausm Lehrbuch wird das aber so verlangt. Und Lösungen
gibts nur eigene^^.
> Und delay in Interrupts ist eine noch viel schlimmere Todsünde.
Ja, da hast du recht, warteschleifen, LCD ausgaben usw. sind der
wahnsinn³ in ISR's
> Lies dir mal diesen Artikel durch:> http://www.mikrocontroller.net/articles/Entprellung>> Insbesondere den Abschnitt "Timer-Verfahren (nach Peter Dannegger)"
Timer- Verfahren würde ich noch nicht durchlesen, weil es da auch
interrupt verfahren gibt, und wie man einen Timer programmiert scheint
anfangs schwer (habs gestern erst gemacht). Von daher mach dann eher mit
interrupts weiter, und wenn du das System dahinter verstanden hast,
dann würde ich mir timer anschauen.
Schau mal in paar Tagen auf youtube interrupt grundlagen an, da müsst
nen video aus koblenz geben, wo der prof das sehr gut erklärt.
mfg,
tommyProg
Tho Wes schrieb:> Timer- Verfahren würde ich noch nicht durchlesen, weil es da auch> interrupt verfahren gibt, und wie man einen Timer programmiert scheint> anfangs schwer (habs gestern erst gemacht).
Timer sind die leichteste Übung von allen
FAQ: Timer
Die Hauptschwierigkeit ist das Begreifen wie einfach die Sache
eigentlich ist, weil alle in einem Timer immer viel mehr sehen, als da
tatsächlich dahinter steckt.
Dagegen ist eine reine externer Interrupt Software-Lösung für einen
Taster eine harte Nuss. Lehrbuch hin oder her.
Ausserdem bringt es ihm nichts, solange er mit delay arbeitet. Der
Prozessor kann nun mal nur eine Sache zu einem bestimmten Zeitpunkt
machen. Wenn er im delay hängt, dann hängt er im delay. Egal ob das in
main() oder in einer ISR ist. Davon kommt man nur weg wenn man Timer
benutzt. Und so schwer ist das auch wieder nicht. Dafür aber sehr
wichtig, das man diese Technik beherrscht. Ganz im Gegensatz zu 'Taster
an externem Interrupt'.
Allenfalls kann man noch über die Beobachtung gehen, dass 1000 mal 1ms
gewartet in Summe auch 1000ms gewartet sind. Will man also eine LED 1
Sekunde nach dem Drücken und Loslassen einer Taste verlöschen lassen und
kann nichts anderes als delay, dann kann man immer noch:
1
intmain()
2
{
3
uint16_twaitTime;
4
5
...
6
7
waitTime=0;
8
9
while(1){
10
...
11
if(PINB&(1<<PINB4)){
12
waitTime=1000;
13
PORTB|=(1<<PB0);// LED an
14
}
15
16
if(waitTime>0){
17
waitTime--;
18
if(waitTime==0)
19
PORTB&=~(1<<PB0);// LED aus
20
}
21
_delay_ms(1);
22
...
23
}
24
}
mit der 1 Millisekunde kann man eventuell leben, für einen Lernenden auf
dem Weg zum Verständnis eines Timers wäre das für mich eine akzeptable
Lösung. Aber auf lange Sicht hilft nur: lernen wie man mit einem Timer
einen Basistakt generiert und davon dann alles weitere ableitet. Das ist
insofern wichtig, weil damit auch ein Wechsel in der
Programmierphilosophie einher geht (der in der letzten Lösung schon ein
wenig angedeutet ist), der extrem wichtig in der µC Programmierung ist.
Timer sind DIE Arbeitspferde in einem µC Programm. Demenstrechend
wichtig ist es auch, mit ihnen umgehen zu können und einige
Softwaretechniken zu können, die auf Timern basieren.
Ich habe da noch mal eine Nachfrage, das mit dem Interrupt habe ich
hinbekommen, war ja gar nicht so schwierig. Allerdings kann ich nur
Pin7, also INT0 nehmen.
1
int main(){
2
MCUCR |= (1<<ISC00) | (1<<ISC01);
3
GIMSK |= (1<<INT0);
4
while(1){
5
...
6
...
7
}
8
}
9
10
ISR(INT0_vect){
11
PORTB |= (1<<PB0);
12
_delay_ms(1000);
13
PORTB &= ~(1<<PB0);
14
}
das funktioniert ja auch. Aber das mit dem _delay_ms(1000) bekomme ich
auch noch weg.
Meine Frage geht aber eher richtung der Funktion.
chris schrieb:> Taster an Interrupts zu hängen ist der nächste Fehler ;)
Wieso?
Hi
>Wieso?
Weil Taster prellen. Aber
>ISR(INT0_vect){> PORTB |= (1<<PB0);> _delay_ms(1000);> PORTB &= ~(1<<PB0);>}
Delays in Interrupts, noch dazu in dieser Größenordnung, sind ein
absoluter NoGo.
MfG Spess
Peter schrieb:>> Taster an Interrupts zu hängen ist der nächste Fehler ;)
Weil Taster prellen.
Du drückst einmal und es werden 5 Interrupts ausgelöst. Wie stellst du
denn fest welche der Interrupts aufgrund eines Prellvorgangs (der dauert
so in der Größenordnung von 5 bis 10ms) ausgelöst wurden und welcher
Interrupt real wegen einem Tastendruck durch den Benutzer ausgelöst
wurde?
Es zeigt sich, dass du durch einen externen Interrupt keinerlei Vorteil
mehr hast. Ganz im Gegenteil wird der Code komplexer als wenn man gleich
auf Pollen in einer Timerschleife setzt. Um zu Entprellen muss in
irgendeiner Form eine zeitliche Steuerung rein. Und zeitliche Steuerung
bedeutet in einem µC zu 99% praktisch immer der Einsatz eines Timers.
Wenn ich den Timer aber sowieso zum Entprellen brauche(*), dann kann
dort auch gleich das Tastenpollen mit gemacht werden. Ein Taster an
einem externen Interrupt macht nur dann Sinn, wenn man den µC dadurch
aus dem Stromspar-Tiefschlaf holen muss.
Und keine Sorge.
Auch wenn deine Taster jetzt noch nicht prellen - irgendwann werden sie
es tun. Das ist so sicher wie das Amen im Gebet.
(*) abgesehen davon hat so gut wie jedes irgendwie ernstzunehmende
Programm mindestens 1 Timer im Einsatz. D.h. das ist noch nicht mal
massig Mehraufwand, den auch noch zum Tastenbehandeln einzusetzen.