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() { { 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) { } 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 // 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.