ATMega Programmierung in c - Interrupt

OP #5149071
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
OP #5149107
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.
Gast #5149129
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.
Gast #5149184
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.
#5149471
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."
Gast #5150910
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
}
#5151050
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren