Data type en PROGMEM

Hola, estoy haciendo un trabajo de visualización de datos, y uso datos temporales en segundos obtenidos de protools en formato 00:00.000, arduino no me reconoce esta escala.
¿Alguien me puede recomendar soluciones? Adjunto el sketch que tengo. la idea es que cada determinados periodos de tiempo la salida 9 sea HIGH para activar un actuador, por un problema de velocidad del actuador mapeo la escala de delay entre dato y dato.
Muchas gracias, Munné.

PINTURA_R.A.P._CANSERBERO.ino (13.3 KB)

Para trabajar con tiempos has de usar milisegundos, y para ello se te queda corto un entero de 16 bits, que es el máximo tamaño que permite manejar "PROGMEM". Así que te he hecho un programita que guarda "tus tiempos" en memoria de programa usando "PROGMEM", pero utilizando 24 bits para guardar cada tiempo. Lo que se usa normalmente para manejar milisegundos es un unsigned long, que es de 32 bits, pero para los valores que manejas vas sobrado con 24 bits para guardarlos. Eso sí, una vez recuperados has de trabajar con 32 bis (unsigned log).

Para guardar los minutos, segundos y milésimas de segundos en 16 bits he definido unas macros para convertirlos a milisegundos y a su vez "trocearlos" en tres bytes para guardarlos en un array de bytes usando "PROGMEM". Estas macros se "traducen" en tiempo de compilación, generando el array que luego se compila. A este array no se puede acceder "directamente", se ha de hacer mediante la función pgm_read_byte_near(), pero para simplificarte la conversión te he hecho la función getMillis() a la que le pasas el índice del tiempo que quieres recuperar (el primero tiene como índice el cero) y te retorna el tiempo en milisegundos.

La cantidad de tiempos que se tiene guardado en el array se calcula automáticamente en tiempo de compilación y se guarda en la constante CANTIDAD_DE_TIEMPOS.

A la macro TIEMPO() se le pasan (separados por comas) el minuto, segundo y milisegundo que se desea guardar. Ojo, no empezar con ceros estos valores ya que el compilador puede interpretar que el valor está en octal (en lugar de poner 023 milisegundos hay que poner 23).

Hay algo que no entiendo, y es el uso del map(). No le encuentro sentido, más que nada porque los valores en milisegundos son muy elevados y se salen del rango que tienes puesto.

Adjunto programa que recorre todos tus tiempos almacenados en un array y muestra su índice, valor en el formato 0:00.000 y el equivalente en milisegundos. Espero que con esto puedas proseguir con lo que estás haciendo.

foro_datos_en_memoria_de_programa.ino (29.7 KB)

Muchas gracias, mi proyecto es activar un relay para cada instante de tiempo del array, el relay activa un motor, el motor que uso es lento y la velocidad máxima es de 750milisegundos. Ahora bien en mis datos el intervalo menor de tiempo es 34 milisegundos y el maximo de 1000 entonces uso map por el uso del motor donde el intervalo sea de 34 sea de 750 y que cuando sea de 1000 sea de 25000. Estaba pensando en que debería hacer un cálculo, que reste el dato tiempo -1 a tiempo para obtener estos intervalos y después mapearlos, si se te ocurre algo para mejorar el funcionamiento te agradezco, buenas noches.
Munné.

Otra posibilidad, en lugar de usar la macro, es traducir la definición externamente y poner directamente los valores en milisegundos. Con unas pocas operaciones con excel puedes convertir el texto de tu definición tal y como la tienes en una definición en milisegundos. Otra opción a mayores sería convertir ya a los valores mapeados, si no vas a necesitar los originales con otros fines.

Creo que empiezo a entender qué es lo que quieres hacer munnevollmer. Pero no entiendo porqué haces que pase la salida de nivel alto a nivel bajo casi instantáneamente. Fíjate que al comienzo de tu loop() pones la salida a nivel bajo. Esperas unos milisegundos (los que sea pero esperas). Pones después la salida a nivel alto y a continuación incrementas n y si no has llegado al final de los datos termina la función loop() y ésta acto seguido vuelve a ejecutarse poniendo de nuevo a nivel bajo la salida. Si te fijas la salida sólo está a nivel alto unos pocos microsegundos (milésimas de milésimas de segundo). Esto te generaría brevísimos pulsos a nivel alto cada cierta cantidad de milisegundos y dudo mucho que sea eso lo que quieres.

El otro problema que tienes es que el valor que estás usando para la pausa del delay() digamos que es es "tiempo absoluto" y no el intervalo que hay entre cada uno de los tiempos. Para ello, tomando como ejemplo tu código, deberías de usar algo así como «voz[n] - voz[n - 1]», que sería el tiempo que hay entre el instante n - 1 y el instante n. Usando el código que te he puesto sería algo así como «getMillis(n - 1) - getMillis(n)».

¿Podrías explicar mejor y con ejemplos de tiempos qué es lo que quieres hacer?

Por ejemplo: si cinco de los tiempos que tienes en el array son (en milisegundos) 16000, 16050, 16200, 17200 y 17500; los intervalos entre ellos serían 50, 150, 1000 y 300 milisegundos. ¿Cuánto tiempo debería de estar la salida a nivel bajo, cuanto tiempo después debería de estar a nivel alto, cuanto a nivel bajo otra vez, cuanto a nivel alto nuevamente, cuanto a nivel bajo... así hasta completar los cuatro intervalos que hay entre los cinco tiempos. ¿Por cada intervalo ha de pasar por los dos estados o es alternando los estados estando un intervalo a nivel bajo, el siguiente a nivel alto, el siguiente a nivel bajo, etc?

noter:
Otra opción a mayores sería convertir ya a los valores mapeados, si no vas a necesitar los originales con otros fines.

Es una muy buena idea. Ya que, si los tiempos no superan los 65535 milisegundos, pueden ser almacenarlos y recuperarlos directamente de "memoria de programa" como enteros sin signos de 16 bits (unsigned int). Con lo que, comparado con mi propuesta, se ahorra un 33% de memoria de programa ya que pasa de usar 3 bytes por valor a usar sólo 2 bytes. Eso sí, antes se han de calcular los intervalos a partir de los tiempos que se tiene, cosa que también se puede hacer fácilmente con Excel.

Primero gracias por la atención, tomando como ejemplo los tiempos que decís los intervalos son correctos:
"16000, 16050, 16200, 17200 y 17500; los intervalos entre ellos serían 50, 150, 1000 y 300."
Lo ideal es que ni bien pasados los 50 milisegundos el El OUTPUT de HIGH, para disparar un relay, despues a los 150 debe ponerse en HIGH denuevo, o sea que en algun momento de esos 150 milisegundos debe pasar a LOW, y así.
Por eso lo escribí primero LOW despues HIGH, cosa de que arranque bajo cuente 50 sea HIGH y se repita, pero también creo que no es lo ideal ese modo.
Los datos tiempo lo resolvi de dos formas, uno con excel como dijeron y otro usando el sketch que me pasaste "ignoranteabsoluto" copie los datos de la consola serial y listo.
Además de esto debería hacer que un sensor ultrasónico varíe el tiempo de lectura entre HIGH y HIGH por lo que seguramente pienso hacer que varíe los valores del delay, en los rangos delimitados por VOZ [N] - VOZ[N-1].
Cualquier ayuda es bienvenida !

No se puede usar PROGMEM y pgm_read_word_near() con float. Sólo sirve para int o para unsigned int. Por eso tuve que hacer tan compleja mi propuesta para guardar y recuperar los datos.

Sigo sin tener muy claro qué es lo que tratas de hacer. Pero he adaptado el código de mi propuesta para tratar de hacer lo último que has puesto. Algunos tiempos estaban "intercambiados" y los he ordenado. También he quitado el primer tiempo (0:00.000). Espero que esto te de ideas y que encuentres la solución que buscas.

Adjunto programa.

foro_datos_en_memoria_de_programa.ino (30.1 KB)

Buenas, este es el sketch que tengo hasta ahora funcionando, tengo un problema todavía y una función que agregar:
El problema que tengo es que después de que pinRelay sea LOW, agrego un delay (10), no quiero usar este delay, pensé solucionar esto dividiendo el delay de los datos a la mitad, y usando 1/2 delay entre que cambio de high a low y el otro medio entre que va de low a high. Que opinás?
La segunda cuestión es que tengo que modular la lectura de los datos, mediante un sensor ultrasónico, pensaba hacer que el sensor modifique el map de tiempoMap, claro que esto significaría dejar de usar delay para trabajar todo el sketch con millis().
Recién ahora pude solucionar varios problemas por eso tardé en subirlo.

PINTURA_R.A.P._CANSERBERO_II.ino (11.1 KB)

No se puede usar PROGMEM y pgm_read_word_near() con float. Sólo sirve para int o para unsigned int.

Un aporte para que mejores esa parte IgnoranteAbsoluto
PROGMEM float arrays

si es puede, se llama pgm_read_float_near() el procedimiento que lo permite.