Forum: PC-Programmierung C++ RS485 Frequenz der Datenübertragung / Befehl senden


von Robin U. (geobin)


Lesenswert?

Hallo Forenmitglieder,

ich arbeite seit einiger Zeit an einer Software, die mittels einer 
seriellen Schnittstelle (RS485) Daten eines Distanzsensors ausliest. 
Soweit so gut. Die Übertragung funktioniert reibungslos und die 
Messwerte sind plausibel.

Nun zum Problem. Der Sensor sollte laut Herstellerangaben mit einer 
Frequenz von 500Hz Messwerte liefern. Das ist leider nicht der Fall. 
Wenn ich den datenstrom mit einem Terminal aufzeichne, kann ich etwa 
eine Frequenz von 50Hz ableiten. Ich stelle mir nun die Frage, ob das 
programmierseitige Gründe haben könnte. Mein Code (Auszüge):
1
  
2
DWORD dwBytesRead = 0;
3
BYTE  abBuffer[3]; //3 Byte für einen Messwert
4
5
//Set g_Serial read timeout to block (3 byte)
6
iResult = g_Serial.SetupReadTimeouts(CSerial::EReadTimeoutBlocking);
7
  
8
// Create a handle for the overlapped operations
9
HANDLE hevtOverlapped = ::CreateEvent(0,TRUE,FALSE,0);;
10
  
11
// Setup the overlapped structure
12
OVERLAPPED ov = {0};
13
ov.hEvent = hevtOverlapped;
14
15
// Open the "STOP" handle
16
HANDLE hevtStop = ::CreateEvent(0,TRUE,FALSE,_T("Overlapped_Stop_Event"));
17
  
18
// Keep reading data, until user breaks action
19
do
20
{
21
     // Wait for an event
22
     iResult = g_Serial.WaitEvent(&ov);
23
    
24
     // Setup array of handles in which we are interested
25
     HANDLE ahWait[2];
26
     ahWait[0] = hevtOverlapped;
27
     ahWait[1] = hevtStop;
28
29
     // Wait until something happens
30
     switch(::WaitForMultipleObjects(sizeof(ahWait)/sizeof(*ahWait)        ,ahWait, FALSE,INFINITE))
31
     {
32
     case WAIT_OBJECT_0:
33
     {
34
     // Save event
35
     const CSerial::EEvent eEvent = g_Serial.GetEventType();
36
37
     // Handle error event
38
     if (eEvent & CSerial::EEventError)
39
     {
40
     //Verwaltung der Fehlermeldung -> bei Programmlauf keine!
41
     }
42
43
44
//--------------START READING (handle data receive event)
45
//-------------------------------------------------------
46
     if (eEvent & CSerial::EEventRecv)
47
     {          
48
     // Read data, until there is nothing left
49
     DWORD dwBytesRead = 0;
50
               
51
     //Read buffer
52
     UCHAR szBuffer[4];
53
                  
54
     do
55
     {
56
     // Read data from the COM-port
57
     iResult = g_Serial.Read(szBuffer,sizeof(szBuffer)-1,&dwBytesRead);
58
59
     //Daten werden verarbeitet... 
60
     }
61
     while (dwBytesRead > 0);
62
     }
63
//--------------END READING-------------------------------
64
//--------------------------------------------------------
65
     }break;
66
67
     case WAIT_OBJECT_0+1:
68
     {
69
     // Set the continue bit to false, so we'll exit
70
     SetActivLoop(false);
71
     }  break;
72
73
     default:
74
     {
75
     // Something went wrong
76
     }break;
77
     }
78
}
79
while (GetActivLoop());

Programmiert wurde das ganze unter XP mit dem Visual Studio 2008 (C++) 
mithilfe von MFC und der Bibliothek CSerial. Das ganze läuft in einem 
separatem Thread und kann durch die while Bedingung abgebrochen werden.

Vielleich sieht jemand die Ursache auf anhieb. Zu erwähnen wäre vlt. 
noch, dass der Sensor nicht direkt an die serielle Schnittstelle des 
Rechners angeschlossen ist. Durch einen Adapter + zugeh. Treiber ist der 
Sensor mittels USB am Rechnerangeschlossen und der Com-Port erzeugt.

Einen identischen Programmcode habe ich für einen weiteren Distanzsensor 
(aber RS232) verwendet, bei welchem alles einwandfrei funktioniert. 
Deshalb fehlen mir zur Zeit die Lösungsansätze...

Vielen Dank und beste Grüße,
Robin

von Arc N. (arc)


Lesenswert?

Dann kann das auch am Treiber bzw. an USB liegen.
Falls da FTDI drin ist, kann mit FT_SetLatencyTimer
bzw. über die Registry versucht werden, dass zu optimieren.
http://www.ftdichip.com/Support/Documents/AppNotes/AN232B-04_DataLatencyFlow.pdf

von Robin U. (geobin)


Lesenswert?

Ich habe den Sensor jetzt testweise direkt an die serielle Schnittstelle 
des Rechners angeschlossen. Das Problem der niedrigen Frequenz besteht 
trotzdem noch. Also schließe ich den Treiber als Fehlerquelle aus. Also 
doch die Programmierung?

von Peter (Gast)


Lesenswert?

Robin Ullrich schrieb:
> Also doch die Programmierung?
dann teste mal ohne das ganze Overlapped zeugt. Das zieht mir unnötig 
kompliziert aus. Einfach nur ein open und read in der schleife sollte 
dafür doch reichen.

von fbi (Gast)


Lesenswert?

Das sollte auch mit Overlaped gehen. Allerdings dürften die Buffer zu 
klein sein. Was hast Du denn beim g_Serial.Open(...) für Queuesizes 
angegeben? Am besten mal mittels GetCommProperties(...) nachsehen, wie 
die defaults sind und was da maximal möglich ist. Deinen Lesebuffer 
solltest Du auch wesentlich größer machen, am besten den selben Wert wie 
für die Queuesizes verwenden.

von Robin U. (geobin)


Angehängte Dateien:

Lesenswert?

Ich habe mein Programm jetzt soweit zu einer Minimalkonfiguration 
heruntergeschraubt, dass der Code schematisch so aussieht:
1
   //Open Com Port
2
   g_Serial.Open(cPort,0,0,true) 
3
   //def: Open(dwInQueue=0,dwOutQueue=0,Overlapped=true)
4
5
   //Read Data
6
   UCHAR szBuffer[4];
7
   do{
8
  iResult = g_Serial.Read(szBuffer,sizeof(szBuffer)-1,&dwBytesRead);
9
   }while(something)

Beim auslesen der CommProperties (siehe Datei im Anhang) wird die 
maximale Rx bzw Tx Queue mit Null angegeben, wodurch meiner Meinung nach 
des Öffnen des Com Ports ohne die Prameter möglich ist (??).

Auch beim erhöhen des Read Buffers wird keine signifikante Steigerung 
der Frequenz während des kontinuierlichen Messens erreicht.

Neu ist dagegen, dass beim Start der Messung die ersten ca 150 Messwerte 
derart schnell übermittelt werden, dass es den Anschein macht, dass die 
herstellerseitige Messfrequenz erreicht wird (500Hz). Danach stagniert 
der Prozess leider wieder und die Messwerte werden wieder mit der 
bereits angesprochenen Frequenz von ca 50Hz übermittelt...

von Peter (Gast)


Lesenswert?

Robin Ullrich schrieb:
> Neu ist dagegen, dass beim Start der Messung die ersten ca 150 Messwerte
> derart schnell übermittelt werden, dass es den Anschein macht, dass die
> herstellerseitige Messfrequenz erreicht wird (500Hz). Danach stagniert
> der Prozess leider wieder und die Messwerte werden wieder mit der
> bereits angesprochenen Frequenz von ca 50Hz übermittelt...

kann es sein das es an der ausgaben liegt? Denn hier

 do{
  iResult = g_Serial.Read(szBuffer,sizeof(szBuffer)-1,&dwBytesRead);
   }while(something)

würdest ja überhaupt nicht erkennen ob es daten ankommen. Kannst ja mal 
so testen:

int test = 0;
 do{
  iResult = g_Serial.Read(szBuffer,sizeof(szBuffer)-1,&dwBytesRead);
  test += dwBytesRead;
  if ( (test % 100)==0 ) print(".");
   }while(something)

von Robin U. (geobin)


Lesenswert?

Peter schrieb:
> würdest ja überhaupt nicht erkennen ob es daten ankommen

Ich habe nebenbei immer ein Terminalprogramm laufen, was den Datenstrom 
der ComPorts überwacht. Dadurch kann ich aussagen über die Frequenz 
machen. Trotzdem habe ich deinen Vorschlag getestet und komme zum 
gleichen Ergebnis. Dabei ist mit noch folgendes aufgefallen:

In meinem Programm habe ich quasi zwei ineinander geschachteltet 
do-while-Schleifen:
1
do
2
{
3
    do
4
    {
5
        //Read Data
6
    }
7
    while(BytesRead > 0);
8
}
9
while(Abbruchkriterium);

Durch deinen Ansatz ist mir jetzt folgendes Aufgefallen. Ab einem 
gewissen Punkt (Anzahl der Messwerte variieren) wird die innere Schleife 
verlassen, also nichts gelesen. Für den ersten Durchlauf ist das dann 
genau der Punkt, an dem die Datenrate stark sinkt.

Wenn ich das Programm neu starte, tritt dieser Effekt immer weiter auf:
- Erster Schleifendurchlauf: Höchste Frequenz
- Folgende: Frequenz bedeutend niedriger

Nun die Frage warum... Kann der Grund ev durch das Nichtsetzen von 
Signalpegeln sein? Sowas in der Art wie SETRTS oder CLRRTS? Bin auf dem 
Gebiet eher unbelesen.

von Purzel H. (hacky)


Lesenswert?

Ihr erwartet 500 Taskwechsel pro Sekunde ? Leute, wir sind an einem 
PC... soll das ein Witz sein ? Nehmt einen AVR, zB einen Mega 32, der 
kann das.

von Robin U. (geobin)


Lesenswert?

Heia Jetzt-aber schrieb:
> soll das ein Witz sein

Wie eingehend erwähnt, mit einem ähnlichen Sensoren kein Problem. Die 
Spezifikationen verlangen übrigens den Einsatz eines PCs.

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.