Why does Arduino stop sending data?

Asked

Viewed 34 times

-1

The application (C# .Net Framework 4.7.2 in Visual Studio 2019) I’m doing sends a command to Arduino via serial and Arduino sends 'n' sensor data. However, the first time I run the program, nothing happens. If I restart the execution, it starts receiving the data as expected, but stops sending before arriving at the word "End" that I used to indicate the end of the sending and freezes there, without error messages. Why does this happen? What I did wrong?

I was able to simulate the problem with the codes below: Visual C#:

using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Ports;
using System.Windows.Forms;

namespace TesteSerial1
{
    public partial class Form1 : Form
    {
        List<string> dados = new List<string>(); //Listas de manipulacao de dados
        string strRec;
        public Form1()
        {
            InitializeComponent();
            string[] baudRates = { "4800", "9600", "19200", "38400", "57600", "115200", "230400" };
            string[] portas = SerialPort.GetPortNames();
            while (portas.Length == 0)
            {
                MessageBox.Show("Ligue o aparelho a uma porta USB", "Aparelho não encontrado", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                portas = SerialPort.GetPortNames();
            }
            foreach (string porta in portas)
            {
                cmbPorta.Items.Add(porta);
            }
            foreach (string baudRate in baudRates)
            {
                cmbVelocidade.Items.Add(baudRate);
            }
            cmbPorta.SelectedIndex = 0;
            serialPort1.PortName = portas[0];
            cmbVelocidade.SelectedItem = "9600";
            serialPort1.BaudRate = int.Parse((string)cmbVelocidade.SelectedItem);
        }

        private void btnLer_Click(object sender, EventArgs e)
        {
            dados.Clear();
            Form1.ActiveForm.Enabled = false;
            if (!serialPort1.IsOpen)
            {
                serialPort1.Open();
                serialPort1.WriteLine("a"); //Envia o comando pro Arduino
                serialPort1.DataReceived += DadoRecebido; //Recebe os dados
            }
        }
        private void DadoRecebido(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                strRec = serialPort1.ReadLine();
                object[] parametro = new object[1];
                parametro[0] = strRec;
                DelegacaoSerial delegado = new DelegacaoSerial(MostraDados);
                this.BeginInvoke(delegado, parametro);
            }
            catch (TimeoutException b)
            {
                MessageBox.Show("Erro no recebimento dos dados: " + b.Message, "ERRO!", MessageBoxButtons.OK, MessageBoxIcon.Error);
                btnLer.Text = "Ler";
                btnLer.Enabled = true;
            }
        }
        public delegate void DelegacaoSerial(string strRec);
        private void MostraDados(string strRecebida)
        {
            if (strRecebida != "Fim\r") //Enquanto não recebe o comando 'Final' vai adicionando dados
            {
                dados.Add(strRecebida); //Adiciona a esta lista para depois tratar os dados
            }
            else
            {
                MessageBox.Show("Leitura terminada.", "Fim da leitura", MessageBoxButtons.OK, MessageBoxIcon.Information);
                Form1.ActiveForm.Enabled = true;
            }

            foreach (string d in dados) //Trata os dados
            {
                try
                {
                    string[] dadosSeparados = d.Split('#');
                    int dadoA = int.Parse(dadosSeparados[0]);
                    int dadoB = int.Parse(dadosSeparados[1]);
                    Console.WriteLine(dadoA + " " + dadoB);
                }
                catch (InvalidCastException e)
                {
                    MessageBox.Show(e.Message, "Erro de leitura", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    break;
                }
                catch (InvalidDataException f)
                {
                    MessageBox.Show(f.Message, "Erro de leitura", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    break;
                }
            }
        }
    }
}

Arduino code:

char rc;
long numA;
long numB;

void setup() {
  Serial.begin(9600);
}

void loop() {
  while (Serial.available() > 0) {
    rc = Serial.read();
    if (rc == 'a') {
      for (int i = 0; i < 5000; i++) {
        numA = random(10);
        numB = random(30);
        Serial.print(numA);
        Serial.print("#");
        Serial.println(numB);
      }
      Serial.println("Fim");
    }
  }
}

The way out is like this:

  • It seems almost a serial buffer problem, but I’m not sure, it doesn’t seem to be a problem in Rduino, but in the desktop application, try to put a small delay between the prints of Rduino.

  • I thought it could be something like this, but since I’m new in the area, I couldn’t imagine how I could solve it. I’ll test it! Thank you! On the other hand, speed is paramount in this project. The faster the data acquisition, the better the result, because it is a chemical reaction. Maybe if I add the collected data to a list and then send it...

  • The placement of the delay’s helped a little, but as you yourself suggested, the problem is in the C#application. It seems to me that it removes data from the input buffer at a lower speed than the Arduino puts them there, and there comes a time that there is an accumulation that locks the ReadLine(). I imagine using the ReadExisting() I would pull the data faster, but I don’t know how to manipulate it and there’s the possibility that they’ll be truncated.

  • Another possibility is to resize the buffer using the ReadBufferSize. I’ll try that.

1 answer

2

I think I was able to solve the problem, maybe not in an elegant way, but it worked out well. Look what I did: I put a while (serialPort1.BytesToRead > 0) to force the application to read the entire buffer. What was happening, I assume, is that the command for closing the reading was executed before all data was read.

The code section was modified, therefore:

        private void DadoRecebido(object sender, SerialDataReceivedEventArgs e)
        {
            while (serialPort1.BytesToRead > 0)
            {
                try
                {
                    strRec = serialPort1.ReadLine();
                    object[] parametro = new object[1];
                    parametro[0] = strRec;
                    DelegacaoSerial delegado = new DelegacaoSerial(MostraDados);
                    this.BeginInvoke(delegado, parametro);
                    Console.WriteLine(strRec);
                }
                catch (TimeoutException b)
                {
                    MessageBox.Show("Erro no recebimento dos dados: " + b.Message, "ERRO!", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    btnLer.Text = "Ler";
                    btnLer.Enabled = true;
                }
            }
        }

Thanks for your help, Mr. Beregula!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.