Problemas con funcion millis () . Conflicto

Buenas noches inicialmente cree este post:

http://forum.arduino.cc/index.php?PHPSESSID=78amoaull8af9bduid21go01v2&topic=272621.0

Donde fueron aclaradas tres de mis dudas.

Agradecido con Jose y Surbyte.

Les comento rapidamente de que trata el proyecto.

Una regleta inteligente autónoma para eliminar el consumo en standby. De 5 tomas 110V AC.

El codigo principal para UN SOLO SENSOR ES ESTE.

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

unsigned long current; //amplitude current
int led1 = 8 ;
int valor = 0 ;
int flag = 0 ;
unsigned long previousMillis = 0;
void setup() 
{
  Serial.begin(9600); 
  digitalWrite(led1,HIGH);
  pins_init();
}
	
	
void loop() 
{	
                int sensor_max;
                sensor_max = getMaxValue();
                current=(float)sensor_max/1024*5/800*2000000; 
                //Serial.println("sensor_max = ");
                //Serial.println(sensor_max);
                Serial.println("The amplitude of the current is(in mA)");
                Serial.println(current);
		
		if ((current < valor*0.4))
		{ 
			if (flag == 1) // Si la bandera esta en 1 apaga el LED
			{
				digitalWrite(led1, LOW);  
				flag = 0;
				valor = 0;
			}
			else
			{
				
                                uint32_t start_time = millis();
                                Serial.println("Comenzo Millis");
                                if ((millis()- previousMillis) >= 5000)
				{
                                flag = 1;
                                Serial.println("Termino Millis");
                                }
				
			}
		}
		else
		{
			valor = current;
                        flag = 0 ;
		}
	
}

void pins_init(){
  pinMode(SENSOR_0, INPUT);
  pinMode(led1, OUTPUT);
}
/*Function: Sample for 1000ms and get the maximum value from the SIG pin*/
  int getMaxValue()
  {
  int sensorValue; //value read from the sensor
  int sensorMax = 0;
  uint32_t previousMillis = millis();
  while((millis()- previousMillis) < 2000)//sample for 1000ms
  {
    sensorValue = analogRead(SENSOR_0);
    if (sensorValue > sensorMax) 
    {
      /*record the maximum sensor value*/
      sensorMax = sensorValue;
    }
  }
  return sensorMax;
}

El problema esta en esta comparacion:

if ((current < valor*0.4))
		{ 
			if (flag == 1) // Si la bandera esta en 1 apaga el LED
			{
				digitalWrite(led1, LOW);  
				flag = 0;
				valor = 0;
			}
			else
			{
				
                                uint32_t start_time = millis();
                                Serial.println("Comenzo Millis");
                                if ((millis()- previousMillis) >= 5000)
				{
                                flag = 1;
                                Serial.println("Termino Millis");
                                }
				
			}

El millis en esa etapa se queda pegado, contando y contando y nunca llega a poner 1 en la variable flag.

O aveces si lo hace, pero cuenta hasta 20 seg, 40 seg, aveces solo 0 seg.

Segun mi analisis lo que puede estar dandome problemas es que para obtener los valores del sensor ya estoy utilizando un millis. Como pueden ver aqui.

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

Entonces al estar funcionando dos millis al mismo tiempo pueden estar presentando ese problema.

Como puedo solventar esto ? .

Es muy importante para mi poder resolver este problema y tenerlo claro, porque luego debo aplicar esa programacion para 5 sensores. y que conjuntamente funcionen de manera correcta.

El funcionamiento de una placa arduino es estar ejecutando siempre el la funcion loop() y a veces nos olvidamos de lo rapido que va el "pequeñin" (16Mhz....) .El problema puede estar en que en cada vez que se ejecuta el loop llamas a la funcion getMaxValue() que asigna a una variable el valor actual de millis() ,luego en el else pones la condicion de que millis() - previousMillis sea >= 5000 pero si el tiempo de ejecucion de cada loop es inferior a 5000 milisegundos,lo cual es bastante factible,la condicion sera siempre falsa.Mira de incluir en la entrada a funciones o en los bloques if else funciones Serial.println() indicando donde estas para luego saber que es lo que se ejecuta y lo que no,a modo de depuracion.Por ejemplo en la funcion getMaxValue() pon un Serial.println("Entrando en funcion getMaxValue") y asi en cada bloque ,y luego podras analizar mejor que es lo que esta fallando.

Yo veo otra cosa, veo que defines previousMillis al comienzo del programa y es contra quien comparas en el if

 if ((millis()- previousMillis) >= 5000)

Pero nunca inicializas a previousMillis sin embargo defines otra variable

uint32_t start_time = millis();

Entonces cual usas?

Ahora vi la parte final del código donde vuelves a usar previousMillis y como bien señalas

while((millis()- previousMillis) < 2000)//sample for 1000ms

esto dice que espere 2 seg, y recien devuelve al loop.

Otra cosa. Porque defines A0 como entrada y luego le pides que lea su valor AD?
#define SENSOR_0 A0

void pins_init(){
pinMode(SENSOR_0, INPUT);
pinMode(led1, OUTPUT);
}

sensorValue = analogRead(SENSOR_0);

Todo eso esta ocurriendo sobre el mismo PIN

Que intentas hacer?

Que es una regleta inteligente autónoma para eliminar el consumo en standby?

Define tu proyecto por favor. Que quieres o pretendes hacer.

La programación es confusa, luce como que tomaste partesde de código de algun sitio y le hiciste modificaciones que ahora no funcionan.
Estoy en lo cierto? Pero responde sobre el proyecto, que quieres hacer, se lo mas detallado posible para entenderte y entonces podremos ayudarte.

Que sensor usas, ya se que es un sensor de corriente y creo que en su momento lo posteaste.

Es en la funcion getMaxValue() donde le asigna el valor de millis() a previousMillis ,y como esta funcion es llamada en cada loop cuando llega a millis() - previousMillis >= 5000 la diferencia de tiempo solo puede ser lo que haya tardado el loop en ejecutarse que no creo que sean mas de 5000 milisegundos ( o 5 segundos) por lo que la comparacion es siempre falsa:

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;
}

Muy buenas tardes, Jose efectivamente esa prueba ya la hice y eso es lo que me esta dando problemas no se porque.

Principalmente pense que era por usar dos variables diferentes como dice surbyte. Luego hice una prueba igualandolas y nada.

Pues bien. Aclarando las dudas y preguntas de surbyte.

La programacion inicial si la agarre de una ejemplo que sale en su misma pagina y pueden visualizarla aqui:

http://www.seeedstudio.com/wiki/Grove_-_Electricity_Sensor

Funciona perfectamente.

Le estoy haciendo las modificaciones necesarias para poder utilizarlo en mi proyecto casero final.

El modulo estara midiendo constantemente la el consumo de corriente de las 5 tomas 110V AC, abra un sensor por toma.

Segun mis pruebas, realice muchas medicions a mas de 15 equipos y observer los valores que me arroja el sensor, estando los equipos apagados y prendidos, realice una tabla para calcular cual era el porcentaje EN STANDBY con respecto AL EQUIPO EN FUNCIONAMIENTO. Conclusion este no supera el 20 % en los mas de 15 Equipos que medi.

Que deseo hacer ?, que la regleta de manera automatica, corte la corriente mediante un triac (abra el circuito 110V AC) cuando detecte que el equipo esta apagado. Y lo hare en base a porcentaje.

El sensor que estoy utilizando es el TA12-100 , sensor de corriente AC hasta 5 A.

Explico brevemente mi comparacion de porcentaje

if ((current < valor*0.4))
 { 
 if (flag == 1) // Si la bandera esta en 1 apaga el LED
 {
 digitalWrite(led1, LOW);  
 flag = 0;
 valor = 0;
 }
 else
 {
 
                                uint32_t start_time = millis();
                                Serial.println("Comenzo Millis");
                                if ((millis()- previousMillis) >= 5000)
 {
                                flag = 1;
                                Serial.println("Termino Millis");
                                }
 
 }

Mi valor leido actual lo tendre en la variable CURRENT , luego ese valor lo paso a otra variable VALOR, para poder compar ahora el nuevo valor leido en CURRENT vs VALOR.

Entonces si el valor leido es 60% menor que el anterior EL EQUIPO ESTA EN STANDBY. Teoricamente no pasan del 20 %, pero previendo que esto no siempre sea asi aumente ese porcentaje a 60 %, por eso multiplico VALOR por el 0.4 para sacarle el 40% y quede solo el 60 % restante.

Ejemplo :

Primera medicion --- > CURRENT = 100
VALOR = CURRENT

Segunda medicion --- > CURRENT = 40

If ( CURRENT < VALOR * 0.4) o lo que es igual a (30 < 1000.4) 1000.4 = 40
entones el equipo esta en apagado y consumiendo corriente en Standby.

Ahora porque este delay con el millis

else
 {
 
                                uint32_t start_time = millis();
                                Serial.println("Comenzo Millis");
                                if ((millis()- previousMillis) >= 5000)
 {
                                flag = 1;
                                Serial.println("Termino Millis");
                                }

Porque por ejemplo si estoy viendo televisión con mi hijo y el por accidente apaga el televisor, y deseo prenderlo nuevamente.

Quiero que la programacion haga lo siguiente.

1- Que siempre este sensando el cambio de consumo de corriente segun el equipo este conectado.
2- If ( CURRENT < VALOR * 0.4) Espere un tiempo en este caso 5 seg -- > if ((millis()- previousMillis) >= 5000) vuelva a medir y si sigue siendo menor corte la corriente. Si es mayor porque se apago por error y lo vuelvo a prender, la medicion vuelve a un numero mayor que VALOR, dejalo encendido.

Principalmente debo hacer funcionar toda esa programacion con un sensor bien, y luego implementarla a 5 sensores y espero que no me de problema con los millis de cada sensor, que en realidad estarian 10 millis simulteaneamente.

Los primeros 5 de la obtencion de valores de los 5 sensores. y luego los otros 5 millis del tiempo en esperar luego de la comparacion.

Logro explicarme? .

Jose , gracias por el apoyo, eso lo entiendo perfectamente.

Por eso es que ese contador millis de los 5 seg, aveces solo cuenta 1seg y cumple la condicion, o cuenta hasta 40seg 30seg , 20 seg, el tiempo nunca es el mismo.

que me recomiendas para resolver esto.

Lee mi respuesta completa anterior donde explico todo lo que realmente deberia hacer la regleta.

Saludos

Si yo elimino esa funcion int getMaxValue()

Y coloco toda la parte de obtención de valores del sensor dentro mismo loop.

Como podria hacer un arreglo de los millis para que uno no interfiera en el otro.

De que es posible debe serlo, porque sino no funcionaria entonces el ejemplo BLINK de dos leds con millis, ya que ahi utilizas dos millis simultáneamente sin importar el intervalo de cada uno, y teniendo intermitencias diferentes.

Espero sus comentarios

Bien, ahora que entendí que quieres hacer, veré de buscarle una solución.
Si no me gana alguien antes..

Entonces parte del programa es detectar el valor pico de la corriente, por eso se pone a leer como tonto, para obtener el valor máximo de la corriente.
Luego que lo tienes empieza tu análisis de donde estas parado, si consumiendo o en stand by.

para solucionarlo creo podrías pasarle el valor actual y previo de millis por medio de la función y luego hacer la comparación

uint32_t previousTime = 0;
uint32_t currentTime = millis();

getMaxValue(currentTime, previousTime);
previousTime = millis();

Las dos variables deberían almacenar el valor antes y después de llamar la función, como en el ejemplo anterior

y luego la función getMaxValue sería algo así:

int getMaxValue(uint32_t currentTime,uint32_t previousTime){
	if(currentTime - previousTime < 5000){
		//valor del sensor
	}
}

En teoría debería funcionar, pero no lo he probado.

saludos!

Gracias gepd suena interesante tu solución. Probare y comentare los resultados.

Surbyte que bueno que me hayas podido entender. exactamente eso quiero. Me entendiste perfectamente.

Agradecido si logras dar con una solucion.

Veremos quien mas puede dar una recomendacion.

gepd:
para solucionarlo creo podrías pasarle el valor actual y previo de millis por medio de la función y luego hacer la comparación

Las dos variables deberían almacenar el valor antes y después de llamar la función, como en el ejemplo anterior

y luego la función getMaxValue sería algo así:

En teoría debería funcionar, pero no lo he probado.

saludos!

Gepd como estas ? Estoy relizando las pruebas y no parece funcionar. Quizas este haciendo algo mal. Podrias explicarme mas detalladamente tu solucion.

Hola.
¿Y cómo tienes previsto rearmar un relé que ya ha sido apagado? ¿reiniciando el arduino? ¿Mediante un pulsador?
Porque entiendo que esa medida ya va a ser cero constantemente.

Hola noter. No es un rele, sino un triac, lo hare mediante una aplicacion en android por comunicacion bluetooth.

Ya esa parte esta 100% operativa.

Mi problema actual es con los millis.

Bueno. He creado algo un poco al vuelo. No está probado, pero al menos compila. Lo he empaquetado en una clase, de manera que si chuta, podrías crear y manejar tantos dispositivos "Relenchufe" (es como lo he llamado) como quieras y te permita la existencia de pines. Si miras el código tras la clase, sólo necesitas una línea de código para crear el objeto y otra en el loop para revisarlo.
Está lo básico para el control de apagado de un pin digital (relé, led, triac o qué se yo). Se le pueden agregar métodos para devolver/imprimir el consumo y demás.

Prueba y me cuentas a ver.

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

const unsigned long TIEMPODESCONEXION=5000;

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);
     };
     
     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é
               }
     }
     
private:
     int pinLectura;     // Pin analógico para leer corriente
     int pinRele;        // Pin relé de enchufe
     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 long milisInicioApagado;
     };
     
     
///////////////////////////////////////// hasta aquí la clase     
     
     Relenchufe enchufe1(A0, 8);

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


void loop() 
{ 
      enchufe1.chequea();
}

Saludos.

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.

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?.

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 .

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

Yo te estoy haciendo algo pero con un enfoque distinto. Aun no lo termino.

Agradecido surbyte. Seguire probando e investigando para dar con na solucion a mi problema mientras amablemente me muestras tu solucion al terminarla.

Yo de entrada te propongo que simplifiques la funcion getMaxValue() para adaptarla a cualquier pin ,que solo haga 3 lecturas (o mas si quieres pero veo absurdo hacer un monton de medidas en 2 segundos) y que
la gestion del tiempo lo hagas fuera de la funcion ,es decir controlar los 5 segundos fuera de la funcion y volver a llamarla:

int getMaxValue(int analogPin){
  int sensorMax = 0;
  int sensorValue = 0;
  for(int cont=0;cont<3;cont++){
    sensorValue =  analogRead(analogPin);
    sensorMax = max(sensorMax,sensorValue);
    delay(100);
  }
  return sensorMax;
}

Para usarla para 5 sensores ,en este ejemplo almaceno resultados en un array ,pero puedes usarlo
como te vaya mejor:

int resultados[5];
for(int cont = 0;cont < 5;cont ++){
  resultados[cont] = getMaxValue(cont);
}