Forum: Mikrocontroller und Digitale Elektronik Interruptprobleme mit Atmel megaAT16


von Wolfgang (Gast)


Lesenswert?

Hallo, beim megaAT16 habe ich folgendes Problem: Sobald der Befehl SEI() 
aufgerufen wird, springt das Programm zurück auf den Reset Vektor. Die 
nachfolgende while-Schleife wird nie erreicht. Der Dissassembler zeigt 
ebenfalls nachdem sei-Befehle einen jump auf Adresse 0x0000 - also Reset 
an.
Was mache ich hier falsch?
Hier ein Auszug des Listing

#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include <util/delay.h>
#include <string.h>

#include "USART.h"

#define F_CPU 16000000
#define USART_BAUD_RATE   19200
#define USART_BAUD_SELECT   (F_CPU/(USART_BAUD_RATE*161)-1)

volatile uint16_t counterNew, counterOld;
char frequency_ascii[6], newDigit, oldDigit;
char zeichenspeicher[35],Ziffer[6], TransFlag, repetition[4], 
sequence[6];
unsigned char Blockzaehler=0, Resetzaehler=0, n, Zeichenzaehler, 
BurstCounter, Flag;

int main(void)
{
  MCUCSR &= ~(1<<ISC2);  //INT2 reagiert auf fallende Flanke

  MCUCR &= ~(1<<ISC11);    //INT1 löst bei Low-Pegel aus
  MCUCR &= ~(1<<ISC10);

  MCUCR &= ~(1<<ISC01);    //INT0 löst bei Low-Pegel aus
  MCUCR &= ~(1<<ISC00);

  GICR |= (1<<INT2);      //Aktiviere INT2

   USART_Init(51);
   TCCR1B |=  (1<<CS11);    //Counter1-Prescaler auf 8

  TIMSK |= (1<<TOIE0);   //Aktiviere Timer0 Overflow Interrupt
  TCCR0 &= ~((1<<CS01) | (1<<CS00));        //Stoppe Timer0

  TCCR2 |= (1<<CS22) | (1<<CS21) | (1<<CS20); // Timer2 Prescaler auf 
1024
  TIMSK |= (1<<TOIE2);    //Aktiviere Timer2 Overflow Interrupt

  sei();            //Aktiviere Interrupts

  while (1)
  {
    if (Flag == 1)
    {
      Flag = 0;
      Zeichenzaehler=0;
      n=0;
      Blockzaehler=0;
    }
  }
}

von Heiko (Gast)


Lesenswert?

Was soll der Interrupt denn erledigen. Hier fehlt die entsprechende 
Routine.

von Wolfgang (Gast)


Lesenswert?

Der externe Interrupt soll Frequenzen messen und dazu die Zeit zwischen 
den Flanken auswerten.
Aber soweit kommt das Proigramm nicht, da es in der main-loop ständig 
zwischen int main (voit) und sei() kreist.

Zur Info die Interrupt-Routine
ISR(INT2_vect)
{
  uint16_t frequency, diffe;
  counterOld = counterNew;
  counterNew = TCNT1;
  diffe = counterNew - counterOld;
  frequency = F_CPU / (diffe * 8);
  diffe = 1;
  TCNT0 = 0x00;  // Timer löschen
  TCCR0 |= (1<<CS01) | (1<<CS00); //Timer 0 starten

  if (frequency > 1020 && frequency < 2660)
  {
    auswertung(frequency);
  }
}

von Stefan B. (stefan) Benutzerseite


Lesenswert?

>   TIMSK |= (1<<TOIE2);    //Aktiviere Timer2 Overflow Interrupt

Die ISR dafür fehlt und das ist ein Resetgrund. Den Rest habe ich nicht 
angesehen.

von Wolfgang (Gast)


Lesenswert?

Danke, ich hatte das Programm zur Fehlersuche weitestgehend abgespeckt, 
aber nach hinzufügen der ISR
ISR(TIMER0_OVF_vect)

  {
  int i;

  TCCR0 &= ~((1<<CS01) | (1<<CS00));  //Stoppe Timer0
  for (i=0; i<=5; i++)
  {
  while (!( UCSRA & (1<<UDRE)))   // warte, bis UDR bereit
  ;
  }
  Zeichenzaehler=0;
  n=0;
  Blockzaehler=0;
}

ist das Ergebnis unverändert. Was mich an der ganzen Geschicht stört ist 
der Dissassembler. Warum generiert er einen RJMP auf 0x0000 also auf 
Reset???
Das macht er immer, egal wo ich den Befehl in der main-loop einbaue!
Ist irgendetwas an der Initialisierung der megaAT16 zu besonders zu 
beachten?
Dies ist mein erstes Projecht mit diesem Rechner - bisher nur Erfahrung 
mit 6800 un 8051 Derivaten.

57:         TIMSK |= (1<<TOIE2);    //Aktiviere Timer2 Overflow 
Interrupt
+000001A8:   B789        IN        R24,0x39       In from I/O location
+000001A9:   6480        ORI       R24,0x40       Logical OR with 
immediate
+000001AA:   BF89        OUT       0x39,R24       Out to I/O location
59:         sei();            //Aktiviere Interrupts
+000001AB:   9478        SEI                      Global Interrupt 
Enable
+000001AC:   CFFF        RJMP      PC-0x0000      Relative jump
@000001AD: USART_Init
---- USART.c ------------------------

von abc (Gast)


Lesenswert?

>+000001AC:   CFFF        RJMP      PC-0x0000      Relative jump
Das ist ein relative Jump auf PC-0x0000 (Programm Counter minus 
0x0000), d.h. eine Endlosschleife.

von Hmm... (Gast)


Lesenswert?

"Flag" wird nie 1 -- der Compiler hat es wegoptimiert!
Könntest Du Deinen Code bitte innerhalb eines
1
[c]..[/c]
 Blocks einstellen (anstelle ihn als reinen Text einzubinden)?

von Edi R. (edi_r)


Lesenswert?

Wolfgang schrieb:

>   while (1)
>   {
>     if (Flag == 1)
>     {
>       Flag = 0;
>       Zeichenzaehler=0;
>       n=0;
>       Blockzaehler=0;
>     }
>   }

Weil "Flag" nie auf 1 gesetzt wird, hat der Compiler (korrekterweise) 
die ganze while-Schleife zu einer einfachen Endlosschleife optimiert. 
Und wozu "Zeichenzaehler", "n" und "Blockzaehler" immer nur auf 0 
gesetzt werden, ist mir unklar.

Was Du vermeiden solltest, ist die Warterei in der ISR:

Wolfgang schrieb:
> while (!( UCSRA & (1<<UDRE)))   // warte, bis UDR bereit
>   ;

von Wolfgang (Gast)


Lesenswert?

Das mit der Warterei in der ISR ist mir bekannt, wurde nur für 
Testzwecke eingebaut.
Das Problem ist der Befehl "sei()" in der main-loop. Sobald, und das ist 
im single stepp reproduzierbar, dieser Befehl ausgeführt wurde, wird der 
Programmablauf unterbrochen und startet wieder am Anfang. Verschiebt man 
den Befehl "sei()" an eine (jede) beliebige Stelle in der loop, so wird 
auch hier jedesmal das Programm abgebrochen.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Die
> ISR(TIMER0_OVF_vect)
für
>   TIMSK |= (1<<TOIE0);   //Aktiviere Timer0 Overflow Interrupt
ist jetzt vorhanden.

Aber wo ist
ISR(TIMER2_OVF_vect)
für
> TIMSK |= (1<<TOIE2);    //Aktiviere Timer2 Overflow

von Wolfgang (Gast)


Lesenswert?

Danke für die guten Ratschläge. Das Problem hat sich zwischezeitlich 
gelöst. Ursache war die leere while-Schleife in der main-loop. Im Laufe 
der weiteren Verabeitung habe ich diese durch eine If-Schelife ersetzt, 
in der ein Bit bei jedem Durchlauf getoggelt werden mußte. Seit dem 
läuft das Programm problemlos.
Nochmals Allen vielen Dank für die Hilfe.

Wolfgang

von David (Gast)


Lesenswert?

Leer ewhile Schleife als Problem?

Wude die wegoptimiert? Das sollte doch eigentlich nicht passieren.

Welchen Optimierrungsfaktor hast du denn eingestellt?

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.