Acceder en cada loop a un único dato en array en sd

Buenas a todos!

estoy intentando hacer un programa para activar un motor a unos tiempos determinados, en un futuro iría sincronizado con un video, esta parte está aun sin hacer.

La idea es meter estos tiempos en un archivo de una sd. Quería poder accerder a este listado de tiempos en cada iteración del loop, pero sólo a un dato por iteración, no a todo el archivo, pero no consigo acceder sólo a un dato. ¿Me podéis echar una mano?

Gracias!

Archivo SD (ejemplo)

10
20
30
...
#include <SD.h>

#define pin_motor3 3

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

const int chipSelect = 10;
int lastposition = 0;
int index = 0;
File data;

void setup() {
  Serial.begin(115200);
  pinMode(7, OUTPUT);
  Serial.print("Initializing SD card...");
  pinMode(pin_motor3, OUTPUT);
  // see if card ready----------------------------
  if (!SD.begin(chipSelect))
  {
    Serial.println("Card failed");
    return;
  }

  Serial.println("card Ready");
}


void loop()
{
  sbi(PORTD, 7);//Frequency test
  Serial.print (index); Serial.print("    ");
  data = SD.open("test.txt");
  int totalbytes = data.size();
  if (data) {
    if (lastposition >= totalbytes) lastposition = 0; index = 0; //Restart count
    data.seek(lastposition); //find index last position
      int newvalue = data.parseInt();
      analogWrite(pin_motor3, newvalue);
      lastposition = data.position();
      Serial.print (newvalue); Serial.print("    "); Serial.println(lastposition);

    data.close();
  } else {
   // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
    cbi(PORTD, 7);
    index++;
  }

Pues ya está solucionado.

Lo único que tarda 12ms por ciclo. ¿Alguna idea para bajar este tiempo?

#include <SD.h>

#define pin_motor3 3

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

const int chipSelect = 10;
int index = 0;
int auxarray[10];
int arraycount = 0;
unsigned int totalbytes;
unsigned long lastposition = 50;
int newvalue;
File data;

void setup() {
  Serial.begin(115200);
  pinMode(7, OUTPUT);
  Serial.print("Initializing SD card...");
  pinMode(pin_motor3, OUTPUT);
  // see if card ready----------------------------
  if (!SD.begin(chipSelect))
  {
    Serial.println("Card failed");
    return;
  }
  data = SD.open("test.txt");
  totalbytes = data.size();
  data.close();
  Serial.println("card Ready");
}


void loop()
{
  sbi(PORTD, 7);//Frequency test
  Serial.print("Index="); Serial.print (index); Serial.print("    ");
  data = SD.open("test.txt");
  // totalbytes = data.size();
  if (data) {
    if (lastposition >= totalbytes) {
      lastposition = 0;
    }
    data.seek(lastposition);
    while (data.available()) {
      switch ((char)data.peek()) {
        case ',': data.read(); Serial.println(" coma"); break;
        case '\n': data.read(); Serial.println(" salto"); break;
        default:
          /* de esta forma tarda 12ms por ciclo*/
          newvalue = data.parseInt();
          auxarray[arraycount] = newvalue;
          arraycount++;
          Serial.print("Pos="); Serial.print(lastposition);
          Serial.print("Leo="); Serial.println (newvalue);
          lastposition = data.position();
          data.close();
          break;
      }
    }
  }
  else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
  analogWrite(pin_motor3, newvalue);
  cbi(PORTD, 7);
  index++;
}

Dispone los números de otro modo. que tal leer 10 números de una sola vez y no 10 lecturas para 10 número o amplia eso a un valor del array que no comprometa tu SRAM.

en ves de disponer

10 20 30 40 50

pon

1020304050 y luego lo separas x software

Es una opción. El archivo que tengo en la sd es de unos 10MB, cambiaré la estructura para meter más datos por línea y separalos via software, pero la velocidad de acceso seguirá siendo la misma, cada vez que tenga que leer el programa se ralentizará.

ymirvk: Lo único que tarda 12ms por ciclo. ¿Alguna idea para bajar este tiempo?

Tengo varias:

  • Codifica los números de forma binaria, es más rápido de trabajar y muy fácil de indexar (tienen siempre el mismo tamaño independientemente del valor). Lo difícil es crear un archivo codificado de esa manera, los editores de texto no sirven, pero los "editores hexadecimales" sí. parseInt() es lento cuando el tiempo importa.
  • Utiliza siempre el tipo de variable más pequeño posible, pero sin restringir más allá de lo que se necesita. Por ejemplo, usa byte si estás seguro que ningún valor excederá 255; o unsigned int si excede 255 pero no 65535.
  • Si estás seguro que tu programa funciona como debería, elimina (o comenta) todas las líneas que involucren a Serial. Si el puerto serial no es realmente requerido para el funcionamiento del programa, ni te molestes en utilizarlo ya que te estará desperdiciendo valioso tiempo de ejecución.
  • Si el archivo se abre para lectura únicamente, no vale la pena estarlo reabriendo constantemente; al contrario, estarías desperdiciando más tiempo todavía. Con una vez basta.

Si haces por lo menos lo primero, te podría decir que ni vectores hacen falta; utilizas el objeto del archivo como uno (seek() para cambiar la posición y read() para obtener los valores).

Veo que manipulas puertos, a eso no digo nada porque ya lo estás haciendo mucho más rápido que con digitalWrite().

PD: otra optimización es que el archivo no esté fragmentado; es muy difícil decir si es el caso porque lo menos que se puede hacer es ordenar una desfragmentación desde la PC. Pero de lo que sí estoy seguro, es que puede (no necesariamente) aplicar en archivos grandes, típicamente de más de 4096 bytes o 4 KB; menos que eso jamás va a suceder.

Lucario448:
PD: otra optimización es que el archivo no esté fragmentado; es muy difícil decir si es el caso porque lo menos que se puede hacer es ordenar una desfragmentación desde la PC. Pero de lo que sí estoy seguro, es que puede (no necesariamente) aplicar en archivos grandes, típicamente de más de 4096 bytes o 4 KB; menos que eso jamás va a suceder.

Corrección: aquí me retracto de lo que dije; ya que, debido a como funciona un sistema de archivos FAT, la librería siempre hace los mismos malabares fragmentado o no. Donde puede haber mejoría es la escritura, cuando el archivo necesita crecer; pero en la lectura realmente no hay diferencia alguna.

Buenas a todos,

¿es posible declarar una variable en una sd?

Por comodidad de acceso y curiosidad, me gustaría declarar un array de int en una sd, e interactuar con él como si estuviese declarado en la memoria de la placa.

He probado los siguiente, pero da error:

sketch\ficherazo.h:1:0: error: unterminated #ifndef

Código del programa

#include <SD.h>
#include "ficherazo.h"

const int chipSelect = 10;

//Array de 500int en sd
const int []SSID = "\"mySSID\";
extern const int[] SSID;


void setup() {
  Serial.begin(115200);
  Serial.print("Initializing SD card...");
  // see if card ready----------------------------
  if (!SD.begin(chipSelect)){    {
    Serial.println("Card failed");
    return;
    }
}

void loop() {
  for (int i = 0; i<500; i++{
    Serial.println(ficherazo[i]);
  }
  delay(500);
}

ficherazo.h

#ifndef ficherazo_h
#define ficherazo_h

ficherazo.ccp ----> este estaría guardado en la sd

#include "ficherazo.h"
int ficherazo[]  = {
0, 	1, 	2, 	3, 	4, 	5, 	6, 	7, 	8, 	9, 
10, 	11, 	12, 	13, 	14, 	15, 	16, 	17, 	18, 	19, 
20, 	21, 	22, 	23, 	24, 	25, 	26, 	27, 	28, 	29, 
30, 	31, 	32, 	33, 	34, 	35, 	36, 	37, 	38, 	39, 
40, 	41, 	42, 	43, 	44, 	45, 	46, 	47, 	48, 	49, 
50, 	51, 	52, 	53, 	54, 	55, 	56, 	57, 	58, 	59, 
60, 	61, 	62, 	63, 	64, 	65, 	66, 	67, 	68, 	69, 
70, 	71, 	72, 	73, 	74, 	75, 	76, 	77, 	78, 	79, 
80, 	81, 	82, 	83, 	84, 	85, 	86, 	87, 	88, 	89, 
90, 	91, 	92, 	93, 	94, 	95, 	96, 	97, 	98, 	99, 
100, 	101, 	102, 	103, 	104, 	105, 	106, 	107, 	108, 	109, 
110, 	111, 	112, 	113, 	114, 	115, 	116, 	117, 	118, 	119, 
120, 	121, 	122, 	123, 	124, 	125, 	126, 	127, 	128, 	129, 
130, 	131, 	132, 	133, 	134, 	135, 	136, 	137, 	138, 	139, 
140, 	141, 	142, 	143, 	144, 	145, 	146, 	147, 	148, 	149, 
150, 	151, 	152, 	153, 	154, 	155, 	156, 	157, 	158, 	159, 
160, 	161, 	162, 	163, 	164, 	165, 	166, 	167, 	168, 	169, 
170, 	171, 	172, 	173, 	174, 	175, 	176, 	177, 	178, 	179, 
180, 	181, 	182, 	183, 	184, 	185, 	186, 	187, 	188, 	189, 
190, 	191, 	192, 	193, 	194, 	195, 	196, 	197, 	198, 	199, 
200, 	201, 	202, 	203, 	204, 	205, 	206, 	207, 	208, 	209, 
210, 	211, 	212, 	213, 	214, 	215, 	216, 	217, 	218, 	219, 
220, 	221, 	222, 	223, 	224, 	225, 	226, 	227, 	228, 	229, 
230, 	231, 	232, 	233, 	234, 	235, 	236, 	237, 	238, 	239, 
240, 	241, 	242, 	243, 	244, 	245, 	246, 	247, 	248, 	249, 
250, 	251, 	252, 	253, 	254, 	255, 	256, 	257, 	258, 	259, 
260, 	261, 	262, 	263, 	264, 	265, 	266, 	267, 	268, 	269, 
270, 	271, 	272, 	273, 	274, 	275, 	276, 	277, 	278, 	279, 
280, 	281, 	282, 	283, 	284, 	285, 	286, 	287, 	288, 	289, 
290, 	291, 	292, 	293, 	294, 	295, 	296, 	297, 	298, 	299, 
300, 	301, 	302, 	303, 	304, 	305, 	306, 	307, 	308, 	309, 
310, 	311, 	312, 	313, 	314, 	315, 	316, 	317, 	318, 	319, 
320, 	321, 	322, 	323, 	324, 	325, 	326, 	327, 	328, 	329, 
330, 	331, 	332, 	333, 	334, 	335, 	336, 	337, 	338, 	339, 
340, 	341, 	342, 	343, 	344, 	345, 	346, 	347, 	348, 	349, 
350, 	351, 	352, 	353, 	354, 	355, 	356, 	357, 	358, 	359, 
360, 	361, 	362, 	363, 	364, 	365, 	366, 	367, 	368, 	369, 
370, 	371, 	372, 	373, 	374, 	375, 	376, 	377, 	378, 	379, 
380, 	381, 	382, 	383, 	384, 	385, 	386, 	387, 	388, 	389, 
390, 	391, 	392, 	393, 	394, 	395, 	396, 	397, 	398, 	399, 
400, 	401, 	402, 	403, 	404, 	405, 	406, 	407, 	408, 	409, 
410, 	411, 	412, 	413, 	414, 	415, 	416, 	417, 	418, 	419, 
420, 	421, 	422, 	423, 	424, 	425, 	426, 	427, 	428, 	429, 
430, 	431, 	432, 	433, 	434, 	435, 	436, 	437, 	438, 	439, 
440, 	441, 	442, 	443, 	444, 	445, 	446, 	447, 	448, 	449, 
450, 	451, 	452, 	453, 	454, 	455, 	456, 	457, 	458, 	459, 
460, 	461, 	462, 	463, 	464, 	465, 	466, 	467, 	468, 	469, 
470, 	471, 	472, 	473, 	474, 	475, 	476, 	477, 	478, 	479, 
480, 	481, 	482, 	483, 	484, 	485, 	486, 	487, 	488, 	489, 
490, 	491, 	492, 	493, 	494, 	495, 	496, 	497, 	498, 	499
} ;

¿Oye por qué no seguiste aquí?
Además, ya te dije para crear archivos binarios necesitas un editor hexadecimal; o sino crear un programa de Arduino para tal efecto.
Ya que por lo menos tienes declarado el vector, puedes dejar que el Arduino cree el archivo binario. Al menos en esa parte te daré un empujón:

#include "ficherazo.h"
#include <SD.h>

void setup() {
 if (!SD.begin(10)) return;

 File f = SD.open("fichrazo.dat", O_WRITE | O_CREATE | O_TRUNC);
 if (!f) return;
 unsigned int cantidad = sizeof(ficherazo) / sizeof(int);
 for (unsigned int i = 0; i < cantidad; i++)
  f.write((byte*)&ficherazo[i], 2);

 f.close();
}

void loop() {}

Si todo sale bien, en la tarjeta debería aparecer un archivo llamado “FICHRAZO.DAT”, el cual contiene lo mismo que el vector ficherazo; pero esta vez sí está como binario (tal cual se almacena en RAM). Termina en “.dat” porque al ser un archivo binario, su contenido no es legible (aparece “basura”) en editores de texto plano.

Desconozco el microcontrolador que ejecutará este código, así que si de lleno no compila por falta de RAM, habrá que proceder un poco diferente.

PD:

ymirvk:
He probado los siguiente, pero da error:

sketch\ficherazo.h:1:0: error: unterminated #ifndef

Las condicionales para el compilador necesitan la marca de finalización; en otras palabras, olvidaste el #endif al final.

Además, para almacenar declaraciones de datos no es necesario crear archivos fuente (.cpp), en la cabecera (.h) va todo.

Gracias!!

Lucario448: ¿Oye por qué no seguiste aquí?

Pues hice un hilo nuevo por considerar que era un tema diferente. Si es verdad que si funciona será el mismo programa, pero como no encontraba información preferí abrir un hilo con la duda. Sigo peleándome con el programa del otro hilo y aplicando tus consejos de meter los datos en hexadecimal.

He añadido, como has comentado, #endif al final del *.h, ya lo coge. Esto no lo había considerado jejeje. No tengo mucha experiencia con esto y voy copiando de mil sitios, al final algo se pierde.

He probado el codigo tal cual, da error: 'ficherazo' was not declared in this scope; y no crea el *.dat

He sustituido "O_WRITE | O_CREATE | O_TRUNC" por O_WRITE y FILE_WRITE y actúa igual.

El programa lo estoy ejecutando en un Arduino UNO.

Lucario448: - Si el archivo se abre para lectura únicamente, no vale la pena estarlo reabriendo constantemente; al contrario, estarías desperdiciando más tiempo todavía. Con una vez basta.

He probado sólo este pnto, si sólo el abro el archivo en el setup, dejándolo abierto, el programa lee todo el archivo cada vez que ejecuta loop. He ido haciendo combinaciones quitando "if (data)" y "while(data.available)" y en el mejor de los casos solo detecta los saltos de línea ("\n").

Cuando tenga el archivo hexadecimal y pruebe el resto os comento

ymirvk:
Pues hice un hilo nuevo por considerar que era un tema diferente. Si es verdad que si funciona será el mismo programa, pero como no encontraba información preferí abrir un hilo con la duda.

Ya no importa, que hasta ahorita me entero que los moderadores tienen el poder de fusionar hilos.

ymirvk:
He probado el codigo tal cual, da error: ‘ficherazo’ was not declared in this scope; y no crea el *.dat

He sustituido “O_WRITE | O_CREATE | O_TRUNC” por O_WRITE y FILE_WRITE y actúa igual.

Es lo que te decía:

Lucario448:
Además, para almacenar declaraciones de datos no es necesario crear archivos fuente (.cpp), en la cabecera (.h) va todo.

Y al parecer no solo no es necesario, sino que ni se debería. Y pues… si el programa ni siquiera se sube, menos va a crear el archivo ::slight_smile:

ymirvk:
El programa lo estoy ejecutando en un Arduino UNO.

Ufff, entonces ficherazo ocupa 1000 bytes en RAM, mientras que la librería se lleva otros 700. Aunque compile y se suba, existe la posibilidad de el archivo igual no se cree, o el programa se congele a medio camino. De ser así, habrá que recurrir al “otro procedimiento”.

ymirvk:
He probado sólo este pnto, si sólo el abro el archivo en el setup, dejándolo abierto, el programa lee todo el archivo cada vez que ejecuta loop.

Sabes que puedes retroceder con seek(), ¿cierto? Si le colocas cero por valor, se devuelve justamente al principio.

PD: supongo que ficherazo es sólo para prueba, digo… si vas a almacenar la cuenta hasta 500 (499 por ser desde 0), eso hasta en tiempo de ejecución se podría obtener sin guardar nada previamente.

De haber reconocido ese patrón antes, ni siquiera el vector haría falta para rellenar el archivo:

for (unsigned int i = 0; i < 500; i++)
  f.write((byte*)&i, 2);

Si, en este caso ficherazo es un archivo ejemplo, el real es un .wav, son 3millones de datos jejejej, pero por comodidad y para el testeo quería probar con algo fácil de crear y comprobar, por eso es de 0-500, así se ve fácilmente si lee todos los valores y por orden

ymirvk: el real es un .wav

Espera un segundo... ¿de qué me perdí?

¿Un archivo .wav? ¿Por qué? Necesito que me refresques la memoria, ¿qué es exactamente lo quieres hacer con archivos de audio .wav?

La idea del programa es meter una lista de tiempos en los que la placa tiene que activar un motor que marque el ritmo. Esta lista en origen era un .wav con la señal tratada para el ritmo.

A día de hoy es una lista con los tiempos en la que se tiene que activar.

Aunque se ha reducido su tamaño considerablemente, la memoria del UNO es más pequeña de lo que necesito.

Esto no lo había comentado, creía que iba a ser más fácila jajajaja

ymirvk: La idea del programa es meter una lista de tiempos en los que la placa tiene que activar un motor que marque el ritmo.

"wav" es una abreviación de la palabra "wave" (onda u ola), lo que quiere decir que es un archivo que almacena ondas. Por "almacenar ondas" se refiere a almacenar el resultado de la conversión de una señal analógica, a una secuencia de números; mediante un proceso llamado "cuantificación", que consiste en asignar un valor numérico a cierto nivel de amplitud (voltaje) capturado en determinado momento (cosa que un Arduino puede hacer, ¿te suena como a analogRead()?). Usualmente se realiza en intervalos regulares (frecuencia de muestreo) para hacer más fácil la posterior recreación de las ondas que se están capturando.

En resumen, los archivos ".wav" se supone que fueron creados para almacenar digitalmente una o varias señales analógicas (que usualmente son de audio); y su posterior reproducción desde sistemas también digitales. No comprendo exactamente cómo es que es usado para guardar "una lista de tiempos".

ymirvk: Esta lista en origen era un .wav con la señal tratada para el ritmo.

Ah ya, ahora tiene más sentido. Sin embargo sigo sin entender qué tiene que ver esa señal con el ritmo de algo. ¿Es meramente PWM (tren de pulsos u onda cuadrada, de ancho variable; como los que controlan servos y ESCs) o en serio es algo que se maneja con una señal completamente analógica?

ymirvk: Aunque se ha reducido su tamaño considerablemente, la memoria del UNO es más pequeña de lo que necesito.

Muy posiblemente era completamente necesaria la tarjeta SD; 2 KB de RAM no dan cabida para casi nada, 1 KB de EEPROM igual o peor, tal vez los 32-4-(lo que se lleve el código) KB de memoria flash interna que todavía es insuficiente para secuencias de datos enormes.

Solo un apunte.

En algún momento he leído que la SD te presenta problemas por lentitud, quizás te interese echar una mirada a esto.

https://www.instructables.com/id/Interface-an-SRAM-bus-to-your-arduino/

Y luego mirar este pdf de Microchip A partir de la pagina 9 donde habla de Serial SRAM con capacidades de 256K-1Mb y sigue con la Serial Flash con capacidades de 512K -64Mb

http://ww1.microchip.com/downloads/en/DeviceDoc/20005356B.pdf

Espero que te sea de utilidad.