Serielle Schnittstelle (COM port)

Previous topic - Next topic

Kitty Hello

Um mit der seriellen Schnittsstelle zu kommunizieren kann man diese Lösung verwenden. Derzeit nur unter Win32 möglich.

Eine neue Datei anlegen, diesen Inhalt reinkopieren und zum Projekt hinzufügen:
Code (glbasic) Select
// --------------------------------- //
// Project: SerialPort
// Start: Wednesday, March 12, 2008
// IDE Version: 5.199




TYPE TComTimeouts
    ReadIntervalTimeout
    ReadTotalTimeoutMultiplier
    ReadTotalTimeoutConstant
    WriteTotalTimeoutMultiplier
    WriteTotalTimeoutConstant
ENDTYPE




INLINE

#define DWORD unsigned long
#define WINAPI __stdcall
#define __in
#define __inout
#define __in_opt
#define BOOL int

HANDLE g_hSerialFile=0;

} // namespace

#define GENERIC_READ                     (0x80000000L)
#define GENERIC_WRITE                    (0x40000000L)
#define CREATE_NEW          1
#define CREATE_ALWAYS       2
#define OPEN_EXISTING       3
#define OPEN_ALWAYS         4



typedef struct _COMMTIMEOUTS {
  DWORD ReadIntervalTimeout;
  DWORD ReadTotalTimeoutMultiplier;
  DWORD ReadTotalTimeoutConstant;
  DWORD WriteTotalTimeoutMultiplier;
  DWORD WriteTotalTimeoutConstant;
} COMMTIMEOUTS,
 *LPCOMMTIMEOUTS;

typedef struct _DCB {
  DWORD DCBlength;
  DWORD BaudRate;
  DWORD fBinary;
  DWORD fParity;
  DWORD fOutxCtsFlow;
  DWORD fOutxDsrFlow;
  DWORD fDtrControl;
  DWORD fDsrSensitivity;
  DWORD fTXContinueOnXoff;
  DWORD fOutX;
  DWORD fInX;
  DWORD fErrorChar;
  DWORD fNull;
  DWORD fRtsControl;
  DWORD fAbortOnError;
  DWORD fDummy2;
  WORD wReserved;
  WORD XonLim;
  WORD XoffLim;
  BYTE ByteSize;
  BYTE Parity;
  BYTE StopBits;
  char XonChar;
  char XoffChar;
  char ErrorChar;
  char EofChar;
  char EvtChar;
  WORD wReserved1;
} DCB,
 *LPDCB;



DECLARE(CreateFileA,  "kernel32.dll", (LPCTSTR,DWORD,DWORD,void*,DWORD,DWORD,HANDLE),HANDLE);
DECLARE(GetCommState, "kernel32.dll", (HANDLE, LPDCB), BOOL);
DECLARE(SetCommState, "kernel32.dll", (HANDLE, LPDCB), BOOL);


DECLARE(GetCommTimeouts, "kernel32.dll", (HANDLE, COMMTIMEOUTS*), BOOL);
DECLARE(SetCommTimeouts, "kernel32.dll", (HANDLE, COMMTIMEOUTS*), BOOL);

DECLARE(WriteFile, "kernel32.dll", (HANDLE, void*, DWORD numwrite, DWORD* nwritten, void* overlapped), BOOL);
DECLARE(ReadFile,  "kernel32.dll", (HANDLE, void*, DWORD numread,  DWORD* nread,    void* overlapped), BOOL);
DECLARE(CloseHandle, "kernel32.dll", (HANDLE), BOOL);

// error handling
DECLARE(GetLastError, "kernel32.dll", (void), DWORD);
DECLARE(FormatMessageA, "kernel32.dll", (DWORD dwFlags, void* lpSource, DWORD dwMessageId, DWORD dwLanguageId, char** lpBuffer, DWORD nSize, void *Arguments), DWORD);
DECLARE(LocalFree, "kernel32.dll", (HANDLE), HANDLE);

namespace __GLBASIC__ {

ENDINLINE

FUNCTION DebugLastError:
INLINE
DWORD err = ::GetLastError();
char* lpMsgBuf;
FormatMessageA(0x00000100 | 0x00001000 | 0x00000200, NULL, err, 1<<10, &lpMsgBuf, 0, NULL);
DEBUG(CGStr(lpMsgBuf));
DEBUG(DGStr("\n"));
LocalFree((HANDLE)lpMsgBuf);
ENDINLINE
ENDFUNCTION



FUNCTION COM_Open: port$, bRead, bWrite
INLINE
    g_hSerialFile = ::CreateFileA(port_Str.c_str(), (bRead?GENERIC_READ:0)|(bWrite?GENERIC_WRITE:0),0,0,OPEN_EXISTING, 0,0);
    if((int)g_hSerialFile == -1)
    DebugLastError();
    return ((int)g_hSerialFile!=-1) ? TRUE:FALSE;
ENDINLINE
ENDFUNCTION

FUNCTION COM_Close:
INLINE
    ::CloseHandle(g_hSerialFile);
    g_hSerialFile=0;
ENDINLINE
ENDFUNCTION

// parity: 0 = none, 1=even, 2=mark, 3=space
FUNCTION COM_SetComState: baud, parity, databits, stopbits
INLINE
    DCB MyDCB;
    for(int i=0; i    {
        ((char*)&MyDCB)[i] = 0;
    }
    MyDCB.DCBlength = sizeof(DCB);
    if( GetCommState(g_hSerialFile, &MyDCB))
    {
        MyDCB.BaudRate=(int)baud;
        MyDCB.Parity = (int)parity;
        MyDCB.ByteSize = (int)databits;
        MyDCB.StopBits = (int)stopbits;
        return SetCommState(g_hSerialFile, &MyDCB);
    }
    return FALSE;
ENDINLINE
ENDFUNCTION


FUNCTION COM_SetCommTimeouts: tout AS TComTimeouts
INLINE
COMMTIMEOUTS co;
    co.ReadIntervalTimeout        =tout.ReadIntervalTimeout;
    co.ReadTotalTimeoutMultiplier =tout.ReadTotalTimeoutMultiplier;
    co.ReadTotalTimeoutConstant   =tout.ReadTotalTimeoutConstant;
    co.WriteTotalTimeoutMultiplier=tout.WriteTotalTimeoutMultiplier;
    co.WriteTotalTimeoutConstant  =tout.WriteTotalTimeoutConstant;
    ::SetCommTimeouts(g_hSerialFile, &co);

ENDINLINE
ENDFUNCTION

FUNCTION COM_Read: buffer[], nbytes
INLINE
    char buf[1024];
    DWORD nread =0;
    if( ReadFile(g_hSerialFile, buf, nbytes, &nread, 0))
    {
        DIM(buffer, nread);
        for(int i=0; i            buffer(i) = buf[i];
        return nread;
    }
    return 0;
ENDINLINE
ENDFUNCTION

FUNCTION COM_Read$:
INLINE
    char buf[1024];
    DWORD nread =0;
    if( ReadFile(g_hSerialFile, buf, 1024, &nread, 0))
    {
        buf[nread] = '\0';
        DGStr str(CGStr((const char*)buf));
        return str;
    }
    return CGStr("");
ENDINLINE
ENDFUNCTION


FUNCTION COM_Write: buffer[], nbytes
INLINE
    char buf[1024];
    DWORD nwrite =0;
    for(int i=0; i<(int)nbytes; ++i)
        buf[i] = (char)buffer(i);
    buf[(int)nbytes]='\0';
    if( WriteFile(g_hSerialFile, buf, (DWORD)nbytes, &nwrite, 0))
    {
        return nwrite;
    }
    return 0;
ENDINLINE
ENDFUNCTION

FUNCTION COM_WriteStr: text$
LOCAL buf[], i, n
n = LEN(text$)
    DIM buf[n]
    FOR i=0 TO n-1
        buf[i] = ASC(MID$(text$, i,1))
    NEXT
    RETURN COM_Write(buf[], n)
ENDFUNCTION
Hier ein Testporgramm:
Code (glbasic) Select
// --------------------------------- //
// Project: SerialPort
// Start: Wednesday, March 12, 2008
// IDE Version: 5.199


port$  = "COM1"
baud   = 19200 // baud rate
parity = 0     // 0=none, 1=odd, 2=even, 3=mark, 4=space
datab  = 8     // data bits
stop   = 0     // stop bits: 0=1 (ONE) stop bit, 1=1.5 bits, 2=2 bits

// Open COM port for writing
IF COM_Open(port$, FALSE, TRUE) = FALSE THEN Error("open COM2 failed")

// Set Baud rate and handshake
IF COM_SetComState(baud, parity, datab, stop) = FALSE THEN Error("Failed to set com state")

// optionally set com timeouts
//    LOCAL tout AS TComTimeouts
//    tout.ReadIntervalTimeout        = ..
//    tout.ReadTotalTimeoutMultiplier = ..
//    tout.ReadTotalTimeoutConstant   = ..
//    tout.WriteTotalTimeoutMultiplier= ..
//    tout.WriteTotalTimeoutConstant  = ..
//    COM_SetCommTimeouts(tout)

// Write something
    IF COM_WriteStr("ABC\n")=0 THEN Error("Failed to write data")

// Read something - make sure you COM_Open(..., TRUE, ...) before
// read$ = COM_Read$()

// close COM port
    COM_Close()

MOUSEWAIT
END


FUNCTION Error: txt$
    PRINT txt$, 0,0
    SHOWSCREEN
    MOUSEWAIT
    END
ENDFUNCTION

sechsrad

habe mich mal an den "dev-c++ version 4.9.9.2" ran gemacht.
der c-compiler ist faszinierend für die verbindung mit glbasic und auch um programme für den gp2x (gpe) herzustellen.
es lohnt sich das ding runterzuladen und damit zu spielen.

habe auch hier nach eine lösung gesucht um für das glbasic routinen zu ergänzen die man evtl braucht.
natürlich dll-routinen. und als übung natürlich wieder die com-schnittstelle , funktionieren fehlerfrei.

war eine googlerei für diese routinen.

FUNCTION glb_empfchar
FUNCTION glb_sendtext: txt$, zahl
FUNCTION glb_sendchar: zahl
FUNCTION glb_open:
FUNCTION glb_close:

Code (glbasic) Select
a$ = "1234567890"+CHR$(13)

glb_open()
SLEEP 100
glb_sendtext(a$,11)

//glb_sendchar(66)
//glb_sendchar(13)
SLEEP 500

FOR c=1 TO 10
SLEEP 500
b=glb_empfchar()
PRINT b,100,100
SHOWSCREEN
NEXT

glb_close()
MOUSEWAIT

FUNCTION nichts:
ENDFUNCTION

INLINE
DECLARE(close_com2, "com-dll.dll", (), void);
DECLARE(open_com2, "com-dll.dll", (), void);
DECLARE(sendtext_com2, "com-dll.dll", (const char*, unsigned int), void);
DECLARE(sendchar_com2, "com-dll.dll", (int), void);
DECLARE(empfchar_com2, "com-dll.dll", (), unsigned int);
ENDINLINE

FUNCTION glb_empfchar:
LOCAL result
   INLINE
       result = empfchar_com2();
   ENDINLINE
   RETURN result
ENDFUNCTION

FUNCTION glb_sendtext: txt$, zahl
INLINE
    sendtext_com2(txt_Str.c_str(),zahl);
ENDINLINE
ENDFUNCTION

FUNCTION glb_sendchar: zahl
INLINE
    sendchar_com2(zahl);
ENDINLINE
ENDFUNCTION

FUNCTION glb_open:
INLINE
open_com2();
ENDINLINE
ENDFUNCTION

FUNCTION glb_close:
INLINE
close_com2();
ENDINLINE
ENDFUNCTION
und hier mal den code zum spielen für die com-dll :
1. die datei wo die dll mit hergestellt wird
2. die dazugehörige comtools.cpp
3. die dazugehörige comtools.h

com2 mit 19200 baud, kann aber geändert werden.
könnte man auch dynamisch ändern/proggen mit übergaben an die routine.

Code (glbasic) Select
#include
#include "ComTools.h"

#define COM1 0
#define COM2 1
#define COM3 2
#define COM4 3

extern "C" __declspec(dllexport) int __stdcall open_com2()
{
       ComOpen(COM2,19200,P_NONE,S_1BIT,D_8BIT);        
}

extern "C" __declspec(dllexport) int __stdcall close_com2()
{      
       ComClose(COM2);
}

extern "C" __declspec(dllexport) int __stdcall sendtext_com2(int *cBuffer, int anzahl)
{    
      ComWrite(COM2,cBuffer,anzahl);  
}

extern "C" __declspec(dllexport) int __stdcall sendchar_com2(int zahl)
{    
      ComWritechar(COM2,zahl);  
}

extern "C" __declspec(dllexport) int __stdcall empfchar_com2()
{      
       char c;
       c=ComReadchar(COM2);
       return c;
}
Code (glbasic) Select
#include
#include "ComTools.h"

#define MAX_COM_PORTS 8

static HANDLE hComFile[MAX_COM_PORTS];
static BOOL bIsOpen [MAX_COM_PORTS];

//*****************************************************************************
//*
//* ComOpen
//*
//*****************************************************************************
// Öffnet eine serielle Verbindung
// Nr : Ist die Nummer des Com-Ports (0=COM1 1=COM2 ...)
// Baud : Ist die Bautrate
// Parity : 0 = kein Parity Bit
//  1 = gerade
//  2 = ungerade
//  3 = immer 0
//  4 = immer 1
// Stopbits : 0 = Ein Stopbit
//  1 = Ein/einhalb Stopbits
//  2 = Zwei Stopbits
// Bits : 0 = 7 Datenbits
//  1 = 8 Datenbits
//  7 = 7 Datenbits
//  8 = 8 Datenbits
// Ergibt 1 wenn eine Schnittstelle geöffnet wurde
int ComOpen(unsigned Nr,int Baud,int Parity,int Stopbits,int Databits)
{
static const int iPMode[]={NOPARITY,EVENPARITY,ODDPARITY,SPACEPARITY,MARKPARITY};
static const int iSMode[]={ONESTOPBIT,ONE5STOPBITS,TWOSTOPBITS,ONESTOPBIT};
char cName[]="COM2";
HANDLE hFile;
COMMTIMEOUTS sTo;
DCB sDcb;

if(Nr>=MAX_COM_PORTS)return 0;
if(bIsOpen[Nr])return 0;

cName[7]='1'+Nr;

  hFile= CreateFile(cName,GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
if(hFile==INVALID_HANDLE_VALUE)
{
hFile=0;
return 0;
}

if(Databits==7)Databits=0;

memset(&sDcb,0,sizeof(sDcb));
sDcb.DCBlength=sizeof(sDcb);
sDcb.BaudRate     = Baud;
sDcb.fParity       = (Parity!=0)? TRUE:FALSE;
sDcb.fBinary       = TRUE;
sDcb.Parity       = iPMode[Parity];
sDcb.StopBits     = iSMode[Stopbits&3];
sDcb.fOutxCtsFlow = FALSE;
sDcb.fOutxDsrFlow = FALSE;
sDcb.fDtrControl = DTR_CONTROL_ENABLE;
sDcb.fRtsControl = RTS_CONTROL_ENABLE;
sDcb.fDsrSensitivity= FALSE;
sDcb.fAbortOnError = FALSE;
sDcb.ByteSize     = (Databits)? 8:7;

if(!SetCommState(hFile,&sDcb))
{
CloseHandle(hFile);
return 0;
}

sTo.ReadIntervalTimeout   = MAXDWORD; // 0 ms Read-Tomeout
sTo.ReadTotalTimeoutMultiplier = 0;
sTo.ReadTotalTimeoutConstant   = 0;
sTo.WriteTotalTimeoutMultiplier= 12000/Baud+1; // ? ms Write timeout per byte
sTo.WriteTotalTimeoutConstant  = sTo.WriteTotalTimeoutMultiplier+1;
if(!SetCommTimeouts((HANDLE)hFile,&sTo))
{
CloseHandle(hFile);
return 0;
}

hComFile[Nr]=hFile;
bIsOpen [Nr]=TRUE;

return 1;
}

//*****************************************************************************
//*
//* ComClose
//*
//*****************************************************************************
// Schließt eine serielle Verbindung
// Nr : Ist die Nummer des Com-Ports (0=COM1 1=COM2 ...)
// Ergibt 1 wenn eine Schnittstelle geschlossen wurde
int ComClose(unsigned Nr)
{

if(Nr>=MAX_COM_PORTS)return 0;
if(!bIsOpen[Nr])return 0;

CloseHandle(hComFile[Nr]);
hComFile[Nr]=0;
bIsOpen [Nr]=FALSE;

return 1;
}

//*****************************************************************************
//*
//* ComReadchar
//*
//*****************************************************************************
// Ein Zeichen lesen
// Nr : Ist die Nummer des Com-Ports (0=COM1 1=COM2 ...)
// Ergibt -1 wenn nichts gelesen wurde sonst das Zeichen
int ComReadchar(unsigned Nr)
{
unsigned char c;
DWORD dwCount;

if(Nr>=MAX_COM_PORTS)return -1;
if(!bIsOpen[Nr])return -1;

if(!ReadFile(hComFile[Nr],&c,1,&dwCount,0))return -1;
if(dwCount!=1)return -1;

return c;
}

//*****************************************************************************
//*
//* ComRead
//*
//*****************************************************************************
// Mehrere Zeichen lesen
// Nr : Ist die Nummer des Com-Ports (0=COM1 1=COM2 ...)
// Buffer : Buffer in dem die Zeichen gespeichert werden
// Max : Maximale Anzahl der zu lesenden Zeichen
// Ergibt die Anzahl der gelesenen Zeichen
int ComRead(unsigned Nr,void *Buffer,int Max)
{
DWORD dwCount;

if(Nr>=MAX_COM_PORTS)return 0;
if(!bIsOpen[Nr])return 0;

ReadFile(hComFile[Nr],Buffer,Max,&dwCount,0);

return dwCount;
}

//*****************************************************************************
//*
//* ComWritechar
//*
//*****************************************************************************
// Ein Zeichen senden
// Nr : Ist die Nummer des Com-Ports (0=COM1 1=COM2 ...)
// Zeichen : Ist das Zeichen das gesendet werden soll.
// Ergibt die Anzahl der gesendeten Zeichen
int ComWritechar(unsigned Nr,int Zeichen)
{
DWORD dwCount;

if(Nr>=MAX_COM_PORTS)return 0;
if(!bIsOpen[Nr])return 0;

WriteFile(hComFile[Nr],&Zeichen,1,&dwCount,0);

return dwCount;
}

//*****************************************************************************
//*
//* ComWrite
//*
//*****************************************************************************
// Mehrere Zeichen schreiben
// Nr : Ist die Nummer des Com-Ports (0=COM1 1=COM2 ...)
// Buffer : Buffer in dem die Zeichen gespeichert werden
// Count : Anzahl der zu sendenden Zeichen
// Ergibt die Anzahl der gesendeten Zeichen
int ComWrite(unsigned Nr,void *Buffer,int Count)
{
DWORD dwCount;

if(Nr>=MAX_COM_PORTS)return 0;
if(!bIsOpen[Nr])return 0;

WriteFile(hComFile[Nr],Buffer,Count,&dwCount,0);

return dwCount;
}

//*****************************************************************************
//*
//* ComGetReadCount
//*
//*****************************************************************************
// Ergibt die Anzahl der Bytes die im Lesepuffer der Schnittstelle sind
// Nr : Ist die Nummer des Com-Ports (0=COM1 1=COM2 ...)
// Ergibt die Anzahl der Bytes im Buffer
int ComGetReadCount(unsigned Nr)
{
COMSTAT sComStat;
DWORD dwErrorFlags;

if(Nr>=MAX_COM_PORTS)return 0;
if(!bIsOpen[Nr])return 0;

dwErrorFlags=0;

if(!ClearCommError(hComFile[Nr], &dwErrorFlags, &sComStat))return 0;

return sComStat.cbInQue;
}

//*****************************************************************************
//*
//* ComGetWriteCount
//*
//*****************************************************************************
// Ergibt die Anzahl der Bytes die im Schreibpuffer der Schnittstelle sind
// Nr : Ist die Nummer des Com-Ports (0=COM1 1=COM2 ...)
// Ergibt die Anzahl der Bytes im Buffer
int ComGetWriteCount(unsigned Nr)
{
COMSTAT sComStat;
DWORD dwErrorFlags;

if(Nr>=MAX_COM_PORTS)return 0;
if(!bIsOpen[Nr])return 0;

dwErrorFlags=0;

if(!ClearCommError(hComFile[Nr], &dwErrorFlags, &sComStat))return 0;

return sComStat.cbOutQue;
}
Code (glbasic) Select
#ifndef __COM_TOOLS_H__
#define __COM_TOOLS_H__
//  Konstanden für Parity
#define P_NONE 0 // 0 = kein Parity Bit
#define P_EVEN 1 // 1 = gerade
#define P_ODD 2 // 2 = ungerade
#define P_SPACE 3 // 3 = immer 0
#define P_MARK 4 // 4 = immer 1

#define D_7BIT 0 // 7-Databits
#define D_8BIT 1 // 8-Databits

#define S_1BIT 0 // 1   Stopbit
#define S_1_5BIT 1 // 1.5 Stopbits
#define S_2BIT 2 // 2   Stopbits

int ComOpen (unsigned Nr,int Baud=19200,int Parity=P_NONE,int Stopbits=S_1BIT,int Databits=D_8BIT);
int ComClose(unsigned Nr);
int ComRead (unsigned Nr,void *Buffer,int Max);
int ComReadchar (unsigned Nr);
int ComWrite(unsigned Nr,void *Buffer,int Count);
int ComWritechar(unsigned Nr,int Zeichen);
int ComGetReadCount (unsigned Nr);
int ComGetWriteCount(unsigned Nr);

#endif

sechsrad

hallo gernot , kannst du noch einmal nach der read$ schauen, die geht nicht  :
read$ = COM_Read$()

mfg

Kitty Hello

Hast Du COM_Open mit bRead=TRUE gemacht?
Was sendest Du?

sechsrad

muss eigentlich eine leere test[] übergeben werden für diese : FUNCTION COM_Read: buffer[], nbytes

DIM test[55]
zahl = COM_Read(test[],55)

mfg

Kitty Hello

ist egal. Macht ein DIM intern.

Schranz0r

Schnalt der doch net was du mit Intern meinst ;)
I <3 DGArray's :D

PC:
AMD Ryzen 7 3800X 16@4.5GHz, 16GB Corsair Vengeance LPX DDR4-3200 RAM, ASUS Dual GeForce RTX™ 3060 OC Edition 12GB GDDR6, Windows 11 Pro 64Bit, MSi Tomahawk B350 Mainboard