-
Sep 16th, 2010, 10:42 AM
#1
Thread Starter
Fanatic Member
Serial Port not writing back
I'm trying to connect to a Mettler Toledo Scale via a serial port to read in the weight of an object and output the wieght into a label or text box on the form.
so I have a button and a text box. Here is my code
Code:
Private Sub btnSendText_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSendText.Click
Dim Port As SerialPort = New SerialPort("COM1", 9600, Parity.None, 8, StopBits.One)
Port.Open()
txtWeight.Text = Port.ReadLine()
Port.Close()
End Sub
My problem is that the program hangs there doing nothing when I click the button.
Does anyone know why?
"...Men will still say THIS was our finest hour"
If a tree falls in the woods and no one is there to see it, do all the other trees make fun of it?
-
Sep 16th, 2010, 01:40 PM
#2
Fanatic Member
Re: Serial Port not writing back
You forgot to set the ReadTimeout property.
The ReadLine function will, by default, block until it actually reads a whole line (a line that is terminated with a line end) So, in theory, it will block forever until it receives a line end character.
That is the behaviour you're experiencing because that's what you've told it to do.
Set the ReadTimeout property to some non-zero value. (By default it's zero which means 'wait forever') Setting a non-zero value tells readline to try to read a line but to come back after the timeout period if there's no data waiting to be read. Just a couple of ms should be enough - don't hang round too long otherwise your app will be sluggish. Best to have a very short timeout and call the ReadLine multiple times until you get your data.
But bear in mind that the readline function won't work for you unless your scales actually terminate the data with a newline character.
Last edited by IanS; Sep 16th, 2010 at 01:48 PM.
-
Sep 16th, 2010, 02:34 PM
#3
Thread Starter
Fanatic Member
Re: Serial Port not writing back
That worked but now i have a different error:
Argument value cannot be null or zero-length.
So I have some thing on the scale that doesn't register as 1 it was .35 is that because it isn't 1?
"...Men will still say THIS was our finest hour"
If a tree falls in the woods and no one is there to see it, do all the other trees make fun of it?
-
Sep 18th, 2010, 12:08 PM
#4
Fanatic Member
Re: Serial Port not writing back
Originally Posted by Dubya007
That worked but now i have a different error:
Argument value cannot be null or zero-length.
So I have some thing on the scale that doesn't register as 1 it was .35 is that because it isn't 1?
You don't say 'Where' the error happens. You've changed your code so let's see what it looks like now and highlight the line where the error occurs.
-
Sep 20th, 2010, 12:17 PM
#5
Thread Starter
Fanatic Member
Re: Serial Port not writing back
I've changed my code and am now getting a different error saying "Timeout exception not handled or soemthing like that.
VBcode Code:
Private Sub btnSendText_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSendText.Click 'Dim weight As String Dim Port As SerialPort = New SerialPort("COM1", 9600, Parity.None, 8, StopBits.One) Port.Open() Port.ReadTimeout = 500 'weight = Port.ReadLine() 'txtWeight.Text = weight txtWeight.Text = Port.ReadLine() Port.Close() End Sub
I'm getting the error where i've put txtWeight.Text = Port.ReadLine()
"...Men will still say THIS was our finest hour"
If a tree falls in the woods and no one is there to see it, do all the other trees make fun of it?
-
Sep 21st, 2010, 10:50 AM
#6
Fanatic Member
Re: Serial Port not writing back
What you are doing isn't what I'd call "best practice."
1. I recommend that you do not use ReadLine, which will not work unless the data stream is properly terminated (default newline is carriagereturn followed by a linefeed).. Instead, I suggest that you use ReadExisting.
Next, it is best (IMO) to attempt to read data only after data has been received by the PC! So, especially for things like scales, you should use the built-in DataReceived event subroutine and process data there. To do that, you should use the SerialPort object from the Toolbox. When you drop it on the design surface, a you don't have to instantiate it in code. If you want to continue to use it in code, move the declaration to and create it as a Private object -- With Events, so that the DataReceive event is created. Example,
Code:
Private With Events Port As New System.IO.Ports.SerialPort
Then, initialize the port in the Button or Form_Load event.
Code:
With Port
.PortName = "Com1"
.RTSEnable = True 'this can be very important
.BaudRate = 9600
.Open()
Code:
Private Sub lPort_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles Port.DataReceived
Dim Buffer As String = Port.ReadExisting()
Debug.Print(Buffer) 'display received data in the Debug window
End Sub
Now, depending on what you want to do with the data, there will be more code required to process and display it.
Also note the comment in the code fragment above. Often you must assert RTS (RTSEnable = True) to allow the connected device to actually send data.
I have an example that you may want to look at on my homepage, www.hardandsoftware.net. See Downloads and look for the Enhanced SerialPort object.
Dick
Richard Grier, Consultant, Hard & Software
Microsoft MVP (Visual Basic)
-
Sep 21st, 2010, 01:43 PM
#7
Thread Starter
Fanatic Member
Re: Serial Port not writing back
Thank you for the help DickGrier. I've downloaded the project from your site and am looking it over to understand what is going on first. Then after I fully understand your project I'll try and implement the changes into my project.
"...Men will still say THIS was our finest hour"
If a tree falls in the woods and no one is there to see it, do all the other trees make fun of it?
-
Sep 24th, 2010, 09:04 AM
#8
Thread Starter
Fanatic Member
Re: Serial Port not writing back
I've been going through your project and I'd like to see where we're actually pulling the wieght it. when i run the project there isn't a button to pull the weight in. Is that something that I have to write myself in your program?
"...Men will still say THIS was our finest hour"
If a tree falls in the woods and no one is there to see it, do all the other trees make fun of it?
-
Sep 24th, 2010, 10:36 AM
#9
Fanatic Member
Re: Serial Port not writing back
My example simply displays data as it is received. If you have to send a command to the scale to send a reading, then add a command button. Then, in the command button click event, add a SerialPort.Write statement that sends the properly formated command.
On of the reasons that I wrote my book, Visual Basic Programmer's Guide to Serial Communications 4 is because there is no "one size fits all" for serial comms. So, examples (by the dozens) try to fill the gap. I have three scale examples, but the probably are half a dozen variations that I haven't done.
Dick
Richard Grier, Consultant, Hard & Software
Microsoft MVP (Visual Basic)
-
Sep 24th, 2010, 11:15 AM
#10
Thread Starter
Fanatic Member
Re: Serial Port not writing back
Thank you so much. That gives me a great starting point. I'll get to work on that and update once I have that working. Your Website is very good and you're very helpful
"...Men will still say THIS was our finest hour"
If a tree falls in the woods and no one is there to see it, do all the other trees make fun of it?
-
Dec 14th, 2010, 11:55 AM
#11
Thread Starter
Fanatic Member
Re: Serial Port not writing back
Originally Posted by DickGrier
My example simply displays data as it is received. If you have to send a command to the scale to send a reading, then add a command button. Then, in the command button click event, add a SerialPort.Write statement that sends the properly formated command.
Actually I think that if you example just shows data as it is recieved then in theory it would be real-time correct? so I were to put something on the scale it should automatically update in the EnhancedSerial project.
I'm following the program a bit but i still can't read anything from the scale in your project.
I've made sure the parity and stop bits and everything are set correctly in the program to match what is set up on the com port but I'm still not gettig anything back from the scale.
Any suggestions?
"...Men will still say THIS was our finest hour"
If a tree falls in the woods and no one is there to see it, do all the other trees make fun of it?
-
Dec 14th, 2010, 12:00 PM
#12
Fanatic Member
Re: Serial Port not writing back
Not real-time, but "eventually".
The DataReceived event is generated by the SerialPort object when it receives ReceiveBytesThreshold or greater number of characters. However... Unlike the built-in SerialPort object, if you use EnhancedSerialPort, you must set ReceiveBytesThreshold = 1 (or greater, but I believe 1 is best). If you leave it at the default (0), DataReceived events are not generated. This "enhancement" over the built-in SerialPort object does require this extra assignment, so make sure that it is included in the port initialization code.
Dick
Richard Grier, Consultant, Hard & Software
Microsoft MVP (Visual Basic)
-
Dec 14th, 2010, 03:41 PM
#13
Re: Serial Port not writing back
Dick wrote the book on serial communications in .NET. I know because I own a copy and it's been invaluable to my work. I actually have code that reads a Mettler Toledo scale indicator when it is set to "Streaming" mode. I can dig it up and post it if you're still having trouble. It doesn't use Dick's EnhancedSerialPort object, but it does use many of the concepts in his book such as using a Queue to collect data from the DataReceivedEvent and form it into packets that you can pull apart to get the weight data from.
When you open the serial port in something like Hyperterm, you can see the streaming scale data, correct? I know Mettler Toledo is kinda foofy and only a few of their indicator modes will stream data. Even fewer will allow you to send commands to the indicator like a "Zero" command.
-
Dec 14th, 2010, 04:04 PM
#14
Thread Starter
Fanatic Member
Re: Serial Port not writing back
That would certainly be helpful if you could post that code.
"...Men will still say THIS was our finest hour"
If a tree falls in the woods and no one is there to see it, do all the other trees make fun of it?
-
Dec 14th, 2010, 04:38 PM
#15
Re: Serial Port not writing back
Here, I edited it a bit since it's part of a much larger, complex program and can handle many other scale types than Mettler Toledo, but it should be all you need. I added in a bunch of comments as well:
Code:
'My Scale Port.
Public WithEvents scalePort As New System.IO.Ports.SerialPort
'Using a StringBuilder as our receiving Queue.
Private rcvQ As New StringBuilder
'Lock object to handle the multi-threaded nature of serial ports.
Private rcvQLock As New Object
'Size of one frame of data. This is discovered dynamically in the routine below.
Private intDataFrame As Integer = 0
Public Function Open_SerialPort() As Boolean
Try
With scalePort
.BaudRate = 9600
.PortName = "COM1"
.DataBits = 8
.Parity = IO.Ports.Parity.None
.StopBits = IO.Ports.StopBits.One
.ReadTimeout = 500
.WriteTimeout = 500
.DiscardNull = False
.ReadBufferSize = 16384
End With
If Not scalePort.IsOpen Then
scalePort.Open()
End If
Return True
Catch ex As Exception
If ex.Message.Contains("Access") Then
'Do something if it is Access to the port 'COM#' is denied. message comes up.
Else
'General error handling
End If
Return False
End Try
End Function
Private Sub weighScale_DataReceived(ByVal sender As System.Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles scalePort.DataReceived
Try
Dim o As Byte = 13
Dim c As Char = Convert.ToChar(o)
Dim ca(intDataFrame) As Char
Dim dblReadholder As Double
If scalePort.BytesToRead = 0 Then Exit Sub
Dim bytsToRead As Integer = scalePort.BytesToRead
Dim buf(bytsToRead - 1) As Byte
'Read the bytes out of the serial buffer.
bytsToRead = scalePort.Read(buf, 0, bytsToRead)
Threading.Monitor.Enter(rcvQLock)
Try
rcvQ.Append(Encoding.ASCII.GetString(buf))
Finally
Threading.Monitor.Exit(rcvQLock)
End Try
'This figures out how large a single frame of data is; i.e. one "reading".
'It does this by waiting for the the queue to become > 50 bytes (which is more than
'twice any scale's data frame) and finds the CR characters (ASCII Byte 13) and the number
'of bytes between them.
If intDataFrame = 0 Then
If rcvQ.Length > 50 Then
Dim i As Integer = 0
Threading.Monitor.Enter(rcvQLock)
Try
'remove bytes until it hits a CR
Do Until rcvQ.ToString.StartsWith(c)
rcvQ.Remove(0, 1)
Loop
'Remove it, we are at the start of a new frame
rcvQ.Remove(0, 1)
'Count until you hit another CF
Do Until rcvQ.ToString.StartsWith(c)
rcvQ.Remove(0, 1)
i += 1
Loop
'This is the size of your frame in bytes.
intDataFrame = i
Finally
Threading.Monitor.Exit(rcvQLock)
End Try
End If
Exit Sub
'Else make sure we got 2 frames +1 worth of bytes to extract the next frame from
ElseIf rcvQ.Length > (intDataFrame * 2) + 1 Then
Threading.Monitor.Enter(rcvQLock)
Try
'Get to the top of the frame...
Do Until rcvQ.ToString.StartsWith(c)
rcvQ.Remove(0, 1)
Loop
'Remove the CF, copy the frame into "ca", remove the frame from the Queue.
rcvQ.Remove(0, 1)
rcvQ.CopyTo(1, ca, 0, intDataFrame)
rcvQ.Remove(0, intDataFrame + 1)
Finally
Threading.Monitor.Exit(rcvQLock)
End Try
'Convert the frame to a string
strHoldingVal = New String(ca)
'If this scale object is set to the Mettler Toledo IND429 then, take the data frame apart
'in the specific way required to get the data you need.
If scConfig.Indicator = ScaleInd.Mettler_Toledo_IND429 Then
'Read the numerical value
dblReadholder = Val(strHoldingVal.Substring(4))
'Convert if we want KGs
If Units = UnitType.Metric Then dblReadholder *= 0.45359237
'Convert to Decimal
sngReading = Convert.ToDecimal(dblReadholder)
'Update the scale control. The second part shows if the scale
'is showing "in motion".
SetScaleValues(sngReading, strHoldingVal.Contains("D"))
Else
'code for other scale indicators
End If
'If for some reason our Queue gets too large, then wipe it and start again
If rcvQ.Length > (10 * intDataFrame) AndAlso rcvQ.Length > 100 Then
Threading.Monitor.Enter(rcvQLock)
Try
rcvQ = New StringBuilder
Finally
Threading.Monitor.Exit(rcvQLock)
End Try
End If
End If
Catch ex As Exception
'General error handling goes here.
End Try
End Sub
Private Sub Close_SerialPort()
Try
If scalePort.IsOpen Then
scalePort.Close()
End If
Catch ex As Exception
'General error handling goes here.
End Try
End Sub
'Need these to do the cross-thread invoke so we can display our data.
Private Delegate Sub ChangeValue(ByVal sng As Decimal, ByVal boo As Boolean)
Private dChVal As New ChangeValue(AddressOf SetScaleValues)
Private Sub SetScaleValues(ByVal sng As Decimal, ByVal booMotion As Boolean)
Try
'Invoke cross-thread if required
If Label1.InvokeRequired Then
BeginInvoke(dChVal, New Object() {sng, booMotion})
'Otherwise, update my controls...
Else
meter1.Value = sng
Label1.Text = String.Format("{0:f3}", sng)
ledMotion.Value = booMotion
End If
Catch ex As Exception
'General error handling goes here.
End Try
End Sub
Last edited by Jenner; Dec 14th, 2010 at 04:43 PM.
-
Dec 15th, 2010, 04:13 PM
#16
Thread Starter
Fanatic Member
Re: Serial Port not writing back
Awesome Thanks. Do i have to add a serial port object?
"...Men will still say THIS was our finest hour"
If a tree falls in the woods and no one is there to see it, do all the other trees make fun of it?
-
Dec 15th, 2010, 04:23 PM
#17
Re: Serial Port not writing back
I add one in code. It's at the top-first line of the code snippit I posted. Yea, if you were attaching this to a form, you could drag one in the designer to the form, but there really is no need. It's not like it's a "control" with a graphical representation on the form so it don't matter. Being able to drag one onto a form is just a courtesy of Visual Studio.
Quite frankly, I don't drag any SerialPort, Timer, OpenFileDialog, etc onto forms anymore. It's quicker just to make one in code:
Code:
Dim odlg As New OpenFileDialog
If odlg.ShowDialog = DialogResult.Ok Then
Dim strFile As String = odlg.Filename
....
The codesnippit above is actually part of a UserControl I made for handling scales. The visible part of the control has a dial-meter control, a LED control, and a nice digital-readout control to display the numerals. These get updated as part of my SetScaleValues() function. I also have a button to Zero the scale or change it's units display (Lbs, Kgs, Oz). There is some parts of the control that Write data back to the serial port to send it Zero commands and such that I didn't include in the code snippit.
In the end, I can just drag one of these controls onto a form, send it a ScaleConfig object as a parameter (the ScaleConfig object holds things like type of indicator, baud, com port, weight range, etc) and you're done.
Last edited by Jenner; Dec 15th, 2010 at 04:31 PM.
-
Dec 15th, 2010, 04:42 PM
#18
Thread Starter
Fanatic Member
Re: Serial Port not writing back
Okay next question
There are a few variables that are underlined because they aren't declared. I've gone through the code to see where they need to be declared but I'm kinda lost on some of them,
strHoldingVal
scConfig
ScaleInd
Units
UnitType
sngReading
meter1
Are these just strings that need to be delcared?
"...Men will still say THIS was our finest hour"
If a tree falls in the woods and no one is there to see it, do all the other trees make fun of it?
-
Dec 15th, 2010, 05:01 PM
#19
Re: Serial Port not writing back
Sorry about that.
strHoldingVal is just a string to hold the current frame of data. It's class-level so I'm not constantly Dim'ing new strings every loop of the code. It's more efficient that way to just make it once and use it.
scConfig is my ScaleConfig object. I thought I removed it from my code, but I see where I'm checking the indicator type from it. scConfig.Indicator is of type ScaleInd (see below).
ScaleInd is an Enum of indicator types: Rice_Lake_IQ355Plus for example.
Units is a variable of type UnitType to hold the currently selected unit type (Lb, Kg, Oz, G).
UnitType is an Enum of unit types: Metric, English, EnglishOz, MetricGram
sngReading is just a Decimal variable to hold the current decimal reading.
meter1 is a control on my UserControl that behaves like a ProgressBar. You give it a Range (0 to 300) and then you set it's value and it moves the needle to that value. It looks like a dial-gauge.
-
Dec 15th, 2010, 05:10 PM
#20
Thread Starter
Fanatic Member
Re: Serial Port not writing back
meter1 isn't needed then if all i want to do is read the value into a textbox right?
"...Men will still say THIS was our finest hour"
If a tree falls in the woods and no one is there to see it, do all the other trees make fun of it?
-
Dec 15th, 2010, 05:13 PM
#21
Re: Serial Port not writing back
No, not at all. As I said, it's a code example. You'll probably have to tweak it a bit for your application.
-
Dec 15th, 2010, 05:23 PM
#22
Thread Starter
Fanatic Member
Re: Serial Port not writing back
The Units then I won't need either so that I can just pull what ever the scale says.
Also what is ledMotion?
"...Men will still say THIS was our finest hour"
If a tree falls in the woods and no one is there to see it, do all the other trees make fun of it?
-
Dec 15th, 2010, 06:06 PM
#23
Re: Serial Port not writing back
Oh, that's a LED control. Basically it's an image of a panel-mount LED. Set ledMotion.Value = True and it shows "lit". False and it shows a darker color to show it as unlit.
I use it to detect if the scale is considered "in-motion" by the indicator. The text that the Mettler Toledo indicator sends will include a letter "D" in the frame if it senses the scale is in motion, so I use the line: strHoldingVal.Contains("D") to get my True/False value for my LED control.
-
Dec 16th, 2010, 10:01 AM
#24
Re: Serial Port not writing back
Originally Posted by Jenner
Here, I edited it a bit since it's part of a much larger, complex program and can handle many other scale types than Mettler Toledo, but it should be all you need. I added in a bunch of comments as well:
....
Some of that code looks familiar, right down to the names.
-
Dec 16th, 2010, 10:02 AM
#25
Thread Starter
Fanatic Member
Re: Serial Port not writing back
I'm a little unclear as to how to get the weight actually show up on the form now. (sorry I've not programmed like this in years)
Which sub or function will i have to call in order to accomplish this?
"...Men will still say THIS was our finest hour"
If a tree falls in the woods and no one is there to see it, do all the other trees make fun of it?
-
Dec 16th, 2010, 12:10 PM
#26
Re: Serial Port not writing back
Originally Posted by dbasnett
Some of that code looks familiar, right down to the names.
I'm not surprised. Every time I find some slicker way to do this routine, I tweak the code and I know I've cribbed a lot of this routine off of here and Dick Grier's book. I believe the last change I did to it was fairly recently was I saw a way to use SerialPort.Read() rather than .ReadExisting() which I formerly used. The full routine though has a send-message queue, handles about 30 different scale indicators on the market, and has an off-thread that monitors connectivity and activity. It's also part of a UserControl and has a lot of UI functions for that as well.
Originally Posted by Dubya007
I'm a little unclear as to how to get the weight actually show up on the form now. (sorry I've not programmed like this in years)
Which sub or function will i have to call in order to accomplish this?
Ok, first, make SURE your Mettler Toledo indicator is turned on in a streaming mode (or you're not going to get anything anyways since it's not sending anything). You can check to see if you're getting data via a program like Hyperterminal or any other terminal emulator like Putty.
Streaming mode means the indicator is sending weight information all the time, non-stop, whether the computer is listening or not.
Call Open_SerialPort. At this point, the computer begins listening and you should immediately be getting data in. The weighScale_DataReceived() routine will automatically be firing as the port detects new data coming in; if you put a breakpoint in that routine, you'll see it get hit now.
If the breakpoint doesn't get hit, then there's no data coming in on the port and either your port settings are off, or the indicator isn't transmitting anything.
-
Aug 13th, 2011, 07:39 PM
#27
New Member
Re: Serial Port not writing back
-
Aug 13th, 2011, 07:40 PM
#28
New Member
Re: Serial Port not writing back
Jenner,
Is there any chance I can get the control you have designed for the multiple scale interfaces?
Thanks,
Henry
-
Aug 15th, 2011, 07:29 AM
#29
Re: Serial Port not writing back
It's posted in post #15. Just make a usercontrol, paste the code in and create some sort of display graphic for it. A label and/or a progressbar would work in a pinch. The code at the end is the part that updates the display.
I can't just give you mine because I'm using a third party library to display the graphics (Measurement Studio). I also have a lot of integration code that integrates it with the rest of my program.
-
Aug 15th, 2011, 11:30 PM
#30
New Member
Re: Serial Port not writing back
Jenner,
Thanks for your feedback/direction. I'm looking for a control that is designed for multiple scale interfaces such as the one you have designed. I'll be testing the code tomorrow and if it works I’ll be very interested in purchasing your code for the multiple interfaces minus the third party graphics.
Thanks,
Henry
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|