Neuigkeiten:

Wenn ihr euch für eine gute Antwort bedanken möchtet, im entsprechenden Posting einfach den Knopf "sag Danke" drücken!

Mobiles Hauptmenü

USB Kommunikation

Begonnen von illusionfactory, Januar 17, 2021, 17:51:39

⏪ vorheriges - nächstes ⏩

illusionfactory

Hallo, zusammen,

ich benutze in mehreren Projekten USB-Geräte - mal über den COM Port, mal über ein ActiveX-Element. In allen Fällen passiert das Gleiche:

Die Kommunikation funktioniert nur sauber, wenn ich im Debug-Modus Schritt für Schritt ausführe. Läuft die Applikation normal, klappt die Kommunikation gar nicht oder unzuverlässig.

Es scheint so, als bekommt das System einfach nicht genug Rechenpower ab, um die Kommunikation durchzuführen. Auch der umfangreiche Einsatz von DoEvents hilft leider nicht.

Hat jemand eine Idee? Danke :-)

markusxy

Zitat von: illusionfactory am Januar 17, 2021, 17:51:39nur sauber, wenn ich im Debug-Modus Schritt für Schritt ausführe.

Vielleicht zeigst du ja mal den Code.

Was passiert, wenn der Fehler auftritt?

Falls du noch nicht weißt an welcher Stelle, welches Problem auftritt, dann wäre der erste Schritt ein
Protokoll, das hilft den Fehler zu finden.


PhilS

Zitat von: illusionfactory am Januar 17, 2021, 17:51:39Die Kommunikation funktioniert nur sauber, wenn ich im Debug-Modus Schritt für Schritt ausführe. Läuft die Applikation normal, klappt die Kommunikation gar nicht oder unzuverlässig.
Vermutung: Du prüfst keine Statuscodes für die gesendeten Daten und schickst gleich die nächsten hinterher, bevor die Vorigen vom Geräte verarbeitet wurden.

Für mehr als diese wage Vermutung reichen die Informationen hier nicht aus.
Neue Videoserie: Windows API in VBA

Klassische CommandBars visuell bearbeiten: Access DevTools CommandBar Editor

illusionfactory

Vielen Dank schon einmal für die Antworten! Ich habe jetzt mal den minimalen Code extrahiert, mit dem ich das Problem reproduzieren kann.

Zur Kommunikation mit der seriellen Schnittstelle nutze ich http://www.thescarms.com/VBasic/commio.aspx (ist wohl der Standard - alle Beiträge zu serieller Kommmunikation in VBA, die ich im Netz gefunden habe, beziehen sich auf dieses Modul).

Wenn sich der Sensor einschaltet, kann ich das anhand einer LED sehen. Ich muss also keine Rückgabewerte lesen.

Option Compare Database
Option Explicit
Sub SensorTest()
    Dim lngStatus As Long
    Dim strError  As String
   

    lngStatus = CommOpen(3, "COM3", "baud=19200 parity=N data=8 stop=1")
    If lngStatus <> 0 Then
        lngStatus = CommGetError(strError)
        Debug.Print "COM Error: " & strError
        Exit Sub
    End If
    DoEvents
    lngStatus = CommSetLine(3, LINE_RTS, False)
    If lngStatus <> 0 Then
        lngStatus = CommGetError(strError)
        Debug.Print "COM Error: " & strError
        Exit Sub
    End If
    lngStatus = CommSetLine(3, LINE_DTR, False)
    DoEvents
    If lngStatus <> 0 Then
        lngStatus = CommGetError(strError)
        Debug.Print "COM Error: " & strError
        Exit Sub
    End If
    DoEvents
    lngStatus = CommWrite(3, einschaltKommando)
    If lngStatus <> 9 Then
        lngStatus = CommGetError(strError)
        Debug.Print "COM Error: " & strError
        Exit Sub
    End If
    DoEvents
    CommClose (3)
End Sub

markusxy

Zitat von: illusionfactory am Januar 20, 2021, 07:24:13mit dem ich das Problem reproduzieren kann.

Wenn du die Problemstelle kennst, warum teilst du sie dann nicht mit?
Außerdem ist deine Debug.Print Ausgabe sehr seltsam - man sieht ja anhand des Ergebnisses nicht eindeutig welche Stelle die Ausgabe gemacht hat.

Weiters verwendest du ein Exit ohne den Port zu schließen?
Wie wird das File Handle dann wieder freigegeben?


illusionfactory

Zitat von: markus888 am Januar 20, 2021, 08:14:01
Zitat von: illusionfactory am Januar 20, 2021, 07:24:13mit dem ich das Problem reproduzieren kann.

Wenn du die Problemstelle kennst, warum teilst du sie dann nicht mit?
Sorry, die Frage habe ich nicht verstanden. Es gibt ja in dem Sinne keine Problemstelle. Das Problem ist, dass der Sensor sich nicht aktiviert, wenn ich das Programm einfach so durchlaufen lasse. Er aktiviert sich allerdings sehr wohl, wenn ich im Debug-Modus Schritt für Schritt ausführe.

Es scheint also so, als würde bei der Ausführung des Programms einfach nicht genug CPU-Zeit für die serielle Kommunikaton übrig bleiben.
Auch wenn ich überall massiv DoEvents einbaue, ändert sich nichts.

Es gibt also keine Fehlermeldung in dem Sinn - auch nicht, wenn das Programm so durchläuft. Es tut sich nur einfac nix :-)


Zitat von: markus888 am Januar 20, 2021, 08:14:01Außerdem ist deine Debug.Print Ausgabe sehr seltsam - man sieht ja anhand des Ergebnisses nicht eindeutig welche Stelle die Ausgabe gemacht hat.
Bin ich bei Dir - ich wollte den Code so eindampfen, dass Ihr nur das Minimum zu Lesen habt. Es treten ja auch gar keine Fehler auf - die Rückgabewerte sind immer korrekt.

Zitat von: markus888 am Januar 20, 2021, 08:14:01Weiters verwendest du ein Exit ohne den Port zu schließen?
Wie wird das File Handle dann wieder freigegeben?

Im Originalprogramm wird im Unload des Formulars der Port wieder freigegeben. Habe ich hier einfach nur nicht drin.

PhilS

Zitat von: illusionfactory am Januar 20, 2021, 17:07:41Es scheint also so, als würde bei der Ausführung des Programms einfach nicht genug CPU-Zeit für die serielle Kommunikaton übrig bleiben.
Auch wenn ich überall massiv DoEvents einbaue, ändert sich nichts.

Es gibt also keine Fehlermeldung in dem Sinn - auch nicht, wenn das Programm so durchläuft. Es tut sich nur einfac nix :-)
DoEvents gibt dem Access-Prozess die Möglichkeit Events aus der MessageQueue zu verarbeiten, aber das externe Gerät an deinem COM-Port hat davon wenig bis gar nichts.

Ich würde mal brachial zwischen den einzelnen Befehlen an den COM-Port ein Sleep einbauen. Erstmal durchaus mit Wartezeiten > 1s. Die kannst du dann per trial&error auf einen sinnvollen Wert reduzieren.

Besser wäre natürlich den Status des externen Geräts abzufragen, um festzustellen ob es denn überhaupt "aufnahmefähig" für den nächsten Befehl ist. - Hatte ich ja schon mal geschrieben.
Neue Videoserie: Windows API in VBA

Klassische CommandBars visuell bearbeiten: Access DevTools CommandBar Editor

markusxy

Was mir schon vorher aufgefallen ist:

    lngStatus = CommSetLine(3, LINE_RTS, False)
    If lngStatus <> 0 Then
        lngStatus = CommGetError(strError)
        Debug.Print "COM Error: " & strError
        Exit Sub
    End If
    lngStatus = CommSetLine(3, LINE_DTR, False)

Bei dem Aufruf von CommSetLine ist der Parameter blnState immer False.
Wozu ist das gut?

illusionfactory

Zitat von: PhilS am Januar 20, 2021, 17:55:07Besser wäre natürlich den Status des externen Geräts abzufragen, um festzustellen ob es denn überhaupt "aufnahmefähig" für den nächsten Befehl ist. - Hatte ich ja schon mal geschrieben.

Nachdem ich viel getestet habe, war das tatsächlich der Grund. Das USB Gerät braucht am Anfang einige Zeit, bis es startklar ist - was nicht in der Dokumentation steht. Alles was vorher gesendet wird, wird ignoriert.

Man muss also so lange Nachrichten schicken, bis das erste Mal eine Antwort kommt und insgesamt sehr viel "robuster" programmieren. Nur, weil man irgendwas macht, was in der Doku steht, heißt es nicht, dass in dem Moment das angeschlossene Gerät auch so reagiert, wie man es erwartet.

Danke für den Tipp und Deine Zeit!

illusionfactory

Zitat von: markus888 am Januar 20, 2021, 18:05:19Was mir schon vorher aufgefallen ist:

    lngStatus = CommSetLine(3, LINE_RTS, False)
    If lngStatus <> 0 Then
        lngStatus = CommGetError(strError)
        Debug.Print "COM Error: " & strError
        Exit Sub
    End If
    lngStatus = CommSetLine(3, LINE_DTR, False)

Bei dem Aufruf von CommSetLine ist der Parameter blnState immer False.
Wozu ist das gut?

Es gibt zwei "Kontroll-Leitungen", RTS und DTR. Bei manchen Geräten muss man diese benutzen (TRUE), bei diesem hier funktioniert es nur, wenn man sie ausschaltet (FALSE)