www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Interruptprobleme mit Atmel megaAT16


Autor: Wolfgang (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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;
    }
  }
}

Autor: Heiko (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was soll der Interrupt denn erledigen. Hier fehlt die entsprechende 
Routine.

Autor: Wolfgang (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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);
  }
}

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>   TIMSK |= (1<<TOIE2);    //Aktiviere Timer2 Overflow Interrupt

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

Autor: Wolfgang (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 ------------------------

Autor: abc (Gast)
Datum:

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

Autor: Hmm... (Gast)
Datum:

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

Autor: Edi R. (edi_r)
Datum:

Bewertung
0 lesenswert
nicht 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
>   ;

Autor: Wolfgang (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Wolfgang (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: David (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Leer ewhile Schleife als Problem?

Wude die wegoptimiert? Das sollte doch eigentlich nicht passieren.

Welchen Optimierrungsfaktor hast du denn eingestellt?

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.