Medicion de Voltaje con ZMPT101B se detiene en 2 horas aprox

Buenas tardes amigos, el problema es usando un arduino Mega 2560 y un sensor ZMPT101B leyendo por análogo y usando código de SOLARDUINO (es el que me funciona mejor, he probado diferentes usando Emonlib y otros y me mandan algunos picos incorrectos) este código funciona perfecto pero a las 2 horas aprox. se detiene y debo reiniciar el monitor serie, he analizado el código pero no logro dar con la respuesta, pensé en la memoria pero veo que si limpia las variables y probé agregando el "Serialflush()" para darle tiempo a la salida serial pero el problema sigue ocurriendo, alguna idea? seguire investigando y haciendo pruebas.... Gracias

// AC Voltage Sensor without LCD By Solarduino (Revision 2)

// Note Summary
// Note :  Safety is very important when dealing with electricity. We take no responsibilities while you do it at your own risk.
// Note :  This AC Votlage Sensor Code is for Single Phase AC Voltage transformer ZMPT101B module use.
// Note :  The value shown in Serial Monitor is refreshed every second and is the average value of 4000 sample readings.
// Note :  The voltage measured is the Root Mean Square (RMS) value.
// Note :  The analog value per sample is squared and accumulated for every 4000 samples before being averaged. The averaged value is then getting square-rooted.
// Note :  The auto calibration (voltageOffset1) is using averaged analogRead value of 4000 samples.
// Note :  The auto calibration (currentOffset2) is using calculated RMS current value including currentOffset1 value for calibration.  
// Note :  The unit provides reasonable accuracy and may not be comparable with other expensive branded and commercial product.
// Note :  All credit shall be given to Solarduino.

/*/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/////////////*/


/* 0- General */

int decimalPrecision = 2;                   // decimal places for all values shown in LED Display & Serial Monitor

/* 1- AC Voltage Measurement */

int VoltageAnalogInputPin = A2;             // Which pin to measure voltage Value (Pin A0 is reserved for button function)
float voltageSampleRead  = 0;               /* to read the value of a sample in analog including voltageOffset1 */
float voltageLastSample  = 0;               /* to count time for each sample. Technically 1 milli second 1 sample is taken */
float voltageSampleSum   = 0;               /* accumulation of sample readings */
float voltageSampleCount = 0;               /* to count number of sample. */
float voltageMean ;                         /* to calculate the average value from all samples, in analog values*/ 
float RMSVoltageMean ;                      /* square roof of voltageMean without offset value, in analog value*/
float adjustRMSVoltageMean;
float FinalRMSVoltage;                      /* final voltage value with offset value*/


/* 1.1- AC Voltage Offset */

float voltageOffset1 = 0.00;              // to Offset deviation and accuracy. Offset any fake current when no current operates. 
                                          // Offset will automatically callibrate when SELECT Button on the LCD Display Shield is pressed.
                                          // If you do not have LCD Display Shield, look into serial monitor to add or minus the value manually and key in here.
                                          // 26 means add 26 to all analog value measured.
float voltageOffset2 = 0.00;              // too offset value due to calculation error from squared and square root 


/* 0- General */
void setup() {
    Serial.begin(9600);                             /* In order to see value in serial monitor */

}
     
void loop() {
    
  /* 1- AC Voltage Measurement */
  if (micros() >= voltageLastSample + 1000 ) {                                                                  // every 0.2 milli second taking 1 reading 
      voltageSampleRead = (analogRead(VoltageAnalogInputPin)- 512)+ voltageOffset1;                             // read the sample value including offset value
      voltageSampleSum = voltageSampleSum + sq(voltageSampleRead) ;                                             // accumulate total analog values for each sample readings
      voltageSampleCount++;                                                                                     // to move on to the next following count 
      voltageLastSample = micros() ;                                                                            // to reset the time again so that next cycle can start again
  }
  
  if (voltageSampleCount == 1000)   {                                                                            // after 4000 count or 800 milli seconds (0.8 second), do the calculation and display value
      voltageMean = voltageSampleSum/voltageSampleCount;                                                        // calculate average value of all sample readings taken
      RMSVoltageMean = (sqrt(voltageMean))*1.5;                                                                 // The value X 1.5 means the ratio towards the module amplification.
      adjustRMSVoltageMean = RMSVoltageMean + voltageOffset2;                                                   // square root of the average value including offset value                                                                                                                                                 /* square root of the average value*/
      FinalRMSVoltage = RMSVoltageMean + voltageOffset2;                                                        // this is the final RMS voltage
      if (FinalRMSVoltage <= 2.5) {                                                                             // to eliminate any possible ghost value
          FinalRMSVoltage = 0;
      }
      Serial.print(" The Voltage RMS value is: ");
      Serial.print(FinalRMSVoltage,decimalPrecision);
      Serial.println(" V ");
      voltageSampleSum =0;                                                                                      // to reset accumulate sample values for the next cycle 
      voltageSampleCount=0;                                                                                     // to reset number of sample for the next cycle 
  }
}

Si se cuelga tal vez no sea a un problema de software a menos que sea exacto a las 2 horas cada vez.
No usas arreglos, ni punteros ni librerías, no veo la razón de tu problema.

Para mi el problema se lo está provocando el overflow de micros() que al compararlo con un float arroja valores negativos y deja de tomar muestras, no se detiene en realidad sino que espera que la comparación sea nuevamente >= 1000.

voltageLastSample debería ser unsigned long

y la comparación debería ser

if (micros() - voltageLastSample >= 1000UL ) {

Saludos

Gracias Surbyte, el dispositivo esta en un cuarto con clima 19 °C, ahorita le puse una fuente de 9V 1A ya que lo tenia alimentado por el mismo cable USB y le soldare un pin a la entrada análoga para ir descartando cosas ajenas al código.

gatul, gracias, acabo de hacer los ajustes que mencionas y lo deje corriendo para ver cuanto dura.

Para darles contexto esto va a ser parte de un sistema para monitorear una planta de emergencia y se podrá reiniciar (el arduino) cada 3 días al menos, solo como mantenimiento preventivo, por lo pronto estoy en la etapa de medición de voltaje y cuando lo tenga terminado con gusto les comparto el proyecto. Gracias!!!!

Estimo que ahora no vas a tener problemas.

Te explico lo que estaba pasando con tu código.

Una variable float puede almacenar valores entre 3.4x10^38 y -3.4x10^38 (aproximadamente), una variable unsigned long almacena valores entre 0 y 4294967295 (poco más de 4.29x10^9).

micros() devuelve un valor unsigned long y cuando la cuenta de useg supera el máximo simplemente vuelve a 0 (no hay valores negativos porque es unsigned, osea, sin signo), esto ocurre aproximadamente cada 71 minutos.

En tu código, cuando la cuenta llegaba justo al segundo anterior al overflow (la vuelta a 0 por desborde de micros()) la variable voltageLastSample almacenaba ese valor cercano a 4.29x10^9.

En la próxima comparación micros() devolvía un valor 0 o muy cercano a 0 (porque se desbordó y reinició la cuenta en 0) y al hacer la comparación

micros() >= voltageLastSample + 1000

obviamente no cumplía con la condición porque micros() era menor a eso, y por lo tanto dejaba de realizar las lecturas. Simplemente "seguía de largo" esperando que se vuelva a cumplir la condición para volver a samplear (algo que probablemente no volviera a ocurrir nunca).

Siempre debes fijarte el tipo de datos que devuelve una función y asignarlo a variables del mismo tipo (salvo que intencionalmente quieras cambiarlo por alguna razón en particular, pero previendo que pueden pasar cosas como ésta).

Por ej., millis() también devuelve un unsigned long y se "resetea" cada 49 días, si tu código hubiera usado millis(), cada 49 días hubiese dejado de samplear.

Saludos

La forma correcta es usando

unsigend long voltageLastSample;
//
 if (micros() - voltageLastSample > 1000UL ) {

De esta forma incluso a los 49.7 dias no hay fallas. Esta demostrado en la sección Documentación.

Ya se lo aclaré antes en #3.

En mi último post solo le ejemplifiqué lo que hubiese pasado con millis() en 49 días en lugar de 70 min con micros() justamente por la definición de tipo incorrecto y la comparación mal planteada.

Saludos

Edito: ahora veo que le "comí" el UL, de todos modos el compilador se las arregla...

Muchas gracias, el problema era el "unsigned long" y el "if", gracias por darse su tiempo para buscar la falla y ademas explicar el error.

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