programming serial.data

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(", ");
      }
   }

Best,
Andy

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

arduino:

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);
    }  
}

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.

Best,
Andy

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.

Hi PaulS.
Ok, I've done something wrong here. I think I used char cause I use this code to split:

      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 remove(char *str, char r){
  char *p, *q;
  p = q = str;
  
  while (*p != '\0')
  {
    while (*p == r) p++;
    *q++ = *p++;
  }
  *q = '\0';
}

Do you have a tip of solving this problem of mine?

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.

Ok.

#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.

Meatloaf has a song called "2 out of 3 ain't bad". Unfortunately, 1 out of 3 is bad.

Sample output?
What is the problem?

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
    }
}

I hope this was understandable.

-Andy

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?

Thanks PaulS.
I'll try this out.

Hmm...
I've tested maaaaaaaaaaaany things now.

When I use this code:

void printTemperature (){
  Serial.print("s1:");
  Serial.print(int(Thermistor(sensorValue1)));
  Serial.print(", ");
  
  Serial.print("k1: 200,");
  Serial.println();
}

I get my k1 value, but when I call it like this:

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;
   }
}

Anyone understand why?
I'm confused...!

-Andy

I'm sorry to have to tell you this, but this is really some lousy code.

String ab;
     for(serOutIndx=0; serOutIndx < serInIndx; serOutIndx++){
       ab += serInString[serOutIndx];
     }

The += operator creates a new string object, and copies all the data from the old string object, for each character added to the string.

String ab(serInString);
would achieve the same end result, but with a lot less memory mangling going on.

Serial.println("k1: 234,");------------------------> I dont get this code. It appears in serial monitor,
but in VB I can't read it!!!!

Looks like a VB problem, then. What does your VB code to read serial data look like?

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;
   
   }
}

When I did this, I got value for "k1"

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).