Senden von Daten auf die RS232 Schnittstelle per Button-Klick



  • Hallo zusammen
    Seit einiger Zeit befasse ich mich mit WinAPI, doch leider klappt das nicht so ganz wie ich will. Mein Problem lautet wie folgt:

    Ich will per Button-KLICK einen int wert über die RS232 (serielle) Schnittstelle versenden. Mithilfe von Tutorials habe ich mir einen Code zusammengefügt.
    Anforderungen an den Code:

    - Per Button-KLICK den COM1 - Port öffnen und Baudrate, etc.. einstellen
    - Per Button-KLICK einen einfachen INT WERT über die Schnittstelle senden

    -Compiler/Software: DevC++ 4.9.9.2
    -Projekt: Windows Application: C++ Project

    Dies sind bereits die ganzen anforderungen. Nun folgen die Probleme, bei welchen Ihr mir hoffentlich weiterhelfen könnt.

    -Wie kann ich im main.cpp ein "Unterprogramm" bei WM_COMMAND aufrufen? (oder muss ich es in WM_CHAR / WM_KEYDOWN aufrufen?)
    -Wie kann ich die variable "wert" vom typ int versenden üer die Schnittstelle?

    Ich hoffe Ihr könnt mir weiterhelfen. Anbei sehr ihr noch meinen kompletten Code mit der Headerdatei. Ich wäre euch sehr dankbar!

    Die Headerdatei "Serial.h"

    // -----------------------------------------------------------------------------------
    // (c) 2003 www.winapi.net
    //
    // Serial.h
    //
    // Headerdatei für eine einfache, aber leistungsfähige 
    // Kommunikation über die Serielle Schnittstelle
    // -----------------------------------------------------------------------------------
    
    #ifndef __SERIAL_H__
    #define __SERIAL_H__
    
    class CSerial
    {
    
    public:
       CSerial(); // Konstruktor
       ~CSerial(); // Destructor
    
       BOOL Open    (int, int, int, int, int); // Öffnen 
       BOOL Close   (void); // Schließen
       BOOL ModeSet (int, int, int, int); // Änderung
    
       int ReadData (char*); // Lesen
       int SendData (const char*, int); // Schreiben
       BOOL WriteCommByte (unsigned char); // Schreiben eines Zeichens
    
    private:
       HANDLE hComm; // Handle für den Zugriff
       DCB dcb_alt; // Um die alten Parameter zu merken
       COMMTIMEOUTS timeouts_alt; // Um die alten Parameter zu merken
    };
    
    #endif
    

    und noch die "main.cpp"

    #include <windows.h>
    #include "Serial.h" // Headerdefinitionen
    
    CSerial::CSerial() : hComm(INVALID_HANDLE_VALUE)
    {
    }
    CSerial::~CSerial()
    {
       Close ();
    }
    
    int wert=0;
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                       PSTR szCmdLine, int iCmdShow)
    {
       MSG          msg;
       HWND         hWnd;
       WNDCLASS     wc;
    
       char szAppName[] = "Serielle Ansteuerung";
    
       wc.cbClsExtra         = 0;
       wc.cbWndExtra         = 0;
       wc.hbrBackground      = (HBRUSH) GetStockObject(WHITE_BRUSH);
       wc.hCursor            = LoadCursor(NULL, IDC_ARROW);
       wc.hIcon              = LoadIcon(NULL, IDI_APPLICATION);
       wc.hInstance          = hInstance;
       wc.lpfnWndProc        = WndProc;
       wc.lpszClassName      = szAppName;
       wc.lpszMenuName       = NULL;
       wc.style              = CS_HREDRAW | CS_VREDRAW;
    
       RegisterClass(&wc);
    
       hWnd = CreateWindow( szAppName,
                            szAppName,
                            WS_OVERLAPPEDWINDOW,
                            CW_USEDEFAULT,
                            CW_USEDEFAULT,
                            800,//CW_USEDEFAULT,
                            600,//CW_USEDEFAULT,
                            NULL,
                            NULL,
                            hInstance,
                            NULL);
    
       ShowWindow(hWnd, iCmdShow);
       UpdateWindow(hWnd);
    
       while (GetMessage(&msg, NULL, 0, 0))
       {
          TranslateMessage(&msg);
          DispatchMessage(&msg);
       }
       return msg.wParam;
    }
    
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    
       static RECT   rect;
       static bool   ArrowKeys[4];
       static HWND hButton;
    
       static HANDLE hBitmap;
    
      switch (message)
       {
      case WM_CREATE:
          { 
          hBitmap= LoadImage (GetModuleHandle (NULL), "logo.bmp",
          IMAGE_BITMAP,0, 0,LR_DEFAULTCOLOR | LR_LOADFROMFILE);
    
          // Jetzt wird ein Button erzeugt. hwnd ist das Handle zum Hauptfenster. 
          //Man beachte das BS_BITMAP!
    
          hButton = CreateWindow("BUTTON", "", WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON|BS_BITMAP, 
                              20, 20, 50, 30, hWnd, 0, GetModuleHandle (NULL),  0);
    
                              //Das Bitmap auf den Button plazieren
          SendMessage (hButton, BM_SETIMAGE, (WPARAM) IMAGE_BITMAP,(LPARAM)(HANDLE) hBitmap);
    
          return 0;
          }
    
       case WM_SIZE:
          {
             MoveWindow(hButton, LOWORD(lParam) / 2 - 100, HIWORD(lParam) - 53, 
                                                               200, 53, TRUE);         
    
             rect.right  = LOWORD(lParam);
             rect.bottom = HIWORD(lParam);
             return 0;
          }
    
        case WM_CHAR:
          {
             switch (wParam)
             {
             case '\r':
                wert=0;
                break;
    
             case '0':
                wert=0;
                   break;
             case '1':
                wert=100;
                   break;
             case '2':
                wert=200;
                   break;
             case '3':
                wert=300;
                   break;
             case '4':
                wert=400;
                   break;
             case '5':
                wert=500;
                   break;
             case '6':
                wert=600;
                   break;
             case '7':
                wert=700;
                   break;                    
             case '8':
                wert=800;
                   break;
             case '9':
                wert=900;
                   break;
             }
             InvalidateRect(hWnd, NULL, FALSE);
             return 0;  
          }
       case WM_KEYDOWN:
          {
    
             switch (wParam)
             {          
             case VK_UP:
                ArrowKeys[0] = true;
                wert++;
                break;
    
             case VK_DOWN:
                ArrowKeys[1] = true;
                wert--;
                break;
    
             case VK_LEFT:
    
                break;
    
             default:
                return 0;
             }
             InvalidateRect(hWnd, NULL, FALSE);
             return 0;
          }
    
          case WM_KEYUP:
          {
             switch (wParam)
             {
             case VK_UP:
                ArrowKeys[0] = false;
                break;
    
             case VK_DOWN:
                ArrowKeys[1] = false;
                break;
    
             default:
                return 0;
             }
             InvalidateRect(hWnd, NULL, FALSE);
             return 0;
          }
    
       case WM_PAINT:
          {
             PAINTSTRUCT  ps;
             HDC          hDC;
    
             SIZE         size;
    
             char szKeyStatus[40];
             int  iKeyLength;
    
             hDC = BeginPaint(hWnd, &ps);
    
             for (int i = 0; i < 2; i++)
             {
                iKeyLength = wsprintf(szKeyStatus,"Status Taste %i: %i",
                                      i, ArrowKeys[i]);
    
                GetTextExtentPoint32(hDC, szKeyStatus, iKeyLength, &size);
                TextOut(hDC, rect.right / 2 - size.cx / 2, rect.bottom / 2 -
                        2 * size.cy + i * size.cy, szKeyStatus, iKeyLength);
             }
    
                iKeyLength = wsprintf(szKeyStatus,"     Wert: %i     ", wert);
    
                GetTextExtentPoint32(hDC, szKeyStatus, iKeyLength, &size);
                TextOut(hDC, rect.right / 2 - size.cx / 2, rect.bottom / 2 -
                        2 * size.cy + 5 * size.cy, szKeyStatus, iKeyLength);
    
             EndPaint(hWnd, &ps);
    
             return 0;
          }
    
       case WM_COMMAND:
          {
             if (lParam == (LPARAM)hButton)
             {
             MessageBox(NULL, "COM1 öffnen",
                              "COM1 öffnen",
                              MB_ICONINFORMATION | MB_OK |MB_DEFBUTTON1);
    
               //if (HIWORD(wParam) == BN_CLICKED)
               //    SendMessage(hWnd, WM_CLOSE, 0, 0);
             }
             return 0;
          }
    
       case WM_DESTROY:
          {
             PostQuitMessage(0);
             return 0;
          }
       }
       return DefWindowProc(hWnd, message, wParam, lParam);
    }
    
    BOOL CSerial::ModeSet (int nBaud, int nBits, int nStopp, int nParity) 
    // Ändern von Baudrate (nBaud), Bits (nBits), Parität (nParity)
    {
       if (INVALID_HANDLE_VALUE == hComm) // COM-Port überhaupt geöffnet?
           return (FALSE);
    
       DCB dcb; // Struktur vom Typ DCB erzeugen
    
       ZeroMemory (&dcb, sizeof(dcb)); // ..und schön löschen (wichtig!)
    // Die bestehenden Parameter holen. Bei Fehler ist hier Schluss!
       if (!GetCommState (hComm, &dcb))
       {
          Close ();
          MessageBox (NULL, "Fehler beim Ändern der COM-Port Parameter\nGetCommState()",
                      0, 0);
          return (FALSE);
       }
    
       // neue Parameter in die Struktur kopieren (Baud: z.B. 9600)
       dcb.BaudRate = nBaud;
       // neue Parameter in die Struktur kopieren (Bits: z.B. 7 oder 8)
       dcb.ByteSize = (BYTE)nBits;
       // neue Parameter in die Struktur kopieren (Parität:(siehe MSDN))
       dcb.Parity   = (BYTE)nParity;
       // Anzahl Stoppbits (siehe MSDN)
       dcb.StopBits = (BYTE)nStopp;
    
       // neue Parameter setzen. Bei Fehler ist hier Schluss!
       if (!SetCommState (hComm, &dcb))
       {
          Close ();
          MessageBox (NULL, "Fehler beim Ändern der COM-Port Parameter\nSetCommState()",
                      0, 0);
          return (FALSE);
       }
    
       return (TRUE); // fertig
    }
    
    // Öffnen von / mit Portnummer (nPort), Baudrate (nBaud), Bits (nBits),
    //Stoppbits (nStopp), Parität (nParity)
    
    BOOL CSerial::Open (int nPort, int nBaud, int nBits, int nStopp, int nParity)
    {
       if (INVALID_HANDLE_VALUE != hComm)  // COM-Port überhaupt geöffnet?
           return (TRUE);
    
       char szPort[15];
        // Aus einer "1" in nPort schreiben wir so "COM1" in szPort z.B..
       wsprintf (szPort, "\\\\.\\COM%d", nPort);
    
       hComm = CreateFile (szPort, // COM-Port öffnen
                           GENERIC_READ | GENERIC_WRITE, // wir wollen lesen und schreiben
                           0,
                           0,
                           OPEN_EXISTING,
                           FILE_ATTRIBUTE_NORMAL,
                           NULL); // nicht OVERLAPPED, wir holen uns den Port exclusiv
    
       if (hComm == INVALID_HANDLE_VALUE) // hat es geklappt? Bei Fehler ist hier Schluss!
       {
          MessageBox (NULL, "Fehler beim Öffnen des COM-Ports!\nCreateFile()", 0, 0);
          return (FALSE);
       }
       // Alte Timeouts merken. Bei Fehler ist hier Schluss!
       if (!GetCommTimeouts(hComm, &timeouts_alt)) 
       {
          Close ();
          MessageBox (NULL, "Fehler beim Öffnen des COM-Ports!\nGetCommTimeouts()",
                      0, 0);
          return (FALSE);
       }
    
       // Eine Struktur vom Typ COMMTIMEOUTS erzeugen und neue Timeouts setzen
       COMMTIMEOUTS timeouts;
       timeouts.ReadIntervalTimeout         = 200;
       timeouts.ReadTotalTimeoutMultiplier  = 200;
       timeouts.ReadTotalTimeoutConstant    = 200;
       timeouts.WriteTotalTimeoutMultiplier = 200;
       timeouts.WriteTotalTimeoutConstant   = 200;
    
       // Neue Timeouts setzen. Bei Fehler ist hier Schluss!
       if (!SetCommTimeouts(hComm, &timeouts)) 
       {
          Close ();
          MessageBox (NULL, "Fehler beim Öffnen des COM-Ports!\nSetCommTimeouts()",
                      0, 0);
          return (FALSE);
       }
    
       DCB dcb; // Struktur vom Typ DCB erzeugen
    
       ZeroMemory (&dcb, sizeof(dcb)); // ..und schön löschen (wichtig!)
       // Die bestehenden Parameter holen. Bei Fehler ist hier Schluss!
       if (!GetCommState (hComm, &dcb))
       {
          Close ();
          MessageBox (NULL, "Fehler beim Öffnen des COM-Ports!\nGetCommState()",
                      0, 0);
          return (FALSE);
       }
    
       dcb_alt = dcb; // alte Parameter sichern
       dcb.DCBlength         = sizeof(DCB);
       dcb.fBinary           = TRUE; // muss immer "TRUE" sein!
       dcb.fParity           = TRUE;
       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_ENABLE;
       dcb.fAbortOnError     = FALSE;
       dcb.wReserved         = 0; // muss immer "0" sein!
    
       // neue Parameter in die Struktur kopieren (Baud: z.B. 9600)
       dcb.BaudRate = nBaud;
       // neue Parameter in die Struktur kopieren (Bits: z.B. 7 oder 8)
       dcb.ByteSize = (BYTE)nBits;
       // neue Parameter in die Struktur kopieren (Parität:(siehe MSDN))
       dcb.Parity   = (BYTE)nParity;
       // Anzahl Stoppbits (siehe MSDN)
       dcb.StopBits = (BYTE)nStopp;
       dcb.fParity = (dcb.Parity != NOPARITY);
    
       // neue Parameter setzen. Bei Fehler ist hier Schluss!
       if (!SetCommState (hComm, &dcb))
       {
          Close ();
          MessageBox (NULL, "Fehler beim setzen der COM-Port Parameter\nSetCommState()",
                      0, 0);
          return (FALSE);
       }
    
       return(TRUE);
    }
    
    BOOL CSerial::Close (void)
    {
       if (INVALID_HANDLE_VALUE == hComm) // COM-Port überhaupt geöffnet?
           return(TRUE);
    
       if (!SetCommTimeouts(hComm, &timeouts_alt))
       {
          MessageBox (NULL, "Fehler beim Schließen des COM-Ports\nSetCommTimeouts()",
                      0, 0);
          return (FALSE);
       }
       // alte Parameter zurückschreiben. Bei Fehler ist hier Schluss!
       if (!SetCommState (hComm, &dcb_alt)) 
       {
          MessageBox (NULL, "Fehler beim Schließen des COM-Ports\nSetCommState()",
                      0, 0);
          return (FALSE);
       }
       CloseHandle (hComm); // Port schließen
       hComm = INVALID_HANDLE_VALUE; // das Handle zurücksetzen
    
       return (TRUE);
    }
    
    BOOL CSerial::WriteCommByte (unsigned char ucByte) // Das zu übertragene Byte (ucByte)
    {
       if (INVALID_HANDLE_VALUE == hComm) // COM-Port überhaupt geöffnet?
           return(FALSE);
    
       // ein Zeichen direkt übertragen. Bei Fehler ist hier Schluss!
       if (!TransmitCommChar(hComm, ucByte))
       {
          MessageBox (NULL, "Fehler beim Schreiben auf COM-Port!\nTransmitCommChar()",
                      0, 0);
       }
    
       return (TRUE);
    }
    
    int CSerial::SendData (const char *buffer, int iBytesToWrite) 
    // Buffer (*buffer), mit den zu sendenen Zeichen und deren Anzahl (iBytesToWrite)
    {
       if(INVALID_HANDLE_VALUE == hComm) // COM-Port überhaupt geöffnet?
           return(0);
    
       DWORD dwBytesWritten = 0;
       // die angegebene Anzahl der Bytes schreiben
       WriteFile(hComm, buffer, iBytesToWrite, &dwBytesWritten, NULL);
    
       return ((int) dwBytesWritten); // die Anzahl der geschriebenen Bytes zurückgeben
    }
    
    int CSerial::ReadData (char *buffer) // Buffer (*buffer), der die Zeichen bekommt
    {
       if (INVALID_HANDLE_VALUE == hComm) // COM-Port überhaupt geöffnet?
           return(0);
    
       DWORD dwRead = 0;
       char chRead;
       int i = 0;
    
       while (ReadFile(hComm, &chRead, 1, &dwRead, NULL)) // wurde ein Zeichen gelesen?
       {
           if (dwRead != 1) // ..wenn nicht, dann ist hier Schluß
               break;
    
           buffer[i++] = chRead; // wann ja, dann das Zeichen in den Buffer schreiben
       }
    
       return (i); // die Anzahl der gelesenen Bytes zurückgeben
    }
    


  • ThomasSch schrieb:

    -Wie kann ich im main.cpp ein "Unterprogramm" bei WM_COMMAND aufrufen? (oder muss ich es in WM_CHAR / WM_KEYDOWN aufrufen?)

    in wParam steht die control-id (button-id oder sowas). einfach bei gleichheit die gewünschte funktion aufrufen. die muss natürlich schnell wieder zurückkehren, damit dein fenster nicht einfriert 😉

    ThomasSch schrieb:

    -Wie kann ich die variable "wert" vom typ int versenden üer die Schnittstelle?

    etwa so;

    int wert;
    DWORD bytes_written;
    WriteFile (comm_port_handle, &wert, sizeof(wert), &bytes_written, NULL);
    if (bytes_written == sizeof(wert))
    {
      // OK
    }
    else
    {
      // nicht alles geschrieben oder fehler
    }
    

    aber endianess beachten, bei x86-kisten wird ein 'int' verdreht gesendet...
    😉



  • Und wie kann ich in diesem Fall das "Unterprogramm" bzw. die BOOL aufrufen?

    Open(1,9600,7,1,0);
    

    etwa so?
    Irgendwie bin ich ein wenig verwirrt im moment, da es bei mir immer fehler gab, als ich ein Unterprogramm aufrufen wollte.


Log in to reply