Forum: Mikrocontroller und Digitale Elektronik RS232 Timeout


von Max P. (max1988)


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

von holger (Gast)


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.

von Max P. (max1988)


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.

von avr (Gast)


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:
1
 Ende=0;
2
Zeitzähler=0;
3
while(!Ende){
4
  Zeitzähler++;
5
  if(Zeitzähler>Zeitgrenze)Ende=1;
6
  if (Zeichenda)Ende=2;
7
 }
8
9
if(Ende==2){
10
  // mach was mit empfangenen Daten
11
   }

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

Hoffe das Prinzip ist klar ;)

avr

von Daniel (Gast)


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:
1
volatile BYTE timer; // wird in Timer-ISR hochgezählt
2
3
timeout = timer + GewuenschterTimeoutInSekunden;
4
5
recvIdx = 0;
6
7
while((timer != timeout) && (recvIdx < AnzahlErwarteterZeichen));
8
9
// Daten auswerten

von Daniel (Gast)


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.
1
char SerialWaitFor(char* s, BYTE i)
2
{
3
  BYTE j, iMatch;
4
  BYTE   tmout; // = (timerCnt + (BYTE)TIMEOUT);
5
6
  j = iMatch = 0;
7
  tmout = (timerCnt + (BYTE)TIMEOUT);
8
9
  while(1)
10
  {
11
    if(recvBuf[i] == s[j])
12
    {
13
      if(j == 0)
14
      {
15
        iMatch = i;
16
      }
17
      j++;
18
19
      if(s[j] == 0)
20
      {
21
        return i;
22
      }
23
24
    }
25
    else
26
    {
27
      if (j != 0)
28
      {
29
        i = iMatch;
30
        j = 0;
31
      }
32
    }
33
34
    while(1)
35
    {
36
      if(i < (recvIdx-1))
37
      {
38
        i++;
39
        break;
40
      }
41
42
      if(timerCnt == tmout)
43
      {
44
        return 0;
45
      }
46
    } // while(1)
47
  } // while(1)
48
} // SerialWaitFor()

Man kann dann z.B. so etwas machen:
1
idx = SerialWaitFor("+CREG: 0,", 0);
2
if(idx)
3
{
4
  SerialWaitFor(",\"", idx);
5
  idx++;
6
  // answer message is \r\n+CREG: 0,1,"620A","26B5"\r\n\r\nOK\r\n
7
  //                           this ^ indicates the network state
8
  if((recvBuf[idx] == '1') || (recvBuf[idx] == '5'))
9
  {
10
    recvIdx = 0;
11
    return 1;
12
  }
13
}
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.

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.