Guten Tag liebes Forum, ich komme mal wieder nicht weiter und hoffe auf erneute Hilfe :D Und zwar soll das Programm folgendes können: Es soll 3 Modi geben die jeweils mit einem Tasterdruck ausgeführt werden soll. Sprich, Lauflicht von links nach rechts Tasterdruck > Lauflicht von recht nach links Tasterdruck > Lauflicht aus und dann wieder von vorne. In meinem vorherigen Programm habe ich den Taster einbinden können, jedoch ohne Interrupt. da sah die Funktion so aus: while(1) { if (PIND & (1<<PD2)) { lampen1an(); } else { lampen2an(); } Hat auch super funktioniert. Mein bisheriges Programm sieht jetzt so aus: #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> volatile unsigned int status = 0 ; void init (void); void mode1 (void); void mode2 (void); void mode3 (void); ISR(INT0_vect) { status++; if (status >=3) { status = 0; } } void main(void) { init(); while(1) { switch(status) { case 0: mode1(); break; case 1: mode2(); break; case 2: mode3(); break; } } } void init(void) { DDRD |= (1<<PD6); DDRB |= (1<<PB2); DDRB |= (1<<PB1); DDRB |= (1<<PB0); DDRD &= ~(1<<PD2); PORTD |= (1<<PD2); GIMSK = 0b01000000; MCUCR = 0b00000001; sei(); } void mode1(void) { PORTD |= (1<<PD6); _delay_ms(500); PORTB |= (1<<PB0); _delay_ms(500); PORTB |= (1<<PB1); _delay_ms(500); PORTB |= (1<<PB2); } void mode2(void) { PORTB |= (1<<PB2); _delay_ms(500); PORTB |= (1<<PB1); _delay_ms(500); PORTB |= (1<<PB0); _delay_ms(500); PORTD |= (1<<PD2); } void mode3(void) { PORTD &= ~(1<<PD6); PORTB &= ~(1<<PB2); PORTB &= ~(1<<PB1); PORTB &= ~(1<<PB0); } Die Frage wäre jetzt, wo genau ich den Taster mit einfüge? Steh gerade richtig auf dem Schlauch. Ich hoffe mir kann jemand helfen :)
Marcel R. schrieb: > Die Frage wäre jetzt, wo genau ich den Taster mit einfüge? Dein Plan ist doch, dass der Tastendruck einen Interrupt auslöst. Die entsprechende ISR hast du bereits geschrieben. Das wird aber nicht wie gewollt funktionieren, weil jeder Taster prellt. Beim Tastendruck wirst du mehrere Interrupts erhalten, so dass das Ergebnis ziemlich zufällig erscheint. Du brauchst einen Timer, der nach erkanntem Tastendruck sicher stellt, dass weitere Impulse für eine gewisse Zeit (z.B. 20ms) ignoriert werden. Ich glaube, das ist für dich (noch) zu kompliziert. Folgende Schaltung entprellt das Signal per Hardware:
1 | 2,2kΩ Taster |
2 | _____ |
3 | GND |---+----[===]-----------+------ --------o 5V |
4 | | | |
5 | +---||---+---[===]---+ |
6 | | |
7 | 100nF | 100Ω |
8 | | |
9 | o |
10 | I/O Pin PD2 |
Danke schonmal für die Antwort, Die Schaltung zu bauen wäre kein Problem, Widerstände und Kondensatoren hab ich noch zur genüge :) Kannst du mir dann noch mit dem Tasterproblem helfen? Also wie bekomme ich es hin, das er weiß, wann er den Status wechseln soll mithilfe des Tasters?
Taster mit Interrupt ist ne ganz schlechte Idee, da mechanische Kontakte prellen. Da bietet sich eine Entprell-Lib an, die in einem festen Raster entprellt. Das 2. Problem, wo wertet man das Ereignis aus, wenn die Routinen ganz lange dauern. Statt Warteschleifen bietet sich da eine Zeitsteuerung an, die neue Pattern aus eine Tabelle liest. Die gibt die Wartezeiten immer zum Main zurück, d.h. kann jederzeit abgebrochen werden. Hier ein Beispiel für beides: Beitrag "AVR Sleep Mode / Knight Rider"
Marcel R. schrieb: > Also wie bekomme ich es hin, das er weiß, wann er den Status wechseln > soll mithilfe des Tasters? Bei Tastendruck löst die Hardware einen Aufruf der ISR aus. Diese reagiert entsprechend. Das sieht in deinem Quelltext schon gut aus, mehr muss man da prinzipiell nicht machen. So wie du fragst funktioniert es wohl nicht. Irgendwo wird sich ein kleiner Fehlerteufel versteckt haben. Peter D. hat schon recht. Eine Entprellung per Software ist flexibler und billiger - also sinnvoller. Sobald du mehrere Tasten hast, muss man da schon etwas mehr Hirnschmalz rein stecken. Mit Interrupt-Routinen landet man da schnell in einer Sackgasse. Noch nicht, aber später wenn das Programm komplexer wird. Probiere das trotzdem mal mit dem Kondensator aus. Wenn man die Vor- und Nachteile durch Fehler-Machen erlebt, prägen sie sich besser ein. Ich lerne im Hobby gerne auf diese Art (im Job geht das leider nicht so). Eine andere Sache, auf die du sehr bald stoßen wirst ist, dass deine Lauflichter bis zum Ende durchlaufen, bevor sie die Richtung ändern. Das wirst du sicher auch verbessern wollen. Aber eins nach dem Anderem. Bleibe erst einmal beim aktuellen Problem, dann erforsche unterschiedliche Methoden des Entprellens.
Danke euch beiden erstmal für die ganzen Infos. @Stefan: Hatte das Programm noch gar nicht ausprobiert, da ich dachte es fehlt noch der Taster irgendwo. Es funktioniert zwar so halb, weiß ehrlich gesagt nicht warum er den Taster erkennt :P Da ich aber heute erst das zweite mal damit arbeite, verstehe ich nur ein Bruchteil und muss mich erst weiter einlesen. Modus eins läuft, da die LEDS's schon in Modus zwei an waren, konnten sie bei Modus 2 natürlich nicht mehr angehen. Dann hab ich den Modus 2 geändert: void mode2(void) { PORTD &= ~(1<<PD6); PORTB &= ~(1<<PB2); PORTB &= ~(1<<PB1); PORTB &= ~(1<<PB0); _delay_ms(500); PORTB |= (1<<PB2); _delay_ms(500); PORTB |= (1<<PB1); _delay_ms(500); PORTB |= (1<<PB0); _delay_ms(500); PORTD |= (1<<PD6); } Jetzt läuft es wie folgt: Modus 1: Licht läuft einmal von links nach rechts und alle bleiben am Schluß an. Modus 2:Licht läuft von rechts nach links, bleibt aber nicht an, sondern es fängt immer wieder von vorne an. Modus 3: Licht geht aus. Naja vll liegt es ja an einem von euren genannten Problemen. So wird dann der Urlaub nächste Woche nicht langweilig.
Marcel R. schrieb: > Es funktioniert zwar so halb, weiß ehrlich gesagt nicht warum er den > Taster erkennt :P Weil du den entsprechenden Interrupt aktiviert hast. Die Verbindung zwischen I/O Pin und Aufruf der Interruptroutine hast du damit aktiviert: > GIMSK = 0b01000000; > MCUCR = 0b00000001; > sei(); Anscheinend ist Dir nicht klar, was du programmiert/kopiert hast. Zieh Dir das mal rein: http://stefanfrings.de/mikrocontroller_buch/index.html Im Mode 1 schaltest du die vier LEDs nacheinander ein. Sie bleiben danach alle an, weil du keinen Code hast, der sie wieder aus schaltet. Im Mode 2 werden erst alle LEDs aus geschaltet, dann nacheinander ein. Hier ist die Wiederholung erkennbar, weil sie beim Beginn der Funktion aus geschaltet werden. Also alles genau so, wie du es programmiert hast.
Ist alles selber geschrieben, nur nicht verstanden dann anscheinen :D
GIMSK = 0b01000000; //für mich ist das das aktievieren des Interrupts
INT0
MCUCR = 0b00000001; // und das beim Ereignis sobald sich eine Flanke
ändert
> sei(); // das war das allgemeine einschalten der Interrupts
kann sein das ich mich jetzt bei GIMSK/MCUCR vertan habe, habe das
Datenblatt nicht mehr auf gerade.
hab nur gedacht, man müsste den Taster nochmal extra einfügen irgendwo.
Marcel R. schrieb: > hab nur gedacht, man müsste den Taster nochmal extra einfügen irgendwo. Warum denn? Der Taster löst den Interrupt aus, der Interrupt sorgt dafür, dass die ISR angesprungen wird. Da fehlt nichts.
Gute Frage warum :D Naja ich hab bisher noch nie was mit programmieren zu tun gehabt, tu mich deshalb noch ein wenig schwer damit. Aber es kann ja nur besser werden :) Danke dir auf jedenfall für deine Hilfe/Zeit.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.