# Serielle Schnittstelle (RS-485 Device) abfragen



## raysprak (28. März 2006)

Hallo Helfer?
Hilfe!
Ich habe den Auftrag bekommen, Daten eines Gertes abzufragen, welche an einer seriellen Schnittstelle (COM1) angeschlossen ist. (RS-485)
Ich habe schon alle Posts durchgewälzt, jedoch nichts brauchbares gefunden.
Das Device, welches ich am Port angeschlossen habe, sollte bei jeder Bewegung einen anderen Wert senden.....tut es aber nicht....sonder immer das gleiche.
Nämlich: 1243596
mehr nicht.
Ich brauche aber die wirklichen Werte....die bekomme ich aber nicht.....da kann ich das Gerät bewegen, wie ich will.
Was mache ich falsch?

Ich der Code, den ich zum Testen schrieb (nicht lachen, falls das Müll ist):

#include <windows.h>
#include <stdio.h>


int main(int argc,char** argv)
{
    DCB dcb;
    COMMTIMEOUTS CTO;
    COMMCONFIG CC;


    ZeroMemory (&dcb, sizeof(dcb)); 

    if(!BuildCommDCB("COM1 baud=19200 parity=N data=8 stop=2",&dcb))
    {
        MessageBox(0,"Error BuildCommDCB","Test",MB_OK);
    }

    HANDLE hFile = NULL;
    hFile = CreateFile("COM1",GENERIC_READ,0,0,OPEN_EXISTING,0,NULL);

    if(hFile == NULL)
    {
        MessageBox(0,"Error CreateFile","Test",MB_OK);
    }

    if(!GetCommState(hFile, &dcb))
    {
        MessageBox(0,"Error GetCommState","Test",MB_OK);
    }


   dcb.DCBlength         = sizeof(DCB);
   dcb.BaudRate = CBR_19200; 
   dcb.ByteSize = (BYTE)8; 
   dcb.StopBits = (BYTE)2; 
   dcb.fBinary           = TRUE; 
   dcb.fParity           = FALSE;
   dcb.fOutxCtsFlow      = FALSE;
   dcb.fOutxDsrFlow      = FALSE;
   dcb.fDtrControl       = DTR_CONTROL_ENABLE;
   dcb.fDsrSensitivity   = FALSE;
   dcb.fTXContinueOnXoff = TRUE;
   dcb.fOutX             = FALSE;
   dcb.fInX              = FALSE;
   dcb.fErrorChar        = FALSE;
   dcb.fNull             = FALSE;
   dcb.fRtsControl       = RTS_CONTROL_DISABLE;
   dcb.fAbortOnError     = FALSE;
   dcb.wReserved         = 0; 

    CTO.ReadIntervalTimeout = 500;
    CTO.ReadTotalTimeoutConstant = 500;
    CTO.ReadTotalTimeoutMultiplier = 500;
    CTO.WriteTotalTimeoutConstant = 500;
    CTO.WriteTotalTimeoutMultiplier = 500;

    if(!SetCommTimeouts(hFile,&CTO))
    {
        MessageBox(0,"Error CommTimeouts","Test",MB_OK);
    }

    if(!SetCommState(hFile,&dcb))
    {
        DWORD error = GetLastError();
        char cerr[64];
        char cerr2[16];
        itoa((int)error,cerr2,10);
        strcpy(cerr,"Error SetCommState: ");
        strcat(cerr,cerr2);
        MessageBox(0,cerr,"Test",MB_OK);
    }


    if(!SetDefaultCommConfig("COM1",&CC,sizeof(CC)))
    {
        MessageBox(0,"Error SetDefaultCommConfig","Test",MB_OK);
    }
    if(hFile == INVALID_HANDLE_VALUE)
        MessageBox(0, "Fehler 1", "", 0);

    char buff; 
    DWORD dlength = 0;

    char sBuffer[1024];

    while(1)
    {
        ReadFile(hFile,&buff,1,&dlength,NULL);              
        sBuffer[0] = buff;
        printf("%d\n",sBuffer);

    }

    return 0;
}


----------



## jokey2 (29. März 2006)

Der Fehler liegt in der Zeile 
	
	
	



```
printf("%d\n",sBuffer);
```
 Da gibst Du die Adresse von sBuffer aus. Die Zeile sollte so lauten:

```
printf("%d\n",sBuffer[0]);
```
oder einfach 
	
	
	



```
printf("%d\n",buff);
```


----------



## raysprak (31. März 2006)

Danke für den Tip, jokey2!
Aber das war es nicht....ich habe nicht das Problem, dass ich die falschen Daten gesendet bekomme, sondern dass ich immer nur diesen einen Wert bekomme, keinen anderen.


printf("%d\n",buff); 
und 
printf("%d\n",sBuffer[0]); 
Habe ich auch schon probiert........:-(


----------



## MCoder (31. März 2006)

Hallo raysprak,

bei der ganzen Sache scheint es noch ein grundsätzliches Problem zu geben. Für die Kommunikation über die serielle Schnittstelle muss in der Regel ein bestimmtes Protokoll beachtet werden, damit die gegenseitige Kommunikation geordnet ablaufen kann.

Was für einen Wert bekommst du den ständig? Ist es vielleicht STX (= 0x02) ?
Dann könnte die Verbindung möglicherweise so ablaufen:

-> Gerät sendet STX (Sendebereitschaft)
<- Du sendest DLE (= 0x10, Empfangbereitschaft)
-> Das Gerät sendet die Datenbytes
-> Das Gerät sendet DLE, ETX (= 0x03) um das Ende der Übertagung anzuzeigen
<- Du sendest DLE (Empfangsbestätigung)

Gruß
MCoder


----------



## raysprak (3. April 2006)

Danke MCoder, aber das ist es wohl auch nicht....
das Gerät sendet: 1243596
Mit diesem Wert kann ich beim besten Willen nichts anfangen......hat noch jemand vielleicht einen Tip?


----------



## MCoder (3. April 2006)

raysprak hat gesagt.:
			
		

> das Gerät sendet: 1243596


Ist das das Ergebnis von einer einzigen ReadFile()-Ausführung? Da du nur immer jweils ein Byte liest, kann der Wert nur zwischen 0 und 255 liegen. Wenn es mehrere Durchläufe (also mehrere gelesene Bytes) sind, solltest du die mal separieren.

Ansonsten denke ich schon, dass du ein bestimmtes Protokoll benötigst. Hast du keine weiteren Infos zu dem Gerät?

Gruß
MCoder


----------



## raysprak (3. April 2006)

ja, Infos über das Gerät habe ich schon, aber das sind nur elektronische Infos und in der Elektronik kenne ich mich nun gar nicht aus.
Ich brauche doch nur ein paar Werte des Gerätes....*heul*


----------



## MCoder (3. April 2006)

Wie schon gesagt, der Wert "1243596" ist nicht so richtig nachvollziehbar.
Lese doch nur mal ein Byte ("while(1)" wegtun) und prüfe das Ergebnis von ReadFile():

```
char  buff; 
DWORD dlength = 0;

if( ReadFile(hFile, &buff, 1, &dlength, NULL) )
{
    if( dlength == 1 )
    {
        printf("Byte gelesen: %d\n", buff);
    }
    else
    {
        printf("%d Bytes gelesen, aber 1 Byte erwartet\n", dlength);                    
    }
}
else
{
    printf("ReadFile() fehlgeschlagen\n");                    
}
```


----------



## raysprak (3. April 2006)

Ein weiteres Danke an MCoder!
Leider ist die Ausgabe: "Byte gelesen = 0".
Jetzt würde jeder normal sterbliche denken, dass das Gerät nicht funktioniert.
Tut es aber.....
Die mit dem Gerät gelieferte Software funktionert 1a und gibt mir jede noch so kleine Drehbewegung aus.
Und was mach ich jetzt?
Nun bin ich schon auf der Suche nach Code, der mich in die mitgelieferte Software "haken" lässt....das ist aber nur die Notlösung, weil ich diese Software gern umgehen möchte...


----------



## MCoder (3. April 2006)

Wenn immer nur '0' zurückkommt könnte es sein, dass die Parameter der Schnittstelle nicht stimmen.
Bist du dir über die Angaben zu Baudrate, Parität etc. sicher?
Auf jeden Fall sollte es reichen nur die DCB-Struktur (am besten alle Member) und die Timeouts zu setzen. Auf "BuildCommDCB()" kannst du verzichen, weil doppelt gemoppelt und "SetDefaultCommConfig()" muss auch nicht sein.
Vielleicht kommst du mit folgenden Einstellungen weiter:

```
dcb.DCBlength         = sizeof(m_DCB);      
dcb.BaudRate          = CBR_19200;
dcb.fBinary           = 1;
dcb.fParity           = 0;
dcb.fOutxCtsFlow      = 0;
dcb.fOutxDsrFlow      = 0;
dcb.fDtrControl       = DTR_CONTROL_ENABLE;
dcb.fDsrSensitivity   = 0;
dcb.fTXContinueOnXoff = 0;
dcb.fOutX             = 0;
dcb.fInX              = 0;
dcb.fErrorChar        = 0;
dcb.fNull             = 0;
dcb.fRtsControl       = 1;
dcb.fAbortOnError     = 0;
dcb.fDummy2           = 0;
dcb.wReserved         = 0;
dcb.XonLim            = 2048;
dcb.XoffLim           = 512;
dcb.ByteSize          = 8;
dcb.Parity            = NOPARITY;
dcb.StopBits          = TWOSTOPBITS;
dcb.XonChar           = 17;
dcb.XoffChar          = 19;
dcb.ErrorChar         = 0;
dcb.EofChar           = 0;
dcb.EvtChar           = 0;
dcb.wReserved1        = 0;

CTO.ReadIntervalTimeout         = 200;
CTO.ReadTotalTimeoutConstant    = 200;
CTO.ReadTotalTimeoutMultiplier  = 0;
CTO.WriteTotalTimeoutConstant   = 0;
CTO.WriteTotalTimeoutMultiplier = 2000;

HANDLE hFile = CreateFile("COM1",GENERIC_READ,0,0,OPEN_EXISTING,0,NULL);

if( SetCommState(hFile,&dcb) ...
if( SetCommTimeouts(hFile,&CTO ...

//... Lesen
```


----------



## raysprak (3. April 2006)

Nochmal danke,MCoder!
Aber ausgabe bleibt "0 Bytes gelesen, aber 1 Byte erwartet".
Ich habe aus folgender Seite 
http://www.mikrocontroller.net/forum/read-4-37992.html
 etwas entdeckt, aber dort wird mit einem Header: 
90s2313.h

gearbeitet, den ich nicht kenne....


----------



## MCoder (4. April 2006)

raysprak hat gesagt.:
			
		

> Aber ausgabe bleibt "0 Bytes gelesen, aber 1 Byte erwartet".


Zumindest ist das schon mal ein Unterschied zum letzten Posting, denn da wurde wenigstens 1 Byte (wenn auch mit dem Wert 0) gelesen. Das bedeutet, das mein letzter Änderungsvorschlag wohl eher was verschlimmbessert hat.

Der von dir angegebene Link zielt, glaube ich, mehr in Richtung Microntrollerprogrammierung, ist also wahrscheinlich für ein PC-Programm nicht so hilfreich.

Du müsstest dir folgende Infos beschaffen:
1. Die Parameter der Schnittstelle (Baudrate, Parität usw.), wobei ich denke, das die schon soweit passen. 
2. Den Kommunikationsablauf mit dem Gerät. Ich kann mir nicht vorstellen, das eine einfache Leseschleife ausreicht. Man wird wahrscheinlich erst was senden müssen (Initialisierung oder Sendeaufforderung?) um das Gerät dazu zu bewegen, was über die serielle Schnittstelle auszugeben. Dann muss man wahrscheinlich auch (wie ich schon geschrieben hatte) ein bestimmtes Protokoll beachten.

Gruß
MCoder


----------



## raysprak (4. April 2006)

Hallo MCoder!
Nochmals vielen dank, dass Du mich so intensiv verarztet hast, oder es versucht hast.
Ich habe gestern den Hersteller des Gerätes angeschrieben.
Dieser hat mir gesagt, dass das Gerät über eine SSI-Schnittstelle läuft.
Um dieses Gerät auszulesen, muss man an der Schnittstelle einen RS-232 Bus simulieren/emulieren und erst wenn das geschehen ist, kann man Werte von dem Gerät auslesen.
Der Hersteller riet mir, dass die Firma einen Schnittstellenkonverter kauft, durch den das dann relativ einfach laufen soll.
Ich warte nun auf die Entscheidung vom Chef, ob wir das Ding kaufen.
Falls Du noch ne Idee hast, ich bin für alles offen.
Trotz allem nochmals vielen Dank!
Viele Grüße
raysprak


----------



## raysprak (10. April 2006)

Hallo MCoder!
Du hattest recht, mit der auslesen Geschichte....man muss zuerst etwas hinschicken und bekommt etwas zurück.
Mein Problem ist nun, dass ich nur 1 Byte zurückbekomme, obwohl ich mindestens2 zurückbekommen müsste....
Kannste weiterhelfen?
Gruß


----------



## MCoder (10. April 2006)

raysprak hat gesagt.:
			
		

> Kannste weiterhelfen?Gruß


Werd's versuchen. Beschreib doch mal, wie die Kommunikation ablaufen soll und wie du das jetzt implementiert hast bzw. wie die (falschen) Ergebnisse aussehen.

Gruß
MCoder


----------



## raysprak (10. April 2006)

Also:
Source Code:
#include <windows.h>
#include <stdio.h>


int main(int argc,char** argv)
{
    DCB dcb;
    COMMTIMEOUTS CTO;
    COMMCONFIG CC;


    ZeroMemory (&dcb, sizeof(dcb));



    HANDLE hFile = NULL;
    hFile = CreateFile("COM1",GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,0,NULL);

    if(hFile == NULL)
    {
    MessageBox(0,"Error CreateFile","Test",MB_OK);
    }

    if(!GetCommState(hFile, &dcb))
    {
    MessageBox(0,"Error GetCommState","Test",MB_OK);
    }


    dcb.DCBlength = sizeof(DCB);
    dcb.BaudRate = CBR_19200;
    dcb.ByteSize = (BYTE)8;
    dcb.StopBits = (BYTE)2;
    dcb.fBinary = TRUE;
    dcb.fParity = FALSE;
    dcb.fOutxCtsFlow = FALSE;
    dcb.fOutxDsrFlow = FALSE;
    dcb.fDtrControl = DTR_CONTROL_ENABLE;
    dcb.fDsrSensitivity = FALSE;
    dcb.fTXContinueOnXoff = TRUE;
    dcb.fOutX = FALSE;
    dcb.fInX = FALSE;
    dcb.fErrorChar = FALSE;
    dcb.fNull = FALSE;
    dcb.fRtsControl = RTS_CONTROL_DISABLE;
    dcb.fAbortOnError = FALSE;
    dcb.wReserved = 0;

    CTO.ReadIntervalTimeout = 500;
    CTO.ReadTotalTimeoutConstant = 500;
    CTO.ReadTotalTimeoutMultiplier = 500;
    CTO.WriteTotalTimeoutConstant = 500;
    CTO.WriteTotalTimeoutMultiplier = 500;

    if(!SetCommTimeouts(hFile,&CTO))
    {
    MessageBox(0,"Error CommTimeouts","Test",MB_OK);
    }

    if(!SetCommState(hFile,&dcb))
    {
    DWORD error = GetLastError();
    char cerr[64];
    char cerr2[16];
    itoa((int)error,cerr2,10);
    strcpy(cerr,"Error SetCommState: ");
    strcat(cerr,cerr2);
    MessageBox(0,cerr,"Test",MB_OK);
    }


    if(!SetDefaultCommConfig("COM1",&CC,sizeof(CC)))
    {
    MessageBox(0,"Error SetDefaultCommConfig","Test",MB_OK);
    }
    if(hFile == INVALID_HANDLE_VALUE)
    MessageBox(0, "Fehler 1", "", 0);

        char helper[6];
//        sprintf(helper,"%c%d%c%c%c",27,1,80,13,10);

        strcpy(helper,"\27");
        strcat(helper,"\3F8");
        strcat(helper,"V");
        strcat(helper,"\13");
        strcat(helper,"\10");

        int written;

    WriteFile(hFile,&helper,strlen(helper),(LPDWORD)&written,NULL);


    DWORD dlength = 0;
    char sBuffer[1024];

    do
    {
        ReadFile(hFile,&sBuffer,25,&dlength,NULL);
        printf("%s %d\n",sBuffer,dlength);
    }
    while(dlength);


    char c;
    scanf("%c",&c);

return 0;
}


Ausgabe:
1
0
0
0
0
0
0
0
0
usw.


----------



## MCoder (11. April 2006)

Hallo,

wenn ich deinen Code richtig interpretiere, schickst du einen 6 Byte großen Initialisierungs- oder Anforderungsblock  zum Gerät und erwartest 25 Byte zurück? Ist dieser Block immer gleich bzw. weißt du was die einzelnen Bytes bedeuten?
Gibt es nicht irgendwelche weiteren Vorgaben für den Datenaustausch? Also z.B. welche Bytes denn den Anfang oder das Ende eines Datenblocks kennzeichnen?
Formal scheint dein Code schon richtig zu sein. Ich kann aber schlecht einschätzen, ob der Ablauf ok ist, wenn ich nicht die Protokollvorgaben kenne.

Gruß
MCoder


----------



## raysprak (11. April 2006)

Die Zahlen in der Ausgabe sind die Anzahlen der gelesenen Bytes.
Es sendet also 1 Byte und dann nichts mehr.
Wenn ich das gelesene Byte als Zahl ausgebe, steht dort 
1243580,
wenn ich als char ausgebe, steht da gar nischt.
Hier die Werte-/Kommandotabelle zu dem Ding


----------

