Problemas con funcion millis () . Conflicto

Bueno esto es lo que hice hasta ahora, te aclaro es un enfoque diferente, que no esta terminado.
Solo para que veas si funciona y le ajustes lo necesario como para que indique los mA y haga las comparaciones.

Bueno hay cosas para eliminar como el LCD lo usé para ver si todo podia funcionar en combinación con la interrupción a 1mseg que cree.
Fijo el TIMER1 a 1khz y eso asegura que tomes muestras cada 1 mseg.
Aca el codigo y te explico dos o tres cosas

#include <LiquidCrystal.h>

#define BAUD_RATE 19200
#define INPUT_PIN A0
#define LED_PIN 13
#define UMBRAL  100

// LiquidCrystal (rs, rw, en, d4, d5, d6, d7)
//LiquidCrystal lcd(12,   11,  5,  4,  3,  2);
LiquidCrystal lcd( 8,          7, 12, 11, 10,  9);

// LiquidCrystal(rs, enable, d4, d5, d6, d7)

volatile int j;
volatile int valorMax = 0;
volatile unsigned int contador = 0;
boolean imprimir = false;
boolean imprimoPasoPorCero = false;
uint8_t sample=0, Pos;
char str[20] = "";
void setup()
{

	Serial.begin(BAUD_RATE);
	pinMode(LED_PIN, OUTPUT);
	cli();                                     // disable interrupts while messing with their settings
	TCCR1A = 0x00;                             // clear default timer settings, this kills the millis() funciton
	TCCR1B = 0x00;
	TCCR1B |= (1 << WGM12);                    // Configure timer 1 for CTC mode
	TCCR1B |= (0 << CS12);                     // Set timer prescaling by setting 3 bits
	TCCR1B |= (1 << CS11);                     // 001=1, 010=8, 011=64, 101=1024
	TCCR1B |= (1 << CS10);
	TIMSK1 |= (1 << OCIE1A);                   // Enable CTC interrupt
	OCR1A  = 50;                               // Set CTC compare value
	sei();                                     // turn interrupts back on
	
   Serial.begin(19200);
	lcd.begin(16,2);                     // columns, rows. size of display
	lcd.clear();                         // clear the screen

}

void loop() {
	
	

        if (imprimir) {
			lcd.setCursor(0,0);
			sprintf(str, "%3d Max = %3d", Pos, valorMax);
			Serial.println(str);
			lcd.print(str);
		}
		if (imprimoPasoPorCero) {
			Serial.print("Paso por cero =");
			Serial.println(contador);
			imprimoPasoPorCero = false;
		}
}


ISR(TIMER1_COMPA_vect)                            // when timer counts down it fires this interrupt
{
	sample++;
	j = analogRead(INPUT_PIN);   // real mode, sample analog pin
	if (j > valorMax) { 
		valorMax = j;
		Pos = sample;
		imprimir = true;
	}
	else imprimir = false;
	if (j  ==  512){
		contador++;
		if (contador > UMBRAL){
			valorMax = 0;
			contador = 0;
			sample	 = 0;
			imprimoPasoPorCero = true;
			
		}
	}
}

Yo supongo que la señal esta debidamente desplazada a 2.5V, pero como lo hice con un simulador eso funciona siempre bien. En la vida real eso no va asi que donde dice
If (j == 512) reemplaza por if(j>510 && j<514) lo que te da un margen. Si ves que funciona con menos estará bien. Incluso si el centro de la alterna no fueran exactos 2.5V igual funcionaría comparando con 512.

Que hago.. .pues como dije, tomo muestras cada 1 mseg y entonces busco el mayor valor igual que tu.
Pero ademas, busco el 0.. o el cruce por cero, y cada vez que pase por 0 incremento contador cuando contador supera UMBRAL (que es modificable) Lo puse en 100 cruces por cero o sea a 20mseg x 100 = 2 segundos. Algo menos que tus 5 seg pero es ajustable. Pones 250 en UMBRAL y tendras 5 seg.

entonces cuando supero UMBRAL es porque hubo varios cruces por cero y reseteo valorMax a 0. y vuelvo a buscar un máximo.

Falta que los valores se transformen en tus valores reales, y se expresen en mA.
Saca el LCD si no te sirve.
Todo se imprime en el loop sin que genere problemas a la interrupción.

Bien.. tal vez te ayude.
Lo sigo y adapto cuando vuelva de ver un cliente

kenny0414, hice algunas modificaciones y ahora si funciona todo correctamente.

El if para llamar la función cada 5 segundos lo hice desde el mismo loop.

unsigned long previousMillis = 0;
const long interval = 5000; //5 segundos

void setup () {
  Serial.begin(9600);
}
void loop () {
  if(millis() - previousMillis >= interval){
    getMaxValue();
    previousMillis = millis();
  }  
}
int getMaxValue(){
  Serial.println("Llamada desde funcion!");
}

creo que si subes el código y revisas el monitor serial entenderás mejor.

Agradecido con todas las soluciones que me han presentado.

Me tomare algunas horas para analizar cada una de ellas e ir probando y ver cual me es mas factible.

Les iré comentando el proceso.

gepd:
kenny0414, hice algunas modificaciones y ahora si funciona todo correctamente.

El if para llamar la función cada 5 segundos lo hice desde el mismo loop.

creo que si subes el código y revisas el monitor serial entenderás mejor.

Gepd, a ver, para poder entendernos mejor estamos claro en lo que deseo hacer? . Te hare un reencuentro rapidamente para ver si efectivamente tu codigo y solucion me es factible. Quizas me cueste entenderlo porque mis conocimiento son bastante basicos en base a programacion en arduino.

La funcion getMaxValue() lo que hace es obtener el valor del sensor. El hace mas de 200 mediciones en el tiempo que establezca yo en ese millis y luego el me suelta el valor mayor de esas 200 mediciones. Esto estando todo fuera del loop.

Ahora dentro del loop cuando realiazo la comparacion de si es menor que el 40% del valor anterior, quiero que espere un TIEMPO DETERMINADO, luego vuelva a compara y verificar si el valor sigue siendo el mismo, si es el mismo, tomar una accion, SINO lo es, seguir midiendo.

entonces creo que lo que hice anteriormente funcionaba más, corregí el ejemplo simulando la lectura del sensor, creo que ahora si es lo que quieres hacer.

unsigned long previousMillis = 0;
const long interval = 5000; //5 segundos

void setup () {
  Serial.begin(9600);
}
void loop () {
  getMaxValue(millis(),previousMillis,interval);    
}
int getMaxValue(unsigned long currM,unsigned long prevM, const long intr){
  //simula función que obtiene valor del sensor y lo retorna en una variable
  int sensorValue = 39; // simulamos que es menor a 40
  
  //si es menor que 40 y han pasado más de 5 segundos
  if(sensorValue < 40 && currM - prevM >= intr){
    Serial.println("Han pasado 5 segundos!");
    Serial.println("El sensor aun es menor a 40");
    //acción cuando han pasado 5 segundos
    
    previousMillis = currM; //esto es para que vuelva a comprar en 5 segundos más
  }
}

comenté el código para que puedas entenderlo

Hola de nuevo. Creía haber contestado ya a tu post, pero por lo visto se ha ido al limbo.

kenny0414:
Noter excelente aporte.

Vamos a ver si entendi completamente.

Creando esta clase lo que logramos es que al utilizar los 5 sensores no deba repetir 5 veces la misma programación correcto ? , Solo debo crear el objeto para luego llamar esa clase en el loop.

Exactamente. Sería posible, incluso, crear un array de "Relenchufes" y recorrerlo con un for.

kenny0414:
Ahora tengo algunas dudas al respecto.

Haciendolo de esta manera, tenemos 5 tomas (Relenchufe), supongamos que en la primera ya esa detecto que el valor actual es menor al anterior en un 40%, y empieza a correr el tiempo de los 5 segundos. Mientras el esta contando esos 5 segundos. Que sucede con las demas tomas ? , siguen obteniendo el valor del sensor de manera paralela?.

Efectivamente, cada Relenchufe tendrá sus parámetros y estado. Debes sólo preocuparte de que cada uno tenga SUS pines, y que éstos sean correctos (el primero de ellos debe ser analógico).

kenny0414:
Esos 5 segundos son referencias, el valor verdadero considero debe ser unos 30 Seg aprox, y en esos 30 que un Relenchufe esta esperando para realmente apagarse, los otros deben estar dando lecturas de igualmanera al procesador .

Tan sólo deberás cambiar el valor de la constante TIEMPODESCONEXION al principio del código.

kenny0414:
Podrias aclararme estos puntos ? .

Valoro mucho el trabajo que te tomaste en montar ese ejemplo de clase. Por si no llegase a funcionar, podrias verificar en mi programacion original cual es el problema que estoy teniendo con los millis ? . Ya probe metiendo todo dentro del mismo loop, para no tener esto por fuera (obtencion del valor del sensor):

int getMaxValue()

{
 int sensorValue; //value read from the sensor
 int sensorMax = 0;
 uint32_t previousMillis = millis();////////////////////////////////////////////////////////Aqui asigna el valor
 while((millis()- previousMillis) < 2000)//sample for 1000ms
 {
   sensorValue = analogRead(SENSOR_0);
   if (sensorValue > sensorMax)
   {
     /record the maximum sensor value/
     sensorMax = sensorValue;
   }
 }
 return sensorMax;
}




Saludos

No entendí mucho tu primer código, pero creo que no inicias previousmillis en el lugar correcto. El temporizador debe iniciarse la primera vez que se detecta la caída de intensidad. Las siguientes no se toca su valor (sólo se compara hasta llegar a final de cuenta), y hay que tener en cuenta que si hay subida de nuevo la siguiente vez que baje deberá volver a iniciarse (igualar a millis()) ese contador. Intenta entender el porqué de todos los if y los else de mi código. No hay ninguno en vano.
Saludos

Hola a todos.

Debedio a que tengo casi 4 soluciones diferentes he estado como loco viendo cada una jajajajaja.

Que he hecho?, viendo un poco de todas he estado modificando la mia original.

Las modificaciones principales que he hecho son:

1- Elimine el Millis en la funcion getMaxValue
2- Elimine dicha funcion y la ingrese directamente en el loop, con la recomendacion de Jose, y estoy tomando 400 muestras. Porque 400 muestras cada medio segundo ? . Porque es aqui cuando el valor es constante. Si bajo las muetras la variacion del valor es grande, mas me marca cero que el valor real que estoy midiendo.

Para poder hacer las pruebas mas rapidamente, la comparacion del 40 % no la estoy haciendo.

Estoy comparando cuando el consumo sea directamente cero.

Y creo haber logrado lo que requiero. Le muestro el codigo final :

#define ELECTRICITY_SENSOR A0 // Analog input pin that sensor is attached to

unsigned long current; //amplitude current
int led= 8; 
int valor;
int flag = 0 ; 
int test ;
long previousMillis = 0;

void setup() 
{
  Serial.begin(9600); 
  digitalWrite(led,LOW);
  pinMode(ELECTRICITY_SENSOR, INPUT);
  pinMode(led, OUTPUT);
}

void loop() 
{
int sensorMax = 0;
int sensorValue = 0;
for(int cont=0;cont<400;cont++)
      {
    sensorValue =  analogRead(ELECTRICITY_SENSOR);
      if (sensorValue > sensorMax) 
          {  
          sensorMax = sensorValue;
          }
      }
    delay(500);
  
  int sensor_max;
  sensor_max = sensorMax ;
  current=(float)sensor_max/1024*5/800*2000000; //Voltaje del sensor 5V
  
if (flag == 1 && current == 0)
      {
      digitalWrite(led, HIGH);  
      flag = 0;
      valor = 0;
      test = 0 ;
      }
if (current == 0)
      { 
      current = test ;
      Serial.println("Comenzo Contador");
      uint32_t start_time = millis();
      if((start_time - previousMillis) >= 5000)//sample for 1000ms
	  {
	  Serial.println("Termino Contador");
          previousMillis = start_time ;
	  flag = 1;
	  }
      }
  else
      {
      valor = current;
      }
  
  
  
  Serial.println("The amplitude of the current is(in mA)");
  Serial.println(current);
 
}

El unico problema esta, en que cuando empieza a realizar esta comparacion :

if (current == 0)
      { 
      current = test ;
      Serial.println("Comenzo Contador");
      uint32_t start_time = millis();
      if((start_time - previousMillis) >= 5000)//sample for 1000ms
	  {
	  Serial.println("Termino Contador");
          previousMillis = start_time ;
	  flag = 1;
	  }
      }

Esto me sale en el monitor serial :

Comenzo Contador
Termino Contador
The amplitude of the current is(in mA)
0
Comenzo Contador
The amplitude of the current is(in mA)
0
Comenzo Contador
The amplitude of the current is(in mA)
0
Comenzo Contador
The amplitude of the current is(in mA)
0
Comenzo Contador
The amplitude of the current is(in mA)
0
Comenzo Contador
The amplitude of the current is(in mA)
0
Comenzo Contador
The amplitude of the current is(in mA)
0
Comenzo Contador
The amplitude of the current is(in mA)
0
Comenzo Contador
The amplitude of the current is(in mA)
0
Comenzo Contador
The amplitude of the current is(in mA)
0
Comenzo Contador
Termino Contador

Efectivamente esta contando de manera correcta, fijense que el monitor serial dice 10 veces "Comenzo contador" que si lo hace cada medio segundo, equivale a 5 segundos, lo que quiero.

EL problema esta en que observer cuando apenas comienza a contar, inmediatamente me dice que TERMINO y luego es que comienza a contar los 5 SEG, pero este error al principio que COMIENZA y TERMINA en el mismo medio segundo me da problemas.

Alguien sabe porque ? .

Noter de todas las soluciones la tuya es la mas compleja, y me estoy tomando aun el tiempo de analizarla. Gracias nuevamente. Una ultima pregunta en base a tu Clase que creaste. Como hago para en esa clase mandar el valor obtenido de cada sensor a una variable y luego ver cual es la suma de los 5 ? .

Yo probé el mio con una señal de AM de amplitud modulada con un coseno 10 veces mas lento que la función seno.
El sistema contaba 100 cruces por cero y volvia a buscar valoresMax. Funciona perfecto.

Ahora te agrego tus elementos y podrías probarlo si te parece, si no te interesa me dice y no lo hago.

Surbyte excelente el aporte que me has dado y el apoyo.

Tu programación por darle otro enfoque como tu mismo menciones no la entiendo mucho . Tampoco quiero hacerte perder tu tiempo, en algo que no creo que utilice primero por no entenderlo y segundo por ser totalmente a mi codigo.

Dejame leer nuevamente tu codigo y ver que puedo extraer de ahi para mi el mio y asi hacerlo que funcione correctamente.

Mientras podrias hecharle un ojo a todas las modificaciones que le hice ?.

Cada ves estoy mas cerca.

Tu idea es interesante por eso yo insisto siempre en que se explique bien que se quiere hacer porque las maneras de encarar algo son muy diversas. 5 programadores dificilmente coincidirán en hacer el mismo programa. Tal es el caso.
Reconozco que los demás aportaron desde tu base pero yo comencé diciendo que tu base estaba mal y quería hacer dos cosas:

  1. samplear a ritmo conocido porque si y porque permite ver siempre que pasa por cero, algo que no tenias antes.
  2. Al hacerlo me aseguro que podré por ejemplo contar cuantas veces pasa por cero y como sabemos que estamos en 50 hz o 20mseg de período eso te da el tiempo o la cantidad de cuentas que requieres para esperar algun evento, como tus 5 segundos.

En fin.. igual me sirvió a mi.

Que bueno que de esa manera ayudándome a mi te hayas auto ayudado y hasta aprender cosas nuevas.

Porque no recurro a tu idea o solución? entiendo lo que me explicas verbalmente, mas para entender toda tu programación completa me llevaria tiempo y cambiar todo el esquematico que ya tengo en cabeza me explico ?.

En cambio modificando mi programación que se lo que hace y entiendo cada parte de ella si me es mucho mas fácil dar con los errores ahorita y a futuro.

Mas tu codigo y programación aunque no lo utilice directamente tus conocimientos y aportes me han ayudado mucho, en aclara las dudas o darme otra visión de las cosas.

noter:
Hola de nuevo. Creía haber contestado ya a tu post, pero por lo visto se ha ido al limbo.

Hola noter gracias por todas tus aclaraciones. De todas las soluciones la tuya es la que mayor me agrada porque este muy bien estructurada y se entiende perfectamente, aparte que es muy parecida a la mia.

noter:
Exactamente. Sería posible, incluso, crear un array de "Relenchufes" y recorrerlo con un for.

Podrias explicarme un poco mas acerca de esto ? .

Como me pediste revisa cuidadosamente todas tus comparaciones e IF and ElSE , hay unos que no comprendo.

void chequea(void){
int lectura=analogRead(pinLectura);
if (lectura > maxValue)
maxValue=lectura;
else
if (map (lectura, 0, maxValue, 0, 100) < 40) { // Si la nueva lectura es menor del 40%
if (milisInicioApagado > 0) { // Si estamos en cuenta atrás verificamos si ha transcurrido el tiempo de desconexión
if ((millis() - milisInicioApagado) >= TIEMPODESCONEXION){
digitalWrite(pinRele, LOW); // Desconectamos
milisInicioApagado = maxValue = 0; // y reseteamos el valor de consumo y el temporizador
}
} else {
milisInicioApagado=millis(); // Iniciamos temporizado
}
} else {
milisInicioApagado=0; // Desactivamos la posible cuenta atrás
digitalWrite(pinRele, HIGH); // Activamos relé
}
}

Como me mencionaste : "El temporizador debe iniciarse la primera vez que se detecta la caída de intensidad. Las siguientes no se toca su valor (sólo se compara hasta llegar a final de cuenta), y hay que tener en cuenta que si hay subida de nuevo la siguiente vez que baje deberá volver a iniciarse (igualar a millis()) ese contador"

En el else que esta en rojo estas iniciando el temporizador luego de hacer la comparacion ? , no entiendo porque.

Revisando la secuencia de tu loop()

1-Obtenemos el valor de la entrada analogica
2- SI la lectura es > a maxValue maxValue = lectura
3- SINO
3.1- SI la lectura es menor que el 40% entonces verifica SI milisInicioApagado > 0 , SI es mayor verificamos si ya pasaron los 5 seg. y reiniciamos maxValue y milisInicioApagado Es aqui donde no comprendo como vamos a verificar ese millis si aun no se inicializo sino luego de ultimo con un else
3.2- SI milisInicioApagado > 0 NO ES MAYOR entonces milisInicioApagado = millis ()
4- SI la lectura NO ES menor que el 40% milisInicioApagado = 0 y digitalWrite(HIGH)

kenny0414:

noter:
Hola de nuevo. Creía haber contestado ya a tu post, pero por lo visto se ha ido al limbo.

Hola noter gracias por todas tus aclaraciones. De todas las soluciones la tuya es la que mayor me agrada porque este muy bien estructurada y se entiende perfectamente, aparte que es muy parecida a la mia.

noter:
Exactamente. Sería posible, incluso, crear un array de "Relenchufes" y recorrerlo con un for.

Podrias explicarme un poco mas acerca de esto ? .

Pues que en teoría se podría hacer algo así para tres relenchufes:

Relenchufe enchufe[3]={Relenchufe(A0, 8), Relenchufe(A1, 9), Relenchufe(A2, 10)};

void loop() 
{ 
      for (int a=0; a<3; a++)
            enchufe[a].chequea();
}

kenny0414:
Como me pediste revisa cuidadosamente todas tus comparaciones e IF and ElSE , hay unos que no comprendo.

void chequea(void){
int lectura=analogRead(pinLectura);
if (lectura > maxValue)
maxValue=lectura;
else
if (map (lectura, 0, maxValue, 0, 100) < 40) { // Si la nueva lectura es menor del 40%
if (milisInicioApagado > 0) { // Si estamos en cuenta atrás verificamos si ha transcurrido el tiempo de desconexión
if ((millis() - milisInicioApagado) >= TIEMPODESCONEXION){
digitalWrite(pinRele, LOW); // Desconectamos
milisInicioApagado = maxValue = 0; // y reseteamos el valor de consumo y el temporizador
}
} else {
milisInicioApagado=millis(); // Iniciamos temporizado
}
} else {
milisInicioApagado=0; // Desactivamos la posible cuenta atrás
digitalWrite(pinRele, HIGH); // Activamos relé
}
}

Como me mencionaste : "El temporizador debe iniciarse la primera vez que se detecta la caída de intensidad. Las siguientes no se toca su valor (sólo se compara hasta llegar a final de cuenta), y hay que tener en cuenta que si hay subida de nuevo la siguiente vez que baje deberá volver a iniciarse (igualar a millis()) ese contador"

En el else que esta en rojo estas iniciando el temporizador luego de hacer la comparacion ? , no entiendo porque.

Revisando la secuencia de tu loop()

1-Obtenemos el valor de la entrada analogica
2- SI la lectura es > a maxValue maxValue = lectura
3- SINO
3.1- SI la lectura es menor que el 40% entonces verifica SI milisInicioApagado > 0 , SI es mayor verificamos si ya pasaron los 5 seg. y reiniciamos maxValue y milisInicioApagado Es aqui donde no comprendo como vamos a verificar ese millis si aun no se inicializo sino luego de ultimo con un else
3.2- SI milisInicioApagado > 0 NO ES MAYOR entonces milisInicioApagado = millis ()
4- SI la lectura NO ES menor que el 40% milisInicioApagado = 0 y digitalWrite(HIGH)

A ver. Creo que no entiendes totalmente cómo funciona lo de millis. Debes tener en cuenta que el loop es en sí un while, es decir que cuando finaliza vuelve a empezar de nuevo y no te quedas esperando en ningún punto esperando que pase el tiempo. Sencillamente una vez "apuntas la hora" y las siguientes revisas cuánto ha pasado desde el apunte, mientras vas haciendo otras cosas.
Es decir, la primera vez que pase el loop con un valor<40%, como milisInicioApagado==0, va a establecer milisInicioApagado=millis(). En el siguiente paso por el loop con valor<40%, como milisInicioApagado ya no es cero, entrará a comparar cuánto ha pasado desde el loop en que se bajó por primera vez del 40%. Tendrá que pasar por varios loop<40% hasta que por fin la comparación diga que ha pasado el tiempo de apagado. Si en uno de esos pasos hay una lectura>40%, volvemos a dejar milisInicioApagado a cero y vuelve a empezar el proceso.
Espero haberte aclarado un poco. Cualquier duda, pregunta. Por cierto ¿Has probado el código? Porque como te dije, está programado al vuelo. No lo he probado.
Saludos

Gracias noter por las aclaraciones.

Mananan realizare la primera prueba a ver como funciona.

Si deseo guardar el valor de cada sensor para luego sumarlos los 5 como la haria, jamas habia trabajado con clase, disculpa.

Entiendo que quieres obtener el valor de la variable maxvalue, ¿no? Tienes dos posibilidades: pasar la declaración de maxvalue a la sección public de la clase:

public: .....
int maxValue;

Y podrías obtenerla desde fuera: Serial.println(enchufe1.maxValue);

o bien añadir una función en public que te devuelva ese valor:

public:
int getMaxValue() {return(maxValue)};

y obtener el valor llamando a la función: Serial.println(enchufe1.getMaxValue());

Aunque la segunda forma parezca dar un rodeo, tiene la ventaja de que la mantienes en privado y puedes controlar si quieres o no dejar que se pueda modificar desde afuera (agregando otra función pública setMaxValue).

Otra cosa, ahora que veo que quieres obtener la medición actual, entiendo.
Creo que he puesto mi solución en este hilo centrándome exclusivamente en el problema actual que tenías. Me acabo de dar cuenta de que proviene de otro hilo anterior, y que estás midiendo una corriente variable, y que lo que haces es tomar muestras consecutivas durante x tiempo para obtener el máximo, que será la medida "actual", que es el que a su vez compararás con el máximo "histórico", ¿no?
Entonces el valor que deseas obtener como medición actual sería el máximo de x lecturas consecutivas, ¿no? ¿Qué frecuencia estás midiendo?
Mi código actual no está tomando esa medida actual. Para un solo dispositivo sería muy sencillo, pero para varios habría que valorar si es mejor tomar medidas interpoladas o consecutivas, es decir
while (tiempomedida){ leosimayor1, leosimayor2, ... leosimayorx} tengo medida de todos

o bien
while(tiempomedida){leosimayor1} tengo medida1
while(tiempomedida){leosimayor2} tengo medida2
while(tiempomedida){leosimayorx} tengo medidax

Digamos que si necesitamos medio segundo de muestras para obtener ese máximo, el primer método obtendría en medio segundo el máximo de todos los dispositivos, pero tomaría menos número de muestras/segundo de cada uno de ellos (digamos, menos precisión). El segundo sistema tomaría más precisión para cada dispositivo, pero necesitaría más tiempo (medio segundo por cada dispositivo)

Prueba a ver esta clase. Está basada en el método 2, osea que si necesitamos controlar cuatro dispositivos, lo haría uno detrás de otro, tomando aproximadamente medio segundo por cada uno. Verás que (ahora sí) utilizo dos timers, como tú. Realmente el segundo no sería necesario. Con contar las veces consecutivas que llega nivel bajo, teniendo en cuenta que me tiro medio segundo tomando medidas, con diez veces sé que habrán transcurrido los cinco segundos, pero dejamos el control de millis.

//////////////////////////////////////////////////////////////////////////////////
///////////////////////////////PEQUEÑA CLASE PARA CONTROL AHORRO//////////////////
///////////////////////////////////////////////////////////////////////////////////
// uso: 
// Crear un dispositivo: Relenchufe enchufe(pin analógico, pin relé);
// Controlar el dispositivo: enchufe.chequea();
// Obtener última lectura: enchufe.getUltimaLectura();

const unsigned TIEMPODESCONEXION=5000; // TIEMPO TRAS EL QUE SE DESCONECTARÁ EL ENCHUFE SI PERMANECE BAJO
const unsigned TIEMPOMUESTRA=500;      // TIEMPO DURANTE EL QUE SE TOMARÁ UNA MUESTRA

class Relenchufe{
public:
      // constructor
      Relenchufe(int pinAnalog, int pinR): 
      pinLectura(pinAnalog), pinRele(pinR), maxValue(0), milisInicioApagado(0){
            pinMode(pinLectura, INPUT);
            pinMode(pinRele, OUTPUT);
            digitalWrite(pinRele, HIGH);
      };
      int getUltimaLectura(){
            return(ultimaLectura);
      };

      void chequea(void){
            int lectura=0;
            unsigned startTime=millis();
            while ( (millis()-startTime) < TIEMPOMUESTRA ){
                  int lecturaInstantanea = analogRead(pinLectura);
                  if (lecturaInstantanea > lectura) lectura=lecturaInstantanea;
            }
            ultimaLectura=lectura; // Pasamos la lectura conseguida a nuestra propiedad
            if (ultimaLectura > maxValue){ // si la nueva lectura es mayor que el máximo establecemos esta como nuevo máximo y desactivamos el temporizador por si acaso.
                  maxValue=ultimaLectura;
                  milisInicioApagado=0;
            } 
            else {
                  if (map (ultimaLectura, 0, maxValue, 0, 100) < 40) {     // Si la nueva lectura es menor del 40%
                        if (milisInicioApagado > 0) {                 // Si estamos en cuenta atrás
                              if ((millis() - milisInicioApagado) >= TIEMPODESCONEXION){ // 
                                    digitalWrite(pinRele, LOW);          // Desconectamos
                                    milisInicioApagado = maxValue = 0;   // y reseteamos el valor de consumo y el temporizador
                              }
                        } 
                        else {
                              milisInicioApagado=millis();          // Iniciamos temporizado
                        }
                  } 
                  else {
                        milisInicioApagado=0;                      // Desactivamos la posible cuenta atrás
                        digitalWrite(pinRele, HIGH);               // Activamos relé
                  }
            }
      }

private:
      int pinLectura;     // Pin analógico para leer corriente
      int pinRele;        // Pin relé de enchufe
      int ultimaLectura;  // Valor de la última lectura (máxima durante TIEMPOMUESTRA)
      int maxValue;       // Valor "alto" de consumo. Se irá estableciendo dinámicamente. Cuando baje del 60% iniciará el temporizador de desconexión
      // milisegundo en el que inicia la bajada de consumo e inicia el temporizado para desconexión. Mayor que cero, significa que se ha iniciado la cuenta.
      unsigned milisInicioApagado;
};


///////////////////////////////////////// hasta aquí la clase     

Relenchufe enchufe1(A0, 8);

void setup() 
{
      Serial.begin(9600);
}


void loop() 
{ 
      enchufe1.chequea();
      Serial.print("Lectura analogica obtenida: ");
      Serial.println(enchufe1.getUltimaLectura());
}

Buenos dias Noter, disculpa que ayer no pude leerte ni responderte. Estaba en muy ocupado. Nuevamente gracias por tus aclaraciones.

No me había fijado correctamente en la comparación del primer IF por eso no entendí. Pero ahora si. muchas gracias.

Porque quiero que el valor Maxvalue final este en una variable ? porque deseo una ves obtenido el valor en los 5 sensores, sumarlos todos y ver cuanto es el total. y tomar una accion sobre el total. Por lo que entiendo

noter:
Entiendo que quieres obtener el valor de la variable maxvalue, ¿no? Tienes dos posibilidades: pasar la declaración de maxvalue a la sección public de la clase:

public: .....
int maxValue;

Y podrías obtenerla desde fuera: Serial.println(enchufe1.maxValue);

o bien añadir una función en public que te devuelva ese valor:

public:
int getMaxValue() {return(maxValue)};

y obtener el valor llamando a la función: Serial.println(enchufe1.getMaxValue());

Aunque la segunda forma parezca dar un rodeo, tiene la ventaja de que la mantienes en privado y puedes controlar si quieres o no dejar que se pueda modificar desde afuera (agregando otra función pública setMaxValue).

De esta manera entonces en el loop puedo realizar esta suma de esta manera?

if (enchufe1.maxValue+enchufe2.maxValue+enchufe3.maxValue < o > que X numero)
     Accion a tomar?

Me has entendido correctamente. Te adelantaste respondiendo una pregunta que te haria. Efectivamente el valor que deseo obtener es variable, y es necesario tomar muchas muestras para poder tener un valor constante. La frecuencia a la que mido no la se, imagino la predeterminada del arduino a 16mhz, pero segui la recomendacion de Jose de este hilo y esto fue lo que obtuve para poder tener un valor constante

int sensorMax = 0;
int sensorValue = 0;
for(int cont=0;cont<400;cont++)
      {
    sensorValue =  analogRead(ELECTRICITY_SENSOR);
      if (sensorValue > sensorMax) 
          {  
          sensorMax = sensorValue;
          }
      }
    delay(500);

Que hago aqui? tomo 400 muestras y de esas 400 agarro el valor mayor y que es SensorValue y lo agrego a la varible sensorMax. y Esto lo realizo cada medio segundo.

Porque 400 ? porque si bajo el numero de muestras el valor no es constante ni tan preciso, es decir supongamos que en 400 muestras me arroja un valor constante entre 100 y 120. Si reduzco las 400 muestras a 180, el valor que me arroja varia mucho 30, 0, 50, 10, 120, 0 , 0, 100, 0, 100

Por lo que veo necesario que en tu clase creada en ves de obtener el valor del sensor asi:

void chequea(void){
          int lectura=analogRead(pinLectura);
          if (lectura > maxValue)
               maxValue=lectura;

Sea asi

void chequea(void){
         int sensorMax = 0;
         int sensorValue = 0;
for(int cont=0;cont<400;cont++)
      {
    sensorValue =  analogRead(ELECTRICITY_SENSOR);
      if (sensorValue > sensorMax) 
          {  
          sensorMax = sensorValue;
          }
      }
    delay(500);

Claro cambiando el nombre de las variables correspondientes a las declaradas.

Efectivamente no necesito que las mediciones se hagan al mismo tiempo, pueden ser consecutivamente y creo que es la mejor manera como tu comentas. El loop deberia quedar algo asi como:

1- Obtengo los valores de los sensores, cada uno por separado de manera consecutiva
1.1- Si el valor actual es menor que el anterior en mas de un 40% espera un tiempo determinado, en ese tiempo si el valor vuelve hacer mayor, reinicia el tiempo a 0, si luego de pasar el tiempo sigue siendo menor, toma una accion.
2- Sumo estos valores veo su resultado total, y tomo una acción si mayor a un numero.
3-Comienza nuevamente el loop y obtiene nuevos valores.

Ahora para no complicar tanto la clase, el tiempo de medicion por sensor no podria hacerse en el loop ? con algun delay pequeño o el mismo millis? . O es mejor hacerlo como tu ejemplo ? .

Habria algun problema con el delay de medio segundo que esta en la clase para que el tome las muestras ? .

Lo que sino veo en la clase y en la comparacion del 40%, es donde pasas el valor leido mayor a otra variable para luego comparar el valor actual con el anterior.

Saludos y muy agradecido con tu ayuda hermano.

Analizando al comparación del porcentaje encuentro un problema. Te explicare como cree yo mi comparación para que puedas entenderme y ver porque digo que tenemos un problema.

if (flag == 1 && current <= test )
      {
      digitalWrite(led, LOW);  
      flag = 0;
      valor = 0;
      test = 0 ;
      }
if (current < current1*0.4)
      { 
      current = test ;
      Espero tiempo determinado y luego que termine ese tiempo asigno a la variable flag =1
      flag = 1
      }
  else
      {
      current1 = current;
      }

En la primera lectura valor=0 porque esta comenzando el loop por lo cual cualquier valor que lea el sensor la condicion del if (current < valor*0.4) es falsa, entra en el ELSE y a current1 se le asigna el valor de current. Supongamos es 100.

En la segunda corrida del loop el valor nuevo de current es 30, al llegar al if comparo si 30 es menor que (100*0,4= 40) , como la condicion es verdadera, asigno a test el valor de current que es 30, , espero un tiempo determinado y al terminar asigno a la variable flag = 1, al tener flag = 1 luego de haber pasado el tiempo y obtener una una medicion del sensor se cumple la primera condicion para realizar la comparacion de verificacion que es el primer if

if (flag == 1 && current <= test )
      {
      digitalWrite(led, HIGH);  
      flag = 0;
      valor = 0;
      test = 0 ;
      }

Si flag = 1 (Que lo esta y certifica que ya paso el tiempo deteminado, y SI el valor actual de corriente es MENOR O IGUAL QUE EL VALOR DE LA PRIMERA COMPARACION Y QUE SE ENCUENTRA ALOJADO EN LA VARIABLE TEST entonces toma una accion.

Mientras el tiempo de espera transcurre el loop sigue corriendo varios ciclos hasta pasar el tiempo total correcto ?, y toma varios valores del sensor, por eso es necesario asignar el primer valor a una variable test para luego poder pedirlo despues que haya pasado el tiempo y comparar el valor actual con el de la variable test.

Tu función Map (valor, fromLow, fromHigh, toLow, toHigh)
valor: el número de mapa
fromLow: el límite inferior del rango actual del valor
fromHigh: el límite superior del rango actual del valor
toLow: el límite inferior del rango objetivo del valor
toHigh: el límite superior del rango objetivo del valor

if (map (ultimaLectura, 0, maxValue, 0, 100) < 40) {     // Si la nueva lectura es menor del 40%

Creo que quizas mi duda viene de aqui, de no entender como haces la comparacion aqui. Que valor comparas con cual ? , como sacas el 40% de un valor ? , no veo que multipliques en ningun lugar por el 0.4 .

Como me explicaste

"Tendrá que pasar por varios loop<40% hasta que por fin la comparación diga que ha pasado el tiempo de apagado. Si en uno de esos pasos hay una lectura>40%, volvemos a dejar milisInicioApagado a cero y vuelve a empezar el proceso. "

Pero SI ES MAYOR que el valor de la primera COMPARACION NO en un 40% ? . porque si por ejemplo el sensor en alto es 100 - 120, pero en bajo es puede variar tambien porque no es una constante fija, puediese ser 30-35 , y si comparas 35>30 si si lo es pero no por esto debe reiniciarse el contador porque aun esto quiere decir que el equipo esta apagado. Por eso trabajo con porcentajes por ser un valor constante.

La condicion para entrar en el conteo del tiempo de espera ES MENOR AL 40% y para salir del conteo MAYOR AL 40% en ambos casos el valor actual en comparacion al PRIMER VALOR QUE SE ASIGNO PARA COMPARAR.

Tambien es necesario aclararte que todo esto de las comparaciones, no es con el valor directo del sensor, sino una ves utilice la formula para determinar la corriente en milamper. Aqui

sensorValue = analogRead(ELECTRICITY_SENSOR);
if (sensorValue > sensorMax)
{
sensorMax = sensorValue;
}
}
delay(500);

int sensor_max;
sensor_max = sensorMax ;
current=(float)sensor_max/10245/8002000000; //Voltaje del sensor 5V

current es el valor que utilizare para todo, que deseo comparar, sumar, y verificar.

No se si logras entenderme o yo explicarme ? .

Si me di a entender y la clase tiene un error podrias ayudarme a corregir ? . y colocarla nuevamente ? .
Porque no quiero colocar mi comparacion en tu clase asi de la nada sin antes corroborar contigo.

Saludos, un abrazo Gracias

Buenas tardas Noter.

En base a todo lo que te dije y explique arriba hice algunas modificaciones a tu Classe a ver que tal. Asi ha quedado el void de la classe "void chequea(void)":

if (current < current1*0.4)   // Realizamos la comparación, si el valor actual es menor del 40% del valor anterior
      {     
          if (millisInicioApagado > 0)  // Si el tiempo es igual o mayor a 0 verificamos cuando tiempo a transcurrido sino iniciamos el temporizador.
          {                 
            if ((millis() - millisInicioApagado) >= TIEMPODESCONEXION)
              {
               if (current <= current1*0.4 ) // Current1 sigue siendo el mismo de la primera comparación sin importar cuantas veces se medio durante el tiempo de desconexion.
                {
                  digitalWrite(led, LOW);     // Apagamos el LED   
                  current1 = current;          // Pasamos el valor actual del sensor a la variable current1        
                  millisInicioApagado = 0;   // Reseteamos el temporizador
                }   
              }
           } 
             else 
              {
               millisInicioApagado=millis();          // Iniciamos temporizado
              }
        } 
   else 
   {
    millisInicioApagado=0;     // Desactivamos la posible cuenta atrás
    current1 = current ;
    digitalWrite(led, HIGH);     // Mantenemos  LED encendio
   }

Hagamos una corrida en frio.

Comienza el loop del void chequea
1- La primera medicion fue 100 y lo comparara con current1 que es cero, condicion no se cumple y pasa al ultimo else verificamos que millisInicioApagado este en cero, pasamos el valor de current a current1 y mantenemos el LED encendido (enchufe empirico para pruebas simulada)

2-Segunda vuelta del loop siempre y cuando current sea mayor que el 40% de current1 siempre se repetira el punto numero 1

3-Tercera vuelta del loop, tenemos un valor de 30 en current, condicion se cumple, verificamos si millisInicioApagado es mayor o igual que cero, como no lo es, saltamos al else del mismo if donde iniciamos el temporizador, comienza nuevamente el loop, si sigue siendo menor se vuelve a verificar cuanto tiempo a transcurrido, si es mayor automaticamente se para el temporizador y se continua con el punto numero 1. Si current sigue siendo menor que el 40% de current1 que a pesar que en el tiempo del temporizador seguimos midiendo esta variable no se sustituye hasta cuando esa condicion sea falsa, entonces, si sigue siendo menor y paso el tiempo, igualamos current a current1 , apagamos el LED (enchufe) y reiniciamos temporizador. y repetimos este proceso por cada sensor, independientemente de manera consecutiva.

Claro aqui aun no esta tu solución para que funcion con todos los sensores de tu ultimo ejemplo.

Que te parece de esta manera? estoy errado en alguna parte?