mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik RS232 Timeout


Autor: Max Pohl (max1988)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,
ich habe folgendes Problem:

Mein PIC kommuniziert über eine RS232 Schnittstelle mit einem 
Servo-Regler.
Der PIC sendet z.B. einen Abfragebefehl an den Regler, dieser Antwortet 
dann entsprechend.

 puts("Befehl"); //Übertrage Abfragebefehl
 gets(Antwort); //Empfange Antwort

Nun habe ich schon öfters das Problem gehabt das der PIC beim Empfangen 
stehen bleibt, da er auf eine Antwort
des Reglers wartet.
Da dieser zu diesem Zeitpunkt jedoch ausgeschalten oder noch nicht 
bereit war hatte er den Abfragebefehl auch nie erhalten.

Bisher hat das zwar funktioniert ist mir aber zu unsicher.

Nun möchte ich eine Funktion die z.B nach 50ms ohne Antwort vom Regler 
den Befehl erneut sendet.

Ich habe dabei an einen Timer Interrupt gedacht, stehe leider total auf 
dem Schlauch und weis nicht wie ich das realisieren soll.

Ich hoffe ihr könnt mir weiterhelfen.

Vielen Dank

Mfg Max

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Ich habe dabei an einen Timer Interrupt gedacht, stehe leider total auf
>dem Schlauch und weis nicht wie ich das realisieren soll.

So wie alle anderen vor dir auch: Datenblatt lesen und machen.

Autor: Max Pohl (max1988)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank für diesen Qualitativ hochwertigen Kommentar.  :)

Wie ich einen Timer Interrupt implementiere ist mir klar.
Es geht mir um die Funktion mit dem Timeout, da habe ich keine Ahnung 
wie ich das am besten realisieren soll.

Autor: avr (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Max,

ich weiß nicht, wie dein gets(antwort) aussieht.
Oft ist es so, daß dort in einer WHILE-Schleife gewartet
wird bis ein Zeichen empfangen wurde.
Dies ist der Blockierer.

Du brauchst eine Schleife mit 2 Abbruchbedingungen:
- Zeichen (oder erwartete Zeichenzahl)
- Zeitzähler abgelaufen

Pseudo:
 Ende=0;
Zeitzähler=0;
while(!Ende){
  Zeitzähler++;
  if(Zeitzähler>Zeitgrenze)Ende=1;
  if (Zeichenda)Ende=2;
 }

if(Ende==2){
  // mach was mit empfangenen Daten
   }

Natürlich Zeitzähler anpassen, evtl. auch in/mit
Interrupt.

Hoffe das Prinzip ist klar ;)

avr

Autor: Daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Angenommen, im Hintergrund läuft ein Timer, der Dir einen Sekundentakt 
vorgibt.
Angenommen, Du hast einen seriellen Empfangspuffer, der recvBuf heißt 
und der im seriellen Interrupt beschrieben wird, wobei der Index recvIdx 
mit jedem empfangenen Zeichen hochgezählt wird.

Dann etwa so:
volatile BYTE timer; // wird in Timer-ISR hochgezählt

timeout = timer + GewuenschterTimeoutInSekunden;

recvIdx = 0;

while((timer != timeout) && (recvIdx < AnzahlErwarteterZeichen));

// Daten auswerten

Autor: Daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier habe ich noch eine etwas ausgearbeitetere Funktion, die auf eine 
bestimmte Zeichenkette wartet.
recvIdx wird bei Empfang eines Zeichens in der ISR hochgezählt.
recvBuf wird mit den empfangenen Zeichen in der ISR beschrieben.
timerCnt wird in der Timer-ISR hochgezählt.
i gibt an, bei welcher Position im Puffer mit dem Warten angefangen 
werden soll.
Es wird 0 zurückgegeben, wenn die erwartete Zeichenkette nicht empfangen 
wurde, oder der Index im Puffer, wo die erwartete Zeichenkette endet.
char SerialWaitFor(char* s, BYTE i)
{
  BYTE j, iMatch;
  BYTE   tmout; // = (timerCnt + (BYTE)TIMEOUT);

  j = iMatch = 0;
  tmout = (timerCnt + (BYTE)TIMEOUT);

  while(1)
  {
    if(recvBuf[i] == s[j])
    {
      if(j == 0)
      {
        iMatch = i;
      }
      j++;

      if(s[j] == 0)
      {
        return i;
      }

    }
    else
    {
      if (j != 0)
      {
        i = iMatch;
        j = 0;
      }
    }

    while(1)
    {
      if(i < (recvIdx-1))
      {
        i++;
        break;
      }

      if(timerCnt == tmout)
      {
        return 0;
      }
    } // while(1)
  } // while(1)
} // SerialWaitFor()

Man kann dann z.B. so etwas machen:
idx = SerialWaitFor("+CREG: 0,", 0);
if(idx)
{
  SerialWaitFor(",\"", idx);
  idx++;
  // answer message is \r\n+CREG: 0,1,"620A","26B5"\r\n\r\nOK\r\n
  //                           this ^ indicates the network state
  if((recvBuf[idx] == '1') || (recvBuf[idx] == '5'))
  {
    recvIdx = 0;
    return 1;
  }
}
Ausgewertet werden soll die Ziffer zwischen "+CREG: 0," und ",\"". Es 
wird also erst auf +CREG: 0, gewartet, dann von der Position idx 
ausgehend auf ," und dann ist klar, dass das Zeichen an idx+1 die 
gesuchte Ziffer ist.

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.