Hacer cambios de este código.

Iniciado por Meta, 25 Enero 2017, 03:05 AM

0 Miembros y 3 Visitantes están viendo este tema.

Meta

Hola:

Tengo este código de abajo que funciona bien. Lo que hace es, al recibir algún dato por el puerto serie, me lo almacena en un array y guarda el archivo en el disco duro. Hecho en C#.
Código (csharp,77) [Seleccionar]

using System;
using System.Diagnostics;
using System.IO;
using System.IO.Ports;

namespace Recibir_archivo_desde_Arduino_consola_02
{
   class Program
   {
       static void Main(string[] args)
       {
           string COM = "";

           // Tamaño ventana consola.
           Console.WindowWidth = 55; // X. Ancho.
           Console.WindowHeight = 15; // Y. Alto.
           Console.Title = "Recoger foto desde Arduino y crearlo en el disco duro"; // Título de la ventana.

           // Crear un nuevo objeto SerialPort con la configuración predeterminada.
           SerialPort Puerto_serie = new SerialPort();

           // Configuración.
           Console.Write(@"
Introduzca un número para seleccionar puerto COM.
Por ejemplo el 4, sería COM4.

Puerto: ");
           COM = Console.ReadLine(); // Escribir el número del puerto.
           Console.Clear();

           Puerto_serie.PortName = "COM" + COM; // Número del puerto serie.


           Puerto_serie.BaudRate = 115200; // Baudios. 115200.
           Puerto_serie.Parity = Parity.None; // Paridad.
           Puerto_serie.DataBits = 8; // Bits de datos.
           Puerto_serie.StopBits = StopBits.Two; // Bits de parada.
           Puerto_serie.Handshake = Handshake.None; // Control de flujo.

           // Establecer la lectura / escritura de los tiempos de espera.
           Puerto_serie.ReadTimeout = -1; // 500.
           Puerto_serie.WriteTimeout = -1; // 500.

           try
           {
               Puerto_serie.Open(); // Abrir el puerto serie.
           }

           catch (IOException)
           {
               Console.ForegroundColor = ConsoleColor.Red; // Texto en rojo.
               Console.CursorVisible = false;
               Console.SetCursorPosition(16, 6);
               Console.WriteLine(@"El puerto " + Puerto_serie.PortName + @" no existe
               o no lo encuentra.");
               Console.ReadKey(); // Pulse cualquier tecla para salir.
           }

           catch (UnauthorizedAccessException e)
           {
               Console.WriteLine(e);
           }
           Puerto_serie.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);

           Console.WriteLine("Esperando datos desde Arduino...");
           Console.Read();
           Puerto_serie.Close(); // Cerrar puerto.
       }

       private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)

       {
           try
           {
               SerialPort sp = (SerialPort)sender;
               int contador = 0;
               byte[] datosArray = new byte[17729]; // Aquí tengo que cambiar el valor cuando recibo datos desde el puerto serie.

               while (contador < datosArray.Length)
               {

                   contador += sp.Read(datosArray, contador, datosArray.Length - contador);

                   Console.SetCursorPosition(10, 2);
                   Console.Write("Datos recibidos:  {0}", contador);
                   Console.WriteLine("                   ");

                   if (contador == 17729)
                   {
                       Console.WriteLine();
                       Console.WriteLine("Creando archivo al disco duro...");
                       File.WriteAllBytes("fotón.jpg", datosArray); // Crear archivo en el disco duro.
                       Console.WriteLine();
                       Console.WriteLine("Archivo creado. Ejecutando imagen.");
                       Process.Start("fotón.jpg"); // Ejecutar visualizador de imágenes.
                       Console.WriteLine();
                       Console.WriteLine("Imagen ejecutada.");
                       Console.WriteLine();
                       Console.ForegroundColor = ConsoleColor.Yellow; // Letras amarillas.
                       Console.WriteLine("FIN DE PROGRAMA.");
                       Console.ForegroundColor = ConsoleColor.Gray; // Letras grises otra vez.
                   }
               }
           }


           catch (TimeoutException)
           {
               //maybe increase ReadTimeout or something, use exponential backoff, your call
           }

           catch (IOException)
           {
               // Console.WriteLine("La operación de E/S se anuló por una salida de subproceso o por una solicitud de aplicación.");
           }
       }
   }
}


Quiero tener ideas para modificar este programa.

Los datos del puerto serie puede llegar desde Arduino o desde otro PC. Como llega desde Arduino en este caso, tiene dos botones, si pulsa el primer botón, C# recibe ciertos comandos que son estos:

Si en Arduino presiono el primer botón, C# le llega este número de 5 Bytes en este caso, 17729. Ese valor tiene que incluirse aquí, en esta parte del código indicado abajo.

Código (csharp) [Seleccionar]
byte[] datosArray = new byte[17729];

Como puedes ver, he puesto manualmente el valor de este array 17729.

¿Cómo hago que al detectar cualquier valor, en este caso 17729 sea para el array datosArray?

Digo 17729 como ejemplo, si le llega 478, pues que sea 478.

Lo que no entiendo que luego de llegar 17729, que son solo 5 dígitos, llegará de inforamación 17729 Bytes detrás.

Si no haz entendido algo, preguntar para explicarlo de otra manera.

Saludos.
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

ivancea96

Si el protocolo es:
N -> 5 bytes
{ N BYTES }


Pues primero lees los primeros 5 bytes, los conviertes a un entero, y se lo pones de longitud al array.
Luego, lees esos N bytes (o lo que sea).

Meta

Hola:

Leyendo por aquí:
Cómo: Convertir una cadena en un número (Guía de programación de C#)

Se puede hacer algo como esto.
Código (csharp) [Seleccionar]
                int cantidadBytes = Int32.Parse("17729");
                byte[] datosArray = new byte[cantidadBytes];


Lo que hace Arduino en enviar esta trama así:

Código (csharp) [Seleccionar]
17729pcomsfgocfgmpsomhgpodmgpdfgsioidchg954y90y4h30x50hg98c9oc0m9vy509hc596h509

Como se puede ver, los 5 primeros bytes corresponde al 17729, es es la cantidad del tamaño del array llamado datosArray en el ejemplo de arriba.

Lo veo así complicado. A lo mejor hay que cambiar la forma de hacer las cosas.

1. C# espera que le lleguen datos.
2. Arduino envía solo este valor 17729.
3. C# convierte de string a int y el arrayDatos ya tiene el tamaño deseado.
4. C# le envía por el puerto serie estos caráscteres, OK.
5. Arduino entiende el OK y envía el resto de tramas de bytes.
6. C# almacena los datos en el arrayDatos, crea el archivo al disco duro y lo abre, en este caso es una foto.

Me parece que aí está mejor que enviar todo de golpe como pretendía en un principio. La pregunta es.

¿Cómo se hace?

Mira que me lavé el cerebro, ajjajaj jaj ajaja para lograr donde he llegado.

Saludos.
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

ivancea96

Si lo que quieres es responderle al Arduino tras recibir el número, pues nada, es eso. Tras enviar el número, el Arduino tendrá que esperar la respuesta. NO sé qué es exactamente lo que no sabes hacer (solo es enviar, esperar y recibir, al fin y al cabo)


Otra opción es recibir el número en una cantidad de bytes fija. Es decir, 2 posibilidades:
1) Enviar el número "en binario". Un int son 4 bytes, así que solo tendrías que leer 4 bytes. (Si nunca trabajaste con datos binarios, puedes saltarte esta opción temporalmente)
2) Enviar, por ejemplo, 8 caracteres fijos, y rellenarcon ceros: 00015678<datos>.

También puedes poner un delimitador:
15678;<datos>
Pones el punto y coma (o cualquier caracter no-numérico) después, y ya sabes cuando dejar de leer el número.

Meta

Buenas:

Gracias porlainformación.
Cómo: Analizar cadenas mediante String.Split (Guía de programación de C#).

Antes de seguir programando, hay que tener las ideas claras y se me ha cambiado.

Cosas tener en cuenta.

Arduino tiene dos fotos dentro del microcontrolador.
Usa tres pulsadores.
Pulsador 1: Le envía información del contenido sobre Arduino que lee C. Por ejemplo:
CitarArduino UNO r3.
Versión: 1.26.
---------------------
Contenido:
Foto 1: 17729 Bytes. (Pulsador 2).
Foto 2: 5000 Bytes. (Pulsador 3).
---------------------

Como puedes ver arriba, Arduino le envía esa información y C# lo lee y muestra en pantalla.

Pulsador 2: Envía la primera foto a C#.
Pulador 3: Envía la otra foro.

Está bien lo de usar delimitadores, en este caso prefiero comandos y respuesta.

1. C# espera algún dato por parte de Arduino.
2. Como la placa de Arduino usa tres botones, pues si pulsa el primero envía información del contenido de Arduino.
3. Si pulsa el segundo o tercer botón, lo primero que hace Arduino es enviar números, por ejemplo, pulso el segundo pulsador y le envía solo esto: 17729.
4. C# lo recibe, en el cual ya modifica el tamaño del array.
5. C# le envía un este dato: OK.
6. Arduino empieza a enviar tramas de bytes de la primera foto.

¿Qué les parece?

Saludos.

PD: Dejo claro que es una idea, no tiene que ser la mejor, de esta idea puede aparecer otras ideas por parte de los visitantes, pueden participar. Ánimos y adelante.
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

ivancea96

Si vas a hacer un protocoo con varios comandos, entonces ponle un identificador del comando al principio:

CMD -> 1 byte
if CMD = A {
    protocolo A 
}else if CMD = B {
    protocolo B
}


Ej. Este mismo protocolo, pero del lado del Arduino: https://github.com/ivancea/Arduino-Interpreter/blob/master/arduino_program.c

Meta

#6
Hola:

Lo que tengo hecho en Arduino y aún no está como debe estar es este.

// Enviar tramas de byte al puerto serie y LCD Keypad Shield.

#include <LiquidCrystal.h>

int estadoActual1 = 0;
int estadoActual2 = 0;
int estadoUltimo = 0;
char caracter;
String comando;

// Teide 22-02-2016.
PROGMEM const unsigned char rawData[] = {
  0xFF, 0xD8, 0xFF, 0xE1, 0x00, 0x18, 0x45, 0x78, 0x69, 0x66, 0x00, 0x00
};

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

// Pin 10 para saber que es luz de fondo.
//int LuzFondo = 10

void setup()
{
  pinMode(2, INPUT); // Entrada digital donde está el pulsador.

  // Baudios.
  Serial.begin(115200);

  // Formato de pantalla.
  lcd.begin(16, 2);
}

void enviarImagen()
{
  for (unsigned int i = 0; i < sizeof(rawData); ) // El i++ de aquí se quita.
  {
    Serial.write(pgm_read_byte(&rawData[i]));
    lcd.setCursor(0, 0); // Posiciona el cursor donde quieras que se imprima la cantidad de bytes enviados.
    // Procura dejar un espacio de entre 5 y 8 caracteres según la cantidad de dígitos a representar.
    lcd.print(++i);
  }
}

void loop()
{
  estadoActual1 = digitalRead(2); // Leer entrada digital número 2.
  delay(10);
  estadoActual2 = digitalRead(2);

  if (estadoActual1 == estadoActual2)
  {
    if (estadoActual1 != estadoUltimo)
    {
      if (estadoActual1 == HIGH)
      {
        Serial.write(0x51); // Envía 0x51 que es ARCHIVO_1_OK en C#.
      }
    }
  }

  estadoUltimo = estadoActual1;

  /* Voy leyendo carácter a carácter lo que se recibe por el canal serie
      (mientras lelgue algún datoallí), 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. Eldelay 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í.
  */

  if (comando.equals(0x01) == true)
  {
    Serial.write("17729");
  }

  if (comando.equals(0xA1) == true)
  {
    enviarImagen(); // Enviar imagen o foto hacia el puerto serie al PC.
    lcd.setCursor(0, 1); // Crusor segunda línea del LCD.
    lcd.print("Archivo: JPG    ");
  }

  // Limpiamos la cadena pra vovler a recibir el siguiente comando.
  comando = "";
}


En C#:
Código (csharp) [Seleccionar]
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Ports;

namespace Recibir_archivo_desde_Arduino_consola_02
{
    class Program
    {
        // Comandos a enviar a Arduino.
        public enum Arduino_Comandos
        {
            ARCHIVO_1 = 0x01,
            ARCHIVO_2 = 0x02
        }

        // Respuestas de Arduino.
        public enum Arduino_Respuestas
        {
            INFO = 0x50,
            ARCHIVO_1_OK = 0x51,
            ARCHIVO_2_OK = 0x52
        }

        static void Main(string[] args)
        {
            string COM = "";

            // Tamaño ventana consola.
            Console.WindowWidth = 55; // X. Ancho.
            Console.WindowHeight = 15; // Y. Alto.
            Console.Title = "Recoger foto desde Arduino y crearlo en el disco duro"; // Título de la ventana.

            // Crear un nuevo objeto SerialPort con la configuración predeterminada.
            SerialPort Puerto_serie = new SerialPort();

            // Configuración.
            Console.Write(@"
Introduzca un número para seleccionar puerto COM.
Por ejemplo el 4, sería COM4.

Puerto: ");
            COM = Console.ReadLine(); // Escribir el número del puerto.
            Console.Clear();

            Puerto_serie.PortName = "COM" + COM; // Número del puerto serie.


            Puerto_serie.BaudRate = 115200; // Baudios. 115200.
            Puerto_serie.Parity = Parity.None; // Paridad.
            Puerto_serie.DataBits = 8; // Bits de datos.
            Puerto_serie.StopBits = StopBits.Two; // Bits de parada.
            Puerto_serie.Handshake = Handshake.None; // Control de flujo.

            // Establecer la lectura / escritura de los tiempos de espera.
            Puerto_serie.ReadTimeout = -1; // 500.
            Puerto_serie.WriteTimeout = -1; // 500.

            try
            {
                Puerto_serie.Open(); // Abrir el puerto serie.
            }

            catch (IOException)
            {
                Console.ForegroundColor = ConsoleColor.Red; // Texto en rojo.
                Console.CursorVisible = false;
                Console.SetCursorPosition(16, 6);
                Console.WriteLine(@"El puerto " + Puerto_serie.PortName + @" no existe
                o no lo encuentra.");
                Console.ReadKey(); // Pulse cualquier tecla para salir.
            }

            catch (UnauthorizedAccessException e)
            {
                Console.WriteLine(e);
            }
            Puerto_serie.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);

            Console.WriteLine("Esperando datos desde Arduino...");
            Console.Read();
            Puerto_serie.Close(); // Cerrar puerto.
        }

        private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)

        {
            try
            {
                SerialPort sp = (SerialPort)sender;
                int contador = 0;

                int cantidadBytes = int.Parse("17729");
                byte[] datosArray = new byte[cantidadBytes];

                if (/* Algo hay que poner aquí y no tengo idea. */ == 0x51)
                {
                    byte[] miBuffer = new byte[1];
                    miBuffer[0] = 0x01;
                    sp.Write(miBuffer, 0, miBuffer.Length);
                }

                    while (contador < datosArray.Length)
                {
                    contador += sp.Read(datosArray, contador, datosArray.Length - contador);

                    Console.SetCursorPosition(10, 2);
                    Console.Write("Datos recibidos:  {0}", contador);
                    Console.WriteLine("                   ");

                    if (contador == 17729) // 17729.
                    {
                        Console.WriteLine();
                        Console.WriteLine("Creando archivo al disco duro...");
                        File.WriteAllBytes("fotón.jpg", datosArray); // Crear archivo en el disco duro.
                        Console.WriteLine();
                        Console.WriteLine("Archivo creado. Ejecutando imagen.");
                        Process.Start("fotón.jpg"); // Ejecutar visualizador de imágenes.
                        Console.WriteLine();
                        Console.WriteLine("Imagen ejecutada.");
                        Console.WriteLine();
                        Console.ForegroundColor = ConsoleColor.Yellow; // Letras amarillas.
                        Console.WriteLine("FIN DE PROGRAMA.");
                        Console.ForegroundColor = ConsoleColor.Gray; // Letras grises otra vez.
                    }
                }
            }


            catch (TimeoutException)
            {
                //maybe increase ReadTimeout or something, use exponential backoff, your call
            }

            catch (IOException)
            {
                // Console.WriteLine("La operación de E/S se anuló por una salida de subproceso o por una solicitud de aplicación.");
            }
        }
    }
}


No se si te dirá algo.

Por ahora solo uso un pulsador para no volvernos locos, cuando todo funcione, pondré los otros dos pulsadores.

Si en Arduino pulsas el pulsador del pin 2, envía este código al PC y C# lo lee.
Serial.write(0x51); // Envía 0x51 que es ARCHIVO_1_OK en C#.

C# debe leer 0x51 que significa el pulsador 1.
Si C# detecta 0x51 desde Arduino, ejecuta esta instrucción y envía el valor 0x01. (Es lo que me falta por corregir y no capto ideas).
Código (csharp) [Seleccionar]
if (/* Algo hay que poner aquí y no tengo idea. */ == 0x51)
                {
                    byte[] miBuffer = new byte[1];
                    miBuffer[0] = 0x01;
                    sp.Write(miBuffer, 0, miBuffer.Length);
                }


Arduino lee 0x01 enviado desde C#. Como le llegó 0x01, pues Arduino le envía a C# el valor 17729, que es el valor donde debe ir el array llamado datosArray, ajusta el tamaño de dicho array en C#.
if (comando.equals(0x01) == true)
  {
    Serial.write("17729");
  }


Dejo claro que el programa no está completado y necesito orientación para completarlo.
Cuando ya reciba el dato 17729 en C#, el array ya tiene que tener este valor así.
Código (csharp) [Seleccionar]
                int cantidadBytes = int.Parse("17729");
                byte[] datosArray = new byte[cantidadBytes];

No se como se hace, cualquier ayuda en bienvenida.

Luego C# envía otro comando al acabar el redimensionado del array datosArray, este comando que debe enviar es 0xA0.

El código de Arduino se ejecuta esto.
  if (comando.equals(0xA1) == true)
  {
    enviarImagen(); // Enviar imagen o foto hacia el puerto serie al PC.
    lcd.setCursor(0, 1); // Crusor segunda línea del LCD.
    lcd.print("Archivo: JPG    ");
  }


Por fin ya puede recoger C# dicha foto.

Saludos.
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

ivancea96

Cita de: Meta en 25 Enero 2017, 23:29 PM
Dejo claro que el programa no está completado y necesito orientación para completarlo.
Cuando ya reciba el dato 17729 en C#, el array ya tiene que tener este valor así.
Código (csharp) [Seleccionar]
                int cantidadBytes = int.Parse("17729");
                byte[] datosArray = new byte[cantidadBytes];

No se como se hace, cualquier ayuda en bienvenida.

No entiendo exactamente qué es lo que no sabes cómo se hace.
¿Cómo leer el número que envía Arduino? Igual que leerías la imagen, por supuesto.
¿Como convertir el número a un número para el array? Igual que pusiste en ese código ahí.
¿?

Meta

Ese código lo puse manualmente en 17729, mi idea es que tiene que captar desde Arduino ese valor y modificar dicho array.
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

ivancea96

Código (csharp) [Seleccionar]
int.Parse(loQueAcabasDeLeerDelArduino)

Lees del Arduino, lo metes en una variable y lo conviertes a int. ¿Qué parte exactamente de esto no das?