Visual C# and Arduino, Arduino freezes after receiving serial data

In my learning project, I running visual C# that sends a number through serial to the arduino, in arduino I have it convert the received data into a usable int, then flash an led on/off accordingly to the number it received.

My Visual C# sketch has two buttons, one button sends "5" the other one sends "12".

It works, but only a few times. After a random amount of clicks, the arduino will not respond to the incoming data. Why is that???
I can't use the serial.print to help debug as I am using an ftdi basic in windows/VMware, arduino is running on my Mac. That is the main reason I am flashing an led accordingly, to see if it is receiving/converting correctly.

Arduino Code:

#include<stdlib.h>


int ledPin = 15;    // LED connected to digital pin 9

int cnt=0;

void setup()  { 
  Serial.begin(115200); 
  pinMode(ledPin,OUTPUT);
} 

void loop()  { 
  

 
 if (Serial.available() > 0){
 
 static char input[16];
 static uint8_t i; 
char c = Serial.read (); 
  
     if ( c != '^' && i < 15 ){ // assuming "Carriage Return" is chosen in the Serial monitor as the line ending character
    input[i++] = c;
     }
     
     else
     {      
    input[i] = '\0';
    i = 0;
      
    int number = atoi( input );
    
     for(int i=0; i<number; i++){  
     digitalWrite(ledPin, HIGH);
     delay(30);
     digitalWrite(ledPin, LOW);
     delay(220);
     }
    
     }     
      }
 
    }

How to use this forum

Meaning: post your code within [ code ] tags. See section 7 of the linked document.

By the way, I am a bit surprised that the code works, if only a few times. What is the ascii value for a digit (0..9)? Not less than 15. But when receiving a value not less than 15, nothing is written in the input buffer.

if ( c != '^' && i < 15 ) // c is copied only if it less than 15
{
  input[i++] = c;
}

So you go to the atoi() part, but before doing that:

input = '\0';

which replaces the address of the input array with a value which points who knows where.

So when you do the atoi() you are transforming the content of this unknown memory position into a number, and the conversion is somewhat successful and the led blinks. Then the same process is repeated, but it's only a matter of chance that atoi() will continue to return a number.

You logic to determine whether you have received the end-of-line is flawed. An end-of-line would usually consist of '\r' or '\n' or both. I suggest you treat either of these as the end of line.

I also suggest that you check for more than zero characters having been received before you try to process them, and check that the input buffer is not already full before appending to it (remember to allow space for the null terminator).

Finally, although you do null-terminate the string before processing it, I suggest you do this at the point of appending a character to the array rather than doing it later.

input[i++] = c;
input[i] = '\0';

Hmm ok. I guess am just having trouble wrapping my head around this.

So I should change it to:

if ( c != '^')
{
  input[i++] = c;
}

and don't use "input = '\0';" ? because it is redundant, and it does throw away the last char?

So I tried:

 if (Serial.available() > 0){

 static uint8_t i; 
char c = Serial.read (); 
  
     if ( c != '\n'){ // assuming "Carriage Return" is chosen in the Serial monitor as the line ending character
    input[i++] = c;
     }
     
     else
     {      
    input[i] = '\0';
    i = 0;
      
    int number = atoi( input );
    
     for(int i=0; i<number; i++){  
     digitalWrite(ledPin, HIGH);
     delay(30);
     digitalWrite(ledPin, LOW);
     delay(220);
     }
    reset();
     }     
      }

 void reset(){  
   for(uint8_t i=0; i<16; i++) input[i] = '0';
 }

only '\n' will work, I get no response from '\r',

and after the 4th time sending a number over, the led then continuously blinks. So this could be because my buffer is full?

This seems to work much better, but still fails after a while. I don't understand why this is failing.

void loop()  { 
  

 
 if (Serial.available()){
delay(3);
static uint8_t i; 
char c = Serial.read(); 
  
  if(i>15){i=0; reset();}
  
     if ( c != '\n'){ // assuming "Carriage Return" is chosen in the Serial monitor as the line ending character
    input[i++] = c;
     }
     
     else
     {      
    input[i] = '\0';
    i = 0;
      
    int number = atoi( input );
    
     for(int i=0; i<number; i++){  
     digitalWrite(ledPin, HIGH);
     delay(30);
     digitalWrite(ledPin, LOW);
     delay(220);
     }
         
     }  
        
      }
    }
    
    
 void reset(){  
   for(uint8_t i=0; i<16; i++) input[i] = '0';
 }

I can't imagine sending lots a data without any errors this way.

No. These two lines together in this order append a character c to the string. First one appends the character, second follows that with the null terminator.

input[i++] = c;
input[i] = '\0';

I suggest you check that the input buffer isn't already full before you append to it.

Also, check for either '\r' (carriage return) or '\n' (newline) as end-of-line markers - currently you're only checking for '\n'.

I get no response when:

if ( c != '\n' || c != '\r')

How to I check if the input buffer is full?

I made a very simple program that sends an 'a' or 'b'. The arduino will turn on an led when it reads 'a' and turn the led off when it reads 'b', but even that simple program doesn't work consistently. I also bounced the serial data back to visual C# to see what arduino read,
and it'll read 98 and 97 (which is correct), then 0 or 255, sometimes random numbers, then simply freezes.

After reading a lot about the micro controller I am using which is a breadboard 1284p DIP package, I found out that there have been timing issues with the ftdi and interference issues with xtal1 and xtal2. So I am going to grab a breakout for the AU package and see if I get more consistent communication.

Arduino Code:

#include<stdlib.h>


int ledPin = 15;    // LED connected to digital pin 9

void setup()  { 
  Serial.begin(9600); 
  pinMode(ledPin,OUTPUT);
} 

void loop()  { 
  
  if (Serial.available() > 0) {
    char inByte = Serial.read();
    switch (inByte) {
    case 'a':    
      digitalWrite(ledPin, HIGH);
      break;
    case 'b':    
      digitalWrite(ledPin, LOW);
      break;
    default:
      // turn all the LEDs off:
        digitalWrite(ledPin, LOW);
      
    }
   
   Serial.write(inByte);
    
  }
  
}

Visual C# Code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.IO.Ports;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
   
        public static System.IO.Ports.SerialPort serialPort1;
        private delegate void LineReceivedEvent(string line);
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e) // Connect Button
        {
            
            System.ComponentModel.IContainer components = new System.ComponentModel.Container();
            serialPort1 = new System.IO.Ports.SerialPort(components); // Creating the new object.
            serialPort1.PortName = "COM" + numericUpDown1.Value.ToString(); // Setting what port number.
            serialPort1.BaudRate = 9600;
            serialPort1.DtrEnable = true;
            //serialPort1.Open(); // Open the port for use.
            button1.Text = "Connected.";
            //MessageBox.Show("Connected.");
            button1.Enabled = false;
            numericUpDown1.Enabled = false;

        }

        private void numericUpDown1_ValueChanged(object sender, EventArgs e)
        {

        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (serialPort1.IsOpen) serialPort1.Close();
        }   



        private void OFF_Click(object sender, EventArgs e)
        {

            serialPort1.Open();
            if (serialPort1.IsOpen)
            {
                serialPort1.Write("b");
              //  serialPort1.DiscardInBuffer();
            }
            int get = serialPort1.ReadByte();
            MessageBox.Show(get.ToString());
            serialPort1.Close();
                 
        }

        private void ON_Click(object sender, EventArgs e)
        {
            serialPort1.Open();
            if (serialPort1.IsOpen)
            {
                serialPort1.Write("a");
   
            }
            int get = serialPort1.ReadByte();

            MessageBox.Show(get.ToString());
            serialPort1.Close();
        }
        



    }
}

Its a bit of a mess, I've been trying to get this to work all day, at the same time not fully wrapping my head around it. I very well could have had it right, but my micro and ftdi is acting up.

Thanks guys for the help, I really appreciate it. I will update my results as soon as I can.

I get no response when:

Code:

if ( c != '\n' || c != '\r')

How to I check if the input buffer is full?

What do you mean, "you get no response". What condition are you actually trying to test for here ?
In fact, as far as I can tell, the condition of this "if" statement will be 100% invariably TRUE.

My advice would be to get the program working with input typed into the Serial monitor before trying to send data from the PC. That way at least you know that the receiving end is working properly.

By the way, your comment

// assuming "Carriage Return" is chosen in the Serial monitor as the line ending character

is meaningless at the moment because the Serial monitor line ending character is what it sends when you press return having entered something, not what it regards as the line ending character when it receives data.

Although I confess to knowing nothing at all about Visual C# I could not resist looking at the code you posted. The only characters that it appears to send are a or b, not 5 or 12 but, as I say, I do not know Visual C#

Opening and closing the serial port, as your C# application does EVERY time a character is sent, resets the Arduino. There is no real wonder why your Arduino is having fits after a while.

Open the serial port ONCE! Close it ONCE!

PaulS:
Opening and closing the serial port, as your C# application does EVERY time a character is sent, resets the Arduino. There is no real wonder why your Arduino is having fits after a while.

Open the serial port ONCE! Close it ONCE!

Good to know.
but I did originally have that, only opened it once, closed it once. Like I said: I've been at this for an entire day, I was trying everything I could think of. Even with the very most simplest program, it just isn't consistent.

UKHeliBob:
Although I confess to knowing nothing at all about Visual C# I could not resist looking at the code you posted. The only characters that it appears to send are a or b, not 5 or 12 but, as I say, I do not know Visual C#

When you send data using serialport1.WriteLine(), it always sends a '/n' at the end.
It doesn't send an '/n' if you just use serialport1.Write()

BTW: I didn't write most of this, I've been gathering any kind of example I could find. I don't know anything about serial communication, so I am learning by example. "Bad examples" I guess.

I've tried:
opening the port once, closing the port once (95% of the time I had it like that)
making arduino send a '$' once it was ready to receive data, then and only then Visual C# can send data
Using different baud rates
Messing with the reset pin / cap from ftdi. Probably has nothing to do with it
Adding a very long delay after: if(Serial.available() > 0) {
Using While(Serial.available() > 0) {
Sending data from Visual C# using "serialport1.Write('a'), fallowed by "serialport1.Write('^')", as my own end line

Nothing seemed to work. Yes I did receive the correct data, a few time, but not consistent at all, CERTAINLY not for any kind of important data transfers.

When you send data using serialport1.WriteLine(), it always sends a '/n' at the end.
It doesn't send an '/n' if you just use serialport1.Write()

Yes, but where do the 5 and 12 come from that you say you are sending ?

UKHeliBob:

When you send data using serialport1.WriteLine(), it always sends a '/n' at the end.
It doesn't send an '/n' if you just use serialport1.Write()

Yes, but where do the 5 and 12 come from that you say you are sending ?

I was literally sending '5' and '12' from Visual C#. Random numbers I chose, one of which I wanted to have 2 digits.

My setup is a little strange.

Using a macbook pro and windows VMware

Breadboard - 1284p, ftdi breakout (sparkfun), AVR MKII
Maniac Bug's - Mighty 1284p 16MHz using optiboot
Running arduino 1.0.3 on mac side
Running Visual C# on windows side

I program the 1284p with the AVR MKII - "Upload using programmer" (because I could never get the ftdi to program the 1284p)
ftdi is connected to the windows side

So, I can't use arduino's serial monitor. The AVR MKII isn't serial, so I have nothing to communicate with it on the mac side/arduino IDE.

I've read that the 1284p DIP package has real issues with the ftdi, programming it at least. So that could be the red flag. I've never been able to program it using that. I have pcb's for the 1284p-AU package, I will solder jumpers to the rx0 and tx0 pins and see if I have better luck.

Is it necessary that I have FTDI DTR tied to reset pin?

bamboosam:
I get no response when:

if ( c != '\n' || c != '\r')

How to I check if the input buffer is full?

You know the buffer is full when your index variable equals the length of the buffer.

Your logic checking for end-of-line is a bit tortuous because you're checking for characters NOT being end of line, so in that case you would need to use 'and' rather than' not. It would be much simplrer if you inverted the logic like this:

const int MAX_LEN = 20;
char buffer[MAX_LEN+1]; // allow space for the terminating null
int length = 0;
...

if ( c == '\n' || c == '\r')
{
  // end-of-line received
  // process content of buffer, if any
  if(length > 0)
  {
     handle(buffer);
     length = 0;
  }
}
else
{
  // not end-of-line
  if(length < MAX_LEN)
  {
    buffer[length++] = c;
    buffer[length] = '\0';
  }
}

You'll notice I renamed 'i' to 'length'; it's common to use single letter variables as local loop counters and your global 'i' would clash with any local variables of the same name.

Ok I managed to get jumper wires soldered to the tx0 and rx0 pins on a1284p-AU package, and... It works perfectly. Not a miss, consistent every time.
I am extremely relieved because that was driving me nuts, I knew I must have been doing it right at some point, and I am absolutely sure I have my breadboard 1284p DIP setup correctly.

So it is definitely something with the 1284p DIP package's tx0 and rx0 pins internally interfering with each other, so watch out.

Thank you guys for the help, I really appreciate it.