Detectar que el USB esta conectado al PC

Mil gracias de nuevo. Lo reviso y te digo

Modbus uso en los HMI del pc en c# y arduino. Lo conozco bien el protocolo, pero esto es para un uso puntual una vez y luego se pone en la moto y ya nada.
Gracias a todos de todas formas, os estais tomando muchas molestias.

Solo falta añadir información desde Arduino y soltar los KM a C# en mi programa.

También hace falta memorizar los Km en la EEPROM.

Puedes hacer tu código para coger ideas, así hago más pruebas.

Saludos.

https://1drv.ms/u/s!AiQIC4nffckhi8d0kH8RhRDR4hk4UQ?e=T5zYkR

Cualquier duda me lo dices. Ya me comentas, Tendras que adaptarlo algo a tu modulo wifi.

Enviado desde Correo para Windows

Hola:

En cuanto puedas, haces un ejemplo de una función que guarde los Km en la EEPROM. Ottra función en leerlo.

En Arduino desde que detecte que se conecta C#, envía los datos de Km y lo muestra en pantalla.

Así voy haciendo experimentos.

Voy haber los archivos que me enviaste.

No estoy usando módulo wifi, solo por cable USB directamente. Esta tarde voy a comprar el transformador para alimentar ARduino que ya no funciona. Solo desde el USB y no me deja hacer las pruebas que quiero realmente.

/*
 * Aquí detecta si el USB está conectado y lo muestra en el LCD 16x2.
 * Si el USB está conectado al PC, en el LCD indica si haz ejecutado
 * C# en el PC o lo cierras.
 */
#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;

// Funciones.
void deteccionUSB()
{
  lcd.setCursor(0, 0); // Línea 1 del LCD.
  lcd.print(F("USB detectado.  "));  
}

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");
  // Llama una función.
  deteccionUSB();
  // 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("C# detectado.   "); // Envía este mensaje al PC.
    lcd.setCursor(0, 1);              // Línea 2 del LCD.
    lcd.print(F("C# 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);              // Línea 2 del LCD.
    lcd.print(F("Sin conexion.   ")); // Mostrar en el LCD.
  }

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

Gracias.

Gracias de nuevo, en cuanto la familia me deje un rato lo hago y lo pruebo.
Lo que mande fue por error, debi mandarlo al correo privado y lo mande aqui, es el vacuometro que hablaba con el compañero, ya se lo mande al privado.

Probe tu codigo pero no me funciona
Si lo modifico si, aqui te paso la modificacion, es simple, no lee la cadena completa, pero si es un solo caracter si funciona bien

#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);
  Serial.print("Conectado");
  // 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("A")) == 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("C")) == 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 = "";
}

Al menos te funciona. En el Monitor Serie puedes introducir los comandos que puse.

Falta hacer las funciones de la EEPROM con un valor guardado, para recuperarlo y enviarlo a C#. Luego, pongo desde C# el km que quiera y se guarda en Arduino, si es mayor. Si es igual o menor, no hace nada.

Una pregunta, no iria mejor si directamente adquiere el long?
Seria algo asi

long num;
EEPROM.get(2,km);

num = km;  // leido antes de la eeprom
Serial.print(num);
while (true)
        {

            // BUCLE
            //(( adquiere dato "long"del puesto serie))
            
            num = Serial.parseInt();
            
            if ((num != 0) && (num != km))
            {
                // if(km != dato_adquirido)
                // lo memoriza en la eeprom
                //(( si es el mismo o cero continua sin cambiarlo))
        
                km = num;
                EEPROM.put(2, km);
                break;
            }
        }

con eso ahorramos encabezado y demas, C# solo tiene que mandar un long.
Es mas, podria mandar el Arduino el long a C# cuando se conecte y almacenarlo en la variable que se va a modificar. Se presenta en pantalla y si se modifica y se envia se cambia y si no queda como estaba y continua.
Creo que es un codigo mas simple. Que opinas?

Me dice en la parte de la EEPROM.put(2, km); que no está declarado.

#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;
long num;
long km;

// Funciones.
void deteccionUSB()
{
  lcd.setCursor(0, 0); // Línea 1 del LCD.
  lcd.print(F("USB detectado.  "));
}

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");
  // Llama una función.
  deteccionUSB();
  // 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("C# detectado.   "); // Envía este mensaje al PC.
    lcd.setCursor(0, 1);              // Línea 2 del LCD.
    lcd.print(F("C# 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);              // Línea 2 del LCD.
    lcd.print(F("Sin conexion.   ")); // Mostrar en el LCD.
  }

// Tu código #####################################
  num = km;  // leido antes de la eeprom
  Serial.print(num);

  // BUCLE
  //(( adquiere dato "long"del puesto serie))

  num = Serial.parseInt();

  if ((num != 0) && (num != km))
  {
    // if(km != dato_adquirido)
    // lo memoriza en la eeprom
    //(( si es el mismo o cero continua sin cambiarlo))

    km = num;
    EEPROM.put(2, km);
    break;
  }
// ################################################

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

Tu codigo funciona en principio bien. Tengo que probarlo con tu C# pero para eso tengo que hacerlo en real con un Arduino.
Te falta el include por eso no compila

#include <EEPROM.h>

En cuanto pueda lo pruebo con un arduino, lo he estado tanteando en Proteus, tengo familia en casa por las fiestas y eso me roba todo el tiempo.
Gracias de nuevo

Se me pasó por alto la librería. :man_facepalming:

Al enviar los datos desde C# poniendo 12345 y pulsas enviar,envías MK12345.

Hay que hacer código como explicaron arriba.

  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
       }
  }

Debo modificar C# para que leas los datos desde Arduino. Por ahora solo puedes enviar.

Un apunte @algec : la eeprom,en teoría, aguanta cien mil ciclos de lectura/escritura. Se de gente que dice que no le ha durado más de diez mil ciclos.
considera usar "update" en vez de "put" y si quieres puedes hacer algún tipo de proceso para que escriba en sitios diferente. así incluso podrías llevar las centenas de metros también guardados en eeprom sin miedo a degradarla
Saludos.

Pues si, mejor update.

Con los PIC16F84A hacía un truco. Lo usaba todo la RAM, si el uC pierde energía, se desactiva el LCD, Led, ventiladores... Menos el propio PIC y uno de los pines le avisaba de ello. Se mantenía el PIC encendido unos buenos segundos gracias a un buen condensador y la fuente de alimentación a 24V. Tiempo suficiente para que le de tiempo en guardar lo que tiene en la RAM a la EEPROM, así no desgasta tanto la memoria.

Si vas a usar mucho la EEPROM, mejor usar memoria EEPROM externa como las 24LC256 por nombrar una, por si te falla. Posibilidad que si detecta error de lectura o escritura, sale en otra posición de memoria o incluso otra EEPROM externa que tengas de auxiliar. Así extiende la vida útil del circuito.

Cuando pueda te paso ejemplos de C# que tengo medio hecho.

Ciertas las dos cosas, lo de la Eeprom externa, que usaba con pic y debo tener un buen puñado por ahi.
Y lo del update que entiendo que si es el mismo no sobreescribe, por lo que no cuenta como ciclo de escritura.
Por otra parte tened en cuenta que los velocimetros marcan 99999 asi que ese ciclo ya vale, y no creo que nadie con una moto de 40 años ya le haga ni 50.000
No creo que se vaya a ir la eeprom por mychos ciclos.
Como los parciales sion muchos mas por eso solo los memoriza cada 500 metros aunque indique en la oled cada 100.
Un buen apunte de todas formas.

En mi caso, si hago un circuito con mi propia PCI, procuro que dura 40 años. :partying_face::rofl:

Tmb he leído de una prueba destructiva (foro de AVR) de alguien que dice que le duró 1 millon de ciclos y mas.
No es por contradecirte pero 10 mil es muy conservador.
Igualmente comparto tu sugerencia de usar update en lugar de put.

Los hay de 100.000 y 1.000.000 de ciclos. Cada vez duran más. En las EEPROM de las centralitas de vehículos en su herramienta de diagnosis, indica la cantidad de veces de escritura, cuando falle, se cambia la centralita completa y volver a configurar todo con su programa.

Estuve viendo la posibilidad de incluir la EEprom externa y no me termina de convencer por varias razones.
Tendria que hacer espacio dentro del velicimetro para el hardware y cablear mas.
No necesito mas espacio de memoria EEprom de hecho me sobra la que hay.
No tiene necesariamente mas ciclos de vida, asi que si se averia la del arduino con cambiar este solucionado
El acceso es muchisimo mas lento, lo que ocasionara problemas con las interrupciones y habria que andar parandolas y arrancandolas
En resumen, no veo demasiado beneficio porque ya os digo, nada electronico dura 40 años por obsoleto, he estado trabajando en electronica industrial precisamente 40 años, ahora estoy jubilado, y de los equipos de entonces no queda nada, todo se cambio.
Ademas si la moto a restaurar tiene ya 40 años como es el caso de la mia, no va a durar 40 mas, si es que aun hay planeta habitable, porque tendra mas que prohibido circular. Con una moto vieja que ya tendra sus buenos miles de km cuando se le ponga el velocimetro modificado, nadie va a hacer muchos km mas.
Con la interna es mas que suficiente.
De todas formas gracias por el aporte.

Se usa el SPI que es mucho más rápido, ejjejej, el lento es el I2C. No tienes porqué usarlo, sino que sepas que hay más posibilidades.

Quiero saber y que hagas a tu manera de guardar datos en la EEPROM y otra función para recuperar datos.

I2C lento? 400khz te parece lento, por favor, no estoy de acuerdo, @Metaconta. Es cierto que SPI es mas veloz pero de qué hablamos?
Estaban debatiendo de ciclos de escritura y pasaste @Metaconta a velocidad de escritura. No son la misma cosa!!

1 Like