Zugriffsverletzung bei Schreiben auf serielle Schnittstelle COM2
Hallo Admins,
ich habe ein programmiertechnisches Problem:
Ich möchte mit einem Delphi-Programm ein Prüfgerät steuern, welches über eine serielle Schnittstelle (COM2) an einen Desktop-PC mit Windows XP angebunden ist. Zum Programmieren verwende ich Borland Delphi 5. Ich habe ein Programm geschrieben, welches beim Druck auf den Button "Button_Pruefung" die COM-Schnittstelle COM2 auf Verfügbarkeit testet, öffnet, ihr die Baudrate 9600 zuweist, eine Initialisierungssequenz sIdenti sendet, den (vom Prüfgerät automatisch gesendeten) Antwortstring an COM2 ausliest und auswertet und anschließend eine Startsequenz sStart für die Prüfung sendet. Innerhalb von ca. 30 Sekunden bekommt die Schnittstelle eine Rückantwort vom Messgerät mit den Messdaten, die dann ausgegeben werden sollen. (Dies ist der vereinfachte Ablauf.) Ich bekomme jedoch in meinem Programm beim Senden des Strings sStart stets eine Fehlermeldung mit der Ausschrift "Zugriffsverletzung bei Adresse 00000000. Lesen von Adresse 00000000.", mit der das Programm abbricht. Seltsamerweise erscheint die Meldung nicht, wenn ich direkt vor dem Senden des Strings einen MessageDlg aufploppen lasse, den der Nutzer bestätigen muss. Dies ist jedoch im normalen Ablauf i.d.R. nicht möglich, weshalb es ohne den MessageDlg gehen muss. Im Code unten ist die entsprechende Stelle mittels "@@@debug" gekennzeichnet.
Bisher habe ich mich noch nicht intensiv mit der Steerung von COM-Schnittstellen beschäftigt und stehe deshalb etwas auf dem Schlauch. Könnt Ihr mir sagen, was ich beim 2. Senden falsch gemacht habe? Ist die Schnittstelle durch den ersten Sendevorgang oder durch den Lesevorgang noch in einem Zustand, der kein weiteres Senden erlaubt? Wie kann man diesen Zustand sinnvoll wieder verlassen?
Viele Grüße,
Sinzal
ich habe ein programmiertechnisches Problem:
Ich möchte mit einem Delphi-Programm ein Prüfgerät steuern, welches über eine serielle Schnittstelle (COM2) an einen Desktop-PC mit Windows XP angebunden ist. Zum Programmieren verwende ich Borland Delphi 5. Ich habe ein Programm geschrieben, welches beim Druck auf den Button "Button_Pruefung" die COM-Schnittstelle COM2 auf Verfügbarkeit testet, öffnet, ihr die Baudrate 9600 zuweist, eine Initialisierungssequenz sIdenti sendet, den (vom Prüfgerät automatisch gesendeten) Antwortstring an COM2 ausliest und auswertet und anschließend eine Startsequenz sStart für die Prüfung sendet. Innerhalb von ca. 30 Sekunden bekommt die Schnittstelle eine Rückantwort vom Messgerät mit den Messdaten, die dann ausgegeben werden sollen. (Dies ist der vereinfachte Ablauf.) Ich bekomme jedoch in meinem Programm beim Senden des Strings sStart stets eine Fehlermeldung mit der Ausschrift "Zugriffsverletzung bei Adresse 00000000. Lesen von Adresse 00000000.", mit der das Programm abbricht. Seltsamerweise erscheint die Meldung nicht, wenn ich direkt vor dem Senden des Strings einen MessageDlg aufploppen lasse, den der Nutzer bestätigen muss. Dies ist jedoch im normalen Ablauf i.d.R. nicht möglich, weshalb es ohne den MessageDlg gehen muss. Im Code unten ist die entsprechende Stelle mittels "@@@debug" gekennzeichnet.
Bisher habe ich mich noch nicht intensiv mit der Steerung von COM-Schnittstellen beschäftigt und stehe deshalb etwas auf dem Schlauch. Könnt Ihr mir sagen, was ich beim 2. Senden falsch gemacht habe? Ist die Schnittstelle durch den ersten Sendevorgang oder durch den Lesevorgang noch in einem Zustand, der kein weiteres Senden erlaubt? Wie kann man diesen Zustand sinnvoll wieder verlassen?
Viele Grüße,
Sinzal
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 384232
Url: https://administrator.de/forum/zugriffsverletzung-bei-schreiben-auf-serielle-schnittstelle-com2-384232.html
Ausgedruckt am: 22.12.2024 um 20:12 Uhr
10 Kommentare
Neuester Kommentar
Moin,
ist jetzt nur geraten, aber dein "Kommunikationstest" und dein Daten senden scheint wohl zeitlich zu nahe aneinander zu liegen. Keine Ahnung ob das Gerät noch ne Sekunde braucht. Du kannst testhalber mal statt des Dialogs mit einem "sleep" (hoffe das hieß so) "warten".
BTW: Du solltest dir dringend mal Prozeduren und Funktionen ansehen. Ist ja grausam der Code
Gruß
ist jetzt nur geraten, aber dein "Kommunikationstest" und dein Daten senden scheint wohl zeitlich zu nahe aneinander zu liegen. Keine Ahnung ob das Gerät noch ne Sekunde braucht. Du kannst testhalber mal statt des Dialogs mit einem "sleep" (hoffe das hieß so) "warten".
BTW: Du solltest dir dringend mal Prozeduren und Funktionen ansehen. Ist ja grausam der Code
Gruß
Zitat von @Kraemer:
Moin,
BTW: Du solltest dir dringend mal Prozeduren und Funktionen ansehen. Ist ja grausam der Code
Wieso er hat doch Prozeduren und Funktionen drin. Moin,
BTW: Du solltest dir dringend mal Prozeduren und Funktionen ansehen. Ist ja grausam der Code
Gruß
Gruss Penny
Moin,
ich denke auch mal, das wird es sein.
Hatten mal einen ähnlichen Fall. Ein Messgerät wurde einst auf einem 386er ausgeliefert und die Messpulenspulen (bzw. das Steuergerät) hingen per RS232 am PC
Nun ist der PC irgendwann mal "abgeraucht" und wir haben den via VMware Player virtualisiert. Der neue Host, ein Core2Duo, war zu schnell für das Messgerät. Startete die VM, hat die Applikation die durchgereichte COM-Schnittstelle abgefragt, aber nicht schnell genug eine Antwort bekommen.
Ein Spiel zwischen "Pause-Taste" und Return verlangsamte dann die VM, sodass die Applikation Zeit hatte, die Spulen zu initialisieren. Hat man dann die VM in den Suspend geschickt und anschließend aufgeweckt, lief das System wie eine 1. Das ganze dann zwei Jahre lang. Danach haben wir das Uraltsystem mal ausgetauscht
Gruß
em-pie
Zitat von @Kraemer:
ist jetzt nur geraten, aber dein "Kommunikationstest" und dein Daten senden scheint wohl zeitlich zu nahe aneinander zu liegen. Keine Ahnung ob das Gerät noch ne Sekunde braucht. Du kannst testhalber mal statt des Dialogs mit einem "sleep" (hoffe das hieß so) "warten".
ist jetzt nur geraten, aber dein "Kommunikationstest" und dein Daten senden scheint wohl zeitlich zu nahe aneinander zu liegen. Keine Ahnung ob das Gerät noch ne Sekunde braucht. Du kannst testhalber mal statt des Dialogs mit einem "sleep" (hoffe das hieß so) "warten".
ich denke auch mal, das wird es sein.
Hatten mal einen ähnlichen Fall. Ein Messgerät wurde einst auf einem 386er ausgeliefert und die Messpulenspulen (bzw. das Steuergerät) hingen per RS232 am PC
Nun ist der PC irgendwann mal "abgeraucht" und wir haben den via VMware Player virtualisiert. Der neue Host, ein Core2Duo, war zu schnell für das Messgerät. Startete die VM, hat die Applikation die durchgereichte COM-Schnittstelle abgefragt, aber nicht schnell genug eine Antwort bekommen.
Ein Spiel zwischen "Pause-Taste" und Return verlangsamte dann die VM, sodass die Applikation Zeit hatte, die Spulen zu initialisieren. Hat man dann die VM in den Suspend geschickt und anschließend aufgeweckt, lief das System wie eine 1. Das ganze dann zwei Jahre lang. Danach haben wir das Uraltsystem mal ausgetauscht
Gruß
em-pie
Hallo Sinzal,
Du hast anscheinend das ganze Konzept von Overlapped I/O unter Windows nicht verstanden. Es genügt nicht, einfach eine OVERLAPPED-Struktur zu erzeugen und den Lese-/Schreib-Routinen des Betriebssystems immer schön brav einen Pointer darauf mit zugeben, man muss den Mechanismus auch richtig nutzen. Lies z.B. mal das hier und das hier. Im letztgenannten Artikel heißt es dann auch:
Genau das passiert in Deinem Fall.
Mit Overlapped I/O kann Dein Programm z.B. weiterhin die Benutzerschnittstelle (Menüzeile, Fensteraktionen wie verschieben oder Größe ändern) reaktionsfähig halten, während das OS eine I/O-Operation ausführt. Das OS benachrichtigt Dein Programm, wenn der I/O fertig ist.
Das kann man auch über Polling erfahren, dann verbrät Dein Programm aber seine Rechenzeit damit, in einer Warteschleife rundzulaufen und belästigt das System mit dauernden Abfragen "Bist Du schon fertig?". Sleep ist auch keine wirkliche Alternative, da die angegebene "Schlafzeit" auf dem einen Rechner ausreichend sein kann, auf einem anderen Rechner jedoch zu kurz ist, das kommt dann auch noch darauf an, womit das System sonst noch so beschäftigt ist. Die Win32 API
Ich würde Dir für den Anfang raten, auf Overlapped I/O zu verzichten und erstmal Deine Routinen von der Ablauflogik her ans Laufen zu bekommen.
Grüße
Friemler
Du hast anscheinend das ganze Konzept von Overlapped I/O unter Windows nicht verstanden. Es genügt nicht, einfach eine OVERLAPPED-Struktur zu erzeugen und den Lese-/Schreib-Routinen des Betriebssystems immer schön brav einen Pointer darauf mit zugeben, man muss den Mechanismus auch richtig nutzen. Lies z.B. mal das hier und das hier. Im letztgenannten Artikel heißt es dann auch:
A data buffer must not be read or written until its corresponding I/O operation has completed; reading or writing the buffer may cause errors and corrupted data.
Genau das passiert in Deinem Fall.
Mit Overlapped I/O kann Dein Programm z.B. weiterhin die Benutzerschnittstelle (Menüzeile, Fensteraktionen wie verschieben oder Größe ändern) reaktionsfähig halten, während das OS eine I/O-Operation ausführt. Das OS benachrichtigt Dein Programm, wenn der I/O fertig ist.
Das kann man auch über Polling erfahren, dann verbrät Dein Programm aber seine Rechenzeit damit, in einer Warteschleife rundzulaufen und belästigt das System mit dauernden Abfragen "Bist Du schon fertig?". Sleep ist auch keine wirkliche Alternative, da die angegebene "Schlafzeit" auf dem einen Rechner ausreichend sein kann, auf einem anderen Rechner jedoch zu kurz ist, das kommt dann auch noch darauf an, womit das System sonst noch so beschäftigt ist. Die Win32 API
GetOverlappedResult
mit dem Parameter bWait
auf TRUE
zu benutzen ist auch nicht sinnvoll, dann kannst Du gleich Non-Overlapped I/O verwenden.Ich würde Dir für den Anfang raten, auf Overlapped I/O zu verzichten und erstmal Deine Routinen von der Ablauflogik her ans Laufen zu bekommen.
Grüße
Friemler