Forum: Mikrocontroller und Digitale Elektronik Variable wird nach verlassen der PCINT ISR wieder auf vorherigen Wert gesetzt


von K. S. (iistatii)


Lesenswert?

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
von Andreas B. (bitverdreher)


Lesenswert?

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
von K. S. (iistatii)


Lesenswert?

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 ;)

von Stefan F. (Gast)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

von erklehr behr (Gast)


Lesenswert?

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.

von K. S. (iistatii)


Lesenswert?

@Stefan F.

Achso alles klar, kliegt nachvollziehbar! :)

Danke !

von Andreas B. (bitverdreher)


Lesenswert?

?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.

von HildeK (Gast)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

Andreas B. schrieb:
> Sicher daß die Kommentare mit dem DB übereinstimmen?

Ja, habe ich geprüft.

von K. S. (iistatii)


Lesenswert?

@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.

von MWS (Gast)


Lesenswert?

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.
von Peter D. (peda)


Lesenswert?

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
von K. S. (iistatii)


Lesenswert?

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
Noch kein Account? Hier anmelden.