Forum: Mikrocontroller und Digitale Elektronik Interruptproblem USART Atmega3250


von C. M. (camel)


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.
1
//##################################################
2
// Datum:    09.01.10
3
// Version    08.15
4
// Editor:    C.M.
5
//##################################################
6
7
//##################################################
8
// Include:
9
  #include <avr/io.h>          // AVR Ein- Ausgabedatei
10
  #include <avr/interrupt.h>      // AVR Interruptdatei
11
  #include <util/delay.h>        // AVR Verzögerungsdatei
12
  #include <string.h>          // AVR Stringdatei
13
  #include <stdint.h>          // AVR Standarddatentypen
14
15
  
16
//##################################################
17
18
//##################################################
19
// global Declarations:
20
21
  void init_UART (void);        // Initialisierung für UART
22
  void init_PORTS (void);        // Initialisierung der Taster    
23
24
  char buffer[15] = "Led 1 an";    // received string 
25
  int stringlength =0;        // string length
26
  int i=0;              // string figure
27
  char function[7];           // array for function 
28
  char number[2];                // array for portpin
29
  char option[8];            // array for action
30
  int firstspace =0;          // 1. Leerzeichenstelle
31
  int secondspace =0;          // 2. Leerzeichenstelle
32
  int n=0,j=0;            // Laufvariablen Schleifen
33
34
//##################################################
35
36
//##################################################
37
// Main Program:
38
  int main (void)
39
  {
40
    init_UART();          // UART inital
41
    init_PORTS();          // Port inital
42
43
    sei();              // global interrupt enable
44
    
45
    while(1)
46
    {
47
    PORTA = 0x00;          // Beschäftigung fürs Hauptprogramm
48
    _delay_ms(500);
49
    PORTA = 0xC0;
50
    _delay_ms(500);  
51
52
    PORTB ^= (1 << PB2);      // Statusled toggeln
53
54
    }
55
56
  return(0);
57
  }
58
//##################################################
59
60
//##################################################
61
// ISR:
62
    
63
    ISR(USART_RX_vect)                      // Atmega3250 RX complete Interrupt
64
    {
65
      cli();                          // clear global interrupt flag
66
67
      buffer[i] = UDR0;                    // write data from UDR to buffer array
68
69
      while( !( UCSR0A & (1<<UDRE0) ))
70
        {
71
          //warten bis "USART Data Register Empty" gesetzt ist
72
        }
73
  
74
      UDR0 = buffer[i];                    // send echo
75
76
      i++;                          // increment figure
77
  
78
      sei();                          // set global interrupt flag
79
    }
80
81
82
83
    ISR(USART_TX_vect)                      // Atmega3250 TX complete Interrupt
84
    {
85
      cli();
86
      i = 0;
87
88
    
89
      PORTA = 0x01;                      // Anzeige das Interrupt ausgeführt wird
90
      _delay_ms(1000);
91
      PORTA = 0x00;
92
93
      stringlength = strlen(buffer);              // Stringlänge ermitteln
94
    
95
    // 1. Wort
96
      for(volatile int temp = 0; temp < sizeof(buffer); temp++)// Ermittlung des 1. Leerzeichens
97
      {
98
        if( buffer[temp] == ' ' )
99
        {
100
          break;
101
        }
102
        firstspace = temp;                  // firstspace count at pos of the first space
103
      }
104
105
      firstspace++;                      // firstspace increment
106
    
107
      strncpy(function, buffer, firstspace );          // 1. Wort kopieren
108
      function[firstspace] = '\0';              // Nulltermining des Strings
109
110
      // Function löschen
111
        for( volatile int temp = firstspace + 1 ; temp < sizeof(function); temp++)
112
        {
113
        function[temp] = 0;                  // write zero to each position
114
        }
115
  
116
    // 2. Wort
117
      if((buffer[(firstspace + 1)] <= 0x39) && (buffer[(firstspace + 1)] >= 0x30))          // second word, number?
118
      {
119
        number[0] = buffer[++firstspace];          // Port-Number to number[0] 
120
        if(number[0] == 0x00)
121
        {
122
          number[1] = 0x00;                 // Nullterminierung des Strings
123
        }
124
        else
125
        {
126
          number[1] = '\0';                 // Nullterminierung des Strings
127
        }
128
        secondspace = (firstspace + 2);            // position for seond space
129
      
130
        // 3. Wort
131
          for(int n = secondspace; n < stringlength; n++)  // write 3. word in option
132
          {
133
            option[j++] = buffer[n];
134
          }
135
          
136
          option[j] = '\0';                // Nullterminierung des Strings
137
        
138
        // Option löschen
139
          for( volatile int temp = ++j; temp < sizeof(option); temp++)
140
          {
141
            option[temp] = 0;
142
          }
143
      }
144
      else                          // second word, text?  
145
      {
146
        // Number löschen
147
        for( volatile int temp = 0 ; temp < sizeof(number); temp++)
148
        {
149
          number[temp] = 0;
150
        }
151
      
152
        // Option löschen
153
        for( volatile int temp = 0 ; temp < sizeof(option); temp++)
154
        {
155
          option[temp] = 0;
156
        }
157
        
158
        secondspace = ++firstspace;              // Space between 2 words is secondspace
159
        
160
        
161
        // 3. Wort
162
        for(int n = secondspace; n < stringlength; n++)    // write 3. word in option
163
        {
164
          if(buffer[n] == ' ')              // break if string end
165
          {
166
            break;
167
          }
168
          else
169
          {
170
            option[j++] = buffer[n];          // write buffer to option
171
          }
172
        }
173
174
        option[j] = '\0';                  // Nullterminierung des Strings
175
      
176
        // Option löschen
177
          for( volatile int temp = ++j; temp < sizeof(option); temp++)
178
          {
179
            option[temp] = 0;
180
          }
181
        
182
      }
183
    
184
      // Buffer löschen
185
        for( volatile int temp = 0; temp < sizeof(buffer); temp++)  // Buffer löschen
186
        {
187
        buffer[temp] = 0;
188
        }
189
190
        j = 0;
191
        firstspace = 0;
192
        secondspace = 0;
193
        stringlength = 0;
194
195
196
      sei();
197
    }
198
199
200
//##################################################
201
202
//##################################################
203
// Routines:
204
205
206
  void init_UART(void)                 // UART Initialiserung
207
  {
208
    UCSR0C  = (1<<UCSZ00) | (1<<UCSZ01);        // Asynchron, keine Parität, 1 Stoppbit, 8 Datenbits
209
    UCSR0B  = (1<<RXEN0) |(1<<TXEN0) | (1<<RXCIE0) | (1<<TXCIE0);     // Daten Register Receive Interrupt, Receive Enable, Transmit Enable
210
    UBRR0H  = 0;                      // USART Baudrate Register (9600)
211
    UBRR0L  = 119;                   //      --"--
212
  }
213
  
214
  void init_PORTS(void)                 // Taster Initialisierung
215
  {
216
    DDRA |= 0xff;                   // Port A als Ausgang definieren (für Led)
217
    PORTA = 0x00;                   // 
218
219
    DDRB |= (1 << DDB2);               // Ausgang für PB2 setzen
220
    PORTB &= ~(1 << PB2);                 // PB2 löschen LED aus
221
222
//    DDRC |= 0x00;                     // Port C als Eingang definieren  
223
//    PORTC |= 0xff;                   // Pull-Up aktivieren
224
  }
225
226
//##################################################

Danke für Hilfe im Voraus.

von Hc Z. (mizch)


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.

von Hc Z. (mizch)


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.

von Tobias P. (hubertus)


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

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.