www.mikrocontroller.net

Forum: Compiler & IDEs Interrupts und Problem mit einem if


Autor: Ronny B. (dmw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moin moin,
ich habe gerade ein Projekt angefangen. Das Ganze soll mal mit einem 
ATTiny2313 laufen und nem externen 16Mhz Quarz. Die Hardware ist noch 
nicht gebaut, aber die Software habe ich in den letzten Tagen 
geschrieben. Nun habe ich einen Windows-Rechner ausgegraben und mein 
Programm simuliert. Doch irgendwas ist das im argen. Hier also kurz die 
wichtigen Code-Teile
ISR(BUTTON_ISR_vect) //Ist eigentlich INT0 - nur damit man das schnell mal ändern kann per #define als Button-Interrupt definiert
{
  cli();
  uint8_t cSREG = SREG; //save the SREG
  //get Code from DIP
  dipcode = 0;
  dipcode = (1<<DIP_PIN1) | (1<<DIP_PIN2) | (1<<DIP_PIN3);

   buttonflag = 0x01; //Button Flag auf 1 setzen
  SREG = cSREG;
  sei();
}      
[...]
//Hier folgen einige Funktionen. u.a. runProtocols(uint8_t parameter), von denen aber hier noch keine aufgerufen wird.

int main()
{ 
//Initialization of DIP Ports
  DIP_DDR &= !((1<<DIP_DDR1) | (1<<DIP_DDR2)  | (1<<DIP_DDR3) | (1<<DIP_DDR4) | (1<<DIP_DDR5) | (1<<DIP_DDR6)); //input
  DIP_PORT &= !((1<<DIP_PORT1) | (1<<DIP_PORT2)  | (1<<DIP_PORT3) | (1<<DIP_PORT4) | (1<<DIP_PORT5) | (1<<DIP_PORT6)); //Tri-State
//Both INT are on D, so use 
  DDRD &= !(1<<BUTTON_DDR); //INT 0 initialisieren 
  PORTD &= !(1<<BUTTON_PORT); //Tristate (?)
//Init BUtton Interrupt
  MCUCR &= !((1<<ISC00) | (1<<ISC01) | (1<<ISC10) | (1<<ISC11)); //disable both INT0 and INT1
  MCUCR |= (1<<BUTTON_ISC); //actiavte the BT_NUM Interrupt to react on any change on that pin
  GIMSK |= (1<<BUTTON_INT); //General Enabling Button Interrupt
  sei();
  buttonflag=0;
  dipcode=0;  
  while (1) //each time we got nothing to do and all interrupts are handled, go to sleep
  {
      set_sleep_mode(SLEEP_MODE_IDLE); //sleep but keep counting, 70% less energy consumption !
    if (buttonflag) //egal, wo man dieses if in der schleife platziert...es ist stets false :(
    {
      runProtocols(dipcode);
      buttonflag = 0;
    }
    sleep_mode();                   // in den Schlafmodus wechseln
    sleep_disable(); //aufwachen
    //wakes up and if flag is set run protocols
  }
} 

So. Das Problem dabei:
Startet man die Simulation, läuft er nett und freundlich los, 
initialisiert alles und geht in der while schleife in sleep-Modus. 
Drückt man nun den Button (also PIND3) und läßt los (falling-edge 
configured) kommt schön der Interrupt. In der Routine wird im 
wesentlichen ein Wert eingelesen von 3 Pins und das buttonflag auf 1 
gesetzt.

Danach kehrt das Programm in die while schleife zurück zum 
sleep_disable(); springt an den Anfang der while schleife und müßte - 
meiner Logik nach - dann ins if wandern und runProtocols(dipcode) 
aufrufen.
Im Speicher steht an der Adresse von buttonflag nach dem INterrupt eine 
1. Fährt man mit der Maus im Simulator über die Variable, taucht auf, 
dass der Wert 1 ist.
In das If geht er aber nicht rein. Und ich weiß nicht wieso.

Hat jemand da eine Idee ? Ich bin noch recht neu auf der Ecke (jaja ich 
programmier sonst ganz gerne Java und mag auch Eagle nich - bitte nich 
hauen ;)) und hab da keine Idee mehr wieso dieses kleine Stück Code 
nicht geht.

Über Tipps und Hilfen wäre ich recht dankbar.

gruß
dmw

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist buttonflag volatile deklariert?

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>  cli();

Das macht der Prozessor schon automatisch, bevor deine ISR aufgerufen 
wird.

>   uint8_t cSREG = SREG; //save the SREG

Das baut der Compiler bereits selbst ein, ist also komplett überflüssig 
und belegt nur unnötig ein weiteres Register.

>   sei();

Das schaltet die Interrupts zu früh wieder ein. Ist auch unnötig, da der 
Prozessor sie zum richtigen Zeitpunkt automatisch wieder einschaltet.

> Hat jemand da eine Idee ?

Du hast leider vergessen, die Definition von 'buttonflag' mit anzugeben. 
Meine Vermutung ist, daß du es nicht volatile definiert hast.

Autor: Ronny B. (dmw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oh. eine schnelle Antwort und sie half. Wow. Und ich hab gestern ne 
Stunde gesucht und dachte schone meine eigene Logik hat irgendwo n 
Fehler.

Danke.

Aber um nicht ganz dumm zu sterben...Wieso muss das volatile sein ?


edit: Danke Rolf, das mit dem automatischen wußte ich auch noch nicht. 
Meine letzten Versuche mit nem ATMEga waren in ASM (was mir zu 
anstrengend ist, deswegen nun mal C :))

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ronny B. wrote:
> Aber um nicht ganz dumm zu sterben...Wieso muss das volatile sein ?
Du hast eine globale Variable, die in einem Interrupt Handler verändert 
werden kann und deren Zustand im Hauptprogramm ausgewertet werden soll. 
Das Problem ist, dass sich diese Variable aus Sicht des Compilers gar 
nicht ändern kann, weil diese Änderung in einem Interrupt Handler 
geschieht, der aus Compiler-Sicht nie aufgerufen wird. Wenn sich eine 
Variable aber zwischen zwei Lese-Zugriffen offensichtlich nicht ändern 
kann, dann darf der Compiler den Lesezugriff wegoptimieren, weil er dann 
ja eigentlich unsinnig ist. Die Deklaration mit volatile sagt dem 
Compiler lediglich, dass die so deklarierte Variable sich außerhalb 
seines Einflussbereichs ändern kann und dass er dementsprechend keine 
Optimierungen auf Zugriffe auf diese Variable machen darf.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Falls button irgendwas wie ein mechanischer Taster ist: pack' es
komplett anders an.  Den in einem Interrupt zu behandeln, hat auf
Grund des Prellens keinen Sinn.  (Keine Regel oder Ausnahme: der
Interrupt hat Sinn, wenn er dazu dient, den Prozessor aus dem
Tiefschlaf zu holen und sich hernach gleich erstmal abschaltet.)
Deine ISR wird bei jeder Tastenbetätigung ansonsten ein paarmal
triggern, schnell hintereinander.

Mechanische Taster entprellt man am besten, indem man sie in einer
Timer-Interruptroutine pollt.  Das Thema ist endlos diskutiert
worden, Codebeispiele solltest du auch zahlreich finden.

Wenn du schon einen Externinterrupt dafür nehmen willst, dann solltest
du zumindest innerhalb der ISR den Interrupt außer Betrieb nehmen und
einen Timer starten, der ihn dann später wieder neu aktiviert.  Damit
verhinderst du wenigstens, dass die ISR x-mal durch das Prellen gerufen
wird.

Autor: Ronny B. (dmw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke Johannes, so macht das auch Sinn volatile zu verwenden. ich habs 
zwar vorhin gemacht hatte es aber nicht verstanden was das ganze soll.

@Jörg,
Jap, ist ein externer Taster der auf fallende Flanke Interrupted - und 
jap da muss noch was zum entprellen hinein, das kommt sobald ich von dem 
restlichen Timer-Spaß weiß, dass er funktioniert, da tut nämlich das 
meiste auch noch nicht.
Anscheinend ist meine Programmierlogik nicht allzu vereinbar mit dem was 
ein avr-gcc gerne sehen würde für das was ich will - hm. Ich denke da 
muss ich noch viel lernen. Aber vorerst danke für die Tipps, ich werde 
das WE wohl vorm Simulator verbringen und sehen, ob ich irgenwie mal 
verstehe wer wann wie welchen Timer wo gerne hätte damit ich meine 
Zeitgeschichten hinkrieg...

gruß
dmw

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.