Discussion:
Zellen anspringen mit Signal von RS232
(zu alt für eine Antwort)
Christof Kluß
2010-12-03 07:34:51 UTC
Permalink
Hallo,

ich möchte ein VB-Skript schreiben, dass, auf ein externem Ereignis hin,
einen Wert in eine Zelle schreibt und dann in eine bestimmte andere
Zelle springt.

Es sollte dann so etwas in der Art möglich sein:

- falls der Cursor beim Ereignis in Spalte D, dann gehe in die nächste
Zeile in Spalte A und schreibe den Wert und gehe in Spalte B
- falls der Cursor beim Ereignis in Spalte B, dann schreibe Wert und
gehe in Spalte C
- falls der Cursor beim Ereignis in Spalte B, dann schreibe Wert und
gehe in Spalte D

Mein Ziel ist es, dass ich einen Knopf an einer Waage drücken kann und
der aktuelle Messwerte automatisch in meine Tabelle geschrieben wird.

Da ich leider sehr wenig Erfahrungen mit Excel/VB habe, bin ich für
jegliche Tipps und im Idealfall Vorlagen, die etwas ähnliches machen,
sehr dankbar.

Gruß
Christof
Andreas Killer
2010-12-03 08:11:32 UTC
Permalink
- falls der Cursor beim Ereignis in Spalte D, dann gehe in die n chste
  Zeile in Spalte A und schreibe den Wert und gehe in Spalte B
- falls der Cursor beim Ereignis in Spalte B, dann schreibe Wert und
  gehe in Spalte C
- falls der Cursor beim Ereignis in Spalte B, dann schreibe Wert und
  gehe in Spalte D
Ist nicht das Problem, aber...
Mein Ziel ist es, dass ich einen Knopf an einer Waage dr cken kann und
der aktuelle Messwerte automatisch in meine Tabelle geschrieben wird.
...wer löst denn das Ereignis aus und woher kommt der Wert?

Wenn man die Waage an einen Rechner anschließen kann, dann gibt es
bestimmt auch Software dazu.

Hat diese eine API und/oder gibt es dazu eine Doku wie die Waage
anzusprechen ist? Das solltest Du beim Hersteller der Waage in
Erfahrung bringen.

Andreas.
Christof Kluß
2010-12-03 18:56:14 UTC
Permalink
Hallo Andreas,
Post by Andreas Killer
- falls der Cursor beim Ereignis in Spalte D, dann gehe in die n chste
Zeile in Spalte A und schreibe den Wert und gehe in Spalte B
- falls der Cursor beim Ereignis in Spalte B, dann schreibe Wert und
gehe in Spalte C
- falls der Cursor beim Ereignis in Spalte B, dann schreibe Wert und
gehe in Spalte D
Ist nicht das Problem, aber...
Das hört sich gut an, kennst du ein Anleitung, wo etwas in der Art
beschrieben wird?
Post by Andreas Killer
Mein Ziel ist es, dass ich einen Knopf an einer Waage dr cken kann und
der aktuelle Messwerte automatisch in meine Tabelle geschrieben wird.
...wer löst denn das Ereignis aus und woher kommt der Wert?
Die Person an der Waage löst das Ereignis aus, dass Excel registrieren
müsste (die Waage müsste über RS232 ein entsprechendes Signal senden).
Ausprobiert habe ich es noch nicht, aber die Anleitung unter
http://dev.emcelettronica.com/serial-port-communication-excel-vba sieht
nützlich aus.

Gruß
Christof
Andreas Killer
2010-12-04 10:08:03 UTC
Permalink
Post by Christof Kluß
Hallo Andreas,
Post by Andreas Killer
- falls der Cursor beim Ereignis in Spalte D, dann gehe in die n chste
Zeile in Spalte A und schreibe den Wert und gehe in Spalte B
- falls der Cursor beim Ereignis in Spalte B, dann schreibe Wert und
gehe in Spalte C
- falls der Cursor beim Ereignis in Spalte B, dann schreibe Wert und
gehe in Spalte D
Ist nicht das Problem, aber...
Das hört sich gut an, kennst du ein Anleitung, wo etwas in der Art beschrieben wird?
Ich denke das kann Dir hier jeder schreiben, ist ziemlich einfach, Du musst nur die Methoden des Range-Objekts benutzen.

--- schnipp ---
Sub Main()
Dim Wert
Wert = "qwe"
Test1 Wert
Test2 Wert
Test3 Wert
End Sub

Sub Test1(Wert)
'- falls der Cursor beim Ereignis in Spalte D, dann gehe in die nächste
' Zeile in Spalte A und schreibe den Wert und gehe in Spalte B
Dim R As Range
Set R = ActiveCell
If R.Column = 4 Then
Set R = Cells(R.Row + 1, 1)
R = Wert
R.offset(0, 1).Select
End If
End Sub

Sub Test2(Wert)
'- falls der Cursor beim Ereignis in Spalte B, dann schreibe Wert und
' gehe in Spalte C
Dim R As Range
Set R = ActiveCell
If R.Column = 2 Then
R = Wert
R.offset(0, 1).Select
End If
End Sub

Sub Test3(Wert)
'- falls der Cursor beim Ereignis in Spalte B, dann schreibe Wert und
' gehe in Spalte D
Dim R As Range
Set R = ActiveCell
If R.Column = 2 Then
R = Wert
R.offset(0, 2).Select
End If
End Sub
--- schnapp ---

Wobei Test3 nie laufen wird, weil die Bedingung in Test2 die gleiche ist...
Post by Christof Kluß
Post by Andreas Killer
...wer löst denn das Ereignis aus und woher kommt der Wert?
Die Person an der Waage löst das Ereignis aus, dass Excel registrieren müsste (die Waage müsste über RS232 ein
entsprechendes Signal senden). Ausprobiert habe ich es noch nicht, aber die Anleitung unter
http://dev.emcelettronica.com/serial-port-communication-excel-vba sieht nützlich aus.
Für die Kommunikation ja, aber das Zauberwort "Event", bzw. "WaitCommEvent" fehlt, d.h. es gibt kein Ereignis das
ausgelöst wird wenn man an der Waage auf den Knopf drückt.

Aber kopier Dir einfach mal den Code von der Webseite, und dann fügst Du diese Zeilen

ActiveCell = lngStatus
ActiveCell.offset(0, 1) = strData
ActiveCell.offset(1, 0).Select

in das Ende von CommandButton3_Click ein und kuckst was passiert und ob Du überhaupt Daten bekommst.

Wenn das geht, dann kommentierst Du den Code wieder aus, kopierst Du Dir den Code von oben und rufst die Sub Main statt
dessen auf.

Die Sache mit dem Event kann man hinterher immer noch einbauen, bzw. ersatzweise einfach einmal pro Sekunde die sub
CommandButton3_Click starten.

Andreas.
Christof Kluß
2010-12-04 17:55:14 UTC
Permalink
Post by Andreas Killer
Ich denke das kann Dir hier jeder schreiben, ist ziemlich einfach, Du
musst nur die Methoden des Range-Objekts benutzen.
Super, vielen Dank für das Beispiel!
Post by Andreas Killer
Wobei Test3 nie laufen wird, weil die Bedingung in Test2 die gleiche ist...
Oh ja, da habe ich mich verschrieben ;)
Post by Andreas Killer
Für die Kommunikation ja, aber das Zauberwort "Event", bzw.
"WaitCommEvent" fehlt, d.h. es gibt kein Ereignis das ausgelöst wird
wenn man an der Waage auf den Knopf drückt.
Ja, scheint mit der "mscomm32.ocx" wesentlich einfacher zu gehen
http://www.pencomdesign.com/support/relay_software/vba_software_example.htm
die habe ich auf meinem System aber leider nicht :(
Post by Andreas Killer
Aber kopier Dir einfach mal den Code von der Webseite, und dann fügst Du diese Zeilen
ActiveCell = lngStatus
ActiveCell.offset(0, 1) = strData
ActiveCell.offset(1, 0).Select
in das Ende von CommandButton3_Click ein und kuckst was passiert und ob
Du überhaupt Daten bekommst.
Wenn das geht, dann kommentierst Du den Code wieder aus, kopierst Du Dir
den Code von oben und rufst die Sub Main statt dessen auf.
Die Sache mit dem Event kann man hinterher immer noch einbauen, bzw.
ersatzweise einfach einmal pro Sekunde die sub CommandButton3_Click
starten.
Alles klar, danke.

Viele Grüße
Christof
Michael Schwimmer
2010-12-05 19:33:45 UTC
Permalink
Hallo Christuf,
Post by Christof Kluß
Post by Andreas Killer
Für die Kommunikation ja, aber das Zauberwort "Event", bzw.
"WaitCommEvent" fehlt, d.h. es gibt kein Ereignis das ausgelöst wird
wenn man an der Waage auf den Knopf drückt.
Ja, scheint mit der "mscomm32.ocx" wesentlich einfacher zu gehen
http://www.pencomdesign.com/support/relay_software/vba_software_example.htm
die habe ich auf meinem System aber leider nicht :(
das Problem mit den Ereignissen ist, dass man Verweise auf "fremde"
Bibliotheken oder Steuerelemente setzen muss und auch darauf angewiesen
ist, dass die benutzten Ressourcen auf dem Rechner vorhanden und korrekt
registriert sind.

Mit Excel-Bordmitteln kann man die Schnittstelle auch abfragen, aber Events
sind nicht drin. Da muss man dann Pollen, das heißt, die Schnittstelle
kontinuierlich abfragen. Das belastet dann natürlich den Rechner und Excel
erscheint dann wie eingefroren.

Wenn man aber keine zeitkritischen Daten auslesen will, also beispielsweise
beim Eintreffen einen Zeitstempel hinzufügen möchte, klappt das recht gut,
denn die eintreffenden Daten werden ja im Eingangspuffer
zwischengespeichert.

Nachfolgend etwas Code, mangels zweitem Rechner habe ich das AVR-Net-IO von
Pollin als Datenlieferant missbraucht, dazu muss man aber erst ein Kommando
senden, deshalb sind die folgenden Zeilen mit drin.

If Senden("getstatus" & vbCrLf) = 0 Then
Debug.Print "Fehler beim Senden"
End If

Die kannst du ja rausnehmen.

Private Type SECURITY_ATTRIBUTES
nLength As Long
lpSecurityDescriptor As Long
bInheritHandle As Long
End Type
Private Type COMSTAT
Bits As Long
cbInQue As Long
cbOutQue As Long
End Type
Private Declare Function CreateFile _
Lib "kernel32" Alias "CreateFileA" ( _
ByVal lpFileName As String, _
ByVal dwDesiredAccess As Long, _
ByVal dwShareMode As Long, _
lpSecurityAttributes As SECURITY_ATTRIBUTES, _
ByVal dwCreationDisposition As Long, _
ByVal dwFlagsAndAttributes As Long, _
ByVal hTemplateFile As Long _
) As Long
Private Declare Function CloseHandle _
Lib "kernel32" ( _
ByVal hObject As Long _
) As Long
Private Declare Function ClearCommError _
Lib "kernel32" ( _
ByVal hFile As Long, _
lpErrors As Long, _
lpStat As COMSTAT _
) As Long
Private Declare Function ReadFile _
Lib "kernel32" ( _
ByVal hFile As Long, _
ByVal lpBuffer As String, _
ByVal nNumberOfBytesToRead As Long, _
lpNumberOfBytesRead As Long, _
ByVal NOlpOverlapped As Long _
) As Long
Private Declare Function WriteFile _
Lib "kernel32" ( _
ByVal hFile As Long, _
ByVal lpBuffer As String, _
ByVal nNumberOfBytesToWrite As Long, _
lpNumberOfBytesWritten As Long, _
ByVal lpOverlapped As Long _
) As Long
Private Declare Function GetLastError _
Lib "kernel32" () As Long

Private Const GENERIC_READ As Long = &H80000000
Private Const GENERIC_WRITE As Long = &H40000000
Private Const OPEN_EXISTING As Long = 3

Private mlngComHandle As Long
Private mblnStop As Boolean

Public Sub StartUeberwachung()
If mlngComHandle <> 0 Then Exit Sub
mlngComHandle = KommunikationOeffnen("Com1")
If mlngComHandle = 0 Then
MsgBox "Fehler beim Öffen der Kommunikation"
Exit Sub
End If
mblnStop = False
Call PollCom
End Sub

Public Sub StopUeberwachung()
mblnStop = True
If KommunikationSchließen(mlngComHandle) = False Then
MsgBox "Fehler beim Schließen der Kommunikation"
Else
mlngComHandle = 0
End If
End Sub

Private Sub PollCom()
Dim strInput As String
Dim lngLast As Long

If mblnStop Then Exit Sub

strInput = Empfangen(2) ' 2 Sekunden Wartezeit
If strInput <> "" Then
With Worksheets("Tabelle1")
lngLast = .Cells(.Rows.Count, 1).End(xlUp).Row
.Cells(lngLast + 1, 1) = strInput
End With
End If
Application.OnTime Now + TimeSerial(0, 0, 10), "PollCom"

If Senden("getstatus" & vbCrLf) = 0 Then
Debug.Print "Fehler beim Senden"
End If

End Sub

Private Function Senden(Text As String) As Long
Dim lngRet As Long
Dim lngWritten As Long

If mlngComHandle = 0 Then Exit Function

' Text senden
lngRet = WriteFile(mlngComHandle, Text, Len(Text), lngWritten, 0)

If lngRet = 0 Then MsgBox "Fehler beim Senden"

Senden = lngWritten

End Function

Private Function Empfangen(Optional lngTimeout As Long = 5) As String
Dim lngRet As Long
Dim strBuffer As String
Dim lngWritten As Long
Dim lngNeeded As Long
Dim lngComError As Long
Dim udtStat As COMSTAT
Dim dteTimeoutWaitForInput As Date
Dim i As Long

If mlngComHandle = 0 Then Exit Function

If lngTimeout = 0 Then lngTimeout = 5

' Timeoutzeit festlegen
dteTimeoutWaitForInput = Now + TimeSerial(0, 0, lngTimeout)

Do

i = i + 1

' Status holen
ClearCommError mlngComHandle, lngComError, udtStat

' Anzahl Zeichen im Puffer auslesen
lngNeeded = udtStat.cbInQue

If lngNeeded > 0 Then

' Puffer anlegen
strBuffer = String(lngNeeded, 0)

' Empfangspuffer in der angelegten Größe auslesen
lngRet = ReadFile( _
mlngComHandle, _
strBuffer, _
lngNeeded, _
lngWritten, 0)

Empfangen = Empfangen & strBuffer

' Ereignisse abarbeiten
DoEvents

' Status holen
ClearCommError mlngComHandle, lngComError, udtStat

' Anzahl Zeichen im Puffer auslesen
If udtStat.cbInQue = 0 Then Exit Do

Else

' Überprüfen, ob Timeout erreicht. Wenn ja,
' Schleife verlassen
If Now > dteTimeoutWaitForInput Then Exit Do

End If

If (i Mod 100) = 0 Then DoEvents

Loop

End Function

Public Function KommunikationSchließen( _
Optional CommHandle As Long _
) As Boolean
If CloseHandle(CommHandle) <> 0 Then
' Schnittstelle erfolgreich geschlossen
KommunikationSchließen = True
End If
End Function

Public Function KommunikationOeffnen( _
Optional strPort As String = "COM1" _
) As Long
Dim udtSecurity As SECURITY_ATTRIBUTES
Dim lngAccess As Long
Dim lngErr As Long
Dim lngComHandle As Long

On Error GoTo ErrHandler

' Zugriffsberechtigung setzen
lngAccess = GENERIC_READ Or GENERIC_WRITE

' Struktur SECURITY_ATTRIBUTES ausfüllen
With udtSecurity
.nLength = 12
.bInheritHandle = 0
.lpSecurityDescriptor = 0
End With

' Fehlerspeicher leeren
lngErr = GetLastError

' Filehandle holen
lngComHandle = CreateFile( _
strPort, _
lngAccess, _
0&, _
udtSecurity, _
OPEN_EXISTING, _
0&, _
0&)

' Fehlerspeicher auslesen
lngErr = GetLastError

If (lngErr <> 0) Or (lngComHandle < 1) Then
GoTo ErrHandler
End If

' Filehandle als Funktionsergebnis zurückgenben
KommunikationOeffnen = lngComHandle

Exit Function

ErrHandler:

End Function

Viele Grüße
Michael
Christof Kluß
2010-12-07 07:33:30 UTC
Permalink
Hallo,

erst mal vielen Dank für die bisherige Unterstützung!

Ich habe noch eine weitere Möglichkeit gefunden von Excel aus die
serielle Schnittstelle abzufragen, ohne eine Lizenz für die MSCOMM zu haben.

Ich habe einfach die "XMComm ActiveX control" benutzt, die ein Wrapper
für die "Microsoft's Communication (MSComm) control" ist
http://home.comcast.net/~hardandsoftware/xmcomm.htm

Dazu bin ich analog zum Beispiel "Do-It-Yourself Automated Mass
Readings" unter http://www.msc-lims.com/lims/diybalance.html
vorgegangen, um die Sartorius Waage LA120A anzusprechen.

Ich bin schon mal so weit, dass ich beim Drücken der Waage in Excel
einen Messwert geliefert bekomme. Wie ich die Daten dann genau auslese,
muss ich mir wohl noch hin fummeln. Wenn das natürlich jemand parat hat,
gerne her damit ;)

Public Sub RequestBalanceData()
If Not XMCommCRC1.PortOpen Then
XMCommCRC1.RThreshold = 1
XMCommCRC1.RTSEnable = True
XMCommCRC1.CommPort = 1
XMCommCRC1.Settings = "1200,o,7,1"
XMCommCRC1.PortOpen = True
End If
End Sub

Private Sub XMCommCRC1_OnComm()
Static sInput As String
Dim Buffer As Variant
' Branch according to the CommEvent property.
Select Case XMCommCRC1.CommEvent
Case XMCOMM_EV_RECEIVE
Buffer = XMCommCRC1.InputData ' Use Input property for MSComm
sInput = sInput & Buffer
MsgBox sInput
End Select
End Sub


Vielen Dank noch mal.

Gruß
Christof
Heiko Nocon
2010-12-07 16:35:47 UTC
Permalink
Post by Christof Kluß
Ich habe einfach die "XMComm ActiveX control" benutzt, die ein Wrapper
für die "Microsoft's Communication (MSComm) control" ist
http://home.comcast.net/~hardandsoftware/xmcomm.htm
Jau, dessen zusätzliche Funktionalität brauchst du allerdings für deine
Anwendung garnicht. Deswegen kannst du auch einfach direkt das vom
Wrapper ja mitgelieferte mscomm benutzen.

Was das "Anspringen" der Zellen betrifft: Du brauchst nicht "springen".
Excel-Zellen kann man auch einfach als zweidimensionales Array über
Indizes ansprechen. Wenn der Comm-Ereignishandler zu dem Arbeitsblatt
gehört, in das auch die Werte geschrieben werden sollen, ist es
besonders einfach:

Cells(0,0).Value=GelesenerWert

z.B. schreibt den Wert in's Feld A1. Durch andere Indizes kannst du in
beliebige Felder schreiben, Cells(3,3) etwa entspricht dem Feld D4.
Lesen Sie weiter auf narkive:
Loading...