Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

MsComm to Weigh Bridge Scale 3

Status
Not open for further replies.

Boris10

IS-IT--Management
Jan 26, 2012
97
KE
Hi Everyone i am trying to write a software that aquires the measurements taken by a scale at a weighbridge. I have written the below code, however, i am not getting any Mscomm1.input information. What am i not doing right?
Please find the code below:

Code:
Private Sub UserForm_Initialize()
    Call Ports.GetPorts
End Sub
Public Sub GetPorts()
With MComm

On Error GoTo PortTest:
 Dim i As Long
 Dim ComPortAvailable As Boolean
 
For i = 1 To 400
    .MSComm1.CommPort = i
    .MSComm1.PortOpen = True
 If .MSComm1.PortOpen Then
    .cmb.AddItem VBA.str$(i)
    .MSComm1.PortOpen = False
    ComPortAvailable = True
 End If
Next

End With
PortTest:
 Resume Next
End Sub

Private Sub cmdConnect_Click()
With MSComm1
    .CommPort = cmb.value
    .Settings = "9600,n,8,1"
    .RThreshold = 1
    .InBufferSize = 4096
    .PortOpen = True
    .SThreshold = 1
    .Handshaking = 2 - comRTS
    .Output = "AT"
    Call GetData
End With
Private Sub GetData()
    Dim MyData As String
    'MSComm1.InputLen = 0
    MSComm1.Output = "AT"
    MyData = MSComm1.Input
    TXT1.Text = MyData
    MSComm1.PortOpen = False
End Sub
End Sub

Thank you for your help!
 
It's been a long time since I did something similar, but I think you have to use the OnComm event, and then clear the buffer, something like:

Code:
Private Sub MSComm1_OnComm()
   Dim strWeight
   strWeight = MSComm1.Input
  [COLOR=#4E9A06] 'clear the input buffer[/color]
   MSComm1.InBufferCount = 0   

End Sub

But it's been a while. Does the balance manufacturer have any vb6 samples? The one I had used did.
 
Hi guitarzan, thank you for your input, i will try to clear the buffer. I have used the onComm event with similar code, but it also didnt give me any results.
 
Then, it's also possible that the balance requires more than just "AT" sent to it (such as "AT" plus a carriage return). You may need to consult with the documentation to find out exactly.
 
>a weighbridge

If you included the weighbridge manufacturer/ model number you could just strike lucky ...
 
I contacted the manufacturer (Klerkscale), they have sent me the following specifications:

To obtain “Printer” data, the printer or computer initiates communication by sending DC1 (ASCII 17).
After DC1 response from the instrument, the computer sends DC2 (ASCII 18) + a 2 character ID (32).
The instrument sends then STX (ASCII 02) and a 2 character data identifier, which is 08 for gross
mass in “Printer” data mode. After this, the weighing instrument waits for DC2 from the computer.
After receiving DC2, the weighing instrument sends the mass data, ETX (ASCII 03), a 4 character
checksum and EOT (ASCII 04).

So does that mean that my Mscomm must be set to :
Code:
Mscomm1.output = vbcontrolkey 'Get Printer Data
 
I am finally getting some output:

胼肀ø胸€€ø€碀＀Ṹøøﹸﹸ碀þ肀肀肀

This is what i am getting.

How do i convert it to numbers?
 
>How do i convert it to numbers?

You talk to Klerkscale to get hold of the full spec of the comms protocol in use. This isn't something we can really help with. Once you have that spec, ask again ...
 
Hi I got my code to finally work and produce meaningfull results. Below is the code that works for KI-20 indicator:

Code:
Public Sub GetWeight(txtBox As textbox)
    Dim criteri() As String
    Dim wieght() As String
    
'Set up the Comm Control
With Wbridge.MSComm1

    .CommPort = 1
    .Settings = "2400,O,7,1"
    .DTREnable = True
    .EOFEnable = True
    .Handshaking = comRTSXOnXOff
    .InputMode = comInputModeText
    .RTSEnable = True
    '.PortOpen = False
    .PortOpen = True

'Communicate
    .Output = VBA.Chr$(17)
    criteri = Split(.Input, "kg")
    wieght = Split(criteri(1), "40")
    
    Select Case val(Trim(wieght(1))) / 1000
        Case val(Trim(wieght(1))) / 1000 < 1
            txtBox.Text = val(Trim(wieght(1)))
        Case val(Trim(wieght(1))) / 1000 > 1
            txtBox.Text = val(Trim(wieght(1))) / 1000
    End Select
    
    ' clear the input buffer
    .InBufferCount = 0
    .PortOpen = False

   End With
End Sub

I have added a "Case Statement" as sometimes the weight captured on scale is for example: 0.019 when the actual reading is 19600 kg. I am wondering if my code is correct or there is anything I am missing?
 
>I am wondering if my code is correct or there is anything I am missing?

Who knows? Since we still have no idea of the protocol, we'd only be guessing.
 
klerkscale said:
The KI-20 weighing instrument is provided with serial data communication capability via RS232 and
20 mA current loop. The RS232 channel and current loop channel are operative simultaniously.
There are 2 receivers - one for RS232 and one for current loop, and one transmitter which sends via
both channels.
“Remote Display” data is transmitted every A/D cycle, that is once per 140 milliseconds. If a request
for data is received via the RS232- or current loop receiver, and the mass reading is within range and
stable, then the transmission of “Remote Display” data will be stopped temporarily and “Printer” data
will be transmitted. In calibration mode, data is only transmitted as a response to commands and requests
received via the RS232 receiver.
The format of the “Remote Display” data block is:
a. STX (ASCII 02).
b. A two (2) character data identifier, which is 40 for gross mass in “Remote Display” data mode.
c. Data, which has the format XXXXXX kg where “X” is numerical data with leading zero’s
replaced by spaces. In case of overcapacity “X” is “;” and in case of below zero “X” is “-“.
d. ETX (ASCII 03).
e. A 4 character checksum, which is the hexadecimal summation of the values of the characters in
ASCII of the datablock including STX and ETX. The checksum is sent as 4 characters, most
significant first, with the value 3 in the high nibble of each character and a hexadecimal digit
(0 – F) in the low nibble.
Example of “Remote Display” data:
|S| |E| CHECK |
|T| |T| SUM |
|X|4|0|1|2|3|4|,|5| |k|g|X| | | | |
To obtain “Printer” data, the printer or computer initiates communication by sending DC1 (ASCII 17).
After DC1 response from the instrument, the computer sends DC2 (ASCII 18) + a 2 character ID (32).
The instrument sends then STX (ASCII 02) and a 2 character data identifier, which is 08 for gross
mass in “Printer” data mode. After this, the weighing instrument waits for DC2 from the computer.
After receiving DC2, the weighing instrument sends the mass data, ETX (ASCII 03), a 4 character
checksum and EOT (ASCII 04).
Example of “Printer” data:
| |D| |S| |E| CHECK |E|
| |C| |T| |T| SUM |O|
KI-20 | |1| |X|0|8| |1|2|3|4|5|0| |k|g|X| | | | |T|
PC |D| |D|3|2| |D| |ACK|
|C| |C| | |C| |or |
|1| |2| | |2| |NAK|
To "ZERO" the weighing Instrument via the serial port:
The computer sends ESC (ASCII 27).
After ENQ (ASCII 05) responsee from the instrument, the computer
sends 0 + EOT.
| |E|
| |N|
KI-20| |Q|
PC |E| |0|E|
|S| | |O|
|C| | |T|
Characters are sent with a baudrate of 2400, the character format is: 1 start bit, 7 data bit, 1 odd parity
bit and 1 stop bit.
-----------------------------------------------------------------
-----------------------------------------------------------------
The above is the communication protocol for KI-20.
The weight on the indicator is displayed in kgs. Before, transferring the weight to the database I divide it by 1000 (converting it to tons).
To be specific the current problems that I am having with my program are:

1. Sometimes the weight is captured as 0.019 when the actual reading is 19600 kg. I have changed my code to check if the weight captured is less then 1 then it must not be divided by 1000 -------------------Not sure if this is reliable.
2.Sometimes the weight is not captured at all, especially when there is a truck with the trailer. the truck weight is displayed as 0 and the trailer is correctly displayed ------------------I am wondering if this is due to wrong Mscomm1.Output command.
3. Sometimes I get an error message saying that the port is already open. --------------------if I restart my computer I can then recapture the weights. --------------yet every time the port is opened it is then closed after the weight is captured.

The above three are the problems that I am currently facing... could anyone point me in the right direction. Thank you!
 
This is the information I get from MScomm1.input when there is no weight on the scale:

40 0 kg022;40 0 kg022;40 0 kg022;40
 
Right ...

From the spec, the weighbridge spams you with Remote Display data every 140ms. And the remote data block is NOT a block of text. SO you should really be reading it as binary (as advised in now missing posts), and then handling it appropriately.

But your earlier code seems to imply you want the Printer Data (which is also not a block of text), because you are sending DC1 (ASCII 17) to the weighbridge - but then you do not follow up with the rest of the required protocol described by the documentation; it is unclear how the weighbridge responds in this scenario (I'd surmise that after a certain amount of time it returns to spamming the remote display data).

I think we now need to see the actual code you are using.
 
Hi Strongm,

Thank you for helping me out on this one.

I have tried to set the inputMode to Binary, but then the output that I get is :胼肀ø胸€€ø€碀＀Ṹøøﹸﹸ碀þ肀肀肀.
Thus, I have changed to inputModeText, which gives a more meaningful result: 40 0 kg022;40 0 kg022;40 0 kg022;40.

The one thing I don't understand is why do I need to send DC1 and then DC2, when DC1 already sends me the results that I require, but keeps on failing after a period of time?

So from what you are saying now, I am missing the DC2 to complete the communication: hence I am getting the problems that I am getting.

With respect to my code, I have a textbox and a capture button. The button calls the getWeight Sub.
Code:
Private Sub cmdTare_Click()
    Call GetWeight(txtTareMass)
    If txtTareMass.Text = 0 Then
        Call GetWeightAgain(txtTareMass)            'if char 17 fails get the weight again with char18
    End If
End Sub

The GetWeight Sub captures the weight and sends it to the txtBox - using the "DC1" protocol.
Code:
Public Sub GetWeight(txtBox As textbox)
    Dim criteri() As String
    Dim wieght() As String
    Dim inp As String
'Set up the Comm Control
With Wbridge.MSComm1

    .CommPort = 1
    .Settings = "2400,O,7,1"
    .DTREnable = True
    .EOFEnable = True
    .Handshaking = comRTSXOnXOff
    .InputMode = comInputModeText
    .RTSEnable = True
    '.PortOpen = False
    .PortOpen = True

'Communicate
    .Output = VBA.Chr$(17)
    inp = .Input
    criteri = Split(inp, "kg")
    wieght = Split(criteri(1), "40")
    MsgBox inp
        If val(Trim(wieght(1))) / 1000 < 1 Then
            txtBox.Text = val(Trim(wieght(1)))
        ElseIf val(Trim(wieght(1))) / 1000 > 1 Then
            txtBox.Text = val(Trim(wieght(1))) / 1000
        Else
            txtBox.Text = val(Trim(wieght(1))) / 1000
        End If
    
    ' clear the input buffer
    .InBufferCount = 0
    .PortOpen = False

   End With
End Sub

If the textbox does not receive any information, DC2 is sent to the indicator:
Code:
Public Sub GetWeightAgain(txtBox As textbox)
    Dim criteri() As String
    Dim wieght() As String
    Dim inp As String
'Set up the Comm Control
With Wbridge.MSComm1

    .CommPort = 1
    .Settings = "2400,O,7,1"
    .DTREnable = True
    .EOFEnable = True
    .Handshaking = comRTSXOnXOff
    .InputMode = comInputModeText
    .RTSEnable = True
    '.PortOpen = False
    .PortOpen = True

'Communicate
    .Output = VBA.Chr$(18)
    inp = .Input
    criteri = Split(inp, "kg")
    wieght = Split(criteri(1), "40")
    MsgBox inp
        If val(Trim(wieght(1))) / 1000 < 1 Then
            txtBox.Text = val(Trim(wieght(1)))
        ElseIf val(Trim(wieght(1))) / 1000 > 1 Then
            txtBox.Text = val(Trim(wieght(1))) / 1000
        Else
            txtBox.Text = val(Trim(wieght(1))) / 1000
        End If
    
    ' clear the input buffer
    .InBufferCount = 0
    .PortOpen = False

   End With
End Sub


This is the only code I have for communicating with the KI-20 Indicator.


 
>but then the output that I get is

Because you are then trying to treat the binary data as a string.

>when DC1 already sends me the results that I require

No, it doesn't. It is timing out, as I surmised earlier, and reverting to sending you the Remote Display data, not the Printer data. Of course, if it is the Rempte Display data that you want, then fine, but in that case you don't need to send DC1 (or DC2)

>DC2 is sent to the indicator:

Almost certainluy too late, though. And even if it wasn't you need to send DC2 plus "a 2 character ID". So once again, you'll just be getting the Remote Display data.

>'if char 17 fails get the weight again with char18

That's not how the protocol works (although this isn't the clearest protocol documentation I've ever seen ...)

If you want Printer data, you need to
a) send DC1
b) listen for DC1 back from weighbridge (essentially an acknowledgement it is waiting for an instruction)
c) Send DC2 plus id code "32"
d) listen for STX (aSCII 2) plus id code "08" from weighbridge
e) send DC2 again
f) listen for block of what appears to be 10 bytes containing the weight data followed by ETX (ASCII 3) then 4 bytes of checksum and terminated by EOT (ASCII 4)
g) All done.
 
Reading binary data with setting to text might appear to show text characters but if say a value of a byte to be transmitted was below 32 and above 127 then you wouldn't see it (as I understand it) so it would be meaningless.
 
Given that the protocol states 7-bit data, it would be quite difficult to get a byte with a value above 127 ...
 
Hi strongm
Code:
With Wbridge.MSComm1

    .CommPort = 1
    .Settings = "2400,O,7,1"
    .DTREnable = True
    .EOFEnable = True
    .Handshaking = comRTSXOnXOff
    .InputMode = comInputModeBinary
    .RTSEnable = True
    '.PortOpen = False
    .PortOpen = True

'Communicate
'1. Send DC1
    .Output = VBA.Chr$(17)
    inp = .Input
'2. Listen for Output
    Do While Len(inp) = 0
    Loop
'3.Send DC2 and id code 32
    .Output = VBA.Chr$(18) + str(32)
    inp = .Input
'4.Listen for reply
    Do While Len(inp) = 0
    Loop
'5.Send DC2 again
    .Output = VBA.Chr$(18)
    inp = .Input

    'criteri = Split(inp, "kg")
    'wieght = Split(criteri(1), "40")
    MsgBox StrConv(inp, vbUnicode)

I have added the above to my capture button. The output is the same as just sending DC1 on its on, except there is 7 repetitive lines instead of 1 ------------- "40 0 kg022;40 0 kg022;40 0 kg022;40" . In other words it seems that it is just the same (correct me if I am wrong)

To answer your question: am I looking for remote display data or printer data?
I am looking for the weight data - displayed on the indicator(which I am guessing is the same as remote display).

I have been testing the program the whole day today: (Only sending DC1). From what I have noticed.
Code:
Msgbox Mscomm1.input
---------------has been so far displaying the correct weight (compared to the indicator)

I think I got all the help needed for this program. I am very thankful to everyone who participated and assisted in solving this problem, especially "strongm" - thank you very much for your input!

 
>which I am guessing is the same as remote display

If all you want is the remote display data, then you don't need to send anything. At all. You just need to enable a comm event, and then consume what you see.

So, initialising your com port has a slight modofication:

Code:
[blue]    With MSComm1
        .CommPort = 3
        .Settings = "2400,O,7,1"
        .DTREnable = True
        .EOFEnable = True
        .Handshaking = comRTSXOnXOff
        [b].InputMode = comInputModeBinary[/b]
        .RTSEnable = True
        .PortOpen = True
        [b].RThreshold = 1 [green]' we could set this higher[/green][/b]
    End With[/blue]

And then you write a comm event, for example:

Code:
[blue]Private Sub MSComm1_OnComm()
    Dim lp As Long
    Dim myWeight As String
    Dim mydata() As Byte
    If MSComm1.InBufferCount > 33 Then [green]' horrendously lazy way of ensuring we have at least one complete block of remote display data[/green]
        mydata = MSComm1.Input [green]' reads and empties buffer[/green]
        For lp = 0 To UBound(mydata)
            If mydata(lp) = 2 Then [green]' find STX in buffer[/green]
                lp = lp + 3 [green]' lazily skip over STX and ID code[/green]
                Do Until mydata(lp) = 3
                    myWeight = myWeight & Chr(mydata(lp))
                    lp = lp + 1
                Loop
                lp = UBound(mydata)
                Text1.Text = myWeight
            End If
        Next
    End If
End Sub[/blue]

Text1.text should now display same value as is shown on weighbridge
 
In writing MSComms (and Winsock) receive routines you should take into account every unlikely possibility that might occur when you get intermittent or corrupted data and indicate that a fault has occurred instead of showing possibly misleading value.

Wouldn't using the "<If MSComm1.InBufferCount > 33" method create a problem if you temporarily disconnected it while it was running then reconnected? You possibly could get parts of 2 different strings mixed together?
I would suggest that if only say 30 bytes was received, you wouldn't have the opportunity to indicate a faulty reading and the next read say an hour later could have the 3 unread bytes tacked on to the head of the next one and the desired string would be missing the last 3 bytes and so on indefinitely.

You could add to the code that started a timer when .InBufferCount was first detected (using Else) and showed an error and blanked the result if it was not >33 by a say second later.

Rather that use the size of the buffer, I have used a highly reliable method that examines and accumulates the received data as it is received and detects when the end of the data (using Instr) has been transmitted then examines only the last (33) characters so it ignores the possibly of spurious or previous data at the head of the last complete string.
If there is no unique end of data character then you can reference (hopefully) a fixed number of bytes past some other unique character.

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top