1

I'm trying to make a voltage/temp logger that will post to SQL. I'm using a WPF to make kind of a UI for people to measure the voltage of a cell, and take the temp of the battery acid in the battery. My end goal is to have the Arduino Bluetooth to a computer. the computer will handle all the SQL. The Arduino will have a physical button to post or save the data to my SQL server. Also the Arduino will have a little display to display the battery S/N, Voltage, Temp. (Side Question: Am I going to be able to do the screen and access the serial, with also sending the serial data over Bluetooth?)

My problem is that when I call my function to get that data sometimes it comes out messed up. Sometimes I get, for example: "3.1234 V=" Or "V= 3.123V=" It also happens with the temperature, sometimes I get the voltage in the temp box and vice versa.

More times than not I get a bad result. When I run it in the Serial Monitor with the Arduino IDE It looks fine. Does anyone have any advice how I can clean up the communication and get more reliable results?

Thanks for any help!

I'm using to place the serial port string into a textbox.

txt_Volt.Text = sp.ReadExisting(); 

I tried using the Serial.flush(); to clear out any old stuff to no avail.

The Arduino code:

else if (c == '3')
 {
   int analog_value = analogRead(A0);
   volt = (analog_value * 5.0) / 1024.0;
   Serial.print("v= ");
   Serial.print(volt, 5);
   Serial.flush();
}

Arduino loop():

void loop() {
  if (Serial.available() > 0)
  { Serial.flush();
    char c = Serial.read();
    if (c == '1')
    {
      digitalWrite(13, HIGH);
      Serial.println("LED is On");
      Serial.flush();
    }

    else if (c == '0')
    {
      digitalWrite(13, LOW);
      Serial.println("LED is off");
      Serial.flush();
    }
    else if (c == '3')
    {
      int analog_value = analogRead(A0);
      volt = (analog_value * 5.0) / 1024.0;
      Serial.print("v= ");
      Serial.print(volt, 5);
      Serial.flush();
    }
    else if (c == '4')
    {
      //Temp Function go HERE
      getTemp();
    }

C# CODE:

         private void Connect_Click(object sender, RoutedEventArgs e)
         {
           while (portNum >= 0) //automaticly connect to correct port.
           {
            try
            {
                String portName = "COM" + portNum;
                comportno.Text = portName;
                //String portName = comportno.Text;
                sp.PortName = portName;
                sp.BaudRate = 9600;
                sp.Open();
                status.Text = "Connected";
            }
            catch (Exception)
            {
                portNum--;
                // MessageBox.Show("Please give a valid port number or check your connection");
                if (portNum == -1)
                {
                    MessageBox.Show("Could not find Arduino\nCheck Connection");
                }
            }
        }

    }

    private void Disconnect_Click(object sender, RoutedEventArgs e)
    {
        try
        {
            sp.Close();
            status.Text = "Disconnected";
        }
        catch (Exception)
        {

            MessageBox.Show("First Connect and then disconnect");
        }
    }

    private void on_Click(object sender, RoutedEventArgs e)
    {
        sp.Write("1");
        rect_LED.Fill = new SolidColorBrush(Color.FromRgb(0, 255, 0));
        // DebugWindow.Text = sp.ReadExisting();
        //  readingStuff();
    }

    private void Of_Click(object sender, RoutedEventArgs e)
    {
        sp.Write("0");
        rect_LED.Fill = new SolidColorBrush(Color.FromRgb(0, 0, 0));
        //  DebugWindow.Text = sp.ReadExisting();
        //  readingStuff();
    }

    private void Get_Volt_On_Click(object sender, RoutedEventArgs e)
    {

        sp.Write("3");
        string volts = sp.ReadExisting();
        int volt_length = volts.Length;

        bool isLetter = !String.IsNullOrEmpty(volts) && Char.IsLetter(volts[0]) && Char.IsDigit(volts[volt_length - 1]);

        if (isLetter)
        {
            DebugWindow.Text = volts;
        }
        else
        {
            DebugWindow.Text = "Error";
            sp.Write("3");
        }
    }

    private void Get_Temp_On_Click(object sender, RoutedEventArgs e)
    {
        sp.Write("4");
        txt_Volt.Text = sp.ReadExisting();
    }

    void readingStuff()
    {
        String comdata = sp.ReadLine();
        Dispatcher.Invoke((Action)(() => DebugWindow.Text += "Data\n" + comdata + "\n"));
    }

What a bad result looks like:

Bad Results

A Good result:

Good

1

Your problem arises from a mix of newline-terminated and un-terminated messages.

The newline terminated values probably would work by themselves as you can use a ReadLine() type method to wait until they have been completely transferred.

But the non-terminated attempts such as your use of the ReadExisting() method cause a problem - these likely fetch whatever has been received up to the time of the call but that will not necessarily be the full message sent (or even anything at all). Whatever is left over (had not been received by the time of the call) will become the beginning of the data achieved during the next partial or until-newline read.

As a solution you should probably either:

  • Terminate each message with a newline

or else

  • Always read only complete lines, and then parse individual messages out of them

or

  • Always read until you find some delimiter character such as a space or comma, or a newline. You may have to write your own read method to accomplish this.

Using delays to try to fix a problem like this is bad practice as it is fragile and can easily break if there is an unexpected delay on the other side, or if the execution speed of one of the components changes. A number of fragile techniques that generally worked with true serial ports subsequently broke when USB converters were introduced in the middle, as USB bunches data into packets with gaps in between, a behavior not necessarily previously seen in many pure serial implementations.

  • So if I wanted to read both voltage and temp at the same time, I would have to have the Serial.print(volts) and Serial.println(temp) then have some way of breaking the string apart in my C# code? – Mason Younger May 20 '16 at 19:16
  • That is one way (if you put something in between) the point is that reads not looking for a defined end condition in the data itself are causing your trouble. – Chris Stratton May 20 '16 at 19:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.