Hi guys
Have some questions here. I have an Arduino board, with multiple input sensors and output LEDs.
I'm sending data every 30 seconds to a visual basic 2010 program. In this program, I will also send signals to the Arduino board to turn on the LED light, and dimming them.
My question is then:
What is the best way to send data?
And how should I treat the signal in the Arduino side.
This is what I have:
if(serInIndx > 0){
//Serial.print("You said: ");
//loop through all bytes in the array and print them out
for(serOutIndx=0; serOutIndx < serInIndx; serOutIndx++){
Serial.print(serInString[serOutIndx]); //print out the byte at the specified index
//serInString[serOutIndx] = ""; //optional: flush out the content
}
//reset all the functions to be able to fill the string back with content
serOutIndx = 0;
serInIndx = 0;
//serInString er texten i serial data!
remove(serInString, ' ');
char * token = strtok(serInString, ",");
int i = 0;
while(token){ // Do something with this word
Serial.print(token); // print as an ASCII-encoded decimal
Serial.print(", ");
// Lengden av stringe strlen (token).
token = strtok(NULL, ",");
i +=1;
//Serial.print(", ");
}
}
Can you describe in detail what is send over the line?
normally it is best to make some sort of packet: "<sensor1; sensor2; sensor3; sensor4;...>" Because of the "<>"char's the receiver knows when a packet starts/stops. You can even enhance this with a packetlength field a CRC etc.
This is true in both directions Arduino -> VB and vice versa
Hi robtillaart.
From my arduino, I send data like this, "s1: value, s2: value, d1: value, d2: value, etc..." where s: is analog input, and d: is digital input.
And since I wanna send setpoint such as "k1: 255, w1: 1, z1: time, etc..." where k: is a "analog" value and w: is high/low value.
The problem is when I receive data from my computer. Then I don't know how to split my data, to determ what is what.
Cause since I have various data sending, I need to split my data, find the first letter in the array, then remove the space between letters and remove the 3 first letters so I only have my values.
In vb this is the code:
For i = 0 To UBound(aryTextFile)
Dim countTextChar(i) As Integer
Dim myLeft(i) As String
Dim myInput(i) As String
Dim myText(i) As String
countTextChar(i) = Len(aryTextFile(i)) ' count letters in array
myInput(i) = Microsoft.VisualBasic.Left(aryTextFile(i), 1) ' find the first letter
myLeft(i) = Microsoft.VisualBasic.Left(aryTextFile(i), 3) ' find the 3 first letters
If myInput(i) = "s" Then
If myLeft(i) = "s1:" Then
myText(i) = Replace(aryTextFile(i), myLeft(i), "")
s1.Text = myText(i) & TempPrefix
End If
'And here comes the rest of the values you want to display in form.
End If
Next i
So this is my problem. I cant figure out how to determ what kind of data I recieve, and use this data later in arduino program.
Hope this was more explanatory.
The serInString is an array of characters. The String in the name implies that you want to use that array of characters as a string. A string is an array of characters THAT IS NULL TERMINATED.
You are not bothering to keep the string NULL terminated.
If you were, you could use any of the string-related functions in C to parse the string. strtok is worth looking at, IF you NULL terminate the string as required.
Do you have a tip of solving this problem of mine?
Sure. Post all of your code, not just the snippets where you think the problem might be. You have Serial.print statements, so some sample output would be good, too.
Also, an explanation of the problem. "I think I've done something wrong here" might not be true.
#include <math.h>
int ledPin = 10; // the number of the LED pin
int brightness = 0; // how bright the LED is
int buttonPin2 = 2; // the number of the pushbutton pin
int sensorValue1 = 0; // variable to store the value coming from the sensor
int sensorValue2 = 0; // variable to store the value coming from the sensor
int sensorPin1 = A0; // select the input pin for the potentiometer
int sensorPin2 = A1; // select the input pin for the potentiometer
int serIn; // var that will hold the bytes-in read from the serialBuffer
char serInString[1000]; // array that will hold the different bytes 100=100characters;
// -> you must state how long the array will be else it won't work.
int serInIndx = 0; // index of serInString[] in which to insert the next incoming byte
int serOutIndx = 0; // index of the outgoing serInString[] array;
//Oppsett for temperatur
double Thermistor(int RawADC) {
double Temp;
Temp = log(((10240000/RawADC) - 10000));
Temp = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * Temp * Temp ))* Temp );
Temp = (Temp - 273.15);
return Temp;
}
void readTemperature () {
sensorValue1 = analogRead(sensorPin1);
sensorValue2 = analogRead(sensorPin2);
}
void readSerialString () {
char sb;
if(Serial.available()) {
//Serial.print("reading Serial String: "); //optional confirmation
while (Serial.available()){
sb = Serial.read();
serInString[serInIndx] = sb;
serInIndx++;
//Serial.println(sb); //optional confirmation
}
//Serial.println(sb);
}
}
void printTemperature (){
Serial.print("s1: ");
Serial.print(int(Thermistor(sensorValue1)));
Serial.print(", ");
Serial.print("s2: ");
Serial.print(int(Thermistor(sensorValue2)));
Serial.print(", ");
Serial.println();
}
void printSerialString() {
if(serInIndx > 0){
//Serial.print("You said: ");
//loop through all bytes in the array and print them out
for(serOutIndx=0; serOutIndx < serInIndx; serOutIndx++){
Serial.print(serInString[serOutIndx]); //print out the byte at the specified index
//serInString[serOutIndx] = ""; //optional: flush out the content
}
//reset all the functions to be able to fill the string back with content
serOutIndx = 0;
serInIndx = 0;
//serInString er texten i serial data!
remove(serInString, ' ');
char * token = strtok(serInString, ",");
int i = 0;
while(token){ // Do something with this word
Serial.print(token); // print as an ASCII-encoded decimal
Serial.print(", ");
// Lengden av stringe strlen (token).
token = strtok(NULL, ",");
i +=1;
//Serial.print(", ");
}
}
}
void setup() {
Serial.begin(9600);
// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
// initialize the pushbutton pin as an input:
pinMode(sensorPin1, INPUT);
pinMode(buttonPin2, INPUT);
pinMode(buttonPin2, INPUT);
}
void loop(){
readTemperature();
readSerialString();
printTemperature();
printSerialString();
delay(1000);
// ******* End Program *******
}
void remove(char *str, char r){
char *p, *q;
p = q = str;
while (*p != '\0')
{
while (*p == r) p++;
*q++ = *p++;
}
*q = '\0';
}
What I wanna do with this, is to send values from arduino to Visual Basic and show the values in forms.
Then I'll send values from VB to arduino like LED on off, LED fade in out, setpoint to later use to example panel heaters.
The problem is I can't figure out how to "grab" the data I want. Like in html i use request.querystring("").
Cause when I send some values from VB, I don't know how to deal with the recieved data in Arduino side.
The data I recieve, is like:
"k1: 214," or "k4: 23," or "t1: on-07:00#off-23:00" or "w6: on,".
K is from k1-k20, w is from w1-w20, z is from z1-z6.
So what I need to do is:
Grab "k4: 23,", split in array if more values after ",". Replace " " to "". count letters, "5"("k4:23"), grab 3 first letters "k4:", then the rest "23".
Now I have something I can use in a if(), like
if (first letter == "k"){
if (first 3 letters =="k4"{
int k4value;
store in something so I coule use it later somewhere
}
}
You appear to have full control over the sending and receiving applications. Make it easy to parse the data. Instead of sending "k4: 23", send "k:4: 23".
Then, the tokens you will get are "k", "4", and " 23". The first token defines the action. The next two define the data, and can be converted to ints, using atoi().
For "t1: on-07:00#off-23:00", the on and off values are position dependent. One occurs before the #, while the other occurs after the #. There is, therefore, no reason to send the "on-" and "off-" parts. They make parsing the text more complicated than it needs to be. So, stop making life difficult for yourself. Send "t:1:07:00#23:00", instead. Then, the tokens are "t", "1", "07:00" (which can be parsed to "07" and "00"), and "23:00" (which can be parsed to "23" and "00"). The "t" is a command. The rest are to be converted to numbers.
The code you posted should be extracting the tokens. Does it work properly?
void printSerialString(){
if(serInIndx > 0){
String ab;
//Serial.println(serInIndx); // serInIndx er antall tall / bokstaver som er sendt i seriellport.
// serInString er texten i serial data!
//loop through all bytes in the array and print them out
for(serOutIndx=0; serOutIndx < serInIndx; serOutIndx++){
ab += serInString[serOutIndx];
}
String myData;
myData = ab;
Serial.println(myData);
Serial.println("k1: 234,");------------------------> I dont get this code. It appears in serial monitor,
but in VB I can't read it!!!!
myData = "";
serOutIndx = 0;
serInIndx = 0;
}
}
Hi PaulS.
I'm no c code guru. I've merged from PLC programming. Cause I'm curious aboute how things inside PLC are...
And I love creating my own stuff...
Here is my VB test program.
Imports System
Imports System.Threading
Imports System.IO
Imports System.IO.Ports
Public Class frmMain
Dim TempPrefix As String = " °C"
Dim PercentPrefix As String = " %"
Dim myPort As Array 'COM Ports detected on the system will be stored here
Delegate Sub SetTextCallback(ByVal [text] As String) 'Added to prevent threading errors during receiveing of data
Private Sub frmMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'When our form loads, auto detect all serial ports in the system and populate the cmbPort Combo box.
myPort = IO.Ports.SerialPort.GetPortNames() 'Get all com ports available
cmbBaud.Items.Add(9600) 'Populate the cmbBaud Combo box to common baud rates used
cmbBaud.Items.Add(19200)
cmbBaud.Items.Add(38400)
cmbBaud.Items.Add(57600)
cmbBaud.Items.Add(115200)
For i = 0 To UBound(myPort)
cmbPort.Items.Add(myPort(i))
Next
cmbPort.Text = cmbPort.Items.Item(0) 'Set cmbPort text to the first COM port detected
cmbBaud.Text = cmbBaud.Items.Item(0) 'Set cmbBaud text to the first Baud rate on the list
btnDisconnect.Enabled = False 'Initially Disconnect Button is Disabled
valueTextBox()
End Sub
Private Sub frmMain_Disposed(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Disposed
If SerialPort1.IsOpen() Then
SerialPort1.Close()
End If
End Sub
Private Sub btnConnect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnConnect.Click
SerialPort1.PortName = cmbPort.Text 'Set SerialPort1 to the selected COM port at startup
SerialPort1.BaudRate = cmbBaud.Text 'Set Baud rate to the selected value on
'Other Serial Port Property
SerialPort1.Parity = IO.Ports.Parity.None
SerialPort1.StopBits = IO.Ports.StopBits.One
SerialPort1.DataBits = 8 'Open our serial port
SerialPort1.Open()
btnConnect.Enabled = False 'Disable Connect button
btnDisconnect.Enabled = True 'and Enable Disconnect button
' Set the read/write timeouts
SerialPort1.ReadTimeout = 500
SerialPort1.WriteTimeout = 500
End Sub
Private Sub btnDisconnect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDisconnect.Click
SerialPort1.Close() 'Close our Serial Port
btnConnect.Enabled = True
btnDisconnect.Enabled = False
End Sub
'************************************************************************************************************
'this is where I get my serial data
Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
ReceivedText(SerialPort1.ReadExisting()) 'Automatically called every time a data is received at the serialPort
Thread.Sleep(1000)
End Sub
Private Sub ReceivedText(ByVal [text] As String)
'compares the ID of the creating Thread to the ID of the calling Thread
If Me.rtbReceived.InvokeRequired Then
Dim x As New SetTextCallback(AddressOf ReceivedText)
Me.Invoke(x, New Object() {(text)})
Else
Me.rtbReceived.Text &= [text]
End If
'************************************************************************************************************
'this is where I get handle my serial data
Dim myFile As String = [text]
Dim aryTextFile() As String
myFile = Replace(myFile, " ", "")
aryTextFile = myFile.Split(",")
'Sett inn sensorene her
Dim i As Integer
For i = 0 To UBound(aryTextFile)
Dim countTextChar(i) As Integer
Dim myLeft(i) As String
Dim myInput(i) As Char
Dim myText(i) As String
countTextChar(i) = Len(aryTextFile(i))
myInput(i) = Microsoft.VisualBasic.Left(aryTextFile(i), 1)
myLeft(i) = Microsoft.VisualBasic.Left(aryTextFile(i), 3)
Dim test As String = myInput(i)
'************************************************************************************************************
'this is where I get my k value.
If test = Chr(107) Then
MsgBox("k")
End If
If myInput(i) = Chr(107) Then
If myLeft(i) = "k1:" Then
myText(i) = Replace(aryTextFile(i), myLeft(i), "")
k1.Text = myText(i) & PercentPrefix
End If
End If
'************************************************************************************************************
If myInput(i) = Chr(115) Then
If myLeft(i) = "s1:" Then
myText(i) = Replace(aryTextFile(i), myLeft(i), "")
s1.Text = myText(i) & TempPrefix
End If
If myLeft(i) = "s2:" Then
myText(i) = Replace(aryTextFile(i), myLeft(i), "")
s2.Text = myText(i) & TempPrefix
End If
End If
Next i
End Sub
Private Sub cmbPort_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmbPort.SelectedIndexChanged
If SerialPort1.IsOpen = False Then
SerialPort1.PortName = cmbPort.Text 'pop a message box to user if he is changing ports
Else 'without disconnecting first.
MsgBox("Valid only if port is Closed", vbCritical)
End If
End Sub
Private Sub cmbBaud_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmbBaud.SelectedIndexChanged
If SerialPort1.IsOpen = False Then
SerialPort1.BaudRate = cmbBaud.Text 'pop a message box to user if he is changing baud rate
Else 'without disconnecting first.
MsgBox("Valid only if port is Closed", vbCritical)
End If
End Sub
Private Sub cmbTrackBar_Scroll(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmbTrackBar.Scroll
cmbTrackBar.Orientation = Orientation.Horizontal
cmbTrackBar.Minimum = 0
cmbTrackBar.Maximum = 255
'cmbTrackBar.
Dim TrackBar1
TrackBar1 = cmbTrackBar.Value
Label3.Text = TrackBar1 & " %"
End Sub
Private Sub cmdSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdSend.Click
SerialPort1.Write("Text fra data: " & rtbSend.Text & ",")
End Sub
Private Sub cmdClose_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdClose.Click
Me.Close()
If SerialPort1.IsOpen() Then
SerialPort1.Close()
End If
End Sub
Private Sub cmbTrackBar_MouseUp(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles cmbTrackBar.MouseUp
Dim TrackBar1
TrackBar1 = cmbTrackBar.Value
'SerialPort1.Write("k1:" & TrackBar1.ToString & "," & vbCr)
SerialPort1.Write("k1:" & TrackBar1.ToString & ",")
End Sub
Public Sub valueTextBox()
With k1
.Font = New Font("Microsoft Sans Serif", 8.0!, FontStyle.Bold)
.ForeColor = Color.DarkBlue
End With
With s1
.Font = New Font("Microsoft Sans Serif", 8.0!, FontStyle.Bold)
.ForeColor = Color.Black
End With
With s2
.Font = New Font("Microsoft Sans Serif", 8.0!, FontStyle.Bold)
.ForeColor = Color.Black
End With
End Sub
Private Sub rtbSend_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles rtbSend.MouseDown
rtbSend.Text = ""
End Sub
End Class
But should I write "String ab(serInString);" inside my printSerialString()?
-Andy
Hmmm....
I thought I was confused earlier...! But when I wrote "Serial.print(myData); Serial.print(myData);", VB could read the data!
void printSerialString (){
if(serInIndx > 0){
/*
String ab(serInString);
Serial.print(ab);
Serial.println();
*/
String ab;
//Serial.println(serInIndx); // serInIndx er antall tall / bokstaver som er sendt i seriellport.
// serInString er text'en i serial data!
for(serOutIndx=0; serOutIndx < serInIndx; serOutIndx++){ //loop through all bytes in the array and print them out
ab += serInString[serOutIndx];
}
String myData;
myData = ab;
Serial.print(myData); Serial.print(myData);
Serial.println();
myData = "";
serOutIndx = 0;
serInIndx = 0;
}
}
I'm not sure what Serial.print() or println() does with String objects. There really is no reason for you to be using them (yet). You can simply Serial.print(ln)(serInString).