Leer bien los datos recibidos.

(1/1)

Meta:
Buenas comper@s:

Uso comunicación por el puerto serie /USB con Arduino y RealTerm para probar y funciona.

Envío el comando tal cual, por ejemplo, B\r desde RealTerm o PuTTY, y recibe el comando exactamente tal cual quiero desde Arduino:

#Comando B recibido\r


Ver zoom.

El problema de C# .net 8.0 usando Windows Form, no lee bien y llevo horas y horas. En mi caso, en vez de usar RealTerm, quiero usar el mio propio hecho con C#. Al enviar comandos como en este ejemplo, B\r a Arduino, lo lee bien, el problema es al devolver los datos que si lo devuelve y bien y C# no lo interpreta bien.

O no recibe los datos, lo recibes a medias, o entre medios hace un salto de línea por la cara, hace cosas muy raras.

Código Arduino:
Código
#include <LiquidCrystal.h>
 
// Inicializa la librería con sus pines indicados
LiquidCrystal lcd(8, NULL, 9, 4, 5, 6, 7);
 
// Definir el pin para la luz de fondo y el LED
const byte LuzFondo = 10;
const byte Led = 13;
 
// Variable para almacenar el comando recibido
String comando = "";  // Asegúrate de declarar la variable de tipo String
char caracter;
 
void setup()
{
 // Inicializa el LCD
 lcd.begin(16, 2);  
 lcd.print("Esperando comando");
 
 // Inicia la comunicación serial
 Serial.begin(2400);
 delay(1000);  // Espera para asegurar que el LCD se inicialice
}
 
void loop()
{
 // Mientras haya datos disponibles en el puerto serie, los leemos carácter a carácter
 while (Serial.available() > 0)
 {
   caracter = Serial.read();  // Leer un carácter del puerto serie
   comando.concat(caracter);  // Concatenar el carácter al comando
   delay(10);  // Pequeña espera para no saturar el canal serie
 }
 
 // Verificamos si el comando es "B\r" o "X72\r" y respondemos en consecuencia
 if (comando == "B\r")
 {
   digitalWrite(Led, HIGH);  // Enciende el Led 13
   Serial.write("#Comando B recibido\r");  // Envía el mensaje de vuelta a C#
   lcd.setCursor(0, 0);
   lcd.print("Comando B       ");  // Muestra en el LCD
 }
 else if (comando == "X72\r")
 {
   digitalWrite(Led, LOW);  // Apaga el Led 13
   Serial.write("#Comando X72 recibido\r");  // Envía el mensaje de vuelta a C#
   lcd.setCursor(0, 0);
   lcd.print("Comando X72     ");  // Muestra en el LCD
 }
 else if (comando == "X5\r")
 {
   digitalWrite(Led, LOW);  // Apaga el Led 13
   Serial.write("#Comando X5 recibido\r");  // Envía el mensaje de vuelta a C#
   lcd.setCursor(0, 0);
   lcd.print("Comando X5      ");  // Muestra en el LCD
 }
 
 // Limpiamos la cadena de comando para volver a recibir el siguiente comando
 comando = "";  
}
 

Código C#:


Código
using System.Text;
using System.IO.Ports;
 
namespace SAI_Arduino_LCD_01
{
   public partial class Form1 : Form
   {
       private SerialPort puertoSerie;
       private string lastReceivedData = "";  // Variable para guardar el último dato recibido
 
       public Form1()
       {
           InitializeComponent();
           InicializarPuertoSerie();
       }
 
       // Método para inicializar la configuración del puerto serie
       private void InicializarPuertoSerie()
       {
           puertoSerie = new SerialPort()
           {
               BaudRate = 2400,
               Parity = Parity.None,                               // Esquema para comprobar la paridad de cada byte recibido.
               StopBits = StopBits.One,                            // Número de bits de parada por byte.
               DataBits = 8,                                       // Número de bits de datos por byte.
               Handshake = Handshake.None,                         // Protocolo de establecimiento.
               Encoding = Encoding.GetEncoding(28591),             // Codificación.
               DtrEnable = true,                                   // Línea de terminal de datos.
               RtsEnable = true,                                   // Línea de solicitud.
               ReadTimeout = 500,                                  // Tiempo de espera de lectura en ms.
               WriteTimeout = 500,                                 // Tiempo de espera de escritura en ms.
               DiscardNull = false,                                // Descartar bytes nulos recibidos.
               ParityReplace = 63,                                 // Reemplaza los bytes recibidos con errores de paridad.
               ReadBufferSize = 4096,                              // Tamaño del búfer de lectura en bytes.
               WriteBufferSize = 2018,                             // Tamaño del búfer de escritura en bytes.
               ReceivedBytesThreshold = 1                          // Número de bytes que se necesitan.
           };
 
           puertoSerie.DataReceived += PuertoSerie_DataReceived; // Suscribimos al evento
       }
 
       // Evento que se activa cuando se reciben datos del puerto serie
       private void PuertoSerie_DataReceived(object sender, SerialDataReceivedEventArgs e)
       {
           try
           {
               // Verificamos si el puerto está abierto
               if (!puertoSerie.IsOpen)
               {
                   ActualizarRichTextBox("Puerto no abierto.");
                   return;
               }
 
               // Leer todos los datos disponibles hasta que no haya más
               string data = puertoSerie.ReadExisting();  // Usamos ReadExisting para leer todo
 
               // Solo actualizar si los datos recibidos son diferentes de los anteriores
               if (!string.IsNullOrEmpty(data) && data != lastReceivedData)
               {
                   lastReceivedData = data; // Actualizar el último dato recibido
                   ActualizarRichTextBox(data);  // Mostrar los datos recibidos
               }
           }
           catch (TimeoutException)
           {
               // Si hay un Timeout, podemos ignorar y no mostrar nada
           }
           catch (Exception ex)
           {
               ActualizarRichTextBox("Error: " + ex.Message + "\r\n");
           }
       }
 
       // Método para actualizar el RichTextBox de manera segura desde cualquier hilo
       private void ActualizarRichTextBox(string mensaje)
       {
           if (InvokeRequired)
           {
               Invoke(new Action<string>(ActualizarRichTextBox), mensaje);
           }
           else
           {
               richTextBox1.AppendText(mensaje + "\r\n");
           }
       }
 
       // Método para enviar un comando por el puerto serie
       private void EnviarComando(string comando)
       {
           try
           {
               // Verificar si el puerto está abierto
               if (!puertoSerie.IsOpen)
               {
                   puertoSerie.Open();
               }
 
               // Enviar cada carácter del comando como valor ASCII
               foreach (char c in comando)
               {
                   puertoSerie.Write(new byte[] { (byte)c }, 0, 1);  // Escribir un byte correspondiente al carácter ASCII
               }
 
               // Enviar el retorno de carro \r como un byte
               puertoSerie.Write(new byte[] { 13 }, 0, 1);  // ASCII de '\r' es 13
 
               // Esperar un breve tiempo para asegurar que Arduino procese el comando antes de continuar
               Thread.Sleep(200); // Ajusta el tiempo según sea necesario
 
               ActualizarRichTextBox("Enviado: " + comando + "\r\n");
           }
           catch (UnauthorizedAccessException ex)
           {
               MessageBox.Show("El puerto COM está en uso por otro proceso. Error: " + ex.Message);
           }
           catch (Exception ex)
           {
               MessageBox.Show("Error al intentar enviar el comando: " + ex.Message);
           }
       }
 
       // Cerrar el puerto de manera segura cuando se cierre el formulario
       private void Form1_FormClosing(object sender, FormClosingEventArgs e)
       {
           if (puertoSerie.IsOpen)
           {
               try
               {
                   puertoSerie.Close();
               }
               catch (Exception ex)
               {
                   MessageBox.Show("Error al cerrar el puerto: " + ex.Message);
               }
           }
       }
 
       private void Form1_Load(object sender, EventArgs e)
       {
           try
           {
               string[] puertos = SerialPort.GetPortNames();
               comboBox_Puertos.Items.AddRange(puertos);  // Llenar el ComboBox con los puertos disponibles
 
               if (comboBox_Puertos.Items.Count > 0)
               {
                   comboBox_Puertos.SelectedIndex = 0; // Seleccionar el primer puerto automáticamente
               }
           }
           catch (Exception ex)
           {
               MessageBox.Show("Error al cargar los puertos: " + ex.Message);
           }
       }
 
       // Método para conectar con el puerto seleccionado
       private void btnConectar_Click(object sender, EventArgs e)
       {
           if (comboBox_Puertos.SelectedItem == null)
           {
               MessageBox.Show("Por favor, selecciona un puerto COM antes de intentar conectar.");
               return;
           }
 
           string puertoSeleccionado = comboBox_Puertos.SelectedItem.ToString();
           puertoSerie.PortName = puertoSeleccionado;  // Configurar el puerto
 
           try
           {
               // Verificar si el puerto ya está abierto y cerrarlo si es necesario
               if (puertoSerie.IsOpen)
               {
                   puertoSerie.Close();
                   ActualizarRichTextBox("Puerto cerrado previamente.\r\n");
               }
 
               // Abrir el puerto
               puertoSerie.Open();
               ActualizarRichTextBox("Conexión exitosa con " + puertoSeleccionado + "\r\n");
           }
           catch (Exception ex)
           {
               MessageBox.Show("Error al abrir el puerto: " + ex.Message);
           }
       }
 
       // Métodos de comando
       private void button_Comando_B_Click(object sender, EventArgs e) => EnviarComando("B");
       private void button_Comando_X72_Click(object sender, EventArgs e) => EnviarComando("X72");
       private void button_Comando_X5_Click(object sender, EventArgs e) => EnviarComando("X5");
   }
}
 

Con RealTerm, Putty y otros, funciona bien.

¿En qué estoy fallando?

Un cordial saludo y muchas gracias por su tiempo.

EdePC:
Cambia tu línea 55:

Código
string data = puertoSerie.ReadExisting();  // Usamos ReadExisting para leer todo

por:

Código
string data = puertoSerie.ReadTo("\r");

Si usas ReadExisting como dice, lees lo que haya hasta ese momento y lo imprimes, por eso a veces sale en trozos

Si usas ReadTo("\r") lees hasta encontrar "\r" y recién imprimes

Si te das cuenta en RealTerm cuando envías el comando y empieza a mostrar el resultado, a veces también tiene un retardo y sale en trozos, pero como está todo seguido (sin saltos de línea) no se ve al finalizar, tu código si pone saltos de línea al imprimir los trozos y por eso se ve raro

Navegación

[0] Índice de Mensajes