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++ ProjectDies 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.