Forum: Mikrocontroller und Digitale Elektronik ATMega Programmierung in c - Interrupt


von Thomas H. (datatom)


Lesenswert?

Hallo zusammen,

ich habe aus dem Atmel Beispiel folgenden Interrupt erstellt:

ISR(USART0_RX_vect)
{

  unsigned char data;
  unsigned char tmphead;

  /* Read the received data */
  data = UDR0;
  /* Calculate buffer index */
  tmphead = (USART0_RxHead + 1) & USART_RX_BUFFER_MASK;
  /* Store new index */
  USART0_RxHead = tmphead;

  if (tmphead == USART0_RxTail) {
    /* ERROR! Receive buffer overflow */
  }
  /* Store received data in buffer */
  USART0_RxBuf[tmphead] = data;
  //USART0_RxBuf_global[tmphead] = data;
}

Der Interrupt wird mehrmals durchlaufen, solange Daten empfangen werden. 
Kann ich das Ende des Interruptes feststellen, denn da wollte ich ein 
Flag setzen?

Vielen Dank.

Gruß

datatom

von Joachim B. (jar)


Lesenswert?

vor der letzten Klammer ist doch das Ende und dort kann dein Flag oder 
Counter rein, aber wozu?

Ich mache das selten am Anfang und Ende einen Port wackeln lassen um mit 
dem Oscar Zeiten zu messen.

: Bearbeitet durch User
von Felix U. (ubfx)


Lesenswert?

das "Ende des Interrupts" ist am Ende des ISR() Kontextes, ich vermute 
also du meinst etwas anderes. Welchen Zustand möchtest du genau 
erkennen?

von Thomas H. (datatom)


Lesenswert?

Wenn der ATMega Daten empfängt die zusammen gehören, Beispiel 
"AT+CPIN=0000", dann wird jeder Ascii-Wert der Buchstaben und Zahlen in 
das Array USART0_RxBuf geschrieben:

USART0_RxBuf[tmphead] = data;

bis das Ende erreicht ist. Da ich nicht weiß welcher Wert als letztes 
kommt, muss ich also wissen, wann das Ende des Interrupt erreicht ist, 
um das Flag zu setzen.

Wenn ich das AT-Kommando absetze und auf die Antwort warte, läuft das 
Programm solange weiter, das soll es aber nicht. Das Programm soll das 
At-Kommando absetzen und auf Antwort warten und dann erst weitermachen.

von W.A. (Gast)


Lesenswert?

Thomas H. schrieb:
> Da ich nicht weiß welcher Wert als letztes
> kommt, muss ich also wissen, wann das Ende des Interrupt erreicht ist,
> um das Flag zu setzen.

Der Interrupt dient zum Abholen der empfangenen Zeichen vom USART. Die 
Interpretation des Datenstroms ist ein ganz anderes Thema und hat mit 
dem Interrupt nichts zu tun. Gewöhnlich schiebt die ISR die Zeichen in 
einen Ringpuffer und über die Position von Schreib- und Lesezeiger wird 
der Puffer koordiniert.

von Thomas H. (datatom)


Lesenswert?

Also gibt es keine Möglichkeit das Ende des Interrupts zu ermitteln?

von Peter II (Gast)


Lesenswert?

Thomas H. schrieb:
> Also gibt es keine Möglichkeit das Ende des Interrupts zu ermitteln?

nein, der Interrupt wird für jedes Zeichen aufgerufen. Es gibt kein 
"ende".

> Da ich nicht weiß welcher Wert als letztes
> kommt, muss ich also wissen, wann das Ende des Interrupt erreicht ist,
> um das Flag zu setzen.
doch das weißt du. Am ende eines AT-Befehles kommt eine '\n'. Dann ist 
der Befehl abgeschlossen.

von Peter D. (peda)


Lesenswert?

Thomas H. schrieb:
> Also gibt es keine Möglichkeit das Ende des Interrupts zu ermitteln?

Wurde doch schon gesagt, die letzte Zeile der ISR.

Aber Du meinst was völlig anderes, nämlich das Ende eines Datenpakets. 
Und das kann man nur feststellen, wenn man das Protokoll kennt. Du mußt 
also zuerst mal ein Protokoll festlegen.

von M. K. (sylaina)


Lesenswert?

Thomas H. schrieb:
> Wenn der ATMega Daten empfängt die zusammen gehören, Beispiel
> "AT+CPIN=0000", dann wird jeder Ascii-Wert der Buchstaben und Zahlen in
> das Array USART0_RxBuf geschrieben:
>
> USART0_RxBuf[tmphead] = data;
>
> bis das Ende erreicht ist. Da ich nicht weiß welcher Wert als letztes
> kommt, muss ich also wissen, wann das Ende des Interrupt erreicht ist,
> um das Flag zu setzen.

Du suchst also gar nicht das Ende des Interrupts sondern willst wissen, 
wann dein Datenempfang vollständig ist. Dazu musst du dir ein Protokoll 
überlegen, das kannst du nicht in der ISR abfangen. Typisch beim 
UART/RS232 ist ein Carrige Return + Linefeed ('\r\n')die das Ende eines 
Datensatzes markieren.
In der ISR kannst du bestenfalls ein Flag setzen, dass aussagt: "Hey, 
ich hab die Zeichenkombination für das Ende eines Datensatzes 
empfangen."

von Florian (Gast)


Lesenswert?

Hallo Thomas,

Deine AT-Antwort wird am Ende des ASCII-Textes auch Steuerzeichen 
enthalten, die das Ende der Nachricht kennzeichnen. Dies ist meist 0x0A 
oder 0x0D, schau mal in eine ASCII-Tabelle im Internet. Auf diese 
Zeichen, kannst Du in Deiner ISR, die eigehenden Zeichen hin prüfen und 
dann mit einem Flag die Nachricht in der main() verarbeiten. Mach dies 
nie in der isr, da dies zu Zeitaufwändig ist. Die isr immer so kurz wie 
möglich halten.

Ich mache das immer so:

ACHTUNG: Der Code ist nur fürs Verständnis runtergeschrieben. Er ist 
nicht compiliert und kann Fehler enthalten!

Gruß
Florian

1
#define RX_BUFFER_SIZE 64 
2
char RxBuffer[RX_BUFFER_SIZE];    // In dieses Array (Buffer) werden die empfangenen Zeichen in der isr gespeichert
3
uchar RxIndex = 0;      // Laufvariable für den Buffer
4
uchar RxCompleteFlag = 0;    // Flag, um ein empfangenes Kommando in der main zu signalisieren
5
6
7
// ggf. RxBuffer[] initialisieren
8
9
main()
10
{
11
  if(RxCompleteFlag)
12
  {
13
    // verarbeite hier Dein Kommando aus dem Buffer
14
    if(strcmp(RxBuffer, "AT+CPIN=0000") == 0)
15
    {
16
      // Do something
17
    }
18
19
    // Am Ende! wieder zurücksetzen
20
    RxCompleteFlag = 0;
21
// Wenn Du magst, kannst Du hier das Buffer-Array auch noch löschen  
22
  
23
  }
24
}
25
26
27
USART_isr()
28
{
29
unsigned char data;
30
31
  data = UDR0;
32
33
  // Nur wenn Daten in den Buffer geschrieben werden können
34
  if(!RxCompleteFlag)
35
  {
36
    if((data == 0x0D) || (data == 0x0A) || (RxIndex >= RX_BUFFER_SIZE))
37
    {
38
      // Zeilenende erreicht, oder Bufferoverflow vermeiden
39
      RxCompleteFlag = 1; 
40
      // Laufvariable wieder auf 0 setzen
41
      RxIndex = 0;      
42
    }
43
    else
44
    {
45
      // Solange Zeichen ankommen, in den Buffer schreiben
46
      RxBuffer[RxIndex] = data;
47
      // Laufvariable inkrementieren
48
      RxIndex++;
49
    }
50
  }  
51
}

von Joachim B. (jar)


Lesenswert?

ich würde ja noch
1
      // Solange Zeichen ankommen, in den Buffer schreiben
2
      RxBuffer[RxIndex] = data;
3
      // Laufvariable inkrementieren
4
      RxIndex++;


1
      // Solange Zeichen ankommen, in den Buffer schreiben
2
      if(isprint(data))
3
      {
4
            if( data != '/r' && && data != '/n' )
5
            {
6
                  RxBuffer[RxIndex] = data;
7
                  // Laufvariable inkrementieren
8
                  RxIndex++;
9
                  var_str_complete = 0;
10
            }
11
            else
12
            {
13
                  RxBuffer[RxIndex] = '\0';
14
                  var_str_complete = 1;
15
            }
16
      }

oder ähnlich einfügen

: Bearbeitet durch User
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.