mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Interruptproblem USART Atmega3250


Autor: C. M. (camel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe vor Weihnachten ein Programm geschrieben, es funktioniert 
plötzlich nicht mehr, ich weiß nicht warum.
Es sollen via Terminal vordefinierte Strings wie z.B. "Led 1 an" über 
die serielle Schnittstelle an einen Atmega3250 gesendet werden. Dieser 
soll dann entsprechend Aktionen ausführen.
Meine Entwicklungsumgebung: Atmel AVR Studio, Verbindung zum Atmega3250 
via AVR Dragon, darüber auch debugging. Verbindung von Atmega3250 über 
USART - Com-Emulator FT232RL via USB an den PC.

Das Problem liegt meiner Ursachenforschung nach irgendwo bei den 
USART-Interrupts, diese werden wenn überhaupt dann nur extrem 
verzögert ausgeführt. An den Warteschleifen (500ms und 1000ms) liegt es 
nicht.

Ich habe unter anderem im Debug-Modus das Problem, dass wenn ich das 
"USART Receive Complete" Bit setze, der Controller nicht in die 
ISR(USART_RX_vect) hineinspringt.

In den "Configuration Options" habe ich noch die Taktfrequenz 
(18432000Hz) meiner Hardware eingetragen. Die Optimierung steht auf 0s.
//##################################################
// Datum:    09.01.10
// Version    08.15
// Editor:    C.M.
//##################################################

//##################################################
// Include:
  #include <avr/io.h>          // AVR Ein- Ausgabedatei
  #include <avr/interrupt.h>      // AVR Interruptdatei
  #include <util/delay.h>        // AVR Verzögerungsdatei
  #include <string.h>          // AVR Stringdatei
  #include <stdint.h>          // AVR Standarddatentypen

  
//##################################################

//##################################################
// global Declarations:

  void init_UART (void);        // Initialisierung für UART
  void init_PORTS (void);        // Initialisierung der Taster    

  char buffer[15] = "Led 1 an";    // received string 
  int stringlength =0;        // string length
  int i=0;              // string figure
  char function[7];           // array for function 
  char number[2];                // array for portpin
  char option[8];            // array for action
  int firstspace =0;          // 1. Leerzeichenstelle
  int secondspace =0;          // 2. Leerzeichenstelle
  int n=0,j=0;            // Laufvariablen Schleifen

//##################################################

//##################################################
// Main Program:
  int main (void)
  {
    init_UART();          // UART inital
    init_PORTS();          // Port inital

    sei();              // global interrupt enable
    
    while(1)
    {
    PORTA = 0x00;          // Beschäftigung fürs Hauptprogramm
    _delay_ms(500);
    PORTA = 0xC0;
    _delay_ms(500);  

    PORTB ^= (1 << PB2);      // Statusled toggeln

    }

  return(0);
  }
//##################################################

//##################################################
// ISR:
    
    ISR(USART_RX_vect)                      // Atmega3250 RX complete Interrupt
    {
      cli();                          // clear global interrupt flag

      buffer[i] = UDR0;                    // write data from UDR to buffer array

      while( !( UCSR0A & (1<<UDRE0) ))
        {
          //warten bis "USART Data Register Empty" gesetzt ist
        }
  
      UDR0 = buffer[i];                    // send echo

      i++;                          // increment figure
  
      sei();                          // set global interrupt flag
    }



    ISR(USART_TX_vect)                      // Atmega3250 TX complete Interrupt
    {
      cli();
      i = 0;

    
      PORTA = 0x01;                      // Anzeige das Interrupt ausgeführt wird
      _delay_ms(1000);
      PORTA = 0x00;

      stringlength = strlen(buffer);              // Stringlänge ermitteln
    
    // 1. Wort
      for(volatile int temp = 0; temp < sizeof(buffer); temp++)// Ermittlung des 1. Leerzeichens
      {
        if( buffer[temp] == ' ' )
        {
          break;
        }
        firstspace = temp;                  // firstspace count at pos of the first space
      }

      firstspace++;                      // firstspace increment
    
      strncpy(function, buffer, firstspace );          // 1. Wort kopieren
      function[firstspace] = '\0';              // Nulltermining des Strings

      // Function löschen
        for( volatile int temp = firstspace + 1 ; temp < sizeof(function); temp++)
        {
        function[temp] = 0;                  // write zero to each position
        }
  
    // 2. Wort
      if((buffer[(firstspace + 1)] <= 0x39) && (buffer[(firstspace + 1)] >= 0x30))          // second word, number?
      {
        number[0] = buffer[++firstspace];          // Port-Number to number[0] 
        if(number[0] == 0x00)
        {
          number[1] = 0x00;                 // Nullterminierung des Strings
        }
        else
        {
          number[1] = '\0';                 // Nullterminierung des Strings
        }
        secondspace = (firstspace + 2);            // position for seond space
      
        // 3. Wort
          for(int n = secondspace; n < stringlength; n++)  // write 3. word in option
          {
            option[j++] = buffer[n];
          }
          
          option[j] = '\0';                // Nullterminierung des Strings
        
        // Option löschen
          for( volatile int temp = ++j; temp < sizeof(option); temp++)
          {
            option[temp] = 0;
          }
      }
      else                          // second word, text?  
      {
        // Number löschen
        for( volatile int temp = 0 ; temp < sizeof(number); temp++)
        {
          number[temp] = 0;
        }
      
        // Option löschen
        for( volatile int temp = 0 ; temp < sizeof(option); temp++)
        {
          option[temp] = 0;
        }
        
        secondspace = ++firstspace;              // Space between 2 words is secondspace
        
        
        // 3. Wort
        for(int n = secondspace; n < stringlength; n++)    // write 3. word in option
        {
          if(buffer[n] == ' ')              // break if string end
          {
            break;
          }
          else
          {
            option[j++] = buffer[n];          // write buffer to option
          }
        }

        option[j] = '\0';                  // Nullterminierung des Strings
      
        // Option löschen
          for( volatile int temp = ++j; temp < sizeof(option); temp++)
          {
            option[temp] = 0;
          }
        
      }
    
      // Buffer löschen
        for( volatile int temp = 0; temp < sizeof(buffer); temp++)  // Buffer löschen
        {
        buffer[temp] = 0;
        }

        j = 0;
        firstspace = 0;
        secondspace = 0;
        stringlength = 0;


      sei();
    }


//##################################################

//##################################################
// Routines:


  void init_UART(void)                 // UART Initialiserung
  {
    UCSR0C  = (1<<UCSZ00) | (1<<UCSZ01);        // Asynchron, keine Parität, 1 Stoppbit, 8 Datenbits
    UCSR0B  = (1<<RXEN0) |(1<<TXEN0) | (1<<RXCIE0) | (1<<TXCIE0);     // Daten Register Receive Interrupt, Receive Enable, Transmit Enable
    UBRR0H  = 0;                      // USART Baudrate Register (9600)
    UBRR0L  = 119;                   //      --"--
  }
  
  void init_PORTS(void)                 // Taster Initialisierung
  {
    DDRA |= 0xff;                   // Port A als Ausgang definieren (für Led)
    PORTA = 0x00;                   // 

    DDRB |= (1 << DDB2);               // Ausgang für PB2 setzen
    PORTB &= ~(1 << PB2);                 // PB2 löschen LED aus

//    DDRC |= 0x00;                     // Port C als Eingang definieren  
//    PORTC |= 0xff;                   // Pull-Up aktivieren
  }

//##################################################

Danke für Hilfe im Voraus.

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mach' mal die cli() und sei() aus den Interrupt-Routinen raus.  Die 
haben dort nichts zu suchen.  Den cli() macht die CPU selbst, und für 
den sei() sorgt der Compiler in Form eines reti.

Dann ist mir völlig unklar, wozu Deine Tx-Interrupt-Routine da ist, wo 
sie doch gar nichts sendet.  Das gesamte Parsen des Inputs gehört im 
Hauptprogramm erledigt und der Tx-Interrupt ist abzuschalten, solange 
nichts zu senden ist.

So wie es geschrieben ist (und wenn ich nichts übersehen habe), bleibt 
das Programm im dauernden Abarbeiten des Tx-Interrupt hängen und 
bearbeitet dazwischen gerade mal eine Assembler-Instruktion aus dem 
Hauptprogramm (oder, wenn vorhanden, den Rx-Interrupt).  Kein Wunder, 
dass das dann langsam ist.

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Weitere Fehler: i ist nicht volatile.  Dafür hast Du die ganzen temps 
unnötigerweise volatile gemacht.  Und durch das sei() läuft Dir der 
Stack in der Tx-Interrupt-Routine über, da der Tx-Interrupt zu diesem 
Zeitpunkt weiterhin ansteht.

Aber verleg' den Parser erst mal ins Hauptprogramm, damit ein Schuh 
draus wird.

Autor: Tobias Plüss (hubertus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
es tauchen hier immer wieder Fragen bezüglich solcher 
"Kommandozeilen-Interpreter" auf.

Ich habe vor einiger Zeit genau einen solchen programmiert.
Mittels vordefinierter Makros kann man ganz einfach die gewünschten 
Commands definieren. Dem Parser muss man dann nur die gewünschte 
Kommandozeile übergeben, der Rest wird automatisch erledigt. Auch die 
Übergabe von Parametern ist kein Problem; die aufgerufenen Funktionen ( 
= die Commands) besitzen nämlich alle ein argc und ein argv.
Frage:
Bestünde Interesse an dem Code? Ich könnte den mal veröffentlichen, da 
er eigentlech ganz ordentlich funktioniert. Alles was man halt machen 
muss ist dem Interpeter die zu interpretierende Zeile zu übergeben.
Als Rückgabewert bekommt man dann den Wert, den man in der aufgerufenen 
Funktion zurückgibt (so kann mna z.B. Errorcodes und dergleichen 
zurückgeben).

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.