Initalisierung einer USB-Karte in Unterprogramm "auslagern"
-
Hallo,
ich hoffe, Ihr könnt mir helfen.
Ich möchte über C++ und die Win-API eine CNC-Steuerung bauen.
Hierfür habe ich mir bereits ein USB-Board (Velleman K8055) und passende Schrittmotoren gekauft.
Die Ansteuerung der USB-Karte geht soweit auch einwandfrei, die von Velleman gegebene Initialisierung + .dll-Dateien funktionieren.
Allerdings habe ich das Problem, dass ich die Initialisierung der USB-Karte immer in meiner Main-Funktion tätigen muss. Ich möchte diese gerne auslagern.
Ich stoße dabei leider auf das Problem, dass ich hier immer wieder Fehlermeldungen bekomme, egal wie ich die Initialisierung ausserhalb der Main-Datei mache.Ich habe in meinem Programm 4 Funktionen:
Testerling.hpp = Funktionsprototyp von Testerling.cpp
USBInit.hpp = Typdefinitionen der USB-Karte
Main.cpp = Hauptprogramm
Testerling.cpp = Funktion zum Testen eines Befehls über „Unterprogramm“Testerling.hpp
______________________________________//Funktionsprototyp fuer Testerling int Testerling();
______________________________________
USBInit.hpp
______________________________________typedef void(CALLBACK* t_func)(int ); typedef void(CALLBACK* t_func0)(); typedef int(CALLBACK* t_func1)(); typedef void(CALLBACK* t_func2)(int *, int *); typedef void(CALLBACK* t_func3)(int , int ); typedef int(CALLBACK* t_func4)(int ); typedef bool(CALLBACK* t_func5)(int ); t_func4 OpenDevice; t_func0 CloseDevice; t_func0 Version_; t_func4 ReadAnalogChannel; t_func2 ReadAllAnalog; t_func3 OutputAnalogChannel; t_func3 OutputAllAnalog; t_func ClearAnalogChannel; t_func0 ClearAllAnalog; t_func SetAnalogChannel; t_func0 SetAllAnalog; t_func WriteAllDigital; t_func ClearDigitalChannel; t_func0 ClearAllDigital; t_func SetDigitalChannel; t_func0 SetAllDigital; t_func5 ReadDigitalChannel; t_func1 ReadAllDigital; HINSTANCE hDLL; int foundDLL = 0;
______________________________________
Main.cpp
______________________________________#include <cstdlib> #include <windows.h> #include <iostream> #include "Testerling.hpp" //Als Test fuer Unterprogramme #include "USBInit.hpp" //Typedefs für USB-Karte using namespace std; //Funktionsprototypen LRESULT CALLBACK WindowProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); HWND ErstelleHauptfenster (HINSTANCE hInst); void ErstelleSteuerelemente (HWND hWnd, HINSTANCE hInst); //IDs der Child-Fenster //Button #define ID_ButtonBeenden 4049 #define ID_ButtonInitialisieren 4050 #define ID_ButtonTest 4051 #define ID_ButtonTestAus 4052 //Button //Globale Variablen //EIGENTLICH NICHT SO ZU MACHEN HWND hButtonBeenden; HWND hButtonInitialisieren; HWND hButtonTest; HWND hButtonTestAus; //Hauptprogramm // int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpcmdline, int ncmdshow) { HWND hWnd; //Fenster-Handle MSG message; //Nachricht //Hauptfenster erstellen hWnd = ErstelleHauptfenster (hInst); //Pruefen, ob alles glattging if (hWnd == NULL) //Wenn der zurueckgegebene Wert 0 ist, dann Programm beenden return(0); //also return (0); //Alle Steuerelemente erstellen ErstelleSteuerelemente(hWnd, hInst); //Der "Herzschlag" des Programms //Hier werden alle Nachrichten abgeholt, //uebersetzt und weitergeleitet while (GetMessage (&message, NULL, 0,0)) { TranslateMessage (&message); DispatchMessage (&message); } //Programm beenden return (int)(message.wParam); } //WinMain //Erstelle Hauptfenster //Hauptfenster erstellen und Handle zurueckliefern HWND ErstelleHauptfenster(HINSTANCE hInst) { HWND hWnd; //Fenster-Handle WNDCLASSEX windowclass; //Nachricht //Der Klassenname des Fenstes ist frei wählbar const TCHAR szClassName[] = TEXT ("CNC-Steuerung"); //Struktur mit gewuenschten Eigenschaften fuellen // //Groesse der Struktur zwischespeichern windowclass.cbSize = sizeof(WNDCLASSEX); //Fenster soll beim Verschieben neu gezeichnet werden windowclass.style = CS_HREDRAW | CS_VREDRAW; //Zeiger auf Callback-Funktion windowclass.lpfnWndProc = WindowProc; //Keine erweiterten Einstellungen windowclass.cbClsExtra = 0; windowclass.cbWndExtra = 0; //Instanz Speichern windowclass.hInstance = hInst; //Icons und Cursor festlegen windowclass.hIcon = LoadIcon (NULL, IDI_APPLICATION); windowclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION); windowclass.hCursor = LoadCursor (NULL, IDC_ARROW); //Hintergrundfarbe festlegen windowclass.hbrBackground = (HBRUSH)COLOR_BACKGROUND+1; //Ein Menue brauchen wir nicht windowclass.lpszMenuName = NULL; //Klassenname angeben windowclass.lpszClassName = szClassName; ///Fensterklasse registrieren if (!RegisterClassEx (&windowclass)) return (NULL); //Das Fenster erzeugen hWnd = CreateWindowEx (NULL, szClassName, TEXT("CNC-Steuerung"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, // x-Position des Fensters - y-Position des Fensters 1200, 600, //Fenstergroesse Breite und Hoehe NULL, // NULL, hInst, NULL); //Fensterhandle zurueckgeben return (hWnd); } //Erstelle Hauptfenster //Erstelle Steuerelemente // //Alle Steuerelemente erstellen void ErstelleSteuerelemente(HWND hWnd, HINSTANCE hInst) { //BUTTON //Beenden-button als Child-Fenster erzeugen hButtonBeenden = CreateWindow (TEXT("BUTTON"), TEXT("Beenden"), BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD, 1050, 500, 95, 40, hWnd, (HMENU)ID_ButtonBeenden, hInst, NULL); hButtonInitialisieren = CreateWindow (TEXT("BUTTON"), TEXT("Initialisieren"), BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD, 100, 150, 95, 40, hWnd, (HMENU)ID_ButtonInitialisieren, hInst, NULL); hButtonTest = CreateWindow (TEXT("BUTTON"), TEXT("Test"), BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD, 100, 200, 95, 40, hWnd, (HMENU)ID_ButtonTest, hInst, NULL); hButtonTestAus = CreateWindow (TEXT("BUTTON"), TEXT("Test Aus"), BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD, 100, 250, 95, 40, hWnd, (HMENU)ID_ButtonTestAus, hInst, NULL); //BUTTON } //Erstelle Steuerelemente //Callback-Funktion zur Nachrichtenverarbeitung // LRESULT CALLBACK WindowProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { //Messages auswerten switch (message) { //Fenster schliessen (Auch Alt+F4) case WM_DESTROY: { //Nachricht zum Beenden schicken PostQuitMessage(0); return (0); } //Ab hier die Nachrichten unserer Child-Fenster bearbeiten case WM_COMMAND: { switch (wParam) { //Wurde Initialisieren angeklickt? case ID_ButtonInitialisieren: { hDLL = LoadLibrary("k8055d"); if (hDLL != NULL) { OpenDevice = (t_func4) GetProcAddress(hDLL, "OpenDevice"); if (!OpenDevice) { // handle the error FreeLibrary(hDLL); return -2; } CloseDevice = (t_func0) GetProcAddress(hDLL, "CloseDevice"); if (!CloseDevice) { // handle the error FreeLibrary(hDLL); return -2; } ReadAnalogChannel = (t_func4) GetProcAddress(hDLL, "ReadAnalogChannel"); if (!ReadAnalogChannel) { // handle the error FreeLibrary(hDLL); return -2; } ReadAllAnalog = (t_func2) GetProcAddress(hDLL, "ReadAllAnalog"); if (!ReadAllAnalog) { // handle the error FreeLibrary(hDLL); return -2; } OutputAnalogChannel = (t_func3) GetProcAddress(hDLL, "OutputAnalogChannel"); if (!OutputAnalogChannel) { // handle the error FreeLibrary(hDLL); return -2; } OutputAllAnalog = (t_func3) GetProcAddress(hDLL, "OutputAllAnalog"); if (!OutputAllAnalog) { // handle the error FreeLibrary(hDLL); return -2; } ClearAnalogChannel = (t_func) GetProcAddress(hDLL, "ClearAnalogChannel"); if (!ClearAnalogChannel) { // handle the error FreeLibrary(hDLL); return -2; } ClearAllAnalog = (t_func0) GetProcAddress(hDLL, "ClearAllAnalog"); if (!ClearAllAnalog) { // handle the error FreeLibrary(hDLL); return -2; } SetAnalogChannel = (t_func) GetProcAddress(hDLL, "SetAnalogChannel"); if (!SetAnalogChannel) { // handle the error FreeLibrary(hDLL); return -2; } SetAllAnalog = (t_func0) GetProcAddress(hDLL, "SetAllAnalog"); if (!SetAllAnalog) { // handle the error FreeLibrary(hDLL); return -2; } WriteAllDigital = (t_func) GetProcAddress(hDLL, "WriteAllDigital"); if (!WriteAllDigital) { // handle the error FreeLibrary(hDLL); return -2; } ClearDigitalChannel = (t_func) GetProcAddress(hDLL, "ClearDigitalChannel"); if (!ClearDigitalChannel) { // handle the error FreeLibrary(hDLL); return -2; } ClearAllDigital = (t_func0) GetProcAddress(hDLL, "ClearAllDigital"); if (!ClearAllDigital) { // handle the error FreeLibrary(hDLL); return -2; } SetDigitalChannel = (t_func) GetProcAddress(hDLL, "SetDigitalChannel"); if (!SetDigitalChannel) { // handle the error FreeLibrary(hDLL); return -2; } SetAllDigital = (t_func0) GetProcAddress(hDLL, "SetAllDigital"); if (!SetAllDigital) { // handle the error FreeLibrary(hDLL); return -2; } ReadDigitalChannel = (t_func5) GetProcAddress(hDLL, "ReadDigitalChannel"); if (!ReadDigitalChannel) { // handle the error FreeLibrary(hDLL); return -2; } ReadAllDigital = (t_func1) GetProcAddress(hDLL, "ReadAllDigital"); if (!ReadAllDigital) { // handle the error FreeLibrary(hDLL); return -2; } Version_ = (t_func0) GetProcAddress(hDLL, "Version"); if (!Version_) { // handle the error FreeLibrary(hDLL); return -2; } OpenDevice(0); return 0; // ok } return -1; // error load DLL return (0); } //Wurde Test angeklickt? case ID_ButtonTest: { WriteAllDigital(1); Sleep(100); WriteAllDigital(2); Sleep(100); WriteAllDigital(4); Sleep(100); WriteAllDigital(8); Sleep(100); WriteAllDigital(0); return (0); } //Wurde Test Aus angeklickt? case ID_ButtonTestAus: { int Testerling(); } //Wurde Beenden angeklickt? case ID_ButtonBeenden: { int Resultat; //Rueckgabewert der Messagebox //Messagebox fuer Sicherheitsabfrage Resultat = MessageBox (hWnd, TEXT("Wirklich Beenden?"), TEXT("Programm beenden"), MB_YESNO | MB_ICONQUESTION); //Wurde Ja angeklickt? if (Resultat == IDYES) { //Ja, also Programm beenden ClearAllDigital(); //Alle Digitalen Ausgänge deaktivieren CloseDevice(); //USB-Karte Beenden FreeLibrary(hDLL); //Library herunterfahren PostQuitMessage(0); return (0); } //Nein, also ganz normal weiter return (0); } } break; }break; } // Die Nachrichgt wurde nicht von uns verarbeitet, also // von Windows verarbeiten lassen return (DefWindowProc (hWnd, message, wParam, lParam)); } //Windowproc
______________________________________
Testerling.cpp
______________________________________#include"Testerling.hpp" #include <windows.h> int Testerling(HWND hWnd, HINSTANCE hInst) { int Resultat; //Rueckgabewert der Messagebox Resultat = MessageBox (hWnd, TEXT("Tester"), TEXT("Test"), MB_YESNO | MB_ICONQUESTION); //Wurde Ja angeklickt? if (Resultat == IDYES) { } //Nein, also ganz normal weiter return(0); }
______________________________________
Wenn ich Initialisierungsbefehle (Alles, was beim Button "ID_ButtonInitialisieren:" ausgeführt wird in Testerling.cpp verschiebe, dann werden die Typdefinitionen nicht erkannt.
Fehlermeldung (Beispiel, eine von Vielen):
t_func5: nichtdeklarierter Bezeichner
Wenn ich dann in die Datei Testerling.hpp die Typdefinitionen includiere kommt die Fehlermeldung, dass alles schon in der Main.obj definiert ist
Wenn ich jetzt in der Main.cpp die #include „USBInit.hpp“ entferne, dann werden in der Main.cpp die USB-Karten-Befehle nicht mehr erkannt.
Was muss ich tun, dass ich die Initialisierung der USB-Karte in ein Unterprogramm „auslagern“ kann, aber trotzdem noch von der Main.cpp die USB-Karten-Befehle verwenden kann?
Vielen Dank vorab für eure Hilfe!!
Gruß Robin Brenner
-
Ich habe keine Lust, Dein Programm zu analysieren.
Aber ... Du hast in USBInit.hpp jede Menge Variablen definiert. Wenn Du USBInit.hpp nun in zwei cpp-Dateien (Testerling.cpp und main.cpp inkludierst, dann sieht der Linker natürlich, dass die alle doppelt definiert sind, das geht so nicht ...
Die Frage ist, müssen die dort definierten Variablen in beiden cpp-Dateien existieren und wenn ja, sollen es dann dieselben oder diegleichen sein?
Brauchst Du also projektglobale Variablen, oder brauchst Du sie vllt. dann nur in Testerling.cpp?Wenn sie nicht projektglobal sein sollen, gehören sie nicht in ein Headerfile, sondern in ein (das richtige) cpp-File.
Ein Versuch ohne allzu großen Änderungsaufwand wäre, sie in einen anonymen Namespace einzubetten ...
-
Wie Belli schon geschrieben hat gehören Dinge wie
t_func4 OpenDevice;
so nicht in ein Headerfile.
Lösungsmöglichkeit: Kopier diese Teile nach Testerling.cpp und mach im Header
ein extern davor.Ich würde das ganze auch in eine Klasse packen, dann ist auch sichergestellt,
das die Library einfach wieder geschlossen werden kann und nichts vergessen wird.
-
Hallo,
Ok, vielen Dank für eure Antworten!
Gruß Robin Brenner