Problem mit Get-Methode
-
Bei sowas
o_Messwerte.SetMesswerte(F_Gaszaehler->GetEdu32fp()->ErfasseVolumen());Wunderst du dich über SegFaults?
Wenn F_Gaszaehler->GetEdu32fp() NULL zurück liefert, passiert das ja.
Du solltest da den Rückgabewert erst auf NULL prüfen (am besten speicherst du den) bevor du Funktionen darauf aufrufst.Wo hast du dich mit dem Debugger reingehängt, um das m_connect zu überprüfen?
Im übrigen ist m_connect ein bool und kein int, den darf man dann direkt mit "false" statt "0" initialisieren. Find ich persönlich einfacher, da ich gleich sehe "Ah, bool".
-
Du kannst das z.B. so machen:
o_Messwerte.SetMesswerte( F_Gaszaehler->GetEdu32fp() ? F_Gaszaehler->GetEdu32fp()->ErfasseVolumen() // Wenn der zurück gegebene Zeiger nicht 0 ist, setze den Wert von ErfasseVolumen() : 0 // Wenn der Zeiger 0 ist dann setz 0 );Oder so, was das gleiche ist nur mit if else anstatt dem ternären operator
if( F_Gaszaehler->GetEdu32fp() ) { o_Messwerte.SetMesswerte( F_Gaszaehler->GetEdu32fp()->ErfasseVolumen() ); // Wenn der zurück gegebene Zeiger nicht 0 ist, setze den Wert von ErfasseVolumen() } else { o_Messwerte.SetMesswerte( 0 ); // Wenn der Zeiger 0 ist dann setz 0 }
-
ja ok, das mit dem bool leuchtet ein. Hab ich gleich mal geändert. Hab mich bei if (m_connect) mit dem Debugger reingehängt. Dann zeigt er an, dass m_connect==true obwohl kein Gerät verbunden ist.
-
rudpower schrieb:
Dann zeigt er an, dass m_connect==true obwohl kein Gerät verbunden ist.
Schau eine Zeile höher:
m_connect = m_port.OpenComm(p_port.c_str());Da weist du dem m_connect einen neuen Wert zu. Wenn eine Zeile darunter m_connect nicht mehr false ist heißt das m_port.OpenComm() hat true zurück gegeben.
Wenn also keine Verbindung besteht heißt das wiederum dass OpenComm Mist baut.
Außer{ m_port.SetDCB(9600); m_port.SetReadTimeouts(100, 10, 10); }machen m_port irgendwie ungültig. Da aber hier über comclass nichts bekannt ist kann man auch nichts darüber sagen.
-
hier ist die comclass:
// Öffnet den Port und gibt ein Handle zurück bool comclass::OpenComm(char* port){ hCom = CreateFile(port,// z.B. "COM1", GENERIC_READ|GENERIC_WRITE,//zum Senden und Empfangen 0, // Für comm devices exclusive-access notwendig 0, // Keine security attributes OPEN_EXISTING, // Für comm devices notwendig 0, // Kein overlapped I/O 0); // Für comm devices muss hTemplate NULL sein if(hCom == INVALID_HANDLE_VALUE) return false; else return true; } // setzen der Einstellungen void comclass::SetDCB(int baud){ DCB dcb; // Device Control Block GetCommState(hCom, &dcb); // DCB lesen dcb.BaudRate = baud; // Baudrate z.B.:9600 dcb.ByteSize = 8; // 8 Datenbits dcb.Parity = NOPARITY; // keine Parity dcb.StopBits = ONESTOPBIT; // 1 Stopbit dcb.fDtrControl = 1; // SetCommState konfiguriert die serielle Schnittstelle SetCommState(hCom, &dcb); } // setzen der Timeout-Zeiten void comclass::SetReadTimeouts(int intervalTO, int readSingleTO, int writeSingleTO){ COMMTIMEOUTS t; // Alle Wert in Millisekunden // Werte für ReadFile: t.ReadIntervalTimeout=intervalTO; // Zeit zwischen zwei Zeichen t.ReadTotalTimeoutMultiplier=readSingleTO; // pro Zeichen t.ReadTotalTimeoutConstant=readSingleTO; // Werte für WriteFile: wenn beide 0 sind, kein Timeout // beim Schreiben t.WriteTotalTimeoutMultiplier=writeSingleTO; t.WriteTotalTimeoutConstant=writeSingleTO; SetCommTimeouts(hCom,&t); } // Daten senden int comclass::SendData(char Data[],int n){ DWORD NumberOfBytesWritten; //Anzahl der gesendeten Bytes WriteFile(hCom, // handle des Com-Ports Data, // Adresse der Daten n, // Anzahl der zu sendenden Bytes &NumberOfBytesWritten, // Adresse übergeben 0); // kein overlapped I/O return NumberOfBytesWritten; } // Daten empfangen DWORD comclass::ReceiveData(char* Data,int n){ DWORD NumberOfBytesRead; // Anzahl der gelesenen Bytes ReadFile(hCom, // handle des Com-Ports Data, // Adresse des Datenpuffers n, // Anzahl der zu lesenden Bytes &NumberOfBytesRead, // Adresse übergeben 0); // kein overlapped I/O return NumberOfBytesRead; } // schließen der seriellen Schnittstelle void comclass::CloseComm(void){ try { if(hCom) CloseHandle(hCom); } catch(...) { ; } }
-
double c_Edu32fp::ErfasseVolumen() { if (m_connect) //hier hatte ich den Haltepunkt gesetzt .... }Hier dürfte er ja gar nicht reinlaufen, da ich doch m_connect mit false im Konstruktor initialisiert habe.
-
Da er dort in die Schleife läuft gibt es denk ich mal meinen EConvertError "" ist kein gültiger Gleitkommawert.
zeigt er in dieser Zeile an:
"F_HO->HO_E_AnzeigeGaszaehlerVolumen->Text = FloatToStr(F_Gaszaehler->GetEdu32fp()->ErfasseVolumen());"
-
ich glaube, das Problem ist, dass er den Konstruktor gar nicht aufruft, da dieser ja erst mit dem Klick auf den Button Gaszaehler_B_PortOeffnen aufruft. Normalerweise würde ich ja das Objekt im Konstruktor der Form F_Gaszaehler erzeugen. Da aber der Konstruktor der Klasse c_Edu32fp einen Parameter erwartet (den Namen der Schnittstelle) kann ich das nicht machen. Wie kann ich das Problem beheben?
-
habe das Problem insoweit gelöst, dass ich nun in der Geräteklasse eine neue Methode erstellt hab, die den COM-Port öffnet und als Parameter diesen entgegennimmt. Den Konstruktor konnte ich so mit dem Konstruktor der Form aufrufen. So existiert das Objekt immer während der Laufzeit. Jetzt kann ich das Programm auch laufen lassen wenn das Gerät ausgeschaltet ist bzw man nicht den Button Port öffnen klickt, der ja die neue Methode öffnet. Verbindet man aber das Gerät (also ruft die Get Methode auf:
void c_Messgeraet::PortOeffnen(AnsiString p_port) { m_connect = m_port.OpenComm(p_port.c_str()); if(m_connect) { m_port.SetDCB(9600); m_port.SetReadTimeouts(100, 10, 10); } else ShowMessage("Messgerät nicht verbunden!"); }und schaltet dann das Gerät ab hab ich wieder eine Exception. Dann funktioniert die Umwandlung String in double nicht mehr. Er versucht dann "" in double zu wandeln (also einen Leerstring). Das ist nicht gut. Das gleiche passiert beim einschalten, da das Gerät dann als String die Typbezeichnung sendet und die natürlich nicht in double gewandelt werden kann.
-
nun funktioniert das soweit ganz gut. Hier meine Methode zur Erfassung:
double c_Messgeraet::ErfasseVolumen() { if (m_connect) { char rec[50] = {0}; unsigned char send[] = {0x16}; while(m_port.ReceiveData(rec,1)>0); // Buffer leeren m_port.SendData(send,1); m_port.ReceiveData(rec,50); try {return StrToFloat(AnsiString(rec).SubString(4,9).Trim());} catch(...) { m_connect = false; return 0; } } else return 0; }wenn das Gerät nicht verbunden ist, steht in dem Feld rec alles /0. Durch die Umwandlung in AnsiString und Trim bleibt dann nur ein Leerstring "".Da dies nicht in ein Float umgewandelt werden kann fange ich dies mit try/catch ab. Das funktioniert.
Beim Aufruf der Methode in meinem Thread wird dann im Editfeld entweder der Messwert ausgegeben oder der AnsiString "getrennt":if (F_Messgeraet->GetMessgeraet()->GetConnect()) F_HO->E_AnzeigeVolumen->Text = FloatToStr(F_Messgeraet->GetMessgeraet()->ErfasseVolumen()); else F_HO->E_AnzeigeVolumen->Text = "getrennt";Problem gibt es in der PortOeffnen-Methode:
void c_Messgeraet::PortOeffnen(AnsiString p_port) { m_connect = m_port.OpenComm(p_port.c_str()); if(m_connect) { m_port.SetDCB(9600); m_port.SetReadTimeouts(100,10,10); } else { m_port.CloseComm(); ShowMessage("Messgerät nicht verbunden!"); } }Gebe ich jetzt nachdem verbunden wurde und die Messwerte auch angezeigt werden hier
void __fastcall TF_Messgeraet::B_OpenPortClick(TObject *Sender) { o_Messgeraet->SetConnect(false); o_Messgeraet->PortOeffnen(E_SerialPort->Text); //Argument aus Editfeld Close(); }einen anderen Port an zeigt er wie gewünscht "getrennt" an. Gebe ich nun wieder den richtigen Port an läuft er immer wieder in die else Verzweigung der PortOeffnen(AnsiString p_port)-Methode. Er setzt m_connect alo nicht auf true und verbindet nicht neu.
Ich hab dann versucht einfach m_port.CloseComm(); vorher aufzurufen. Das gibt dann gleich eine "externe Exception C0000008".