www.mikrocontroller.net

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


Autor: Robin Ullrich (geobin)
Datum:

Bewertung
0 lesenswert
nicht 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):
  
DWORD dwBytesRead = 0;
BYTE  abBuffer[3]; //3 Byte für einen Messwert

//Set g_Serial read timeout to block (3 byte)
iResult = g_Serial.SetupReadTimeouts(CSerial::EReadTimeoutBlocking);
  
// Create a handle for the overlapped operations
HANDLE hevtOverlapped = ::CreateEvent(0,TRUE,FALSE,0);;
  
// Setup the overlapped structure
OVERLAPPED ov = {0};
ov.hEvent = hevtOverlapped;

// Open the "STOP" handle
HANDLE hevtStop = ::CreateEvent(0,TRUE,FALSE,_T("Overlapped_Stop_Event"));
  
// Keep reading data, until user breaks action
do
{
     // Wait for an event
     iResult = g_Serial.WaitEvent(&ov);
    
     // Setup array of handles in which we are interested
     HANDLE ahWait[2];
     ahWait[0] = hevtOverlapped;
     ahWait[1] = hevtStop;

     // Wait until something happens
     switch(::WaitForMultipleObjects(sizeof(ahWait)/sizeof(*ahWait)        ,ahWait, FALSE,INFINITE))
     {
     case WAIT_OBJECT_0:
     {
     // Save event
     const CSerial::EEvent eEvent = g_Serial.GetEventType();

     // Handle error event
     if (eEvent & CSerial::EEventError)
     {
     //Verwaltung der Fehlermeldung -> bei Programmlauf keine!
     }


//--------------START READING (handle data receive event)
//-------------------------------------------------------
     if (eEvent & CSerial::EEventRecv)
     {          
     // Read data, until there is nothing left
     DWORD dwBytesRead = 0;
               
     //Read buffer
     UCHAR szBuffer[4];
                  
     do
     {
     // Read data from the COM-port
     iResult = g_Serial.Read(szBuffer,sizeof(szBuffer)-1,&dwBytesRead);

     //Daten werden verarbeitet... 
     }
     while (dwBytesRead > 0);
     }
//--------------END READING-------------------------------
//--------------------------------------------------------
     }break;

     case WAIT_OBJECT_0+1:
     {
     // Set the continue bit to false, so we'll exit
     SetActivLoop(false);
     }  break;

     default:
     {
     // Something went wrong
     }break;
     }
}
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

Autor: Arc Net (arc)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Robin Ullrich (geobin)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: fbi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Robin Ullrich (geobin)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe mein Programm jetzt soweit zu einer Minimalkonfiguration 
heruntergeschraubt, dass der Code schematisch so aussieht:
   //Open Com Port
   g_Serial.Open(cPort,0,0,true) 
   //def: Open(dwInQueue=0,dwOutQueue=0,Overlapped=true)

   //Read Data
   UCHAR szBuffer[4];
   do{
  iResult = g_Serial.Read(szBuffer,sizeof(szBuffer)-1,&dwBytesRead);
   }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...

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: Robin Ullrich (geobin)
Datum:

Bewertung
0 lesenswert
nicht 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:
do
{
    do
    {
        //Read Data
    }
    while(BytesRead > 0);
}
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.

Autor: Zwölf Mal Acht (hacky)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Robin Ullrich (geobin)
Datum:

Bewertung
0 lesenswert
nicht 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.

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.