Hallo Leute, habe zurzeit ein Problem bei meinem Programm. Aber vorher erstmal die Daten zu der MCU: - ATMega328PB - Atmel Studio IDE - Atmel ICE Debugger Meine Einstellungs-Taste ist mit einem Pin Change Interrupt Pin verbunden. Ich habe alle Flags in den entsprechenden Registern eingestellt, sodass die ISR für den PCINT abgerufen wird, sobald ein Pegelwechsel stattfindet. Soweit funktioniert auch alles wunderbar. Der Taster ist Low Active geschaltet. Halte ich die Taste nun gedrückt, wird die ISR einmal aufgerufen und abgearbeitet. Sobald ich loslasse, wird die ISR erneut aufgerufen. In meinem Code habe ich es so vorhergesehen, dass beim gedrückt halten ein Counter hochgezählt wird, sodass ich bspw. verschiedene Einstellungen mit nur einem Taster machen kann (z.B. gedrückt halten, einmal drücken, zweimal drücken etc.). Nun zum Problem: Wer die Debugger von Atmel kennt und schonmal mit Atmel Studio gearbeitet hat weiß, dass man das laufende Programm durch "Break All" "anhalten" kann. Wenn man dann mit der Mouse über die Variablen fährt, sieht man den aktuellen Wert der Variable. Also, halte ich den Taster gedrückt für ca. 3 Sek, drücke auf Break All und lese die Variable in Atmel Studio aus. Funktioniert wunderbar, irgendein Wert mit 3223 (da _delay_ms(1) in der if-Schleife ist). Sobald ich jetzt den Taster jedoch loslasse, wird die Variable wieder auf 0 gesetzt bzw. auf den Wert gesetzt, wie sie deklariert wurde. Hier der Quellcode: #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> #include <avr/eeprom.h> // PORTB Definition #define BUZZER (1<<PB1) #define COIL (1<<PB0) // PORTC Definition #define COILTEMPSENSOR (1<<PC2) #define SETTINGBUTTON (1<<PC5) // PORTD Definition #define MDI_CLK (1<<PD3) #define MDI_DATA (1<<PD4) #define LED_CTRL (1<<PD6) #define LED_REF (1<<PD7) // TEST VALS volatile int PCINT_counter = 0; void init_peripheral() { // ADC Setup ADMUX |= 0b11100000; ADCSRA |= (1<<ADEN); ADCSRA |= (1<<ADPS2) | (1<<ADPS1); // Dummy Readout ADCSRA |= (1<<ADSC); while (ADCSRA & (1<<ADSC)); int x = ADC; // Timer0 8-Bit Setup TCCR0A |= 0b10000011; TCCR0B |= 0b010; //Timer2 8-Bit Setup TCCR2B |= 0b100; TIMSK2 |= (1<<TOIE2); TCNT2 = 5; /* //Timer1 16-Bit Setup TCCR1B |= 0b011; TIMSK1 |= (1<<TOIE1); TCNT1 = 0; */ // Pin Change Interrupt Setup PCICR |= 0b010; PCMSK1 |= 0b00110000; // External Pin Interrupt Setup EICRA |= 0b1000; EIMSK |= 0b10; } int main(void) { //***** IO-PIN SETUP ****** DDRB |= BUZZER | COIL; DDRC = 0x00; DDRD = LED_REF | LED_CTRL; PORTC |= SETTINGBUTTON; PORTD |= MDI_DATA | MDI_CLK; init_peripheral(); sei(); while(1) { _delay_ms(1); asm("NOP"); } } /**********************************************INTERRUPT-ROUTINES******* *************************************** ************************************************************************ **************************************/ ISR(PCINT1_vect) { // while (!(PINC & SETTINGBUTTON)) { _delay_ms(1); PCINT_counter++; } } Danke im Voraus! BEARBEITUNG: Ich habe alle Kommentare aus dem Programm entfernt, da es hier im Forum zu Zeilenumbrüchen kommt und alles unübersichtlich wird.
:
Bearbeitet durch User
Gewöhn Dir mal an, aussprechende Bezeichungen (1<<xxx) für Deine Konfigurationsbytes zu verwenden wie das bei AVR üblich ist. Beim Deinem ADC Setup ging es ja teilweise auch. (Sieht also nach zusammenkopiert aus) So lese ich das zumindest nicht, davon abgesehen, daß auch auf die code Tags (
1 | So sieht Code aus |
2 | oder so |
) verzichtet wurde.
:
Bearbeitet durch User
Kurzes Update: Ich habe die Ursache gefunden. Dadurch das ich die Timer und eventuell die Externe Pin Interrupt Routine deklariert habe, jedoch keine ISR Schleifen vorhanden waren, wurde der Wert immer wieder auf das deklarierte geändert. Nun aber die Frage: Warum passiert das? Es scheint so, als würde er nach dem Loslassen des Tasters wieder komplett von vorne beginnen. Also direkt bei main() statt dort, wo er aufgehört hatte. Warum das geschieht, kann ich mir aber nicht erklären. Vielleicht kennt sich einer hier gut aus damit ;)
Zusätzlich zum Pin-Change-Interrupt aktivierst du außerdem den External-Interrupt. Dafür fehlt allerdings die entsprechende ISR. Ich denke, da passiert nun folgendes: Nach Abarbeitung deiner ISR will er die nächste ISR (für den External-Interrupt) ausführen, die es nicht gibt. Und immer wenn das passiert, führt der Controller eine Reihe NOP Befehle aus bis er beim Programmstart ankommt. Denn der befindet sich direkt hinter den Interrupt-Vektoren. Deswegen wird deine Variable wieder neu initialisiert. Im Grunde genommen startet das ganze Programm neu durch.
K. S. schrieb: > Sobald ich jetzt den Taster jedoch loslasse, wird die Variable wieder > auf 0 gesetzt bzw. auf den Wert gesetzt, wie sie deklariert wurde. Vermutlich einen Interrupt ohne Handler freigegeben.
K. S. schrieb: > Nun zum Problem: Dein vorrangiges Problem ist erst mal - wie mein Vorredner schon angedeuted hat - dass du deine Source nicht in einem gut les- baren Format präsentierst. Dazu gibt es auch Hinweise bei jedem Beitrag den man postet ("Wichtige Regeln - erst lesen, dann posten!") die du nicht lesen und/oder nicht beachten willst. Längliche Sourcen wie deine gehören in einen Datei-Anhang. Der Sinn dahinter ist unter anderem dass man leicht unterscheiden kann was du zu zeigen und was du zu sagen hast.
@Stefan F. Achso alles klar, kliegt nachvollziehbar! :) Danke !
?Stefan ⛄ F. schrieb: > Zusätzlich zum Pin-Change-Interrupt aktivierst du außerdem den > External-Interrupt. Sicher daß die Kommentare mit dem DB übereinstimmen? Ich jedenfalls mache mir nicht die Mühe, das mit der Bitschreibweise herauszufinden.
K. S. schrieb: > Dadurch das ich die Timer und eventuell > die Externe Pin Interrupt Routine deklariert habe, jedoch keine ISR > Schleifen vorhanden waren, wurde der Wert immer wieder auf das > deklarierte geändert. > > Nun aber die Frage: Warum passiert das? Wenn du einen Interrupt einschaltest, aber keine ISR schreibst, dann geht der Sprung in die zugehörige ISR in Leere. Damit landet der Ablauf des Codes beim Resetvektor.
@Andreas B. Brauchst Du auch nicht, um Gottes Willen. Wie schon beschrieben stimmt bei der Deklaration alles. Es ging lediglich um das Zurücksetzen der Variablen.
K. S. schrieb: > BEARBEITUNG: Ich habe alle Kommentare aus dem Programm entfernt, da es > hier im Forum zu Zeilenumbrüchen kommt und alles unübersichtlich wird. Wie schon geschrieben, es gibt Code-Tags und es gibt die Möglichkeit als Anhang zu posten. In der ISR zu warten ist Quark. > wird die ISR einmal aufgerufen und abgearbeitet. In Real Life (tm) wird die ISR jeweils einmal mehr aufgerufen, da das Prellen des Tasters in der ISR selbst zum erneuten Setzen des Pinchange-Interruptflags führt. > wird die Variable wieder auf 0 gesetzt Das wiederum dürfte von dem hier kommen:
1 | TIMSK1 |= (1<<TOIE1); |
und dem Fehlen einer ISR für den Timer, da gibt's einen Bad Vector und nachfolgend einen Reset.
Beitrag #6647007 wurde vom Autor gelöscht.
Man nimmt besser einen Timerinterrupt, z.B. 10ms. Der macht dann Entprellen, Flanke erkennen, kurz/lang/repeat unterscheiden, Ereignisflags fürs Main setzen. Quasi die eierlegende Wollmilchsau fürs Tasten einlesen. Der Pin-Change Interrupt macht nur das Aufwachen bei Batteriebetrieb, nichts weiter. Beitrag "Universelle Tastenabfrage"
:
Bearbeitet durch User
Peter D. schrieb: > Man nimmt besser einen Timerinterrupt, z.B. 10ms. Der macht dann > Entprellen, Flanke erkennen, kurz/lang/repeat unterscheiden, > Ereignisflags fürs Main setzen. Quasi die eierlegende Wollmilchsau fürs > Tasten einlesen. Danke für den Vorschlag! Echt eine gute Idee, werde ich mal ausprobieren.
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.