Almacenar imagen en un array en Arduino

Hola:

Poniendo una imagen como estedentro de una placa de Arduino con suficiente memoria en la memoria programa del microcontrolador.

Este es un ejemplo de un array de Arduino.
https://www.arduino.cc/en/Reference/Array

No habla de como se hace guardar byte en hexadecimal en array que es lo que quiero. La propia imagen de Arduino que vez arriba ocupa 2,32 KB (2.378 bytes).

En otros lenguajes como C#, se guarda así:

byte[] rawData = {
    0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D,
    0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0xE6, 0x00, 0x00, 0x00, 0xAF
};

Es lo que quiero saber, ya pondré ejemplo en C# para dar más ideas.

Saludos.

Y? Cuál es el problema?

Binario, octal, decimal o hexadecimal; todos estas son formas válidas, para el compilador, de escribir valores.

Los arrays ni que decir; pueden ser de absolutamente cualquier tipo de dato conocido. La diferencia está en que en C++ los [] van después del nombre de la variable.

PD: si es para colocar en la memoria del programa como dices, entonces debe cumplir un par de condiciones:

  • El array debe ser inmutable (const).
  • Se debe usar la palabra reservada PROGMEM (fuera de un sketch de Arduino, debe importarse <avr/pgmspace.h>), antes del símbolo '='.

Hola:

El ejemplo de C# es algo parecido lo de pasar la imagen al disco duro. También lo demuestra.

using System;
using System.IO; // No olvidar.
using System.Diagnostics; // No olvidar.

namespace Byte_Hex_ocultos_5
{
    class Program
    {

        #region Imagen de ARduino en un array de byte.
        /* C:\Users\Meta\Desktop\Puerto_serie-C.png (27/12/2016 23:42:46)
   Posición Inicial: 00000000, Posición Final: 00000949, Longitud: 0000094A */

        byte[] rawData = {
    0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D // En realidad no cabe todo los Hex aquí.
};

        #endregion

        static void Main(string[] args)
        {
            Console.Title = "Imagen oculto de Arduino. - By Metaconta"; // Título de la ventana.
            Program variable = new Program(); // Crea un objeto.
            Console.WriteLine("¿Deseas crear la imagen de Arduino en el disco duro del PC? y / n");
            variable.Arduino(); // Llama al método Arduino();
        }

        public void Arduino()
        {
            string input = Console.ReadLine(); // Todo lo que escribas en el teclado se guarda en esta variable.

            if ((input == "y") || (input == "s"))
            {
                Console.WriteLine("Creando imagen en el dico duro...");
                File.WriteAllBytes("Image_Arduino.jpg", rawData); // Creando imagen.
                Console.WriteLine("Imagen creada en el disco duro al lado de esta aplicación.");
                Console.WriteLine("");
                input = " ";
                Console.WriteLine("¿Ver imagen creada? s / n");
            }

            input = Console.ReadLine();
            if ((input == "y") || (input == "s"))
            {
                Console.WriteLine("Mostrando imagen...");
                Process.Start("Image_Arduino.jpg");
                Console.WriteLine("Imagen cargada.");
            }

            else
            {
                Console.WriteLine("Saliendo...");
            }
        }
    }
}

Sí, el array es constante o simplemente no se modifica nunca. A pesar que lo he hecho en el mismo archivo en C#, tamibien se puede separarlo creando otra clase o archivo a parte los hex para que no moleste al leer el código principal.

Lo último que comentas no se como se hace.

Ahora, lo que quiero hacer en Arduino es, que al conectarlo al puerto serie, otro programa creado en C#, captura los datos desde Arduino y lo guarda en el PC. Esto ya me encargo yo lo de C# y lo mostraré aquí como curiosidad si alguien le pica.

En Arduino UNO, cuando pulse un botón, envian el contenido del array al puerto serie. C# lo captura y lo guarda al PC, en el escritorio de Windows por poner un ejemplo. También C# visualiza en el propio programa la imagen recibida. Si es Arduino UNO, tendrá que ser una imagen muy pequeña, pero que funcione.

Cualquier idea es bienvenida.

Saludos.

Supongo que el programa es para codificar/decodificar un archivo a/desde un array de bytes, cierto?
Para la parte del codificado yo utilizo el programa bin2h, el cual convierte un archivo en un array de unsigned char (equivale al tipo byte definido en la IDE de Arduino) y le agrega una variable con su longitud. El resultado es un archivo de texto .h

Por limitación del compilador para AVR (y espacio de memoria flash de un ATmega328P y otros más), el array (por ende, el archivo) no debe superar los 32767 bytes de longitud. Aunque a eso le tienes que restar el espacio que ocupa el programa por sí solo, y el tamaño del bootloader.

Metaconta:
Lo último que comentas no se como se hace.

El uso de PROGMEM o dónde van ubicados los []?

Lo que te dice Lucario es que si agregas 2,32 KB (2.378 bytes) a tu código te quedas sin RAM en un UNO o comprometes la de otro Arduino.
Un camino es usarlo como constante

const byte[] rawData = {
    0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D,
    0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0xE6, 0x00, 0x00, 0x00, 0xAF
};

y otro mejor es usarlo con PROGMEM que lo reserva para la flash y no compromete espacio para código.

#include <avr/pgmspace.h>

const byte[] rawData PROGMEM = {
    0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D,
    0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0xE6, 0x00, 0x00, 0x00, 0xAF
};

Para darte cuenta de como cambia con cada opción prueba este mismo array en un código simple y mira las respuestas del compilador y toma nota de RAM, CODE y FLAHS
un caso usando RAM => byte[]
otro como constante => const byte[]
y finalmente en flash => const byte[] PROGMEM
Y luego saca conclusiones.

Buenas:

Arudino UNO con su magnífico ATmega328P se le puede poner cosas muy pequeñas. Voy hacer pruebas de las más tontas o aparentemente inútiles solo por mera curiosidad.

Con Photoshop he hecho una tontería de añadir una foto a un bit, como solo me interesa poner "Hola mundo" por probar, lo he hecho pequeño, con la latra del 11 como tamaño y su fuente "Arial Bold".

Lo guardé en gif y pesa solo desde Photoshop 141 bytes, al guardarlo en el disco duro dice pesar algo más grande como 1.197 bytes, ha crecido, así que no me interesa. Lo guardé esta vez nombre.wbm y ocupa 139 bytes, tal como indica Photoshop, no hay aumento por ningún tipo como el.gif.

La imagen que vez abajo es el que digo, en este caso está en gif y el que usaré es .wbm.

Teniendo en cuenta el espacio del Arduino UNO memoria programa o flash, de unos 32 KB, el bootloader de 500 Byte más otros tantos bytes de tu propio programa, pues 139 bytes parece que no, pero puedo alargarlo.

Con la misma técnica un archivo .png más grande me ocupa 1.621 bytes, si lo pongo en esta ocasión en wbm me ocupa unas 5 KB, increible. En este ejemplo un png.

Puedo meter en el TAmega328P más todavía de información cuando me sobre. :wink:

Para los que les pica la curiosida. ¿Cómo se consigue los bytes de una imagen?
En C# como ejemplo se hace así:

Se coge la imagen con el editor hexadecimal, en este caso HxD gratuito, se selecciona todo.

Luego pegas dentro del IDE dicha variable. Con Arduino eslo mismo.

Todo esto sin cifrar, que se puede hacer desde Arduino o simplemente ya lo metes cifrado desde otro programa creado por ti o por terceros, así que al pasar los datos al disco duro desde Arduino, no saben lo que es. Esto es ya otra curiosidad. Como curiosidad o para que se hagan una idea, puedes hacerlo simplemente cifrar una imagen así con XOR.

C#.

    for (int i = 0; i < rawData.Length; i++)
    {
        rawData[i] = (byte)(rawData[i] ^ 10);
    }

Solo me falta hacer un programa de Arduino que envíe esos datos por el puerto serie/USB y otro programa en C# para el PC que captura los datos y los guarda en el disco duro cifrado o no.

En cuanto a la RAM, lo tendré en cuenta, ya que en el CP puedo pasar por el puerto a otro PC una peli de Blu-Ray sobre unas 50 GB de datos y no uso mucha RAM, solo flujo de datos con un mínimo de RAM, mientras por un lado almacena, entrega y borra de nuevo para introducir nuevos datos.

Felices fiestas 2016.

He usado la imagen de que tiene muchos escrito la palabra Texto indicado arriba.

El código me cabe bien la trama de bytes. Por ahora enviar al puerto serie no me sirve, da error, pero dejo el código aquí. Loque hace es básico, encender y apagar un Led con un botón.

Lo que hay que modificarlo para enviar la foto al puerto serie del PC.

// Enviar tramas de byte al puerto serie.

int estadoBoton=0; // Guardará el estado del botón HIGH o LOW.
int anteriorBoton=0;
char caracter;
String comando;
int flagMensaje=0;
unsigned char rawData[] = {
  0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D,
  0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x00, 0xD9,
  0x08, 0x03, 0x00, 0x00, 0x00, 0x68, 0xE3, 0xD8, 0x7C, 0x00, 0x00, 0x00,
  0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72,
  0x65, 0x00, 0x41, 0x64, 0x6F, 0x62, 0x65, 0x20, 0x49, 0x6D, 0x61, 0x67,
  0x65, 0x52, 0x65, 0x61, 0x64, 0x79, 0x71, 0xC9, 0x65, 0x3C, 0x00, 0x00,
  0x03, 0x26, 0x69, 0x54, 0x58, 0x74, 0x58, 0x4D, 0x4C, 0x3A, 0x63, 0x6F,
  0x6D, 0x2E, 0x61, 0x64, 0x6F, 0x62, 0x65, 0x2E, 0x78, 0x6D, 0x70, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x3C, 0x3F, 0x78, 0x70, 0x61, 0x63, 0x6B, 0x65,
  0x74, 0x20, 0x62, 0x65, 0x67, 0x69, 0x6E, 0x3D, 0x22, 0xEF, 0xBB, 0xBF,
  0x22, 0x20, 0x69, 0x64, 0x3D, 0x22, 0x57, 0x35, 0x4D, 0x30, 0x4D, 0x70,
  0x43, 0x65, 0x68, 0x69, 0x48, 0x7A, 0x72, 0x65, 0x53, 0x7A, 0x4E, 0x54,
  0x63, 0x7A, 0x6B, 0x63, 0x39, 0x64, 0x22, 0x3F, 0x3E, 0x20, 0x3C, 0x78,
  0x3A, 0x78, 0x6D, 0x70, 0x6D, 0x65, 0x74, 0x61, 0x20, 0x78, 0x6D, 0x6C,
  0x6E, 0x73, 0x3A, 0x78, 0x3D, 0x22, 0x61, 0x64, 0x6F, 0x62, 0x65, 0x3A,
  0x6E, 0x73, 0x3A, 0x6D, 0x65, 0x74, 0x61, 0x2F, 0x22, 0x20, 0x78, 0x3A,
  0x78, 0x6D, 0x70, 0x74, 0x6B, 0x3D, 0x22, 0x41, 0x64, 0x6F, 0x62, 0x65,
  0x20, 0x58, 0x4D, 0x50, 0x20, 0x43, 0x6F, 0x72, 0x65, 0x20, 0x35, 0x2E,
  0x36, 0x2D, 0x63, 0x30, 0x31, 0x34, 0x20, 0x37, 0x39, 0x2E, 0x31, 0x35,
  0x36, 0x37, 0x39, 0x37, 0x2C, 0x20, 0x32, 0x30, 0x31, 0x34, 0x2F, 0x30,
  0x38, 0x2F, 0x32, 0x30, 0x2D, 0x30, 0x39, 0x3A, 0x35, 0x33, 0x3A, 0x30,
  0x32, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x3E, 0x20,
  0x3C, 0x72, 0x64, 0x66, 0x3A, 0x52, 0x44, 0x46, 0x20, 0x78, 0x6D, 0x6C,
  0x6E, 0x73, 0x3A, 0x72, 0x64, 0x66, 0x3D, 0x22, 0x68, 0x74, 0x74, 0x70,
  0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, 0x77, 0x33, 0x2E, 0x6F, 0x72,
  0x67, 0x2F, 0x31, 0x39, 0x39, 0x39, 0x2F, 0x30, 0x32, 0x2F, 0x32, 0x32,
  0x2D, 0x72, 0x64, 0x66, 0x2D, 0x73, 0x79, 0x6E, 0x74, 0x61, 0x78, 0x2D,
  0x6E, 0x73, 0x23, 0x22, 0x3E, 0x20, 0x3C, 0x72, 0x64, 0x66, 0x3A, 0x44,
  0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x72,
  0x64, 0x66, 0x3A, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x3D, 0x22, 0x22, 0x20,
  0x78, 0x6D, 0x6C, 0x6E, 0x73, 0x3A, 0x78, 0x6D, 0x70, 0x3D, 0x22, 0x68,
  0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x6E, 0x73, 0x2E, 0x61, 0x64, 0x6F,
  0x62, 0x65, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x78, 0x61, 0x70, 0x2F, 0x31,
  0x2E, 0x30, 0x2F, 0x22, 0x20, 0x78, 0x6D, 0x6C, 0x6E, 0x73, 0x3A, 0x78,
  0x6D, 0x70, 0x4D, 0x4D, 0x3D, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F,
  0x2F, 0x6E, 0x73, 0x2E, 0x61, 0x64, 0x6F, 0x62, 0x65, 0x2E, 0x63, 0x6F,
  0x6D, 0x2F, 0x78, 0x61, 0x70, 0x2F, 0x31, 0x2E, 0x30, 0x2F, 0x6D, 0x6D,
  0x2F, 0x22, 0x20, 0x78, 0x6D, 0x6C, 0x6E, 0x73, 0x3A, 0x73, 0x74, 0x52,
  0x65, 0x66, 0x3D, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x6E,
  0x73, 0x2E, 0x61, 0x64, 0x6F, 0x62, 0x65, 0x2E, 0x63, 0x6F, 0x6D, 0x2F,
  0x78, 0x61, 0x70, 0x2F, 0x31, 0x2E, 0x30, 0x2F, 0x73, 0x54, 0x79, 0x70,
  0x65, 0x2F, 0x52, 0x65, 0x73, 0x6F, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65,
  0x66, 0x23, 0x22, 0x20, 0x78, 0x6D, 0x70, 0x3A, 0x43, 0x72, 0x65, 0x61,
  0x74, 0x6F, 0x72, 0x54, 0x6F, 0x6F, 0x6C, 0x3D, 0x22, 0x41, 0x64, 0x6F,
  0x62, 0x65, 0x20, 0x50, 0x68, 0x6F, 0x74, 0x6F, 0x73, 0x68, 0x6F, 0x70,
  0x20, 0x43, 0x43, 0x20, 0x32, 0x30, 0x31, 0x34, 0x20, 0x28, 0x57, 0x69,
  0x6E, 0x64, 0x6F, 0x77, 0x73, 0x29, 0x22, 0x20, 0x78, 0x6D, 0x70, 0x4D,
  0x4D, 0x3A, 0x49, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x49, 0x44,
  0x3D, 0x22, 0x78, 0x6D, 0x70, 0x2E, 0x69, 0x69, 0x64, 0x3A, 0x35, 0x31,
  0x30, 0x35, 0x43, 0x43, 0x37, 0x42, 0x43, 0x45, 0x36, 0x35, 0x31, 0x31,
  0x45, 0x36, 0x41, 0x45, 0x44, 0x46, 0x41, 0x33, 0x45, 0x43, 0x35, 0x38,
  0x42, 0x46, 0x39, 0x39, 0x41, 0x38, 0x22, 0x20, 0x78, 0x6D, 0x70, 0x4D,
  0x4D, 0x3A, 0x44, 0x6F, 0x63, 0x75, 0x6D, 0x65, 0x6E, 0x74, 0x49, 0x44,
  0x3D, 0x22, 0x78, 0x6D, 0x70, 0x2E, 0x64, 0x69, 0x64, 0x3A, 0x35, 0x31,
  0x30, 0x35, 0x43, 0x43, 0x37, 0x43, 0x43, 0x45, 0x36, 0x35, 0x31, 0x31,
  0x45, 0x36, 0x41, 0x45, 0x44, 0x46, 0x41, 0x33, 0x45, 0x43, 0x35, 0x38,
  0x42, 0x46, 0x39, 0x39, 0x41, 0x38, 0x22, 0x3E, 0x20, 0x3C, 0x78, 0x6D,
  0x70, 0x4D, 0x4D, 0x3A, 0x44, 0x65, 0x72, 0x69, 0x76, 0x65, 0x64, 0x46,
  0x72, 0x6F, 0x6D, 0x20, 0x73, 0x74, 0x52, 0x65, 0x66, 0x3A, 0x69, 0x6E,
  0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x49, 0x44, 0x3D, 0x22, 0x78, 0x6D,
  0x70, 0x2E, 0x69, 0x69, 0x64, 0x3A, 0x35, 0x31, 0x30, 0x35, 0x43, 0x43,
  0x37, 0x39, 0x43, 0x45, 0x36, 0x35, 0x31, 0x31, 0x45, 0x36, 0x41, 0x45,
  0x44, 0x46, 0x41, 0x33, 0x45, 0x43, 0x35, 0x38, 0x42, 0x46, 0x39, 0x39,
  0x41, 0x38, 0x22, 0x20, 0x73, 0x74, 0x52, 0x65, 0x66, 0x3A, 0x64, 0x6F,
  0x63, 0x75, 0x6D, 0x65, 0x6E, 0x74, 0x49, 0x44, 0x3D, 0x22, 0x78, 0x6D,
  0x70, 0x2E, 0x64, 0x69, 0x64, 0x3A, 0x35, 0x31, 0x30, 0x35, 0x43, 0x43,
  0x82
};


void setup()
{
  pinMode(13,OUTPUT); // Donde está el Led 13.
  pinMode(8,INPUT); // Entrada digital donde está el pulsador.
  Serial.begin(115200);
}

void loop()
{
    estadoBoton=digitalRead(8); // Leer entrada digital número 8.
    
    // Si el pulsador está pulsado, se enciende el Led 13 y
    // envía comando HIGH por el puerto serie.

    if(estadoBoton != anteriorBoton) // Comprueba si ha habido un cambio en el estado del botón.
    { 
      flagMensaje = 0;                // Resetea la bandera a 0.
      anteriorBoton = estadoBoton;    // Guarda el estado actual del botón.
    }

 if (estadoBoton == HIGH && flagMensaje == 0) // Comprueba que el botón esté pulsado y que no se haya enviado el mensaje.
    {
      digitalWrite(13,HIGH);
      Serial.write("ON");
      //Serial.write(rawData); // Enviar imagen o foto hacia el puerto serie al PC.
      delay(50);
     
      if(flagMensaje == 0)  // Si se envío el mensaje aumenta la variable a 1 para no enviarlo la próxima vez.
        flagMensaje++;
    }
    
 // De lo contrario, Led 13 epagado y envía LOW al puerto serie.
 else if(flagMensaje == 0) // Si el botón no está presionado y aún no se envía el mensaje.
    {
      digitalWrite(13,LOW);
      Serial.write("OFF");
      delay(50);
     
      if(flagMensaje == 0) // Si se envió el mensaje aumenta la variable en 1 para no enviarla la próxima vez.
        flagMensaje++;
    }
}

Compilado da:

El Sketch usa 3534 bytes (10%) del espacio de almacenamiento de programa. El máximo es 32256 bytes.
Las variables Globales usan 212 bytes (10%) de la memoria dinámica, dejando 1836 bytes para las variables locales. El máximo es 2048 bytes.

Por ahora, el tema de las memorias andan bien.

Sigo experimentando...

Nota: He recortado la mitad de las tramas de byte porque en el foro no cabe.

Serial.write(rawData); // Enviar imagen o foto hacia el puerto serie al PC

Ese comando está incompleto.
rawData es un array y Serial.write envía de a 1 byte.
dime sin no indexas el array como sabe Serial.write que enviar?

Esta sería la forma correcta si leo bien el tamaño del array.

// creo que sizeof(rawData) debería dar correctamente el tamaño del array porque lo definiste como unsigned char
// sino debe usarse de este modo sizeof(rawData)/sizeof(unsigned char *) para obtener el valor correcto

for (uint8_t i=0; i<sizeof(rawData); i++) {  // supongo que son menos de 255 elementos
    Serial.write(rawData[i]);
}

O aprovechando la otra forma de write:

Serial.write(rawData, sizeof(rawData));

Me compila bien con el ejemplo simple que han puesto arriba pero me advierte de la memoria.

El Sketch usa 5152 bytes (15%) del espacio de almacenamiento de programa. El máximo es 32256 bytes.
Las variables Globales usan 1826 bytes (89%) de la memoria dinámica, dejando 222 bytes para las variables locales. El máximo es 2048 bytes.
Poca memoria disponible, se pueden producir problemas de estabilidad.

Por lo que veo, debo de alguna forma, poner todos esos byte en la memoria Flash y que me deje la RAM que se gaste todo de golpe. Tal como dijeron más arriba.

Y que te dije mucho antes que debías usar? PROGMEM y mira bien como debe emplearse.

Recién leo la sugerencia de noter. Me gusta mucho mas esa opción antes que usar un for;;

Quizá sea porque a duras penas el array rawData cabe en la memoria RAM.
A esto se refería surbyte:

const unsigned char rawData[] PROGMEM = {/* Los bytes */}

Solo que para leer directamente desde ahí, habrá que irse por una propuesta similar a la de surbyte también:

void enviarImagen() {
  for (unsigned int i = 0; i < sizeof(rawData); i++)
    Serial.write(pgm_read_byte(&rawData[i]));
}

Hola:

Ya está bien de tantas fiestas y como loco quiero estar aquí, a experimentar y aprender. :wink:

Siguiendo el tema...
Como me mmaló la atención el PROGMEM (deduzco que significa PORGGRAMMER MEMORY) seguí más a fondo por aquí (Inglés), aquí (españól), aquí y aquí.

En C# trabajar en la RAM es mucho más rápido que desde un archivo externo o en el propio programa. En Arduino me imagino que será lo mismo, pero hay muchos peros, la RAM suele ser limitada. ¿Cómo conseguirlo?
Con PROGMEN o usar más AVR con mucho más RAM, y si no, pues RAM externa sea en serie o paralelo. Los hay de 64 Mb (8 MB) que se puede ver aquí.

Arriba pusieron:

const unsigned char rawData[] PROGMEM = {/* Los bytes */}

También se puede poner así según este enlace.
http://wiki.erikcrane.net/index.php/PROGMEM

PROGMEM const int a[] = {0,3,4,2};

Por lo que parece, cuestión de gustos.
Sigo haciendo pruebas y les comento.

Feliz año nuevo 2017.

No terminas de entenderlo Metaconta.
La opción de usar PROGMEM es aprovechar la FLASH no usada pero disponible, para que agregar una EEPROM o RAM externa?

Si entendí, solo que si no tienes ni flash para ella hay más opciones.

La RAM externa se usa más de lo que la gente cree, sobre todo para aquellos que hacen aparatos en empresas y luego venden, nosotros solos hobbystas.

Haciendo pruebas al compilar:

unsigned char rawData[] = {

El Sketch usa 5152 bytes (15%) del espacio de almacenamiento de programa. El máximo es 32256 bytes.
Las variables Globales usan 1826 bytes (89%) de la memoria dinámica, dejando 222 bytes para las variables locales. El máximo es 2048 bytes.
Poca memoria disponible, se pueden producir problemas de estabilidad.

PROGMEM const unsigned char rawData[] = {

El Sketch usa 5154 bytes (15%) del espacio de almacenamiento de programa. El máximo es 32256 bytes.
Las variables Globales usan 206 bytes (10%) de la memoria dinámica, dejando 1842 bytes para las variables locales. El máximo es 2048 bytes.

Ahora si que estoy tranquilo, ya que como me queda mucho de lamemoria Flash, pues puedo poner una imagen mucho más grande.

El Sketch usa 31788 bytes (98%) del espacio de almacenamiento de programa. El máximo es 32256 bytes.
Las variables Globales usan 206 bytes (10%) de la memoria dinámica, dejando 1842 bytes para las variables locales. El máximo es 2048 bytes.

Sigo experimentando.

Te dije que usaras PROGMEM en el post #4, te hubieras ahorrado algún tiempo, jaja!!

Bueno hay que verlo para creerlo, y creo que ese fue tu aprendizaje en este tema y enhorabuena por ello.

Te sobra espacio para almacenar todo tipo de cosas GRANDES, sin agregar hardware.
Ahora si por alguna razón requieres velocidad o mas tamaño, habrá que analizar si este es el mejor método, pero creo que por tenerlo disponible es difícil considerar otra opción salvo que requieras de una SD y archivos mayores a 32K.

Metaconta:
En C# trabajar en la RAM es mucho más rápido que desde un archivo externo o en el propio programa. En Arduino me imagino que será lo mismo

En mismo microcontrolador, leer desde la RAM o desde la memoria flash; la diferencia en velocidad es casi nula.

La contraparte de un "archivo externo" en un microcontrolador, es la obtención de datos desde hardware externo (vía UART, I2C, SPI o demás protocolos implementados por software).

PD: me sorprende que hayan tantas similitudes entre C# y Java, será acaso que Java se basa en C#? O viceversa? O ninguna de las anteriores? :confused:

surbyte:
Te dije que usaras PROGMEM en el post #4, te hubieras ahorrado algún tiempo, jaja!!

Ya veo.

Bueno hay que verlo para creerlo, y creo que ese fue tu aprendizaje en este tema y enhorabuena por ello.

Por supuesto que lo verás aún sin creerlo, ejkjejejejjejjeje. Y si, he aprendido gracias a ustedes.

Te sobra espacio para almacenar todo tipo de cosas GRANDES, sin agregar hardware.
Ahora si por alguna razón requieres velocidad o mas tamaño, habrá que analizar si este es el mejor método, pero creo que por tenerlo disponible es difícil considerar otra opción salvo que requieras de una SD y archivos mayores a 32K.

La idea es camuflar el archivo sin usar memoria externas, jejejeje. :wink:

Lucario448:
PD: me sorprende que hayan tantas similitudes entre C# y Java, será acaso que Java se basa en C#? O viceversa? O ninguna de las anteriores? :confused:

C# viene adaptado similitud a Java y a C/C++ para que precisamente esos usuarios se pasen a C# sin tener complicaciones o pereza en aprender algo nuevo. Otro lenguaje que no veo mucho que se use es el F#, no confundir con PowerShell en el cual Microsoft dice que es el sustituto del CMD.

Continuando el tema, y por supuesto, cuando acabe, pasaré los códigos fuentes tanto de Arduino como C# para que lo prueben ustedes mismos para curiosos.

Arduino IDE:

// Enviar tramas de byte al puerto serie.

int estadoBoton = 0; // Guardará el estado del botón HIGH o LOW.
int anteriorBoton = 0;
char caracter;
String comando;
int flagMensaje = 0;

// Esta trama de bytes corto en realidad es extremadamente largo, en este caso es como ejemplo.
PROGMEM const unsigned char rawData[] = {
  0xFF, 0xD8, 0xFF, 0xE1, 0x00, 0x18, 0x45, 0x78, 0x69, 0x66, 0x00, 0x00
};

void setup()
{
  pinMode(13, OUTPUT); // Donde está el Led 13.
  pinMode(8, INPUT); // Entrada digital donde está el pulsador.
  Serial.begin(115200);
}

void enviarImagen() {
  for (unsigned int i = 0; i < sizeof(rawData); i++)
    Serial.write(pgm_read_byte(&rawData[i]));
}

void loop()
{
  estadoBoton = digitalRead(8); // Leer entrada digital número 8.

  // Si el pulsador está pulsado, se enciende el Led 13 y
  // envía comando HIGH por el puerto serie.

  if (estadoBoton != anteriorBoton) // Comprueba si ha habido un cambio en el estado del botón.
  {
    flagMensaje = 0;                // Resetea la bandera a 0.
    anteriorBoton = estadoBoton;    // Guarda el estado actual del botón.
  }

  if (estadoBoton == HIGH && flagMensaje == 0) // Comprueba que el botón esté pulsado y que no se haya enviado el mensaje.
  {
    digitalWrite(13, HIGH);
    //Serial.write("ON");
    enviarImagen(); // Enviar imagen o foto hacia el puerto serie al PC.
    delay(50);

    if (flagMensaje == 0) // Si se envío el mensaje aumenta la variable a 1 para no enviarlo la próxima vez.
      flagMensaje++;
  }

  // De lo contrario, Led 13 epagado y envía LOW al puerto serie.
  else if (flagMensaje == 0) // Si el botón no está presionado y aún no se envía el mensaje.
  {
    digitalWrite(13, LOW);
    //Serial.write("OFF");
    delay(50);

    if (flagMensaje == 0) // Si se envió el mensaje aumenta la variable en 1 para no enviarla la próxima vez.
      flagMensaje++;
  }
}

Consola C#:

  1. Tiene que ser capaz de capturar cualquier dato desde Arduino.
  2. C# al tener ya los datos capturado, crear el archivo en memoria al disco duro.
  3. Si quieres al final, te lo abre automaticamente.

En este mismo momento, trabajando en C#............

Feliz año nuevo 2017.

Hola:

Por fin acabé la parte de C# que me volvió loco. :o :o :o :o :o

Está hecho muy básico pero funciona, ya es posible capturar los datos desde arduino, lo que sea, guardarlo al disco duro y procesarlo.

Les dejo el programa en consola C#, código de Arduino para prueben y cuenten sus primeras impresiones.

Más adelante lo mejoraré con Visual C# en vez de consola y haré tutorial sobre ello en C#,VB.net y C++.

El que haya visto la imagen de prueba que hay escondido en Arduino, lo suben por aquí. :wink:
No está codificada en esta versión, que también haré otro ejemplo si les interesa, es decir, en Arduino se pone una archivo o imagen codificado y cuando lo capture C#, lo codifica y se puede ver.

Les dejo la descarga.

Saludos.

Programa_v1.zip (44.7 KB)

Ups, archivo en el sketch muy grande para un ATmega328P.
Tendré que hacerlo en mi Arduino Mega (o incluso puedo hacerlo sin necesidad de un Arduino).