Hallo, mein Name ist Patrick und ich beschäftige mich seit kurzem mit µC's. Bin gerade dabei, mit Timer herum zu experimentieren. Dabei beabsichtige ich folgenden Versuchsaufbau: Atmega8, interner Takt 8Mhz Taster wird eingelesen, eine LED soll dadurch leuchten und zwar eine bestimmte Zeit (über Timer eingestellt) ca. 5sec. Ich möchte jedoch, dass bei erneutem Drücken der Tastre die LED sofort ausgeht oder eben von selbst nach 5 sec. Danach soll die LED wieder durch erneutes Drücken des Tasters für 5sec angehen (oder eben bis der Taster wieder gedrückt wird) Soweit so gut. Den Timer habe ich initialisiert, Prescaler, etc. eingestellt, Interrupts aktiviert. In der Interrupt Routine zähle ich die Sekunden mittels Variablen, soweit habe ich das aus dem Tutorial entnehmen können. Nur wie ich den Timer dann in das Programm integriere, ist für mich fraglich bzw. wie der µC das Programm abarbeitet. Geschrieben wird das Programm in C und ist bis jetzt aufgrund des fehlenden Verständnisses nicht komplett, sonst würde ich den Code hier mal posten. Für mich stellt sich generell der Frage, wie ich an so ein Problem programmiertechnisch herangehe. Im Hauptprogramm lese ich den PIN ein, wo der Taster hängt. Ist dieser gedrückt, setze ich den Ausgang der LED auf HIGH. Nur wie integriere ich dann den Timer in das Programm? Und was macht der µC während dieser "Wartezeit". Nach der Wartezeit soll der Ausgang wieder auf LOW gesetzt werden. Nur wie bekomme ich es dann hin, dass wenn der Taster erneut gedrückt wird, dass die LED sofort ausgeht bzw. der Ausgang eben direkt auf LOW gesetzt wird? Kann ich dies einfach durch eine IF Abfrage lösen? Oder würde man hier ein weiteres (exgternes) Interrupt benötigen, welches durch den Taster ausgelöst wird? Vielleicht kann mir jemand einmal die Arbeitsweise näher bringen oder vielleicht ein Beispiel C Code eines ähnlichen Programms posten. Im Tutorial konnte ich dazu leider nichts finden. Danke. Viele Grüße Paddy
In diesem Fall wuerde ich sagen: Initialisiere den Timer, starte ihn und schicke das Hauptprogramm in eine Endlosschleife. Aendere den Timerintervall so ab, dass er 1000 mal pro Sekunde auftritt. Jetzt fragst du jede Millisekunde die Taste ab (das erspart dir erstmal Entprellroutinen, ist nicht perfekt, aber geht so). Die LED steuerst du ueber eine Variable, die du bei jedem Interruptaufruf runter zaehlst, solange sie nicht 0 ist. Wird sie 0, schaltest du die LED aus. Wird eine Taste gedrueckt, pruefst du die Variable: Ist sie nicht 0, ist die LED gerade an. Also schaltest du sie aus und setzt den Zaehler auf 0. Ist sie 0, ist die LED gerade aus. Also schaltest du sie ein und setzt den Zaehler auf 5000.
Hi, mal auf die schnelle geschrieben. Die Kommentare musste selbst in den Registern einstellen. Sollte aber funzen oder zumindest annähernd.
1 | #include <avr\io.h> |
2 | #include <interrupt.h> |
3 | |
4 | volatile char Taster , Merker; |
5 | int main() |
6 | {
|
7 | Taster = 0; |
8 | Merker = 0; |
9 | switch(Taster) |
10 | {
|
11 | case 1: |
12 | {
|
13 | //Timer konfigurieren und starten
|
14 | //LED ein
|
15 | Taster = 0; |
16 | break; |
17 | }
|
18 | case 2: |
19 | {
|
20 | //Timer aus
|
21 | //LED aus
|
22 | Taster = 0; |
23 | break; |
24 | }
|
25 | default:
|
26 | {
|
27 | break; |
28 | }
|
29 | }
|
30 | }
|
31 | |
32 | //CTC Interrupt
|
33 | ISR(TIMER1_COMPA_vect) |
34 | {
|
35 | //LED aus
|
36 | //Taster = 0;
|
37 | }
|
38 | |
39 | ISR(INT0_vect) |
40 | {
|
41 | if(!Taster && !Merker) |
42 | {
|
43 | Taster = 1; |
44 | Merker = 1; |
45 | }
|
46 | else if(!Taster && Merker ==1) |
47 | {
|
48 | Taster = 2; |
49 | Merker = 0; |
50 | }
|
51 | else
|
52 | {
|
53 | //TODO
|
54 | }
|
55 | }
|
Ups, habe den ISR0 Einstellungs Kommentar am Anfang der main() vergessen ! Oje und sei() auch vergessen, peinlich ! Entprellung fehlt natürlich auch !
Jean schrieb: > Ups, > habe den ISR0 Einstellungs Kommentar am Anfang der main() vergessen ! > Oje und sei() auch vergessen, peinlich ! > Entprellung fehlt natürlich auch ! Und while fehlt auch^^
Den volatile char Merker; tät ich als static char Merker=0; in der ISR deklarieren. Wegen der Sauberkeit !
Hallo zusammen, vielen Dank für die Antworten Bei dem Vorschlag von Peter Stegemann frage ich die Zustände des Tasters im Hauptprogramm ab oder? Für mich ist als Anfänger nicht ganz klar, was ich im Hauptprogramm abfragen muss und was muss in die Interrupt Routinen? @Jean, vielen Dank für das Programm. Ich denke, dies ist bestimmt sehr hilfreich. Möchte aber zunächst versuchen, das ganze selbst schreiben (man will ja lernen). Aber zur Not dient es bestimmt als gute Spicklösung oder Anregung, falls ich nicht weiterkomme. Viele Grüße Paddy
Paddyr schrieb: > Hallo zusammen, > > vielen Dank für die Antworten > Bei dem Vorschlag von Peter Stegemann frage ich die Zustände des Tasters > im Hauptprogramm ab oder? Nein, auch im Interrupt. Der tritt ja jede Millisekunde auf und kann das elegant erledigen. Stelle doch mal deinen aktuellen Code ein... oder naehere dich dem Ganzen schrittweise: Mach mal im Timerinterrupt nur die LED an und aus, so im Sekundentakt. > Für mich ist als Anfänger nicht ganz klar, was ich im Hauptprogramm > abfragen muss und was muss in die Interrupt Routinen? Muessen tust du mal gar nichts - allerdings gibt es gewisse Vorgehensweisen, die sich als praktisch erwiesen haben ;-) Ich erledige z.B. die ganzen Zeichenaufgaben (ich habe bei meinem Hauptprojekt umfrangreiche, grafische Menues) im "Hauptprogramm". Einfach aus dem Grund, weil diese Aufgaben die niedrigste Prioritaet haben und jederzeit von den Timern, die in mehr oder weniger strikten Intervallen Aufgaben zu erledigen haben, unterbrochen werden koennen.
Peter hat es ja schon angesprochen. Für einen Neuling würde ich unbedingt zu der grundelgenden Arbeitsweise raten: Sieh die Timer-ISR wie eine Art Uhr an, die in regelmässigen Abständen 'tickt', also Code ausführt. Dieser Code kann zb sein: eine Variable erhöhen (das wäre dann zb eine normale Uhr) oder erniedrigen (das wäre dann eine Countdown-Uhr). Mehr aber sollte die ISR nicht wirklich machen (Taster auf gedrückt abfragen ist ok). Alles weitere, was es zb bedeutet, wenn eine Countdown-Uhr auf 0 heruntergezählt wurde, findet in der Hauptschleife statt. Das ist die grundlegende Schleife innerhalb main int main() { ... while( 1 ) { .... } } in der die eigentliche, komplette Logik steckt. Dort wird zb die Countdown-Uhr auf 5 Sekunden eingestellt. Die ISR zählt diese wieder auf 0 herunter. Wiederrum in der Hauptschleife findet auch die Überwachung statt, ob die Countdown-Uhr noch läuft oder ob sie bereits wieder auf 0 heruntergezählt wurde. Ganz wichtig: In der Hautpschleife keine Warteschleifen veranstalten. Also nicht darauf aktiv warten, dass die Countdown-Uhr 0 erreicht hat. Du musst das eher so sehen, dass die Hauptschleife eine Reihenfolge von Aktionen enthält, die nacheinander wieder und immer wieder ausgeführt werden. Also sowas wie eine Vorschrift: * zuerst schau nach ob eine taste gedrückt wurde * dann sieh nach, ob die Uhr schon runter ist * und das ganze ständig wiederholen Dieser Ansatz ist selbstverständlich nicht der einzig mögliche. Wie Peter schon schrieb: "müssen tust du gar nichts". Aber ein derartiger Aufbau hat sich in der Praxis bewährt und funktioniert bei vielen Aufgabenstellungen sehr gut. Daher sollte man gerade als Neuling sich an diese Strukturen gewöhnen.
Hallo, so, das Programm habe ich nun fertig geschrieben, aber es läuft nicht. Eckdaten: Prozessor Atmega8 PB0 hängt der Taster gegen Masse, an PB0 ist 5V angelegt, interne Pullups aktiviert PB1 hängt die LED, die leuchten soll Sobald die Schaltung an Spannung anliegt, leuchtet die LED bereits ohne, dass der Taster gedrückt wurde. Wird der Taster gedrückt, so entsteht ein Kurzschluss. Da ich blutiger Anfänger bin, finde ich leider den Fehler nicht. Vielleicht kann mir jemand helfen. Hier der Sourcecode:
1 | #define F_CPU 8000000UL // 8MHz
|
2 | |
3 | #include <avr/io.h> |
4 | #include <avr/interrupt.h> |
5 | #include <util/delay.h> |
6 | #include <inttypes.h> |
7 | |
8 | // ------------------------------------------------------------------------------------------------
|
9 | // DEFINES
|
10 | // ------------------------------------------------------------------------------------------------
|
11 | |
12 | #define COUNTER_INCS_PER_MILLISECOND_T0 1000 // (8.000.000 / 8) / 1000
|
13 | #define COUNTER_INCS_PER_SECOND_T0 1000000
|
14 | |
15 | // PIN Definitionen
|
16 | #define Taster PB0 // PIN des Tasters
|
17 | #define LED PB1 // PIN der LED, die blinkt
|
18 | |
19 | // ------------------------------------------------------------------------------------------
|
20 | // Funktionsdeklarationen
|
21 | // ------------------------------------------------------------------------------------------
|
22 | void init(void); //Funktion zum Initialisieren der Ports |
23 | void debounce (uint8_t *, uint8_t); //Funktion zum Entprellen |
24 | |
25 | // ------------------------------------------------------------------------------------------
|
26 | // globale Variablen, die von Interruptroutinen verändert werden
|
27 | // ------------------------------------------------------------------------------------------
|
28 | volatile unsigned long ulCurrentCounterTimer0G=0; // enthält den aktuellen Wert des laufenden Timers 0 in Datenticks |
29 | volatile unsigned long ulSecondCounter0G = 0; // enthält (annähernd) die Sekundenanzahl des Timers |
30 | volatile unsigned char zeitmerker = 0; // Zeitmerker für den Vergleich, ob Zeit schon abgelaufen ist |
31 | |
32 | // ------------------------------------------------------------------------------------------
|
33 | // globale Variablen
|
34 | // ------------------------------------------------------------------------------------------
|
35 | |
36 | /*
|
37 | * Timer 0 Overflow Interrupt
|
38 | */
|
39 | ISR(TIMER0_OVF_vect) |
40 | {
|
41 | // --------------------------------------------------------------------------------------------
|
42 | // Bei jedem Overflow wird the TimerCounter um 256 (Ticks) inkrementiert.
|
43 | // Nach ca. 1 Sekunde wird der Sekundenzähler erhöht
|
44 | //---------------------------------------------------------------------------------------------
|
45 | ulCurrentCounterTimer0G+=256; //bei jedem overflow wird der Timer um 256 inkrementiert |
46 | |
47 | if (ulCurrentCounterTimer0G>=COUNTER_INCS_PER_SECOND_T0) |
48 | {
|
49 | //es ist eine Sekunde vergangen, Sekundenzähler erhöhen
|
50 | ulSecondCounter0G++; |
51 | zeitmerker = ulSecondCounter0G; |
52 | |
53 | // den Counter und den Tickzähler wieder zurücksetzen
|
54 | |
55 | TCNT0 = 0; //Counter wird zurückgesetzt, der Preload Wert wird nicht ausgerechnet (Zeit, die der TC zu groß ist) |
56 | ulCurrentCounterTimer0G = 0; //Tickzähler wird zurückgesetzt |
57 | }
|
58 | }
|
59 | |
60 | // Das Hauptprogramm (Einsprungpunkt)
|
61 | int main() |
62 | {
|
63 | // Ports und Interrupts initialisieren
|
64 | init(); |
65 | |
66 | while(1) |
67 | {
|
68 | // ----------------------------------------------------------------------------------------
|
69 | // in der Hauptschleife des Programmes werden die Taster eingelesen
|
70 | // ----------------------------------------------------------------------------------------
|
71 | |
72 | // den Taster abfragen, Funktion kehrt zurück, wenn der Status stabil ist (Entprellung)
|
73 | debounce( (uint8_t*)&PINB, (1<<Taster) ); |
74 | |
75 | if ( !(PINB & (1 << Taster)) ) //frägt den Zustand des Tasters ab |
76 | {
|
77 | PORTB |= (1<< LED ); //PB1 an dem die LED hängt anschalten |
78 | TCCR0 |= (1<<CS01); //Den Timer starten |
79 | }
|
80 | |
81 | if ( PINB & (1 << LED) ) //frägt den Zustand des Ausganges der LED ab |
82 | {
|
83 | if (zeitmerker>=25) |
84 | |
85 | {
|
86 | PORTB &= ~(1<< LED ); //PB1 an dem die LED hängt ausschalten |
87 | |
88 | // --------------------------------------------------------------------------------------
|
89 | // Timer stoppen und Rücksetzen
|
90 | // --------------------------------------------------------------------------------------
|
91 | TCCR0 &= ~(1<<CS01); //Den Timer stoppen |
92 | ulSecondCounter0G = 0; |
93 | ulCurrentCounterTimer0G=0; |
94 | zeitmerker=0; |
95 | TCNT0 = 0; |
96 | }
|
97 | |
98 | else
|
99 | {
|
100 | // den Taster abfragen, Funktion kehrt zurück, wenn der Status stabil ist (Entprellung)
|
101 | debounce( (uint8_t*)&PINB, (1<<Taster) ); |
102 | |
103 | if ( !(PINB & (1 << Taster)) ) //frägt den Zustand des Tasters ab, prüft ob dieser wieder gedrückt wird für Abbruch |
104 | |
105 | {
|
106 | PORTB &= ~(1<< LED ); //PB1 an dem die LED hängt ausschalten |
107 | |
108 | |
109 | // --------------------------------------------------------------------------------------
|
110 | // Timer stoppen und Rücksetzen
|
111 | // --------------------------------------------------------------------------------------
|
112 | TCCR0 &= ~(1<<CS01); //Den Timer stoppen |
113 | ulSecondCounter0G = 0; |
114 | ulCurrentCounterTimer0G=0; |
115 | zeitmerker=0; |
116 | TCNT0 = 0; |
117 | |
118 | }
|
119 | |
120 | }
|
121 | }
|
122 | }
|
123 | }
|
124 | |
125 | /*
|
126 | * Funktion init(): Initialisierung des µC
|
127 | */
|
128 | void init(void) |
129 | {
|
130 | // --------------------------------------------------------------------------------------------
|
131 | // PORTB konfigurieren
|
132 | //
|
133 | // B0 --> Eingang für Taster
|
134 | // B1 --> Ausgang für LED
|
135 | // --------------------------------------------------------------------------------------------
|
136 | DDRB = 0x00; |
137 | DDRB |= (1 << DDB1) ; // B1 (Transistor) (LED) als Ausgang deklarieren, Rest (und damit PB0) Eingänge |
138 | PORTB |= (1<<PB0); // internen Pull-Up an PB0 aktivieren // |
139 | |
140 | |
141 | // --------------------------------------------------------------------------------------------
|
142 | // Timer 0 (8-Bit)
|
143 | // --------------------------------------------------------------------------------------------
|
144 | TCCR0 &= ~(1<<CS01); //Timer0 zunächst gestoppt, es wird mit einem Prescaler von 8 gearbeitet |
145 | TCNT0 = 0; // Counter auf 0 initialisieren |
146 | TIMSK |= (1<<TOIE0); // Bei overflow wird timer interrupt 0 ausgelöst |
147 | |
148 | sei(); // setzt globales Interrupt Enable Bit |
149 | return; |
150 | }
|
151 | |
152 | /*
|
153 | * Funktion debounce(): Funktion zum entprellen von Tasten, Schalter, etc
|
154 | * "Warteschleifenvariante mit Maske und Pointer (nach Christian Riggenbach)"
|
155 | * gefunden auf microcontroller.net
|
156 | */
|
157 | void debounce( uint8_t *port, uint8_t maske ) |
158 | {
|
159 | uint8_t port_puffer; |
160 | uint8_t entprellungs_puffer; |
161 | |
162 | for( entprellungs_puffer=0 ; entprellungs_puffer!=0xff ; ) |
163 | {
|
164 | entprellungs_puffer<<=1; |
165 | port_puffer = *port; |
166 | _delay_us(150); |
167 | if( (*port & maske) == (port_puffer & maske) ) |
168 | {
|
169 | entprellungs_puffer |= 0x01; |
170 | }
|
171 | }
|
172 | }
|
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.