Process / Task und RS485 Problem

pvs-deck
PowerUser
Avatar
Gender:
Age: 53
Homepage: pvs-deck.de
Posts: 1340
Registered: 02 / 2009
Subject:

Process / Task und RS485 Problem

 · 
Posted: 14.11.2018 - 11:18  ·  #1
Hallo Leute,

ich hänge gerade an einem Problem fest und hoffe ihr habt eine Idee wie ich das mit AVRco lösen könnte.

In meinem aktuellen Projekt habe ich folgenden Task- / Processaufbau und das ganze System läuft richtig rund und sauber.

Aber da ich mit einem Ausweisleser-System über RS485 reden muss (meine Steuerung ist der Master) wollte ich hier was ändern.

Code
...
  SysTick                = 10;                 // msec
  StackSize              = 384, iData;
  FrameSize              = 768, iData;
  Scheduler              = iData;
...
// RS485 Leserbus
  SerPortC0      = 19200, Databit8,parNone, Stop1, timeout;
  RxBufferC0     = 255, iData;
  TxBufferC0     = 255, iData;
  SerCtrlC0      = PortA, 6, positive; {control line for RS485 driver negative oder positive}
...
  TaskStack      = 768, iData;
  TaskFrame      = 1023;
...

Hier die Tasks/Processe:

Code
{--------------------------------------------------------------}
// task für Leser Schnittstelle
Task ControlJobZKS(iData, suspended);
...
//--------------------------------------------------------------
// Display Process  Fuss und LOGs speichern;
//--------------------------------------------------------------
process LCD_DisplBott(256, 512 : iData; 5);  {Stacksize = 256 bytes, Framesize = 512 bytes, 5 Systicks}
...
//--------------------------------------------------------------
// Display Process Obere Screen LCD / Menü
process LCD_Displ(256, 512 : iData; 5);  {Stacksize = 256 bytes, Framesize = 512 bytes, 5 Systicks}
...
{--------------------------------------------------------------}
  // The USB_ControlJob must be repeatedly called to process common PC requests
Task ControlJob(iData, resumed);
{--------------------------------------------------------------}
Process USB_RxTx (256, 256 : iData ); {Stacksize = 256 bytes, Framesize = 256 bytes}
...
{--------------------------------------------------------------}
{ Main Program }
{$IDATA}
...


Mein Problem ist nun, der Leser sendet verschiedene Längen,
z.B. :
ACKN $FF $AA
NACK $FF $BB

Beim Telegramm Anfang: $FF $CC (Start of Text)
Beim Telegramm Ende: $FF $DD (End of Text) gefolgt von 2 Byte Checksumme

Also kann das Telegramm vom Leser immer zwischen 2 bis 128 Zeichen liegen.

Im Task hatte ich das so gelöst:
Code
// ziehe alle Daten aus der Ser, bis SerStat False oder ZKSTimer Zero ist
//
if SerStatC0 then
   rxCnt:= 0; // Zähler auf 0
    rxCnt:= PipeStat(RxBufferC0); // wieviele Daten sind vorhanden
     zksClearIn; // lösche EingangsBuffer
      if SerInpBlockP_TO( UsartC0, @inZKS,  word( rxCnt ), 10) then
..


Aber hier ist leider nicht immer sichergestellt, das innerhalb eines TaskZyklus das komplette Telegramm kommt. Das hat immer zu problemen geführt, wenn ich das ganze mit NACKs gestresst habe.

Deswegen wollte ich nun den Task in einem Process umbauen:
Code
//--------------------------------------------------------------
function ReadZKSData2: byte;
var
  itest      : byte;
  rxCnt      : byte;
  inByte     : byte;
  inByte1    : byte;
  inByte2    : byte;
  inByte3    : byte;

begin
   inByte    := 0;
    inByte1 := 0;
     inByte2 := 0;
      inByte3 := 0;

  if WaitPipe( RxBufferC0, 200 ) then
     // Lösche Speicher
      zksClearIn();
     //inZKS[79]:=0; // lösche EingangsBuffer Zähler auf 0
         rxCnt:= 0;

       while SerInpBlock_TO( UsartC0, inByte, 1) do
         inZKS[rxCnt]:= inByte;
          inc(rxCnt);

          if    (inByte1=$FF) AND  (inByte=$AA)  then break;
          elsif (inByte1=$FF) AND  (inByte=$BB)  then break;
          elsif (inByte3=$FF) AND  (inByte2=$DD) then break;
          Endif;

           inByte3:=inByte2;
            inByte2:=inByte1;
             inByte1:=inByte;
       endwhile;

       inZKS[79]:= rxCnt; // setze Datenmenge in den Empfangsbuffer


        return(rxCnt);

  else // Waitpipe
   return(0);
  endif; // Waitpipe

end ReadZKSData2;


Damit dachte ich mir, ich warte hier im Process einfach bis Daten kommmen (WaitPipe) oder alle Daten da sind bzw. das TimeOut kommt "SerInpBlock_TO( UsartC0, inByte, 1)"

Den ControlJobZKS habe ich in einem Process geändert:
Code
{--------------------------------------------------------------}
// Process für Leser Schnittstelle
Process ControlJobZKS (256, 512 : iData; 2, resumed ); // 2 Systicks
...


Der Ser-Daten-Empfang funktioniert so zwar wunderbar, aber alle paar Sekunden hängt das ganze System. Das Display wird nicht mehr aktualisiert und die die ganzen / Tasks / Processe scheinen für 2-3 Sekunden zu blocken.

Muss ich hier meine Task-/Processplanung überdenken / Optimieren oder darf ich hier vieleicht doch keine Funktion wie "SerInpBlock_TO" / "Waitpipe" nehmen?

Evtl. sollte ich hier doch lieber mit "SerStatC0", oder habt ihr evtl. eine andere Idee / Lösungsansatz?

Thorsten
pvs-deck
PowerUser
Avatar
Gender:
Age: 53
Homepage: pvs-deck.de
Posts: 1340
Registered: 02 / 2009
Subject:

Re: Process / Task und RS485 Problem

 · 
Posted: 14.11.2018 - 14:28  ·  #2
OK, ich denke ich habe eine mögliche Lösung gefunden.

Da ich meine Routine an einen Task Ablauf ausgerichtet hatte, wurde diese einfach von Oben nach Unten durchlaufen, beim nächsten Start wurde dann der nächste Leser abgearbeitet usw.

Ich habe hierfür einen Zyklus (SysTimer) genommen und starte diesen alle 400ms, wenn er den Process einmal durchlaufen hat gebe ich die restliche Rechenleistung mit "Schedule" frei.

Code
Process ControlJobZKS (256, 512 : iData;1,suspended );
begin

  // wenn ein Leser aktiv ist und der Systimer 0 dann GO
  //
  if (isSysTimerZero(ZKSTimerStart)) AND (CfgLeser[1].bAdr <> 0)OR (CfgLeser[2].bAdr <> 0) OR (CfgLeser[3].bAdr <> 0) OR (CfgLeser[4].bAdr <> 0)  then
   ReadZKSProcess; // Wenn Ausweisleser vorhanden
  endif;
    Schedule; // Nichts mehr zu tun...  dann sofort Rechenleistung freigeben.
end;


Code
function ReadZKSData3: byte;
var
  rxCnt, inByte1, inByte2, inByte3    : byte;

begin
   inByte    := 0; inByte1 := 0; inByte2 := 0; inByte3 := 0;

  if WaitPipe( RxBufferC0, 200 ) then
     inZKS[79]:=0; // lösche EingangsBuffer Zähler auf 0
         rxCnt:= 0;

       while SerStatC0  do  //Daten vorhanden dann abarbeiten
       
         if not SerInpBlock_TO( UsartC0, inByte, 1) then
          // in TimeOut gelaufen, keine Daten verwerten!!!
           zksClearIn();
             return(0);
         endif;
         
          inZKS[rxCnt]:= inByte; // lege Daten im Empfangsspeicher ab
           inc(rxCnt);

          // Bereits Telegramm vorhanden? Dann raus, rest im nächsten Aufruf abholen
          if    (inByte1=$FF) AND  (inByte=$AA)  then break;
          elsif (inByte1=$FF) AND  (inByte=$BB)  then break;
          elsif (inByte3=$FF) AND  (inByte2=$DD) then break;
          Endif;
           // Versatz für Auswertung...
           inByte3:=inByte2; inByte2:=inByte1; inByte1:=inByte;
       endwhile;

       inZKS[79]:= rxCnt; // setze Datenmenge in den Empfangsbuffer

        return(rxCnt);

  else // Waitpipe
   inZKS[79]:=0; // lösche EingangsBuffer Zähler auf 0
    return(0);  // TimeOut WaitPipe
   
  endif; // Waitpipe

end ReadZKSData3;


Aber das diese einzelne Zeile "Schedule" am Ende so eine Auswirkung hat, wahrscheinlich ist er einfach in den Process rein und ohne Arbeit wieder raus, bis der Scheduler den nächsten Process genommen hat.

Ich denke so kann ich jetzt das ganze abarbeiten.

Thorsten
Thomas.AC
Benutzer
Avatar
Gender: n/a
Age: 43
Posts: 308
Registered: 07 / 2013
Subject:

Re: Process / Task und RS485 Problem

 · 
Posted: 14.11.2018 - 21:51  ·  #3
Quote

Aber das diese einzelne Zeile "Schedule" am Ende so eine Auswirkung hat


Das liegt nicht am Schedule.

Die erste Lösung mit
Code

while SerInpBlock_TO( UsartC0, inByte, 1) do

blockiert. Es wurde mit WaitPipe gewartet, dass ein Byte im Empfangspuffer vorhanden ist. Anschließend werden aber mehrere Bytes gelesen.

Die zweite Lösung funktioniert, weil hier
Code

while SerStatC0 do

verwendet wird
pvs-deck
PowerUser
Avatar
Gender:
Age: 53
Homepage: pvs-deck.de
Posts: 1340
Registered: 02 / 2009
Subject:

Re: Process / Task und RS485 Problem

 · 
Posted: 15.11.2018 - 07:43  ·  #4
Hallo Thomas,

Ja aber auch mit Serstat bleibt es ohne das schedule nach dem ersten Durchlauf kurz hängen.

Aber so Laufen jetzt alle Tasks.

Thorsten
Thomas.AC
Benutzer
Avatar
Gender: n/a
Age: 43
Posts: 308
Registered: 07 / 2013
Subject:

Re: Process / Task und RS485 Problem

 · 
Posted: 15.11.2018 - 18:58  ·  #5
seltsam, dass das mit WaitPipe in Kombination mit SerStat nicht funktionieren soll.
Ich benutzte das WaitPipe auch irgendwo, um in einem Thread auf UART Empfang zu warten.
Daher jetzt meine Besorgnis.

Hätte noch eine Frage zu
Code

  if (isSysTimerZero(ZKSTimerStart)) AND (CfgLeser[1].bAdr <> 0)OR (CfgLeser[2].bAdr <> 0) OR (CfgLeser[3].bAdr <> 0) OR (CfgLeser[4].bAdr <> 0)  then
   ReadZKSProcess; // Wenn Ausweisleser vorhanden 
  endif; 
    Schedule; // Nichts mehr zu tun...  dann sofort Rechenleistung freigeben.

Wo wird der Systimer eigentlich zurückgesetzt?
Wenn der Timer einmal abgelaufen ist, dann liefert isSysTimerZero(ZKSTimerStart) immer true und das Schedule würde überhaupt nicht mehr aufgerufen werden.

Gruß
pvs-deck
PowerUser
Avatar
Gender:
Age: 53
Homepage: pvs-deck.de
Posts: 1340
Registered: 02 / 2009
Subject:

Re: Process / Task und RS485 Problem

 · 
Posted: 15.11.2018 - 19:21  ·  #6
Hallo Thomas,

das ist richtig so, der Timer wird vor dem LOOP im Main-Process aktiviert und dann nie wieder. ;-)

Code
...
SetSysTimer( ZKSTimerOnline, 300 ); // ca. 0,3 sekunden Zyklus pro Ausweisleserabfrage
 BZKSStart:=true; // Schmiermerker Processstart
  SetSysTimer(ZKSTimerStart, 1000); // Zeitverzögerung bis die Kommunikation zum Ausweisleser beginnnt 
  
/////////////////////////////////////////////
//  LOOP START
//
 loop   // Main LOOP
  WDCheck;  // aktiviere den externen Watchdog, wenn in der Konfig nicht abgeschalet
   WDTrig;  // WD triggern wenn eingeschaltet
...


Nach dem booten soll er 10s abwarten bis die eigentliche Ausweisleserabfrage anläuft.
Danach wird alle 0,3s ein Leser abgearbeitet. Im fastpoll liegt er unter 0,05s pro Leser.
Das setze ich aber nur ein, wenn ich mehr als 4 Leser verarbeite. In der aktuellen Steuerung sind nur 4 Leser Lokal möglich, bei Vernetzung bis zu 32 pro Steuerung.

Thorsten
Thomas.AC
Benutzer
Avatar
Gender: n/a
Age: 43
Posts: 308
Registered: 07 / 2013
Subject:

Re: Process / Task und RS485 Problem

 · 
Posted: 15.11.2018 - 21:36  ·  #7
Danke für die Antwort. Hoffentlich nerve ich nicht zu sehr.

Hätte nämlich noch eine Frage.
Liest der Main Process auch vom RXBufferC0?

Gruß
pvs-deck
PowerUser
Avatar
Gender:
Age: 53
Homepage: pvs-deck.de
Posts: 1340
Registered: 02 / 2009
Subject:

Re: Process / Task und RS485 Problem

 · 
Posted: 16.11.2018 - 10:10  ·  #8
Quote by Thomas.AC

Danke für die Antwort. Hoffentlich nerve ich nicht zu sehr.

Hätte nämlich noch eine Frage.
Liest der Main Process auch vom RXBufferC0?

Gruß


Hallo Thomas,

nein Du nervst nicht :-)
Nur wer fragt kommt weiter und es gibt in der Programmierung viele mögliche Lösungen für ein Problem.

Nein, ich lese nur in dem Process, und ich locke den Process während ich auf die RS485 schreibe.
Das mache ich jetzt schon ein paar Jahre so.

Code
//--------------------------------------
// Sende Daten an RS485
//
procedure ZKSSendRS485;
begin
   LOCK(self);  // Process vor Unterbrechung schützen
    SetSerEnable(UsartC0, true); 
     SerOutBlock_P(UsartC0, @outZKS,  word(outZKS[79]));  // Ausgangspuffer schreiben, Länge liegt in 79
      SetSerEnable(UsartC0, false);
        UNLOCK(self); // Unterbrechung wieder freigeben
end ZKSSendRS485;


Habe zwar auch schon gehört das meine Steuerungen zu schnell die Umschaltungen für das SetSerEnable() ,machen. Aber ich hatte bis jetzt noch nie Probleme damit, nur einige Analyser haben damit Probleme :-D

Thorsten
Selected quotes for multi-quoting:   0

Registered users in this topic

Currently no registered users in this section

The statistic shows who was online during the last 5 minutes. Updated every 90 seconds.
MySQL Queries: 15 · Cache Hits: 14   141   155 · Page-Gen-Time: 0.023953s · Memory Usage: 2 MB · GZIP: on · Viewport: SMXL-HiDPI