Detectar que el USB esta conectado al PC

Buenas camarada:

Pedazo de proyecto, tiene que ser la leche. :clap: :clap: :clap: :clap: :clap:
Suena muy bien.

Se lo que le pasa y me pasaba lo mismo, hasta se me colgaba C#.

Hay varias maneras de hacerlo. Arduino tiene que esperar un mensaje o comando a recibir al conectarlo al PC para que se cumple la condición.

Si al desconectarse C# con Arduino se cumple la condición siguiente. C# tiene que enviar de forma periódica un comando como bandera (flag en Inglés), esto indica a Arduino que por cada cierto tiempo indicado en Arduino, por ejemplo, 5 segundos y es bueno usar milli no sleep.

Ya sabes, crear una interrupción y continue Arduino seguir su rutina.

Si desconecta o cierra C#, envía un comando avisando a Arduino que siga con su rutina. Así no se cuelga.

Voy hacer la parte de C# ahora mismo, elmás usado me imagino que usarás .Net FrameWork 4.7.2, para que sea lo más compatible posible. Ya que están el 4.8 y elmás nuevo el .Net 6.0 que es novedad desde finales de este año. Haré como prueba el 4.7.2, si quieres otra versión lo adapto.

Voy a empezar ya los primeros códigos. En el formulario el botón CONECTAR y DESCONECTAR puerto. Si detecta el cable USB/Serie, C# lo detecta, añade el nuevo el puerto enel textBox automáticamente e envía un comando que tu quieras a Arduino.

Empezando...

Edito:
Lo más básico de Arduino es este código.

void setup()
{
  // Baudios del puerto serie.
  Serial.begin(115200);
// Espere a que se conecte el puerto serie. Necesario USB nativo.
  while (!Serial); 
// Envía un OK para confirmar. 
 Serial.println("OK");
}

Ese video es de las primeras pruebas, no se ve muy bien
Cuando hago algo, lo que sea, y son muchas cosas, todo es abierto a quien lo quiera, software y hardware. Ficheros 3d para piezas, CNC para piezas o placas de Circuito.....y software.
Hago muchas cosas porque vivo en pueblo y como ya estoy jubilado me aburro.
Suelen ser cosas para motos, que es otra de mis aficiones.

Buenísimo el vídeo. Pareces que controla bien el tacómetro con Arduino.
Arduino detectar USB

Enlace para descargar el ejecutable.

Descargar

Prueba haber si te funciona la detección del USB cuando conectar Arduino. Se tiene que mostrar automáticamente cuando tienes un PORT nuevo o no.

Saludos.

Y este es el codigo completo del Arduino, aunque esta a medio modificar, para usar dos oled, ya que antes usaba dos arduinos, uno por oled, ya que a las pantallas no se les puede cambiar la direccion.
Ahora estoy modificandolo para usar un multiplexor I2c.
Por eso estta a medias sin parciales y GPS en ese codigo
VEras que esta supercomentado porque comparto el codigo con quien lo quiera, asi que asi se entiende mejor

type or paste code here
/*VELOCIMETRO  
VELOCIDAD Frecuencia
20          2,86
40          5,71
60          8,57
80          11,43
100         14,28
120         17,14
140         19,99
160         22,85
180         25,71
----------------
Conexiones
Sensor hall 2
GPS 3 y 4
Motor 5,6.7 y 8
Pulsador 11
I2c SDA A4 SCL A5
*/

#include <Adafruit_SPIDevice.h>
#include <Adafruit_I2CRegister.h>
#include <Adafruit_I2CDevice.h>
#include <Adafruit_BusIO_Register.h>
#include "SwitecX25.h"          // Libreria para el control del motor paso a paso
#include <SPI.h>                // Libreria para el uso del i2c de comunicacion del LCD
#include <Wire.h>               // Libreria para el uso del i2c de comunicacion con el LCD
#include <Adafruit_GFX.h>       // Libreria para el uso del LCD OLED
#include <Adafruit_SSD1306.h>   // Libreria para el uso del LCD OLED  
#include "TinyGPS++.h"          // Libreria para el uso del modulo GPS
#include <EEPROM.h>             // Libreria para el uso de la memoria fija



//************ DATOS A VARIAR EN FUNCION DE CADA MOTO Y KM RECORRIDOS ************

// Datos para una rueda 90/90/18

const float desarollo_rueda = 1.945;   //En mm, hace falta para calcular la velocidad 


// ***** DEFINICIONES (valores fijos) *******

#define hallPin  2              // Pin donde esta conectado el sensor hall
#define STEPS (315*3)           // recorrido total en pasos del motor 945 pasos
#define RECORRIDO_ESCALA 780    // pasos del recorrido desde el tope cero al tope max velocidad
#define SCREEN_WIDTH 128        // OLED display ancho, en pixels
#define SCREEN_HEIGHT 32        // OLED display alto, en pixels

// Declaracion para un display SSD1306 conectado a I2C (SDA, SCL pins)

// Los pins para I2C estan definidos en la libreria Wire-library. 
// En un arduino NANO:       A4(SDA), A5(SCL)
// es donde conectamos la tarjeta de multiplexor I2C Pines A4 y A5


#define OLED_RESET     -1        // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C     // <Direccion de la pantalla OLED; 0x3D para 128x64, 0x3C para 128x32


//*********************************************************************************

// *** VARIABLES QUE USA EL PROGRAMA *******

volatile float tiempo0 = 0;
volatile float tiempo1 = 0;
float rpm_rueda;
float rps_rueda;
float velocidad;
float metros;
long km;
int posicion_aguja;
long num;
    

//*****************************************

// CREA INSTANCIAS A LA PANTALLA OLED, AL MOTOR Y AL BOTON, PARA SU USO

Adafruit_SSD1306 display1(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_SSD1306 display2(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// Motor conectado a los pins 56,7,8

SwitecX25 motor1(STEPS,5,6,7,8);


//**********************************************



//*********** SETUP DE INICIO DEL ARDUINO, SE EJECUTA UNA VEZ AL CONECTARLE ALIMENTACION ****


void setup() 
{

  //Inicializacion del sistema
  
    pinMode(8, OUTPUT);
    pinMode(hallPin, INPUT_PULLUP);
    
    
  // PREPARAR COMUNICACION SERIAL
     Serial.begin(9600);
     // Prepara el display

     // Start Wire library for I2C
     Wire.begin();


     // initialize OLED-1 with I2C addr 0x3C

  

  TCA9548A(1);

  if(!display1.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) 
  {
    for(;;); // No responde, espera en bucle infonito
   }
  display1.setTextColor(SSD1306_WHITE); // Texto en blanco
  display1.setTextSize(4);              // Escala del texto 4X

  
  TCA9548A(2);

  if (!display2.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS))
  {
      for (;;); // No responde, espera en bucle infonito
  }
  display2.setTextColor(SSD1306_WHITE); // Texto en blanco
  display2.setTextSize(4);              // Escala del texto 4X

  
  
 
 // lee los km del total de la memoria del velocimetro. Si lee cero graba la que esta predefinida en el #define KM_HOY

  EEPROM.get(2, km);
  
  
  if ((km == -1)||(km==0)) // Si es la primera vez que se usa, no hay km recorridos memorizados, asi que memoriza
  {                        // lo que se haya fijado en la cabecera del programa como inicial     
      EEPROM.put(2, km);
  }
  
  dato_al_display(km,0,1);               // manda al display los km recorridos memorizados en la eeprom
 
  // PREPARA EL INSTRUMENTO DE AGUJA HACIENDO UN BARRIDO
  
  prepara_gauge();      // hace un barrido del recorrido del motor paso a paso y lo pone a 0km/h
  
     
  //Declaramos la interrupcion. En el arduino NANO. En el pin 2 se encuentra la interrupcion 0
  //Como tenemos una resistencia de PULL-UP nos interesa ejecutar el codigo cuando pasa de 5V a 0V --> FALLING
  
   attachInterrupt(0, pulsoRueda, FALLING);
 }
//****************************************************************
// PROGRAMA QUE SE EJECUTA DE FORMA CICLICA REPETITIVA ***********

void loop() 
{ 
  
    // si la moto esta parada, no llegan pulsos de la rueda y el tiempo entre pulsos es largo

  if ((micros() - tiempo1) > 1000000) 
  {
      // considera que la velocidad es cero, por debajo de un valor
      rpm_rueda = 0;
  }
  
  // calcula la posicion de la aguja en funcion de la velocidad medida 
  // (el recorrido real de la aguja desde el bloqueo a 10km/h es 180-10 => 780 pasos)

  
  // por tanto se ajusta la escala de rpm_rueda a esos 780 pasos de recorrido de la aguja

  delay(2); // para quitar la vibracion de la aguja actualiza la posicion paso a paso cada 8 mseg

  if (posicion_aguja < int(rpm_rueda * 0.21477))
      posicion_aguja++;
  if (posicion_aguja > int(rpm_rueda * 0.21477))
      posicion_aguja--;
  
  motor1.setPosition(posicion_aguja);   // pone la aguja en la posicion de velocidad actual
  motor1.updateBlocking();
   
  if(metros > 1000)     // se se han recorrido 1000 metros suma un km al total
  {
    metros = 0;
    km++;
    if(km > 99999)
      km=0;
    dato_al_display(km,0,1);
    EEPROM.put(2,km );    // graba en la memoria los km recorridos
  }
}

//***********************************************************
//****************** FUNCIONES ******************************

// hace el barrido de todo el recorrido de la aguja para preparar el velocimetro

void prepara_gauge(void) 
{
    motor1.maxVel=30;
    motor1.setPosition(0);
    motor1.updateBlocking();
    motor1.setPosition(STEPS);  // lleva el motor a la pos 180km/h
    motor1.updateBlocking(); 
    delay(400);
    motor1.setPosition(0);  // lleva el motor a la pos 180km/h
    motor1.updateBlocking();
    motor1.maxVel=80;
    motor1.update();
 }

// visualiza en el display un nuevo valor 

void dato_al_display(float dato, int decimales, int pantalla)
{  
  TCA9548A(pantalla);
  display1.clearDisplay();
  if ((dato > 9999))
    display1.setCursor(5,2);             // Comienza en la esquina superior izda
  if ((dato > 999) && (dato < 10000))
    display1.setCursor(30,2);             // Comienza en la esquina superior izda
  if ((dato > 99) && (dato < 1000))
     display1.setCursor(42, 2);             // Comienza en la esquina superior izda
  if ((dato < 100)&&(dato > 9))
     display1.setCursor(55, 2);             // Comienza en la esquina superior izda
  if (dato < 10)
     display1.setCursor(65, 2);             // Comienza en la esquina superior izda
  display1.println(dato,decimales);
  display1.display();
}


// funcion que se ejecuta cada vez que hay un pulso enl detector de la rueda

void pulsoRueda()
{
  tiempo1 = micros();
  rps_rueda = (1000000 / (tiempo1 - tiempo0)); 
  tiempo0 = tiempo1;
  rpm_rueda = rps_rueda * 60;                       // pasa de rps a rpm
  velocidad = (rps_rueda * desarollo_rueda * 3.6);  // pasa de rps a m/h
  metros =  metros + desarollo_rueda;
 }

// funcion para el multiplexor i2c

void TCA9548A(uint8_t bus)
{
    Wire.beginTransmission(0x70);  // TCA9548A address is 0x70
    Wire.write(1 << bus);          // send byte to select bus
    Wire.endTransmission();
}


OK gracias mañana lo pruebo, ahora ya es tarde y estare liado...
Mil gracias y un saludo.

Buenas:

Cuando puedas lo pruebas. Dejo el código fuente de C# con .Net 4.7.2.

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

namespace Velocímetro_Arduino_Puerto_serie_01
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // Añado los puertos disponible en el PC con SerialPort.GetPortNames() al comboBox_Puerto.
            try
            {
                comboBox_Puerto.DataSource = SerialPort.GetPortNames();
            }

            catch
            {
                MessageBox.Show("No encuentra ningún puerto físico ni virtual.", "Aviso:",
                    MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }

            // Añado los puertos disponible en el PC con SerialPort.GetPortNames() al comboBox_Puerto.
            comboBox_Puerto.DataSource = SerialPort.GetPortNames();

            // // Añade puertos disponibles físicos  y virtuales.
            serialPort1.PortName = comboBox_Puerto.Text.ToString();
        }

        // Detecta USB o puerto serie virtual cuando lo conecta y desconecta del cable.
        protected override void WndProc(ref Message USB)
        {
            if (USB.Msg == 0x219)
            {
                comboBox_Puerto.DataSource = SerialPort.GetPortNames();
            }

            base.WndProc(ref USB); // Detecta si hay cambios en el usb y si los hay los refleja.
        }

        private void button_Conectar_Click(object sender, EventArgs e)
        {
            try
            {
                serialPort1.PortName = comboBox_Puerto.Text.ToString(); // Puerto seleccionado previamente.
                serialPort1.Open(); // Abrir puerto.
                comboBox_Puerto.Enabled = false;
                comboBox_Baudios.Enabled = false;
                button_Conectar.Enabled = false;
                button_Desconectar.Enabled = true;
            }

            catch
            {
                MessageBox.Show("El puerto no existe.", "Aviso:",
                MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        private void button_Desconectar_Click(object sender, EventArgs e)
        {
            serialPort1.Close(); // Cerrar puerto.
            comboBox_Puerto.Enabled = true;
            comboBox_Baudios.Enabled = true;
            button_Conectar.Enabled = true;
            button_Desconectar.Enabled = false;
        }

        // Al cerrar el formulario, cierra el puerto si está abierto.
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            try
            {
                serialPort1.Close(); // Cerrar puerto.
            }

            catch (Exception error)
            {
                MessageBox.Show(error.Message, "Aviso:",
                MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }
    }
}

Muy buen código tuyo documentado.

Ya dirás lo que hará C# también. Por ahora no recibe datos. Solo tienes que indicarme que es lo que quieres hacer. Lo que por ahora entiendo y no está hecho, es enviar comando a Arduino cuando detecte el USB. Me dices que comando o una palabra y lo pongo.

Saludos.

El setup quedaria algo asi

void setup() 
{

  //Inicializacion del sistema
  
    pinMode(8, OUTPUT);
    pinMode(hallPin, INPUT_PULLUP);
    
    
 
     // Prepara el display

     // Start Wire library for I2C
     Wire.begin();


     // initialize OLED-1 with I2C addr 0x3C

  

  TCA9548A(1);

  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) 
  {
    for(;;); // No responde, espera en bucle infonito
   }
  display.setTextColor(SSD1306_WHITE); // Texto en blanco
  display.setTextSize(4);              // Escala del texto 4X

  
  TCA9548A(2);

  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS))
  {
      for (;;); // No responde, espera en bucle infonito
  }
  display.setTextColor(SSD1306_WHITE); // Texto en blanco
  display.setTextSize(4);              // Escala del texto 4X

  
  
 
 // lee los km del total de la memoria del velocimetro. Si lee cero graba la que esta predefinida en el #define KM_HOY

  EEPROM.get(2, km);

  // PREPARAR COMUNICACION SERIAL
 
  Serial.begin(9600);
  if(Serial)
  {
  
  // aqui debe detectar si esta conectado al PC y si es asi mandar los km memorizados, el programa del PC
  // debe dar la opcion de cambiarlos y si no se cambian o no esta conectado al PC seguir el setup sin hacer nada
  //Si esta conectado espera en un bucle si no continua y se sale siguiendo el setup
   //(( adquiere dato "long"del puesto serie))
   // if(km != dato_adquirido)
      // lo memoriza en la eeprom

  //    EEPROM.put(2, km);
  //(( si es el mismo o cero continua sin cambiarlo))
  }
  
  
  dato_al_display(km,0,1);               // manda al display los km recorridos memorizados en la eeprom
 
  // PREPARA EL INSTRUMENTO DE AGUJA HACIENDO UN BARRIDO
  
  prepara_gauge();      // hace un barrido del recorrido del motor paso a paso y lo pone a 0km/h
  
     
  //Declaramos la interrupcion. En el arduino NANO. En el pin 2 se encuentra la interrupcion 0
  //Como tenemos una resistencia de PULL-UP nos interesa ejecutar el codigo cuando pasa de 5V a 0V --> FALLING
  
   attachInterrupt(0, pulsoRueda, FALLING);
 }

y el programa del PC haria eso que indico en el setup, si esta conectado el Arduino establece conexion, lee los km que tiene memorizado en la EEprom , ofrece cambiarlos y si se cambia envia el dato y si no envia cero. El arduino si no esta conectado continiua el setup y si esta conectado y le llega el dato cambiado lo memoriza en EEProm y si no continua
Basicamente ese debe ser el funcionamiento
Aun no proble lo tuyo ahora a ver si me pongo un rato.
Mil gracias por tanta molestia

Buenas.

Por lo que entiendo...... Tengo dudas y hago preguntas.

  1. ¿C# tiene km memorizado y lo envía a Arduino?

  2. ¿Arduino compara si es igual o 0 los km los datos que tiene C#?

Por lo que he entendido.

C# al conectar el usb, Arduino lo detecta. C# tiene km guardados y no haz dicho si quieres poner los que quiera para luego enviarlo a Arduino. No lo tengo claro.

Si es así, C# envía km a Arduino y lo compara con los datos que tiene guardad en la EEPROM.

Si los datos enviados desde C# son iguales o 0,sigue con la rutina.

Sí los km es mayor desde C# comparado con la EEPROM de Arduino, se memoriza.

  1. ¿Dónde se memoriza, en C# o en Arduino?

Si se desconecta el cable o cierro el programa C#. Arduino sigue su curso.

Saludos.

A ver, los km estan en la eeprom de arduino, al conectar c# los pide a arduino, ya arduino los tiene en la variable long km, leidos de su eeprom.
C# los presenta en pantalla y ofrece cambiarlos, si se cambian los envia a arduino y arduino los mete en la eeprom sustituyendo los memorizados. Si se mete en c# cero o los mismos que ha leido de arduino envia cero y con eso arduino sale del bucle y termina el setup....

Parece que nos hemos entendido.

  1. C# detecta Arduino con el USB automático.
  2. C# muestra en pantalla los datos que está actualmente en la RAM de Arduino. Tipo de datos Long.
  3. C# incluye un textBox que sólo acepta números que son km a la hora de introducir datos por parte del usuario.
  4. C# tiene un botón de envío de km hacia Arduino que se introdujo por el usuario.
  5. Arduino detecta la introducción de km en una variable.
  6. Dicha variable enviado desde C# se compara si es igual o es 0.
  7. Depende de la condición si es mayor km enviado desde C# comparado con Arduino. Arduino hace una copia de los km obtenidos de C# en la EEPROM.
  8. Finalizada la copia, Arduino sigue su curso.

Cuando llegue a mi casa, pongo las manos en C#.

Te has explicado perfecto.
Es asi. Si no esta arduino conectado al pc continua y listo y si esta conectado haria eso que dices.
Si el C# lo haces tu favor gordo me haces.
Mil gracias

Yo simplificaría y en el bucle principal (loop) del arduino pondría algo similar a esto:
En el setup() poner la velocidad del serial a 9600.
en el loop() mirar si ha llegado algo por el puerto serie:

  String cadenaKm="";
  long km=0;
  if (mySerial.available()) //hay caracteres esperado a ser leidos? 
  {
      cadenaKm= mySerial.readString(); //leer la cadena que hay esperando ser leida
       if (cadenaKm.subString(0,1)=="KM")  //comienza con KM en mayúsculas?
       {
            cadenaKm.remove(0,2);   //quitar "KM" y dejar los números
            km=atol(cadenaKm);  //convertir lo que queda de la cadena (los números) a long
           //aqui faltaría escribir en la eeprom el valor de KM
       }
  }

Y para establecer los KM símplemente conectar el arduino al puerto serie, saber qué puerto está conectado el arduino nano (p.e. com3) y escribir desde la consola de msdos:

MODE COM3:9600,N,8,1
ECHO KM12345>COM3

Así establecemos el puerto COM3 del PC en 9600 baudios, y damos salida por ese puerto a la cadena "KM12345". Arduino detectará que empieza por KM y el resto lo establecerá en la eeprom (12345).
No se necesitaría ningún programa especial ni nada. solo ejecutar una ventana de comandos (CMD) y esas dos líneas de código que he pegado antes.

Ojo, no lo he probado pero es lo que yo haría para simplificar al máximo.
Saludos.

@algec:
No he podido bajar el video dado que no me deja pero de un viejo motero a otro, mi más sentida enhorabuena por tu proyecto.
En su día hice algo relativamente similar con acelerómetro, SD y un par de servomotores (no P2P) para ver aceleraciones, inclinaciones, etc (telemetría) y me lo pasé muy bien haciéndolo.
Te ha quedado muy bien!
Saludos.

A riesgo que me excomulguen ¿Por que no intentar una solución por Hardware? Suponiendo que estas alimentando el sistema por Vin, y tienes un pin libre, conectas la entrada de 5 v del usb, de ese modo si detecta que hay alimentación USB entra a un modo "transferencia" .
Saludos

Siento que no puedas bajarte el video. No se porque porque es un enlace a mi nube.
Tengo hecho velocimetro y tacometro, son de una guzzi v50 con 40 años y quedan exactos al antiguo, ya que uso las carcasas y caratulas y agujas....
Sustituyo el mecanismo por electronica y arduino, y el alumbrado por una tira led.
El interior esta hecho en abs con una 3d.
Tengo hechos varios proyectos mas con arduino, como vacuometros para ajuste de carburadores, lcd, tft y bluettoh para salida en el movil. Lo tengo hecho en 2,3 y 4 cilindros. Tambien para pc portatil con una app en c#, para taller.
Un encendido electronico bicilindrico, con curva programable con y sin sensor de vacio. Ese va con una app en c# para ajustar curvas y demas, y el encendido en arduino nano....
Todo a disposicion de quien lo quiera
En cuanto a lo que sugieres puede ser lo que busco, una solucion simple......lo miro.
Muchas gracias

Si, se dio esa solución antes pero el estar conectado podría implicar que únicamente tienes alimentación y no que tienes comunicación. Y si llegaras a tener señales dtr/rts tendrías que hacer seguramente todo un protocolo con un programa para poder realizar un envío simple para actualizar el cuentakilómetros o ajustes del velocímetro por cambios de cubiertas etc.

Gracias, personalmente me interesaría el vacuometro. Gasto tanto 2 (África twin) como 4 cilindros (Suzuki) que dada la antigüedad, sobretodo la Suzuki hay que estar retocando mucho.
Actualmente hago limpieza con ultrasonido de la batería de carburadores, ajustes iniciales de apertura de mariposas con rodamientos calibrados (bolas) y vacuometro de dos en dos con vacuometro casero (nada de mercurio, aceite denso).
Y retoques finales a mano según coloración de las bujias. Para las monocilindricas uso una bujía de esas falsas que se ve el color de la combustión (cambia de color según rica o pobre).
Si puedes mándame un privi
Saludos

Sin problemas en lo del vacuometro, yo lo llevo por bluetooh, montado fijo en la moto y asi reviso donde quiero los ajustes sin casi ni bajarme de ella. Ajusto relenti y tension de los cables y en el movil voy viendo como queda.
Es lo mas facil, un Nano, dos sensores de vacio, un modulo bluetooh y uno de alimentacion de 12 a 5V.
Como se tu mail para el contacto?

Por eso aclare que funcionaria si se alimenta el proyecto por Vin. En el nano hay un diodo que Zener que separa los dos circuitos.
Si fuera mi proyecto utilizaría un protocolo Modbus, de esa manera se podrían actualizar y visualizar fácilmente un montón de parámetros, kilometros, alarmas, máximos , mínimos, etcétera.
Hay muchos editores modbus gratuitos que harían el proyecto fácil de usar y no habría interrupción del funcionamiento normal del dispositivo sin importar que esta conectado a que.
Simpleza máxima.

Buenas:

Me funciona a medias pero va avanzando. Uso Arduino UNO y LCD Keypad Shield para hacer pruebas reales. También estoy usando el COM4 por defecto en C#. Si quieres, te pongo uno que tu quieras y vuelvo a subir el programa nuevo. (Lo ideal es que te muestre todos los puerto COM y lo seleccione tal como hice en el primer programa, como estamos de pruebas, por ahora no pasa nada).

Arduino detectar USB2

Código Arduino:

#include <LiquidCrystal.h>

// Inicializa la librería con sus pines indicados.
// RS, RW, Enable, D4, D5, D6, D7.
LiquidCrystal lcd(8, NULL, 9, 4, 5, 6, 7);
// LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

// Pin 10 para saber que es luz de fondo.
const byte LuzFondo = 10;
char caracter;
String comando;

void setup()
{
  Serial.begin(9600);           // Puerto serie 9600 baudios.
  lcd.begin(16, 2);             // Formato de pantalla.
  lcd.clear();                  // Borra la pantalla y su posición superior izquierda.
  lcd.print(F("    Arduino     "));// Muestra título en la LCD.
  //delay(1000);                  // Retardo de 1 segundo.
  // Espere a que se conecte el puerto serie. Necesario USB nativo.
  while (!Serial);
  // Envía un OK para confirmar.
  // Serial.println("OK");
  // O ejecutas alguna función dentro del propio Arduino.
  // Función aquí.
}

void loop()
{
  /*
    Voy leyendo carácter a carácter lo que se recibe por el canal serie
    (mientras llegue algún dato allí), y los voy concatenando uno tras otro
    en una cadena. En la práctica, si usamos el "Serial monitor" el bucle while
    acabará cuando pulsamos Enter. El delay es conveniente para no saturar el
    canal serie y que la concatenación se haga de forma ordenada.
  */
  while (Serial.available() > 0)
  {
    caracter = Serial.read();
    comando.concat(caracter);
    delay(10);
  }

  /*
    Una vez ya tengo la cadena "acabada", compruebo su valor y hago que
    la placa Arduino reacciones según sea este. Aquí podríamos hacer lo
    que quisiéramos: si el comando es "tal", enciende un Led, si es cual,
    mueve un motor... y así.
  */

  // Si los carácteres es recibido y verdadero.
  // ¿USB conectado?
  if (comando.equals(F("USB_DETECTADO")) == true) // Sí. Se ejecuta las instrucciones.
  {
    Serial.write("USB detectado.  ");    // Envía este mensaje al PC.
    lcd.setCursor(0, 1);
    lcd.print(F("USB detectado.  ")); // Mostrar en el LCD.
  }

  // ¿Haz cerrado C# desde el PC?
  if (comando.equals(F("CERRADO")) == true) // Sí.
  {
    Serial.write("SIN CONEXION USB");  // Envía este mensaje al PC.
    lcd.setCursor(0, 1);
    lcd.print(F("Sin conexion.   ")); // Mostrar en el LCD.
  }

  // Limpiamos la cadena para volver a recibir el siguiente comando.
  comando = "";
}

Código C#:

using System;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace Velocímetro_Arduino_Puerto_serie_02
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            UsbDetectado();
        }

        // Detecta USB o puerto serie virtual cuando lo conecta y desconecta del cable.
        protected override void WndProc(ref Message USB)
        {
            if (USB.Msg == 0x219)
            {
                try
                {
                    UsbDetectado();
                }
                catch 
                {
                    //...
                }
            }

            // Detecta si hay cambios en el usb y si los hay los refleja.
            base.WndProc(ref USB);
        }

        void UsbDetectado()
        {
            Thread.Sleep(2500);
            serialPort1.Open(); // Abrir puerto.
            byte[] miBuffer = Encoding.UTF8.GetBytes("USB_DETECTADO");
            serialPort1.Write(miBuffer, 0, miBuffer.Length);
        }

        // Al cerrar el formulario, cierra el puerto si está abierto.
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            try
            {
                // Al cerrar este programa, indica a Arduino cerrado.
                // Arduino sigue con su rutina al detectar CERRADO.
                serialPort1.Write("CERRADO");

                // Retardo.
                Thread.Sleep(100);

                // Cerrar puerto.
                serialPort1.Close();
            }

            catch (Exception error)
            {
                MessageBox.Show(error.Message, "Aviso:",
                MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        private void button_Enviar_Click(object sender, EventArgs e)
        {
            byte[] miBuffer = Encoding.UTF8.GetBytes("KM" + textBox_Km.Text);
            serialPort1.Write(miBuffer, 0, miBuffer.Length);
        }

        // Permite solo escribir números en el textBox.
        private void textBox_Km_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar) && (e.KeyChar != '.'))
            {
                e.Handled = true;
            }

            // Solo escribe un punto. Si quieres escribir m´sa puntos, documenta con // los códigos de abajo.
            if ((e.KeyChar == '.') && ((sender as TextBox).Text.IndexOf('.') > -1))
            {
                e.Handled = true;
            }
        }
    }
}

Falta hacer más cosas que no me ha dado tiempo. Por ejemplo. Si envías en el textBox 12345 Km.

Envía al puerto serie "KM12345". Faltó introducir más códigos de Arduino que quite el KM y se quede con los números, luego lo guarda en una variable tipo Long.

Velocímetro Arduino Puerto serie 02.zip (4.7 KB)

Saludos.