Cargar un ARRAY mediante FOR en sincronía con MILLIS.

Hola a todos! Soy novato, este es mi primer post, busco ayuda! Gracias de antemano por su dedicación!!!
Trataré de explicar lo mejor posible el problema...
Se trata de cargar un array con 60 datos, pero esos datos surgen cada 15 segundos.
Y además con la condicionante de que los espacios de tiempo entre lecturas deben realizarse mediante la función millis ya que no debo usar delay.

Las declaraciones:

long tPeriodo = 900000;                //Periodo = Tiempo de carga de un array completo = 15min
const int N = 60;                            //Cantidad de mediciones por Periodo
int tiempoCiclo = tPeriodo / N;      //Ciclo = Tiempo entre datos para el array

int estadoSalida;                           //bus para lectura de sensor
int contPulsos = 0;                        //bus donde suma cantidad de pulsos por ciclo

En el void loop tengo un bloque de código que cuenta pulsos de un sensor:
(Este debe estar todo el tiempo funcionando por lo que debo evitar el uso de Delay en el resto del código)

int estado = digitalRead(D1);
if (estado == HIGH) {
estadoSalida = 1;
}
if (estadoSalida == 1 && estado == LOW) {
contPulsos++;
estadoSalida = 0;
}

Ahora el problema!
El tema es cuando quiero tomar cada 15 segundos, los pulsos que conté en la variable contPulsos e ir completando el array de datos que luego debo seguir procesando (parte que no les muestro porque está resuelta y para no aburrirlos) no puedo lograrlo.
Obviamente mi falta de formación me pasa factura y es evidente que estoy encarando mal la respuesta.
Las aproximaciones que tengo que no resuelven el tema son la siguientes:

for (p = 0; p < N; p++)
{ if (millis() > (starTime + tiempoCiclo)) {
velPulsos = (contPulsos * 0.242);
datos[p] = velPulsos;
starTime = millis();
contPulsos = 0;
}
Serial.println("Posicion:");
Serial.print(p);
Serial.println("Velocidad:");
Serial.print(datos[p]);
}

Espero haber explicado bien la cuestión, les agradezco la paciencia. Saludos!!

Y además con la condicionante de que los espacios de tiempo entre lecturas deben realizarse mediante la función millis ya que no debo usar delay.

Pues con esta frase has logrado mi atención total!!

Pero.... has puesto tres partes del código pero no el código completo y entonces no podemos verlo en su totalidad.

Por favor postea todo el código.

Mientras algunas observaciones menores. Como digo son menores por ahora.
Si usas millis() todo debes ser unsigned long, no long como leo en la defincion de tus variables.

long tPeriodo = 900000;                //Periodo = Tiempo de carga de un array completo = 15min
const int N = 60;

y de nuevo

int tiempoCiclo = tPeriodo / N;

Mal! tiempoCiclo debe ser de nuevo unsigned long y N tmb unsigned long

Comienza ajustando eso mas alla del pedido del código completo que si no entra en el post solo adjúntalo.

Pues con esta frase has logrado mi atención total!!

En ese caso me alegro de haberla escrito!

Hola y gracias por tu respuesta.

Primero lo pedido, acá está el código...
(recordar que soy novato, vengo de leer el manual y alimentarme de youtube)

unsigned long tPeriodo = 900000;          //Periodo = Tiempo de carga de un array completo = 15min
unsigned long N = 60;                         //Cantidad de mediciones por Periodo
const int Db = 35;                        //Cantidad de datos para baja
const int Dr = 25;                        //Cantidad de datos para alta
unsigned long tiempoCiclo = tPeriodo / N; //Ciclo = Tiempo entre datos para el array
unsigned long starTime = 0;
unsigned long tiempoAhora = 0;
int p, j;                       //Posicion y valor en el array datos
float aux;                      //Var decimal p cambio de posicion en burbuja
float baja;                     //Var decimal baja
float alta;                    //Var decimal alta
float datos[N];                 //Array
int estadoSalida;               //bus para lectura de sensor
int contPulsos = 0;             //bus donde suma cantidad de pulsos por ciclo
float velPulsos;                //velocidad

void setup() {
  Serial.begin(9600);
  pinMode(D1, INPUT);
  starTime = millis();
}

void loop() {
  int estado = digitalRead(D1);
  if (estado == HIGH) {
    estadoSalida = 1;
  }
  if (estadoSalida == 1 && estado == LOW) {
    contPulsos++;
    estadoSalida = 0;
  }
  for (p = 0; p < N; p++)
  { if (millis() > (starTime + tiempoCiclo)) {
      velPulsos = (contPulsos * 0.242);         //Calcula nudos
      datos[p] = velPulsos;
      starTime = millis();
      contPulsos = 0;                          //Reinicia contador
    }
    Serial.println("Posicion:");
    Serial.print(p);
    Serial.println("Velocidad:");
    Serial.print(datos[p]);
  }

  for (p = 0; p < N - 1; p++) {            //burbuja!
    for (j = 0; j < N - 1; j++) {
      if (datos[j]  > datos [j + 1]) {
        aux = datos[j];
        datos[j] = datos[j + 1];
        datos[j + 1] = aux;
      }
    }
  }

  float sumaB = 0;                           //promedia velocidades bajas
  for (p = 0; p < Db; p++) {
    sumaB += datos[p];
  }
  baja = sumaB / ((N / 5) * 2);

  float sumaR = 0;                           //promedia velocidades altas
  for (p = (N - Dr); p < N; p++) {
    sumaR = sumaR + datos[p];
  }
  alta = sumaR / ((N / 5) * 2);

  Serial.println("");
  Serial.print("Bajas: ");
  Serial.println(baja);
  Serial.print("Altas: ");
  Serial.println(alta);
  Serial.println("*********************************************");

}

Y lo de las variables ahí está, tal como me lo has recomendado, gracias!

Tratare de explicar lo que quiero conseguir en caso de que no haya quedado claro.
Porque tal vez estoy encarando mal el tema desde lo general o tal vez me falta arreglar algo particular.

El origen de los datos que es la lectura de pulsos me parece correcta y funciona bien.

 int estado = digitalRead(D1);
  if (estado == HIGH) {
    estadoSalida = 1;
  }
  if (estadoSalida == 1 && estado == LOW) {
    contPulsos++;
    estadoSalida = 0;
  }

De esa lectura lo que quiero es tener cada 15 minutos, un muestreo de 60 mediciones de velocidad de pulsos (cada medición de 15 seg.) Y con ese muestreo calcular un promedio de los 25 valores mas altos y otro promedio de los 35 mas bajos.
Con eso soy felizzzzz!!! Gracias nuevamente!

Ahora estoy pensando que tal vez mi problema está en lo único que creía tener bien, la toma de datos del sensor. Porque leyendo el proyecto de @victorjam “Tacómetro y efecto no deseado en el código” veo que tenemos algunas similitudes dado que medimos frecuencia de pulsos y el utiliza la función attachInterrupt() que yo no conocía.
En lugar de medir velocidad cada 15 segundos tal vez pueda medir el tiempo entre pulsos y tener velocidad instantánea pero no se como llegaría eso a completar el array de 15 minutos y ahí es cuando empiezo a patinar por desconocimiento y necesito alguien que me de un vistazo de buen cubero!

Fijate si te sirve

unsigned long tPeriodo = 900000;          //Periodo = Tiempo de carga de un array completo = 15min
unsigned long N = 60;                         //Cantidad de mediciones por Periodo
const int Db = 35;                        //Cantidad de datos para baja
const int Dr = 25;                        //Cantidad de datos para alta
unsigned long tiempoCiclo = tPeriodo / N; //Ciclo = Tiempo entre datos para el array
unsigned long starTime = 0;
unsigned long tiempoAhora = 0;
int p, j;                       //Posicion y valor en el array datos
float aux;                      //Var decimal p cambio de posicion en burbuja
float baja;                     //Var decimal baja
float alta;                    //Var decimal alta
float datos[60];                 //Array
int estadoSalida;               //bus para lectura de sensor
int contPulsos = 0;             //bus donde suma cantidad de pulsos por ciclo
float velPulsos;                //velocidad
const int D1 = 3;

void setup() {
  Serial.begin(9600);
  pinMode(D1, INPUT);
  starTime = millis();
  tiempoAhora = starTime;
  p = 0;
}

void loop() {
  int estado = digitalRead(D1);
  if (estado == HIGH) {
    estadoSalida = 1;
  }
  if (estadoSalida == 1 && estado == LOW) {
    contPulsos++;
    estadoSalida = 0;
  }

  if (millis() - starTime >=  tiempoCiclo) {  // pasaron 15 segundos?
    starTime += tiempoCiclo;
   
    velPulsos = (float)contPulsos * 0.242;         //Calcula nudos
    datos[p] = velPulsos;
  
    Serial.println("Posicion:");
    Serial.print(p);
    Serial.println("Velocidad:");
    Serial.print(datos[p]);
   
    contPulsos = 0;                          //Reinicia contador
    p++;
    p %= 60; // equivale a if(p == 60) p = 0;
  }

 if(millis() - tiempoAhora >= tPeriodo) { // pasaron 15 minutos ?
   tiempoAhora += tPeriodo;
   for (p = 0; p < N - 1; p++) {            //burbuja!
     for (j = 0; j < N - 1; j++) {
       if (datos[j]  > datos [j + 1]) {
          aux = datos[j];
          datos[j] = datos[j + 1];
          datos[j + 1] = aux;
        }
      }
    }
 
    float sumaB = 0;                           //promedia velocidades bajas
    for (p = 0; p < Db; p++) {
      sumaB += datos[p];
    }
    baja = sumaB / ((N / 5) * 2);

    float sumaR = 0;                           //promedia velocidades altas
    for (p = (N - Dr); p < N; p++) {
      sumaR = sumaR + datos[p];
    }
    alta = sumaR / ((N / 5) * 2);
    p = 0;
    Serial.println("");
    Serial.print("Bajas: ");
    Serial.println(baja);
    Serial.print("Altas: ");
    Serial.println(alta);
    Serial.println("*********************************************");
  }
}

Use tiempoAhora (que no la usabas) para controlar los 15 minutos.
Le asigné a D1 el valor 3 (o sea pin 3), ajustala a tu necesidad

Saludos

@gatul
¡¡¡ Si FUNCIONA !!!
Devuelve exacto lo que necesito. Que bueno! Muchas gracias @gatul!!!
Me queda una duda con un cambio que propusiste...
Al declarar

unsigned long N = 60;    //Cantidad de mediciones por Periodo

No se puede usar la N en lugar del 60 en este caso...

float datos[60];                 //Array

y en este...

p %= 60;    // equivale a if(p == 60) p = 0;

Consulto porque en algunos usos se necesita cambiar los parámetros generales y sería mas fácil modificar solo en las primeras declaraciones.
Otra duda que capaz no se debe preguntar acá, es que no entiendo lo del karma, jeje.
Siento una deuda de gratitud con los que me ayudaron e incluso con los que leyeron para ver si podían ayudar y se los agradezco!

Gracias Gatul nuevamente por tu dedicación!

Primero aclaro que usé ArduinoDroid para compilar (desde el celular).

float datos(N);

Me daba error, por eso lo puse literal.
No probé en la computadora si daba el mismo error, pero creo que no se puede asignar la dimensión a una variable en la "zona" de declaraciones.

p %= 60;

Es lo mismo que

p = p % 60;

o sea, p módulo 60.
Módulo devuelve el resto de una división entera.
Por ej.

// suponiendo p = 1
p = p % 60;  // p = 1 porque 1/60 = 0 con resto 1 (recuerda que son enteros, no hay decimales)
p++;  // p = 2
p %= 60;  // p = 2 porque 2/60 = 0 con resto 2

// ahora p = 59
p %= 60; // p = 59 porque 59/60 = 0 con resto 59
p++; // p= 60
p %= 60;  // p = 0 porque 60/60 = 1 con resto 0

entonces, p se incrementa en cada pasada pero cuando llegue a 60, el módulo es 0 y p se pone a 0.
Por eso te dije que, en este caso en particular, es lo mismo que

if(p == 60) p = 0;

No se si me explico... ::slight_smile:

Agrego: si, como te dije no se puede asignar la dimensión de un array a una variable en las declaraciones peeero... si se puede a una constante.
Entonces es simple

const unsigned long N = 60;

y ahora sí

float datos[N];

es válido.

Saludos

Clarísimo, muy didáctico! Lo agrego...

Gracias de nuevo Gatul !!!

De nada, fue un gusto ayudarte.

Saludos

PD: recién ahora noto que originalmente habías puesto en tu código

const int N = 60;

eso era correcto
Yo modifiqué el código que posteaste en #2 y ahí pusiste

unsigned long N = 60;

como no es const provocaba el error, lo demás ya lo aclaré
Tranquilamente puedes volver a la definición original, o sea,

const int N = 60;

y ahorras 2 bytes de memoria.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.