Hallo Leute, ich steh hier leider vor einem Problem. ISR (INT0_vect) { setLedMode(15,true); } Ich wollte eigentlich das bei einem Interrupt eine Led immer eingeschaltet wird. Mein Problem ist gerade, dass der Interrupt immer ausgelöst wird, sobald mein µC geflasht worden ist mit meinem neuen Programm. Es liegt immer 5 V an und bei einem Interrupt fällt die Flanke auf 0 V. (ich denke daran liegt der fehler). Hier ist die Doku für die Lichtschranke: http://www.produktinfo.conrad.com/datenblaetter/125000-149999/140268-da-01-en-IR_SENSOR_APDS_9102_L22.pdf und es handelt sich um ein ATMEGA88. Danke im Vorraus!
1 | //TIMSK0 |= (1 << TOIE0);
|
2 | //TCCR0B |= (1<<CS00 | 0<<CS01 | 0<<CS02);
|
3 | // Port B auf Ausgang setzen
|
4 | DDRB = 0xff; |
5 | // Port C auf Ausgang setzen
|
6 | DDRC = 0xff; |
7 | // Port D auf Ausgang setzen
|
8 | DDRD = 0xff; |
9 | // Lichtschranke PD2 auf Eingang
|
10 | DDRD = DDRD & ~(1<<PD2); |
11 | |
12 | // LEDs auf den Ports ausschalten
|
13 | PORTB = 0xff; |
14 | PORTC = 0xff; |
15 | PORTD = 0xff; |
16 | |
17 | EIMSK |= _BV(INT0); // PD2 = INT0 enablen |
18 | EICRA |= _BV(ISC01); // Triggern auf fallende Flanke des INT0 |
19 | |
20 | //Timer1 fuer die Umlaeufe konfigurieren
|
21 | TCCR1B = (1 << CS10) | (1 << CS21) ; //kein Prescaler |
22 | TIMSK1 = (1 << TOIE1) | (1 << OCIE1A) ; |
23 | |
24 | TIMSK2 |= (1 << TOIE2); |
25 | TCCR2B |= (1<<CS20 | 0<<CS21 | 0<<CS22); |
26 | |
27 | // Timer0 fuer die Stundenanzahl konfigurieren
|
28 | // CompareMatchInterupt ausloesen
|
29 | // Timer0 fuer die Uhrzeiten-Logik und Overflow fuer Timer0
|
30 | TIMSK0 = _BV(OCIE0A) | _BV(TOIE0); // Enable Interrupt TimerCounter0 Compare Match A (SIG_OUTPUT_COMPARE0A) |
31 | TCCR0A = _BV(WGM01); // Mode = CTC |
32 | TCCR0B = _BV(CS02) | _BV(CS00); // Clock/1024, 0.001024 seconds per tick |
33 | OCR0A = 244; // 0.001024*244 ~= .25 SIG_OUTPUT_COMPARE0A will be triggered 4 times per second. |
34 | |
35 | // Das Makro sei() schaltet alle Interrupts ein.
|
36 | sei(); |
:
Bearbeitet durch User
Tuji de Assis Moreira schrieb: > // Port D auf Ausgang setzen > DDRD = 0xff; > // Lichtschranke PD2 auf Eingang > DDRD = DDRD & ~(1<<PD2); Diese Initialisierung produziert einen kurzen Low-Impuls auf PD2 und triggert damit den INT0! Wieso den Port D nicht gleich richtig initalisieren?
1 | DDRD = 0xff & ~(1<<PD2); |
Unabhängig von dem ISR-Problem: Mach mal Deine Schaltung heil! AVCC muß an VCC angeschlossen werden (und mit 100nF gegen GND geblockt), auch dann, wenn der A/D-Wandler nicht benutzt wird. Der Pin versorgt nämlich nicht nur den A/D-Wandler, sondern auch PORT C (PC0..PC3). (siehe Datenblatt, Seite 6)
:
Bearbeitet durch User
Es ist auch eine gute Idee, vor der Freigabe des Interruptes etwaige anstehende Anforderungen zu löschen:
1 | EIFR = (1<<INTF0); |
Matthias Sch. schrieb: > Es ist auch eine gute Idee, vor der Freigabe des Interruptes > etwaige > anstehende Anforderungen zu löschen:EIFR = (1<<INTF0); Habe es versucht und trotzdem, funktioniert es nicht.
Hat niemand eine Ahnung ? oder überhaupt, an was es liegen könnte, warum der interrupt immer ausgelöst wird?
Tuji de Assis Moreira schrieb: > Hat niemand eine Ahnung ? > oder überhaupt, an was es liegen könnte, warum der interrupt immer > ausgelöst wird? Weil die Erkennungslogik nicht riechen kann, ob die Bedingung zur Registreierung eines Interrupts jetzt deswegen eingetreten ist, weil sich am Eingang tatsächlich eine Flanke ereignet hat, oder ob diese Flanke 'pseudo-mässig' dadurch enstanden ist, dass du die Auswertebedingungen während der Intialisierungsphase des Programms geändert hast. Nachdem alles fertig konfiguriert ist, lösche eventuell aufgelaufene 'falsche und unerwünschte' Interrupt Anforderungen ehe du mit sei() alles für den tatsächlichen Betrieb freigibst und gut ists. Das ist weder anrüchig noch schlechte Praxis. Hinweis: derartige Interrupt-Registrierungsflags werden durch Einschreiben eines 1-Bits an der entsprechenden Bitposition ins entsprechende Register gelöscht.
:
Bearbeitet durch User
Karl Heinz schrieb: > Weil die Erkennungslogik nicht riechen kann, ob die Bedingung zur > Registreierung eines Interrupts jetzt deswegen eingetreten ist, weil > sich am Eingang tatsächlich eine Flanke ereignet hat, oder ob diese > Flanke 'pseudo-mässig' dadurch enstanden ist, dass du die > Auswertebedingungen während der Intialisierungsphase des Programms > geändert hast. Ich hab versucht es zurückzusetzen. Iwie funktioniert es aber nicht, vllt habe ich es nur falsch gemacht: GIFR = (1<<INF1); EIFR = (1<<INTF0); Habe ich das was falsches gemacht? Wie heißt den der Code zum zurück setzen?
Hi >und es handelt sich um ein ATMEGA88. >GIFR = (1<<INF1); Wo hat der ATMEga88 ein GIF-Register? MfG Spess
Stefan P. schrieb: > Was macht denn setLedMode(15,true); ? Ich hab auf meiner Platine 16 LED´s. Wenn diese methode aufgerufen wird, wird die LED eingeschalten. Das Problem bei der ganzen Sache ist, dass der immer anbleibt(ist ja auch richtig). Aber wenn ich in meiner Main dann sage, schalte die LED wieder aus, leuchtet die LED auf und wieder zu, die ganze zeit. Darum denke ich, dass diese ISR(INT0_vect) immer wieder aufgerufen wird, obwohl kein externer Interrupt geschieht.
spess53 schrieb: > Wo hat der ATMEga88 ein GIF-Register? > > MfG Spess Muss ehrlich zugeben, dass ich noch ein newbie bin. Ich kenne mich halt nicht perfekt aus, suche mir gerade alles ausm Internet zusammen. Versuche aber auf über den µController zu lernen. Aber es tut sich einfach nicht.
Kann es vielleicht sein, dass ich diese Register setzen muss: GICR|=0x40; MCUCR=0x02; Ich bin mir halt nicht sicher.
Tuji de Assis Moreira schrieb: > Darum denke ich, dass diese ISR(INT0_vect) immer wieder aufgerufen wird, > obwohl kein externer Interrupt geschieht. Zeig doch mal dein ganzes Programm. Immer diese Ratespielchen von wegen: ich denke, das das und das passiert. Unabhängig davon: wenn man den Verdacht hat, dass eine bestimmte Komponente ein Problem verursacht, dann ist es auch kein Beinbruch sich erst mal ein Testprogramm zu machen, welches nur und ausschliesslich diese Komponente testet. In deinem Fall willst du wissen, ob der externe Interrupt korrekt funktioniert. Dazu braucht es keinen Timer oder sonstiges Zeugs. Einfach nur dir Lichtschranke und die LED um das Ansprechen der Lichtschranke anzuzeigen. Mehr braucht es dazu nicht. Dann läuft man auch nicht Gefahr, dass man sich mit all den anderen Zusatzteilen im Programm irgendwo einen Bock geschossen hat, den man selbst nicht mehr findet. Bei der Fehlersuche bzw. wenn man erst mal ratlos ist, ist die Konzentration aufs Wesentliche der erste wichtige Punkt. Alles was nichts mit diesem Wesentlichen zu tun hat, fliegt erst mal raus.
:
Bearbeitet durch User
Tuji de Assis Moreira schrieb: > Kann es vielleicht sein, dass ich diese Register setzen muss: > > GICR|=0x40; > MCUCR=0x02; > > Ich bin mir halt nicht sicher. Das weiß ich nicht, weil ich eine Abneigung dagegen habe, einzelne BIts (die eine Bedeutung haben, die sich in ihrem Namen wiederspiegelt) per Hex-Zahl zu setzen. Die Bits haben Namen. Atmel hat dir diese Namen zur Verfügung gestellt. Benutzte sie auch! Immer dieses Hex-Zahl mit dem Datenblatt auseinanderpfriemeln. Da scrollt man sich doch regelmässig einen Tennisarm beim Nachverfolgen im PDF.
Am besten wäre es wenn sie das komplette Projekt mit Atmel Studio öffnen.
Tuji de Assis Moreira schrieb: > Darum denke ich, dass diese ISR(INT0_vect) immer wieder aufgerufen wird, > obwohl kein externer Interrupt geschieht. IN deinem Eröffnungsposting klingt das alles aber nocht ganz anders > Mein Problem ist gerade, dass der Interrupt immer ausgelöst wird, > sobald mein µC geflasht worden ist mit meinem neuen Programm. da ist vom Einspielen eines neuen Programms die Rede. Was denn nun?
Tuji de Assis Moreira schrieb: > Am besten wäre es wenn sie das komplette Projekt mit Atmel Studio > öffnen. Nö. Sorry. Aber das tu ich mir nicht an. Entweder du reduzierst dein Programm auf einen einfachen Fall * lichtschranke + 1 LED oder du musst dir den Fehler selbst suchen
Das ist immer noch das alte Programm. Mit kleinen Veränderungen die mir hier vorgeschlagen worden ist.
Tuji de Assis Moreira schrieb: > Das ist immer noch das alte Programm. Mit kleinen Veränderungen die mir > hier vorgeschlagen worden ist. Ja. Aber ich analysiere jetzt nicht 30 Minuten lang, was da im Programm alles abgeht und welche Querverflechtungen für welchen Effekt verantwortlich sein könnten, wenn ein simples
1 | #include <avr/io.> |
2 | #include <util/delay.h> |
3 | |
4 | int main() |
5 | {
|
6 | DDRC = 0xFF; |
7 | |
8 | EIMSK |= _BV(INT0); // PD2 = INT0 enablen |
9 | EICRA |= _BV(ISC01); // Triggern auf fallende Flanke des INT0 |
10 | PORTD |= _BV(PD2); |
11 | |
12 | while( 1 ) { |
13 | PORTC |= _BV( PC0 ); |
14 | _delay_ms( 1000 ); |
15 | }
|
16 | }
|
17 | |
18 | ISR (INT0_vect) |
19 | {
|
20 | PORTC &= ~ _BV( PC0 ); |
21 | }
|
... auch ausreichend ist, um die Funktion des externen Interrupts für sich alleine zu testen. Und bei sowas
1 | ISR (INT0_vect) |
2 | {
|
3 | turnOffLeds(); |
4 | _delay_ms(5000); |
5 | ....
|
fangen bei mir sowieso alle Alarmglocken zu klingeln an.
:
Bearbeitet durch User
Karl Heinz schrieb: > Nö. Sorry. Aber das tu ich mir nicht an. > > Entweder du reduzierst dein Programm auf einen einfachen Fall > * lichtschranke + 1 LED > oder du musst dir den Fehler selbst suchen
1 | int main (void) |
2 | {
|
3 | init(); |
4 | |
5 | |
6 | |
7 | }
|
8 | |
9 | /************************************************************************/
|
10 | /* Initialisierungsmethode */
|
11 | /************************************************************************/
|
12 | void init() { |
13 | board_init(); |
14 | resetRegisters(); |
15 | // Port D auf Ausgang setzen
|
16 | DDRD = 0xff; |
17 | // Lichtschranke PD2 auf Eingang
|
18 | DDRD = DDRD & ~(1<<PD2); |
19 | |
20 | // LEDs auf den Ports ausschalten
|
21 | |
22 | PORTD = 0xff; |
23 | |
24 | EIMSK |= _BV(INT0); // PD2 = INT0 enablen |
25 | EICRA |= _BV(ISC01); // Triggern auf fallende Flanke des INT0 |
26 | |
27 | |
28 | |
29 | |
30 | // Das Makro sei() schaltet die Interrupts ein.
|
31 | sei(); |
32 | }
|
33 | |
34 | void resetRegisters() { |
35 | // Port D auf Ausgang setzen
|
36 | DDRD = 0b11100111; |
37 | // Lichtschranke PD2 auf Eingang
|
38 | DDRD = DDRD & ~(1<<PD2); |
39 | |
40 | DDRC = 0x00; |
41 | PORTC = 0x00; |
42 | PORTD = 0x00; |
43 | }
|
44 | /************************************************************************/
|
45 | /* Lichtschranken-Interrupt */
|
46 | /* Hier Timer starten für Counter der Umläufe und der Geschwindigkeit. */
|
47 | /************************************************************************/
|
48 | ISR (INT0_vect) |
49 | {
|
50 | turnOffLeds(); |
51 | _delay_ms(5000); |
52 | }
|
:
Bearbeitet durch User
Hi >Kann es vielleicht sein, dass ich diese Register setzen muss: >GICR|=0x40; >MCUCR=0x02; >Ich bin mir halt nicht sicher. Welchen Controller setzt du nun wirklich ein? MCUCR/GICR/GIFR gehören zum ATMega8. Beim ATMega88 heißen die richtigen Register EICRA, EIMSK und EIFR. Könnte es sein, das du dein Programm für einen ATMega8 compilierst? MfG Spess
Tuji de Assis Moreira schrieb: >
1 | > int main (void) |
2 | > { |
3 | > init(); |
4 | >
|
5 | >
|
6 | >
|
7 | > } |
8 | >
|
schon besser. Aber da fehlt die obligate Hauptschleife. Ohne Hauptschleife läuft das Programm aus main() raus zurück in die C-Runtime. Und die hat als erstes nichts besseres zu tun, als alle Interrupts mittels eines cli() abzuschalten. Daher braucht JEDES Programm eine Hauptschleife. Selbst wenn die leer ist. Du willst das Programm aus main() nie wieder rauslassen.
1 | int main (void) |
2 | {
|
3 | init(); |
4 | |
5 | while( 1 ) |
6 | ;
|
7 | }
|
:
Bearbeitet durch User
Ich verwende einen ATMEGA 88 und kompelieren tu ich das auch für einen ATMEGA 88.
Karl Heinz schrieb: > #include <avr/io.> > #include <util/delay.h> > > int main() > { > DDRC = 0xFF; > > EIMSK |= _BV(INT0); // PD2 = INT0 enablen > EICRA |= _BV(ISC01); // Triggern auf fallende Flanke des INT0 > PORTD |= _BV(PD2); > > while( 1 ) { > PORTC |= _BV( PC0 ); > _delay_ms( 1000 ); > } > } > > ISR (INT0_vect) > { > PORTC &= ~ _BV( PC0 ); > } Was machen Sie da im Interrupt ? Weil bei mir 2 Led´s aufleuchten.
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.