RS232 Ablaufsteuerung
-
ich habe ein Gerät mit dem ich über RS232 kommuniziere. Die Ansteuerung soll nicht timergesteuert sondern ablaufgesteuert sein. Die Kommunikation über die serielle Schnittstelle funktioniert bereits. Für jede Aktion gibt es einen Befehl den ich an das Gerät per WriteFile sende. Bevor die jeweils nächste Aktion gestartet wird soll gewartet werden, bis die vorherige Aktion abgeschlossen ist. Dafür gibt es für das Gerät Kommandos, mit dessen Hilfe ich den Status der jeweiligen Aktion abrufen kann. Das mach ich mit ReadFile.
Wie setz ich das am besten programmtechnisch um?
Bisher hab ich es so gemacht:
int TForm1::SendData(AnsiString data) { DWORD numberOfBytesWritten; data = data + "\r\n"; if(!WriteFile(hCom, data.c_str(), data.Length(), &numberOfBytesWritten, 0)) return -1; else return numberOfBytesWritten; } //--------------------------------------------------------------------------- int TForm1::ReceiveData() { const int bufferSize = 100; char buffer[bufferSize] = {0}; DWORD bytesRead = 0; do { if(!ReadFile(hCom, buffer, bufferSize, &bytesRead, 0 )) ShowLastError("ReadFile"); //Fehlerausgabe if(bytesRead != 0) readBuffer.insert(readBuffer.end(), buffer, buffer + bytesRead); } while(bytesRead != 0); return readBuffer.size(); } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) //Button startet den Ablauf { char buffer[100] = {0}; SendData("Go"); //Aktion 1 (Antwortet mit "\r\n") do { memset (buffer, 0, 100); SendData("GetStatus"); //Status abfragen (Antwortet mit "01", "02" oder "03" ReceiveData(buffer, 100); } while (AnsiString (buffer) != "\r\n03"); SendData("Aktion2"); //Aktion 1 (Antwortet mit "\r\n") // u.s.w. }
So funktioniert es natürlich nicht, da der Puffer scheinbar immer weiter gefüllt wird. Ich könnte mir vorstellen, dass man das irgendwie triggern könnte bzw. Events definiert (so ähnlich wie beim Timer).
Hat jemand eine Idee bzw. einen Lösungsansatz.
-
Ich hab das bei mir mit einem Thread gemacht. Die Daten zu senden in einen Vector legen und den vom Sendeteil abarbeiten lassen. Sowie die Empfangen Daten auch in einem Vector legen und bei Zeiten abarbeiten lassen. Damit es keine Crashs gibt sperre ich die Vectoren mit Enter/Leave CriticalSection.
Somit läuft die RS232 verbinden komplett autark ohne das der Thread mit der Form synchronisiert werden muss.
void __fastcall TRS232Com::ThreadExecute() { DWORD dwBytesRead; char input[256]; while(SendArray.size()) { LockSendThread.EnterSection(); { TransmitCommChar(hComm, SendArray[0]); SendArray.erase(&SendArray[0]); } LockSendThread.LeaveSection(); } ReadFile(hComm, input, 255, &dwBytesRead, NULL); if(dwBytesRead) { LockReadThread.EnterSection() ; { for(unsigned int i=0;i<dwBytesRead;i++) { InBuff.resize(InBuff.size()+1); InBuff[InBuff.size()-1]=input[i]; } } LockReadThread.LeaveSection(); ConCounter=0; } } void TRS232Com::SendBytes(char *Send, int Anzahl) { if(Anzahl<=0) return; try { LockSendThread.EnterSection(); { for(int i=0;i<Anzahl;i++) { SendArray.resize(SendArray.size()+1); SendArray[SendArray.size()-1]=Send[i]; } } LockSendThread.LeaveSection(); }catch(...) { DebugText("SendError"); } }
geht mit Sicherheit noch schöner, aber das funktioniert so bei mir. Zum Abarbeiten von InBuff nehme ich noch einen Thread der mit der Form Synchronisiert ist.
ThreadExecute läuft übrigens in einer while Schleife im Thread.