Serial Port Send Data in VB.NET with Packed message - vb.net

I have the Manual of Programming protocol, but when I write code vb.net returns error message.
The following is the table structure of bytes array
position 1 2 3 4 5 6 7 8
Name SOH LEN SEQ CMD DATA Post-amble BCC ETX
Lenth/bytes 1 1 1 1 0-200 1 4 1
Value (01h) (20h-FFh) (20h-FFh) (20h-FFh) (20h-FFh) (05h) (30h-3Fh) (03h)
Abbreviations:
“SOH”- (Start Of Heading) start of packed message
“LEN”- total number of bytes from position 2 to position 6, plus fixed offset of 20h.
“SEQ”- serial number of packet. SLAVE puts the same “SEQ” in the reply message. In case when SLAVE
receives a message with the same “SEQ”and “CMD” like the last correctly received message, the device ignores
the message and repeats the last packet sent to the HOST.
“CMD” – code of command
“DATA”- data, according to the command. If there is no data, the length field is zero.
“BCC” – control sum(0000h-FFFFh). Sum of data bytes from position 2 to position 6. The control sum is
transferred in ASCІІ type (12АВ is transferred as 31h 32h 3Аh 3Вh).
“ETX” – (End of TeXt) end of packed message.
Codes sample:
Public Class Form1
Private WithEvents sp As System.IO.Ports.SerialPort
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
For Each y As String In System.IO.Ports.SerialPort.GetPortNames
Me.ComboBox1.Items.Add(y)
Next
sp = New IO.Ports.SerialPort("COM4")
sp.StopBits = IO.Ports.StopBits.One
sp.BaudRate = 9600
sp.DataBits = 8
sp.Parity = IO.Ports.Parity.None
sp.Handshake = IO.Ports.Handshake.None
sp.Open()
Dim by As Byte = &H20
' MsgBox(&H20)
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Try
Dim By(9) As Byte
By(0) = 1
By(1) = &H2 + &H20
By(2) = &H58
By(3) = &H45
By(4) = &H5
Dim S As String = Hex(&H58 Xor &H45)
' MsgBox(S)
By(5) = &H30
By(6) = &H30
By(7) = &H31
By(8) = &H3D
By(9) = &H3
sp.Write(By, 0, By.Length - 1)
' MsgBox(sp.ReadByte)
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
Private Sub sp_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles sp.DataReceived
Dim rec As System.IO.Ports.SerialPort = sender
MsgBox(Hex(rec.ReadByte))
End Sub
End Class

Annael you could probably do this, by invoking an updating function and giving a delay of 500ms will make a difference. Now on receiving data you can receive input data
Dim inputData As String = ""// Declare this as a global variable in the program
Private WithEvents sp As System.IO.Ports.SerialPort
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
For Each y As String In System.IO.Ports.SerialPort.GetPortNames
Me.ComboBox1.Items.Add(y)//the code you have written to add Serial ports
SerialPort1.PortName = ComboBox1.Text//this will access your com port as your button
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim by As Byte = &H20
By(0) = 1
By(1) = &H2 + &H20
By(2) = &H58
By(3) = &H45
By(4) = &H5
Dim S As String = Hex(&H58 Xor &H45)
' MsgBox(S)
By(5) = &H30
By(6) = &H30
By(7) = &H31
By(8) = &H3D
By(9) = &H3
SerialPort1.BaudRate = 115200
SerialPort1.Open()
SerialPort1.Write(By)
Private Sub SerialPort1_DataReceived(sender As System.Object, e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
Threading.Thread.Sleep(500) ' 500ms delay induced to receive the email
inputData = SerialPort1.ReadExisting 'or SerialPort1.ReadLine
Me.Invoke(New EventHandler(AddressOf DoUpdate))
Public Sub DoUpdate()
MsgBox(inputData)

Related

VB.NET Serial Port reading HEX data and insert in the textbox

I want to read the data from UHF RFID reader that is connected on one of my com port, the data should be in HEX and must be a complete HEX that should be pasted in the textbox in my windows form application that I made in VB.NET.
Kindly help me I am new in VB.NET Programming.I need a vb.net code for this task:
My code:
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For Each s In System.IO.Ports.SerialPort.GetPortNames()
ComboBox1.Items.Add(s)
Next s
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If ComboBox1.SelectedIndex = -1 Then
MessageBox.Show("Please select a port")
Exit Sub
Else
SerialPort1.BaudRate = 9600
SerialPort1.DataBits = 8
SerialPort1.Parity = IO.Ports.Parity.None
SerialPort1.StopBits = IO.Ports.StopBits.One
SerialPort1.PortName = ComboBox1.SelectedItem.ToString
SerialPort1.Open()
End If
End Sub
Private Shared buffer As String = ""
Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
Try
Dim rcv As String = _SerialPort1.ReadExisting()
buffer = String.Concat(buffer, rcv)
Dim hexVal As Integer
hexVal = Convert.ToInt32(rcv, 16) '16 specifies the base
txtReceived.Text = hexVal
Catch ex As Exception
End Try
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
SerialPort1.Close()
End Sub
End Class
I see your problem..
the line
hexVal = Convert.ToInt32(c, 16) '16 specifies the base
is trying to convert a character to int32, but the function is assuming that the incoming value is already hexadecimal and you're getting a completely wrong answer.
Incidentally, your data is 8 bit binary and your serial port reader reads each 8 bits as a char type.
What you need is to use the VB built in function Hex, which takes an integer/byte (in this case the ascii code of each character) and returns a hex value as a string so
Dim x As Integer = 15
Dim s As String = hex(x)
will assign "F" to the string
All well and good. However, If you want a 2 digit hex string, you'll need to check if the returned string is only one character and if it is, add a "0" to the beginning.
So, your lines
Dim hexVal As Integer
hexVal = Convert.ToInt32(rcv, 16) '16 specifies the base
txtReceived.Text = hexVal
should be replaced with ..
Dim hexVal As string =""
For Each c As Char In rcv
hexVal = heval & AsciiCharToHexSring(c)
Next
txtReceived.Text = hexVal
and add this function to convert the character and add a "0" if necessary ..
Private Function AsciiCharToHexSring(s As Char) As String
Dim hexdigit As String = Hex(Asc(s))
If hexdigit.Length = 1 Then
hexdigit = "0" & hexdigit
End If
Return hexdigit
End Function
If you don't need a 2 digit hex number every time, just delete the If..End If block

code modified lines added

I have data like this
date value
24sep2014 2:23:01 0.1
24sep2014 2:23:02 0.3
24sep2014 2:23:03 0.2
24sep2014 2:23:04 0.3
These are not coma seprated value. I wanted to write in CSV file. Apend the value for next row.
1)How to open file only once here. when it run next time file name has to change to other name
2) How to append the next values
Imports System
Imports System.IO.Ports
Imports System.ComponentModel
Imports System.Threading
Imports System.Drawing
Imports System.Windows.Forms.DataVisualization.Charting
Public Class Form1
Dim myPort As Array
Dim Distance As Integer
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
myPort = IO.Ports.SerialPort.GetPortNames()
PortComboBox.Items.AddRange(myPort)
BaudComboBox.Items.Add(9600)
BaudComboBox.Items.Add(19200)
BaudComboBox.Items.Add(38400)
BaudComboBox.Items.Add(57600)
BaudComboBox.Items.Add(115200)
ConnectButton.Enabled = True
DisconnectButton.Enabled = False
Chart1.Series.Clear()
Chart1.Titles.Add("Demo")
'Create a new series and add data points to it.
Dim s As New Series
s.Name = "CURRENT"
s.ChartType = SeriesChartType.Line
End Sub
Private Sub ConnectButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ConnectButton.Click
SerialPort1.PortName = PortComboBox.Text
SerialPort1.BaudRate = BaudComboBox.Text
SerialPort1.Open()
Timer1.Start()
Timer2.Start()
'lblMessage.Text = PortComboBox.Text & " Connected."
ConnectButton.Enabled = False
DisconnectButton.Enabled = True
End Sub
Private Sub DisconnectButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DisconnectButton.Click
SerialPort1.Close()
DisconnectButton.Enabled = False
ConnectButton.Enabled = True
End Sub
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
Dim counter As Integer
counter = 0
Try
SerialPort1.Write("c")
System.Threading.Thread.Sleep(250)
Dim k As Double
Dim distance As String = SerialPort1.ReadLine()
k = CDbl(distance)
ListBoxSensor.Text = k
Dim s As New Series
s.Points.AddXY(1000, k)
Chart1.Series.Add(s)
Dim headerText = ""
Dim csvFile As String = Path.Combine(My.Application.Info.DirectoryPath, "Current.csv")
If Not File.Exists(csvFile)) Then
headerText = "Date& time ,Current"
End If
Using outFile = My.Computer.FileSystem.OpenTextFileWriter(csvFile, True)
If headerText.Length > 0 Then
outFile.WriteLine(headerText)
End If
Dim y As String = DateAndTime.Now
Dim x As String = y + "," + distance
outFile.WriteLine(x)
End Using
Catch ex As Exception
End Try
End Sub
Private Sub Relay_ON_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Relay_ON.Click
SerialPort1.Write("1")
End Sub
Private Sub Relay_Off_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Relay_Off.Click
SerialPort1.Write("0")
End Sub
End Class
Here i am opening file again and again. that reason i can store only one value
# steve error
The second parameter of OpenTextFileWriter allows to append instead of overwrite your file.
So it is simply a matter to check if the file exists (so you insert the header names) and then write your data
Dim headerText = ""
Dim csvFile As String = Path.Combine(My.Application.Info.DirectoryPath, "Current.csv")
If Not File.Exists(csvFile) Then
headerText = "Date& time ,Current"
End If
Using outFile = My.Computer.FileSystem.OpenTextFileWriter(csvFile, True)
If headerText.Length > 0 Then
outFile.WriteLine(headerText)
End If
Dim y As String = DateAndTime.Now
Dim x As String = y + "," + distance
outFile.WriteLine(x)
End Using
Notice the Using Statement to be sure to close and dispose the file resource also in case of exceptions.
However given the simple text that need to be written you could also choose to use the method WriteAllText
Dim headerText = ""
Dim csvFile As String = Path.Combine(My.Application.Info.DirectoryPath, "Current.csv")
If Not File.Exists(csvFile) Then
headerText = "Date& time ,Current" & Environment.NewLine
End If
Dim y As String = DateAndTime.Now
Dim x As String = headerText & y & "," + distance & Environment.NewLine
My.Computer.FileSystem.WriteAllText(csvFile, x, True)

Run Random event once?

The code below runs and keeps repeating over and over again. I only pasted the up_timer but others do the same. Any ideas on how to make it run once, then repeat to the random loop and so on?
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
Application.DoEvents()
Randomize()
Dim value As Integer = CInt(Int((4 * Rnd()) + 1))
If value = 1 Then
MsgBox("Up")
up.Start()
ElseIf value = 2 Then
MsgBox("Down")
down.Start()
ElseIf value = 3 Then
MsgBox("Left")
left.Start()
ElseIf value = 4 Then
MsgBox("Right")
right.Start()
End If
Timer1.Stop()
End Sub
Private Sub up_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles up.Tick
Static moveCount As Integer = 1
If Me.mob2.Location.Y > 12 Then
Me.mob2.Location = New Point(Me.mob2.Location.X, Me.mob2.Location.Y - 5)
End If
moveCount += 1
If moveCount = 10 Then
moveCount = 1
Me.Timer1.Start()
Me.up.Stop()
End If
End Sub
Looks like this is what you need, based on your complaint that timer1 repeats same numbers
Dim rand1 As New Random(CInt(Date.Now.Ticks And &h0000FFFF))
Dim value As Integer = rand1.Next(1, 4)
This will not repeat
Plus, you have to move Timer1.Stop() to beginning of the method

The button.BackColor statement seem to be executed, but no colour change is show

I'm trying to re-create the classic game "Simon" for a project. The code I have here should hopefully create a random number, translate that to a colour change for a random button, wait a short time, and then do the same for another random button. I can't spot any problems, but on execution the buttons remain uchanged.
Public Class MenuForm
Dim failure As Boolean
Dim pattern() As Integer
Dim maincounter As Integer = 1
Dim diff As Integer
Dim sender As Object
Dim e As EventArgs
Dim timewaited As Integer
Dim timefinished As Boolean
Private Sub Menuform_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Get the difficulty level from the player
Dim InputtedDifficulty As Integer = InputBox("Please enter difficulty. 1-Easy 2-Medium 3-Hard")
'Validate difficulty choice
Do While InputtedDifficulty > 3 Or InputtedDifficulty < 1
InputtedDifficulty = InputBox("Input incorrect. Please re-enter selection. 1-Easy 2-Medium 3-Hard")
Loop
'Set speed of blinking based on difficulty choice
Select Case InputtedDifficulty
Case 1
diff = 1000
Case 2
diff = 500
Case 3
diff = 20
End Select
End Sub
Private Sub run_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles run.Click
Call GameController()
End Sub
Private Sub GameController()
Dim buttonRepeater As Integer
'Call checkFail()
Do While failure = False
maincounter = maincounter + 1
Call Pattern_creator(sender, e)
For buttonRepeater = 1 To maincounter
Call button_controller(sender, e)
timewaited = 0
timefinished = False
ButtonTimer.Enabled = True
If timefinished = True Then
End If
Button1.BackColor = Color.Blue
Button2.BackColor = Color.Blue
Button3.BackColor = Color.Blue
Button4.BackColor = Color.Blue
Next buttonRepeater
Loop
End Sub
Private Sub Pattern_creator(ByVal sender As System.Object, ByVal e As System.EventArgs)
ReDim Preserve pattern(maincounter)
Randomize()
pattern(maincounter) = Int((Rnd() * 4) + 1)
ReDim Preserve pattern(maincounter + 1)
End Sub
Private Sub button_controller(ByVal sender As System.Object, ByVal e As System.EventArgs)
'Ths case statement takes the random number generated earlier and translates that to
'a button flash
Select Case pattern(maincounter)
Case 1
Button1.BackColor = Color.Red
Case 2
Button2.BackColor = Color.Red
Case 3
Button3.BackColor = Color.Red
Case 4
Button4.BackColor = Color.Red
End Select
End Sub
Private Sub ButtonTimer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonTimer.Tick
If timewaited = 5 Then
ButtonTimer.Enabled = False
timefinished = True
Else
timewaited = timewaited + 1
End If
End Sub
End Class
Any help would be very much appreciated, I've been staring at this for ages with no progress.

How can I reduce this code to a single procedure

I am relatively new to the whole .NET thing, coming from a VB classic background.
On my form I have a tabcontrol, with 4 tabs. Most of the code is handled using a shared handler, but for the others I have to write a handler for each.
How can I optimize these routines into a single procedure?
Private Sub cboCalc0_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cboCalc0.SelectedIndexChanged
'Page 0
If (Not (IsNothing(trvSignals0.SelectedNode)) And txtSignalName0.Enabled = True) AndAlso trvSignals0.SelectedNode.Level = 3 Then
tempChannelProp(0, trvSignals0.SelectedNode.Tag).CalcVariant = cboCalc0.SelectedIndex
End If
End Sub
Private Sub cboCalc1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cboCalc1.SelectedIndexChanged
'Page 1
If (Not (IsNothing(trvSignals1.SelectedNode)) And txtSignalName0.Enabled = True) AndAlso trvSignals1.SelectedNode.Level = 3 Then
tempChannelProp(1, trvSignals1.SelectedNode.Tag).CalcVariant = cboCalc1.SelectedIndex
End If
End Sub
Private Sub cboCalc2_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cboCalc2.SelectedIndexChanged
'Page 2
If (Not (IsNothing(trvSignals2.SelectedNode)) And txtSignalName2.Enabled = True) AndAlso trvSignals2.SelectedNode.Level = 3 Then
tempChannelProp(2, trvSignals2.SelectedNode.Tag).CalcVariant = cboCalc2.SelectedIndex
End If
End Sub
Private Sub cboCalc3_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cboCalc3.SelectedIndexChanged
'Page 3
If (Not (IsNothing(trvSignals3.SelectedNode)) And txtSignalName3.Enabled = True) AndAlso trvSignals3.SelectedNode.Level = 3 Then
tempChannelProp(3, trvSignals3.SelectedNode.Tag).CalcVariant = cboCalc3.SelectedIndex
End If
End Sub
I have handled the other bits as follows, and it works great, but I just cannot figure out how to do it with code like that above.
Private Sub trvSignals_AfterCheck(ByVal sender As Object, ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles trvSignals0.AfterCheck, trvSignals1.AfterCheck, trvSignals2.AfterCheck, trvSignals3.AfterCheck
'Handles Page 0,1,2,3
sender.SelectedNode = e.Node
If e.Node.Level = 3 Then
tempChannelProp(sender.tag, e.Node.Tag).Active = e.Node.Checked
End If
End Sub
I use the tag property of the control of each page to hold either 0,1,2 or 3 as appropriate.
Thanks
Graham
Create control arrays that you can reference by index, and put the index in each controls' Tag.
Class MyForm
Private ReadOnly cboCalcArray As ComboBox()
Private ReadOnly trvSignalsArray As TreeView()
Private ReadOnly txtSignalNameArray As TextBox()
Public Sub New()
InitializeComponent()
cboCalcArray = new ComboBox() {cboCalc0, cboCalc1, cboCalc2, cboCalc3}
trvSignalsArray = new TreeView() {trvSignals0, trvSignals1, trvSignals2, trvSignals3}
txtSignalNameArray = new TextBox() {txtSignalName0, txtSignalName1, txtSignalName2, txtSignalName3}
End Sub
Private Sub cboCalcX_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs) _
Handles cboCalc0.SelectedIndexChanged,
cboCalc1.SelectedIndexChanged,
cboCalc2.SelectedIndexChanged,
cboCalc3.SelectedIndexChanged
Dim index As Integer = sender.Tag
If (Not (IsNothing(trvSignalsArray(index).SelectedNode)) And txtSignalNameArray(index).Enabled = True) AndAlso trvSignals2.SelectedNode.Level = 3 Then
tempChannelProp(index, trvSignalsArray(index).SelectedNode.Tag).CalcVariant = cboCalcArray(index).SelectedIndex
End If
End Sub
End Class
You can leverage a couple of features:
1) The VB Handles statement can hook multiple control events to the same method.
2) You can get the combobox from the sender, then extract the index.
3) From the index, you can find the other associated controls.
Private Sub cboCalc_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cboCalc0.SelectedIndexChanged, cboCalc1.SelectedIndexChanged, cboCalc2.SelectedIndexChanged, cboCalc3.SelectedIndexChanged
Dim oCombo As ComboBox
oCombo = DirectCast(sender, ComboBox)
Dim wIndex As Integer
Dim oTree As TreeView
Dim oTextBox As TextBox
wIndex = CInt(oCombo.Name.Substring(oCombo.Name.Length - 1))
oTree = DirectCast(Me.Controls.Find("trvSignals" & wIndex.ToString, True)(0), TreeView)
oTextBox = DirectCast(Me.Controls.Find("txtSignalName" & wIndex.ToString, True)(0), TextBox)
If oTree.SelectedNode IsNot Nothing AndAlso oTextBox.Enabled AndAlso oTree.SelectedNode.Level = 3 Then
tempChannelProp(wIndex, oTree.SelectedNode.Tag).CalcVariant = oCombo.SelectedIndex
End If
End Sub
There is likely a more elegant solution to your problem somewhere. I find that, if I am defining the same controls and methods for multiplpe tabs on a tab control, it might be time to examine my design . . . Not always, though. :-)
This might be a little less clumsy, although using Select Case to choose between otherwise identical configurations of UI elements gives me the heebie-jeebies (It DOES get all your code into one handler, however):
Private Sub PerformCalcs(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles _
cboCalc0.SelectedIndexChanged,
cboCalc1.SelectedIndexChanged,
cboCalc2.SelectedIndexChanged,
cboCalc3.SelectedIndexChanged
Dim cboCalc As ComboBox = DirectCast(sender, ComboBox)
' The Parent of the combo box is the TabPage, and the Parent of the TabPage is the TabControl:
Dim t As TabControl = cboCalc.Parent.Parent
Dim SelectedNode As TreeNode
Dim TxtSignalName As TextBox
' The TabControl knows the index value of the currently selected tab:
Select Case t.SelectedIndex
Case 0 'Page 0
SelectedNode = trvSignals0.SelectedNode
TxtSignalName = txtSignalName0
Case 1 ' Page 1
SelectedNode = trvSignals1.SelectedNode
TxtSignalName = txtSignalName1
Case 2 ' Page 2
SelectedNode = trvSignals2.SelectedNode
TxtSignalName = txtSignalName2
Case 3 ' Page 3
SelectedNode = trvSignals3.SelectedNode
TxtSignalName = txtSignalName3
Case Else ' Ooops! Something horrible happened!
Throw New System.Exception("You have passed an invalid Control as a parameter")
End Select
If (Not (IsNothing(SelectedNode)) And TxtSignalName.Enabled = True) AndAlso trvSignals3.SelectedNode.Level = 3 Then
tempChannelProp(3, SelectedNode.Tag).CalcVariant = cboCalc.SelectedIndex
End If
End Sub