Haz una pregunta
  Foros de Electrónica » Diseño digital » Microcontroladores y sistemas embebidos » Arduino y Raspberry Pi
Foros Registrarse ¿Olvidaste tu contraseña?
05/01/2013 #1

Avatar de Scooter

Lectura de un tiempo con Arduino
Un par de notas previas:
De programar en C estoy pez; pese a haberlo intentado en las últimas décadas nunca lo he "interiorizado" osea que es probable que tenga errores muy muy básicos.
Programar en código máquina si que se, lo he hecho durante años en varias plataformas.


El problema:
Mediante interrupciones para cargar lo mínimo la CPU hago lo siguiente. Un sensor hall manda un pulso que activa una salida y un tiempo después se apaga. Ambas señales van por interrupciones; una externa para inicio y una por el timer2 para el final. Parece funcionar correctamente, pero al haber añadido unas instrucciones para contar el tiempo de la amplitud del pulso salen tiempos muy grandes.
No he podido medir la amplitud real del pulso y puede que sea correcta y el "medidor" con lafunción millis() o con micros() da mas o menos lo mismo no mida bien porque las funciones del sistema sean muy lentas.
El caso es que el tiempo mínimo son 16mS y debería de ser menos.

El código:
Código:
    #include <avr/interrupt.h>
    #include <avr/io.h>
    int Inyector = 3;    //
    int LED = 13;        //Pin del led
    int PotOn=A0;
    int recarga=100;
    int RPM;
    unsigned long tOn=0;
    unsigned long tOnOld;
    unsigned long apertura;
    volatile int state = LOW;
    // 
    
    ISR(TIMER2_OVF_vect) {
    digitalWrite( Inyector, LOW);
//Parar el timer 2
    TCCR2B &= ((0<<CS22) | (0<<CS21) | (0<<CS20));
    //TIMSK2 |= (0<<TOIE2) ;  //InHabilita interrupción por desbordamiento del Timer2
    apertura=millis()-tOn;
    state = !state;
    Serial.print("R=");
    Serial.print(recarga);
    Serial.print("  Ap=");
    Serial.print(apertura);
    Serial.print("mS ");
    Serial.print(RPM);
    Serial.println("rpm");
    };
    void setup() {
    //Parar el timer 2
    TCCR2B &= ((0<<CS22) | (0<<CS21) | (0<<CS20));      
    // Use normal mode
    TCCR2A |= (0<<WGM21) | (0<<WGM20);
    // Usar reloj interno. No se usa el reloj externo en arduino
    ASSR |= (0<<AS2);
    TIMSK2 |= (1<<TOIE2) | (0<<OCIE2A);  //Habilita interrupción por desbordamiento del Timer2
    //Initialize serial and wait for port to open:
    Serial.begin(9600); 
    // prints title with ending line break 
    Serial.println("ECU 004 (c) Felix Diaz"); 

      // initialize the digital pin as an output.
  pinMode(Inyector, OUTPUT);  
  pinMode (LED  , OUTPUT);
   attachInterrupt(0, inicio, FALLING); //Puede ser LOW, CHANGE, RISING Y FALLING
    }

    void loop() {
        recarga=255-analogRead(PotOn)/4;    //El potenciometro va al revés que el timer
          digitalWrite(LED, state);
        delay(100);
    }

void inicio()
{
  digitalWrite( Inyector, HIGH);
  tOnOld=tOn;
  tOn=millis();
  sei();
  //Recargar el timer:
    TCNT2=recarga;
    //Configuración del timer 2: Preescaler /1024,
    TCCR2B |= ((1<<CS22) | (1<<CS21) | (1<<CS20));
    //Resetear el preescaler
    GTCCR |= (1<<PSRASY);
  RPM=60000/(tOn-tOnOld);
}
Dado lo taruguín que soy programando en C, a ver si veis algún error gordo o algo. Es probable que tenga alguna orejada tonta.

Otra idea que he tenido es usar otro arduino para leer lo que hace este, pero si es que no hacen bien el cálculo del tiempo lo mismo va a dar.



Edición/ampliación:
Pido disculpas a Fogo por mi ruda forma de expresarme (es que soy rústico)
Creo que el medidor va bien; he estado generando pulsos a mano de 1Hz y el medidor de rpm da 60 que es lo correcto, osea que parece que por algún motivo desconocido se tarda 16ms adicionales en ejecutar una interrupción, y 16ms en un animalito que va a 16MHz son una eternidad o dos.
07/01/2013 #2

Avatar de cosmefulanito04

Tal como decís, 16mS es una eternidad, algo ahí falla.

Fijate si te sirve este código que uso:

Código PHP:
void configura_timer2(u8 offset_contador,u8 preescaler)
{
    
ASSR&=~(1<<AS2); //Clk-I/O elegido
    
    
TCCR2&=0xf8;        //Deja de contar
    
TCNT2=offset_contador;
    
    switch(
preescaler)
        {
            case 
1:    {TCCR2|=0x01; break;} // clk-io
            
case 2:    {TCCR2|=0x02; break;} // clk-io/8
            
case 3:    {TCCR2|=0x03; break;} // clk-io/32
            
case 4:    {TCCR2|=0x04; break;} // clk-io/64
            
case 5:    {TCCR2|=0x05; break;} // clk-io/128
            
case 6:    {TCCR2|=0x06; break;} // clk-io/256
            
case 7:    {TCCR2|=0x07; break;} // clk-io/1024
        
}
    
TIMSK |=(1<<TOIE2);    //Habilito mascara de interrupción del timmer2    

Ejemplo de uso:

- Usando 8MHz como base de tiempo, quiero 1mSeg:

Código PHP:
...
//Contador de 8bits => 256 max. cuenta => Usando un reescaler de 32 => 8MHz/32=250kHz => Tick=4uS => 1mS/Tick=250 cuentas => cuenta inicial=256-250=6

configura_timer2(6,3);
.... 
Después yo suelo usar flag, pero vos lo querés resolver todo en la interrupción para evitar el loop, no sé como trabajará la función Serial.print, si influye o no.
09/01/2013 #3

Avatar de Scooter

Muchas gracias por interesarte, ya lo solucioné.
No se exactamente que era pero los registros se deben de escribir en una secuencia determinada. Encontré un código que funcionaba perfecto.
Es razonablemente exacto verificándolo con un osciloscopio.
12/01/2013 #4

Avatar de Scooter

Ya no puedo editar mi anterior mensaje, pongo el enlace del código que funciona por si a alguien le interesa el tema:
http://arduinomega.blogspot.com.es/2...-lets-get.html
14/04/2016 #5


Hola Arduineros...

Tengo el siguiente código que saca por monitor serial temperaturas máximas y mínimas, así como la temperatura actual. Sin embargo, resulta que noto que la comparación que hace el código para cambiar la temperatura máxima registrada en el evento anterior (minuto anterior); o la mínima registrada, se hace al momento de hacer el registro (cada munuto), el cual depende del delay(60000) que tengo al final, porque quiero que se registren las temperaturas en cada minuto. Es decir, que si al segundo 15 ó 23 ó 37 existió un momento donde la temperatura estuvo por debajo o por encima (de la última temperatura registrada sea máxima o mínima) el código "se lo lleve en memoria" y me lo registre (al momento del registro aunque en ese momento la temperatura actual no sea máxima o mínima según el registro anterior) porque lo que me interesa es lo que sucedió en cualquier momento del minuto previo respecto a las máximas y mínimas, y ya que de por sí, tendré cual es el valor de la temperatura actual, pues tengo una variable que resgitra eso (temperatura en el sensor exactamente al momento del registro).

De esta forma yo entenderé:

oye cubalibre: en algun momento del último minuto hubo un instante en que la temperatura máxima bajó o subió con respecto al registro del minuto anterior, así que te lo dejo registrado aquí... o bien, oye cubalibre en algún momento del último minuto hubo un instante en la temperatura mínima bajó o subió con respecto a lo que tenías registrado en el minuto anterior, así que te modifico (registro el nuevo dato) ...

Es decir, realmente no me interesa que el evento se dio al segundo 23 o al 37 o cuando fuera, pero que el sensor me lo registre (en los datos al momento del registro, es decir lo ande en memoria mientras llega el momento de registrar), y no como está el código actualmente, que solamente lee lo que dice el sensor en el segundo 60 y lo compara con el registro del minuto anterior y listo...
Este es el código:

Código:
#include &lt;Time.h&gt;
#include &lt;TimeAlarms.h&gt;
#include &lt;DS1307RTC.h&gt;   


#include &quot;DHT.h&quot;       
#define DHTTYPE DHT21  
#define DHTPIN 4       
DHT dht(DHTPIN, DHTTYPE);
float tavg, tmax=0, tmin=50, havg, hmax=0, hmin=95; 




void setup() {
   Serial.begin(9600);
  
  setSyncProvider (RTC.get); 
  //setTime(13,06,0,13,04,16); 

 if (timeStatus()!=timeSet){
  Serial.println (&quot;No está el reloj&quot;);
  }else{
  Serial.println (&quot;El reloj se sincronizo&quot;);
  }
 dht.begin(); 
}

void loop() {
  
   
  float h= dht.readHumidity();
  float t= dht.readTemperature();

  if(t&gt;=tmax){tmax=t;}
  if(t&lt;=tmin){tmin=t;}
  if(h&gt;=hmax){hmax=h;}
  if(h&lt;=hmin){hmin=h;}
  
String dataString= &quot;&quot;;
  
  dataString+= String (day());
  dataString+= (&quot;/&quot;);
  dataString+= String (month());
  dataString+= (&quot;/&quot;);
  dataString+= String (year());
  dataString+= (&quot;  &quot;);
  dataString+= String (hour());
  dataString+= String (&quot;:&quot;);
  dataString+= String (minute());
  dataString+= String (&quot;:&quot;);
  dataString+= String (second());
  dataString+= (&quot;  &quot;);
  dataString+= String (t);
  dataString+= (&quot;  &quot;);
  dataString+= String (tmax);
  dataString+= (&quot;  &quot;);
  dataString+= String (tmin);
  dataString+= (&quot;  &quot;);
  dataString+= String (h);
  dataString+= (&quot;  &quot;);
  dataString+= String (hmax);
  dataString+= (&quot;  &quot;);
  dataString+= String (hmin);
  Serial.println(dataString);                   
delay (60000);
}
14/04/2016 #6

Avatar de Nuyel

El código se ponía en cuadro [ code ] (el botón #) no en [ quote ]
Si quieres llevar el registro, entonces también agrega una variable para guardar el dato del minuto anterior y comparas con el nuevo. Además, estas usando un delay de un minuto, para lo que quieres, deberías hacer 60 ciclos con for o while cada uno de un segundo, hacer la comparativa a cada segundo y enviar el dato al completar los 60 ciclos, pero hay otro detalle, si usas delay se suspende X milisegundos, no te dará un tiempo preciso y a eso debes agregar la perdida de tiempo en transmitir los datos. al menos podrías usar millis() para generar una espera con un tiempo más constante.
14/04/2016 #7

Avatar de Scooter

No uses delays

Enviado desde mi fnac 5.7 mediante Tapatalk
14/04/2016 #8


Gracias Nuyel, he estado leyendo en internet y en alguna literatura que me prestaron. Y concluyo que la observación que me haces acerca de usar for o while es lo que me resolvería el problema, pero no se como hacerlo, porque no logro comprender esas variables.
Me podrías orientar un poco o quizas remitir a un ejemplo donde pueda comprender como hacer esos 60 ciclos comparativos y que al final de los sesenta ciclos comparativos se registre la temperatura más baja encontrada (en la variable tmin) y la temperatura más alta encontrada (en la variable tmax).

Gracias
14/04/2016 #9

Avatar de Scooter

Sencillo, lees sesenta veces. Una fuera del bucle y 59 en un bucle.
La primera lectura la guardas en tmin y las demás las guardas en tmin si es menor que tmin y si no, no.

Enviado desde mi fnac 5.7 mediante Tapatalk
14/04/2016 #10


Pero no sé cómo crear esas sentencias porque nunca he usado for. Necesito un ejemplo parecido para estudiármelo y adaptarlo.
14/04/2016 #11

Avatar de Scooter

Pues mira la ayuda que para eso está.

Enviado desde mi fnac 5.7 mediante Tapatalk
14/04/2016 #12


Generé esta línea de código, pero aunque el código carga sin problema me da la impresión que no "busca en los 60 segundos el valor de menor y mayor temperatura y humedad relativa" respecto del último segundo, sino que sigue haciendo la comparación en el último minuto.

Nota alguien algún error en el for?

Código:
for (int i=0; i<60; i++){
if (t>=tmax){tmax=t;}
else if (tmax<t) {tmax=t;}
else if (t<=tmin) {tmin=t;}
else if (tmin>t){tmin=t;}
if (h>=hmax){hmax=h;}
else if (hmax<h) {hmax=h;}
else if (h<=hmin) {hmin=h;} 
else if (hmin>h) {hmin=h;}
}
El código completo está así:

Código:
#include <Time.h>
#include <TimeAlarms.h>
#include <DS1307RTC.h>   


#include "DHT.h"       
#define DHTTYPE DHT21  
#define DHTPIN 4       
DHT dht(DHTPIN, DHTTYPE);
float tmax, tmin, tmaxant, tminant, hmax, hmin, hmaxant, hminant; 


void setup() {
   Serial.begin(9600);
  
  setSyncProvider (RTC.get); 
  //setTime(13,06,0,13,04,16); 

 if (timeStatus()!=timeSet){
  Serial.println ("No está el reloj");
  }else{
  Serial.println ("El reloj se sincronizo");
  }
 dht.begin(); 
}

void loop() {
  
   
  float h= dht.readHumidity();
  float t= dht.readTemperature();

    
    //for (int i=0; i<60; i++){if (t>=tmax){tmax=t;}else if (tmin<=t){tmin=t;}if (h>=hmax){hmax=h;}else if (hmin<=h) {hmin=h;}}

      
        
    for (int i=0; i<60; i++){if (t>=tmax){tmax=t;}else if (tmax<t) {tmax=t;}else if (t<=tmin) {tmin=t;}else if (tmin>t){tmin=t;}if (h>=hmax){hmax=h;}else if (hmax<h) {hmax=h;}else if (h<=hmin) {hmin=h;} else if (hmin>h) {hmin=h;}}
    




  
 
  
String dataString= "";
  
  dataString+= String (day());
  dataString+= ("/");
  dataString+= String (month());
  dataString+= ("/");
  dataString+= String (year());
  dataString+= ("  ");
  dataString+= String (hour());
  dataString+= String (":");
  dataString+= String (minute());
  dataString+= String (":");
  dataString+= String (second());
  dataString+= ("  ");
  dataString+= String (t);
  dataString+= ("  ");
  dataString+= String (tmax);
  dataString+= ("  ");
  dataString+= String (tmin);
  dataString+= ("  ");
  dataString+= String (h);
  dataString+= ("  ");
  dataString+= String (hmax);
  dataString+= ("  ");
  dataString+= String (hmin);
  
  Serial.println(dataString);                   
delay (60000);
}
14/04/2016 #13

Avatar de Nuyel

Bueno, defíneme tus variables, en cuanto al ciclo, usar while es más simple si lo haces
Código:
int ciclos = 60;
while(ciclos)
{
   //procesos aquí
  --ciclos
}
//enviar datos
Cualquier valor diferente a cero es considerado verdadero y el ciclo continua. Respecto al resto, necesito entender bien que es lo que quieres enviar, dado a que en cada instante la temperatura máxima puede variar respecto a la anterior, no se si solo quieres pasar los que son máximos y mínimos dentro de cada minuto, en tal caso podrías iniciar los valores según máximo y mínimo del sensor (el máximo en el valor mínimo y el mínimo en el máximo) así solo comparas cuando el valor es superior al ultimo registrado de esta forma:
primero declaramos una variable global (fuera de setup o loop) que seria "unsigned long ticks", esta es para tomar nuestro registro millis y tener la base para el tiempo, al final del setup colocamos ticks = millis(); para asignar el valor y ya podemos pasar al loop, lo siguiente seria en el loop.
Código:
/**********************************************************************
 * Iniciar en valores limites definidos reduce comparaciones
 **********************************************************************/
int segundos = 60;
float tMax = 0.0, tMin = 100.0, hMax = 0.0, hMin = 100.0; 
while (segundos)
{
	ticks += 1000; //cargamos +1000 que seria 1s en nuestro registro del tiempo
	float h = dht.readHumidity();
	float t = dht.readTemperature();
	if (t > tMax) tMax = t; //dado a que tMax inicia en cero, cualquier valor que sea superior al anterior lo sustituirá
	if (t < tMin) tMin = t; //dado a que tMin inicia en el valor más alto, cualquier valor inferior sustituye al ultimo registrado
	if (h > hMax) hMax = h;
	if (h < hMin) hMin = h;
	while (millis() < ticks); //esperar hasta que haya pasado 1s con millis()
	--segundos;
}
//enviar los datos
El problema aquí es que millis() sigue contando siempre y al transmitir los datos si estos no son enviados en menos de 1s se perdería la poca sincronía de este método, lo ideal es juntar los datos por eventos de interrupción del timer, esto se hace programando el chip directamente, no con lenguaje Arduino ya que no esta integrado, así que hay que saber que modelo estas usando debido a que hay que mover los registros directamente debajo de todo el maquillaje que tiene Arduino para hacerlo ver como si fuera tan fácil programar un microcontrolador.

Si usas ticks = millis() antes de entrar al while al menos te asegurarias de que el valor no se ha superado aun y volverías a reiniciar el cronometro para tomar las medidas, de lo contrario, las primeras medidas puede no ser con 1s de diferencia entre sí.
15/04/2016 #14


Gracias por tu ayuda Nuyel; he estado trabajando en tu recomenación y reconstruí este código, para eliminar el delay (con TimeAlarms), que te parece?


Código:
#include <Time.h>
#include <TimeAlarms.h>
#include <DS1307RTC.h>   


#include "DHT.h"       
#define DHTTYPE DHT21  
#define DHTPIN 4       
DHT dht(DHTPIN, DHTTYPE);

float t, h, tmax = 0.0, tmin = 100.0, hmax = 0.0, hmin = 100.0; 
int segundos = 120;
unsigned long ticks;


void setup() {
   Serial.begin(9600);
  
  setSyncProvider (RTC.get); 
  //setTime(2,22,0,15,04,16); 

 if (timeStatus()!=timeSet){
  Serial.println ("No está el reloj");
  }else{
  Serial.println ("El reloj se sincronizo");
  }
 dht.begin();

 int horas = hour();
 int minutos = (minute()/2)*2+2; // Intervalos de registros cada 2 minutos.

  if (minutos == 60) {
     minutos = 0;
     horas   = hour()+1;
  }  

 Alarm.alarmOnce(horas, minutos, 0, AlarmStart);

 

  
}

void loop() {
   Alarm.delay(1); // wait one second between clock display
}
void Registros(){   
 

while (segundos)
{
 ticks += 1000; //cargamos +1000 que seria 1s en nuestro registro del tiempo
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  if (t > tmax) tmax = t; //dado a que tMax inicia en cero, cualquier valor que sea superior al anterior lo sustituirá
  if (t < tmin) tmin = t; //dado a que tMin inicia en el valor más alto, cualquier valor inferior sustituye al ultimo registrado
  if (h > hmax) hmax = h;
  if (h < hmin) hmin = h;
  while (millis() < ticks); //esperar hasta que haya pasado 1s con millis()
 



String dataString= "";
  
  dataString+= String (day());
  dataString+= ("/");
  dataString+= String (month());
  dataString+= ("/");
  dataString+= String (year());
  dataString+= ("  ");
  dataString+= String (hour());
  dataString+= String (":");
  dataString+= String (minute());
  dataString+= String (":");
  dataString+= String (second());
  dataString+= ("  ");
  dataString+= String (t);
  dataString+= ("  ");
  dataString+= String (tmax);
  dataString+= ("  ");
  dataString+= String (tmin);
  dataString+= ("  ");
  dataString+= String (h);
  dataString+= ("  ");
  dataString+= String (hmax);
  dataString+= ("  ");
  dataString+= String (hmin);
  dataString+= ("  ");
  //dataString+= String (tavg);
  //dataString+= ("  ");
  //dataString+= String (havg);
  Serial.println(dataString);                   
 break;
}


}


void AlarmStart() {
  
  Alarm.timerRepeat(120, Registros);        // Para un dato cada 2 minutos.
}

Respondiendo a tu interrogante:
Respecto al resto, necesito entender bien que es lo que quieres enviar, dado a que en cada instante la temperatura máxima puede variar respecto a la anterior, no se si solo quieres pasar los que son máximos y mínimos dentro de cada minuto,
Lo que necesito enviar es la temperatura y HR máxima y mínima que se presentó en el intervalo que haya definido para el registro de datos (en este caso "este código" estoy trabajando con 2 minutos, pero quiero que puedan ser cualesquier submúltiplo de 60 minutos). Por otra parte también me interesa el promedio...

Me gustaría que le "echaras un ojo" al código que estuve trabajando con estos fines: es una modificación al código Smoothing que está en: Archivo->Ejemplos->Analog->Smoothing...

Código:
//File->Sketchbook->Examples->Analog->Smoothing.

#include <Time.h>
#include <TimeAlarms.h>
#include <DS1307RTC.h>   


#include "DHT.h"       
#define DHTTYPE DHT21  
#define DHTPIN 4       
DHT dht(DHTPIN, DHTTYPE);
float tmax, tmin, hmax, hmin; 

const int numReadings = 10;

int readings[numReadings];      // the readings from the analog input
int readIndext = 0;              // the index of the current reading
int readIndexh = 0;              // the index of the current reading
float totalt = 0;                  // the running total
float averaget = 0;                // the average
float totalh = 0;                  // the running total
float averageh = 0;                // the average
float max=0;
float min=0;


void setup() {
  Serial.begin(9600);
  setSyncProvider (RTC.get); 
 
 if (timeStatus()!=timeSet){
  Serial.println ("No está el reloj");
  }else{
  Serial.println ("El reloj se sincronizo");
  }
 dht.begin(); 

    for (int thisReading = 0; thisReading < numReadings; thisReading++) {
    readings[thisReading] = 0;
  }
}

void loop() {

  float h= dht.readHumidity();
  float t= dht.readTemperature();
  totalt = totalt - readings[readIndext]; // subtract the last reading:
   totalh = totalh - readings[readIndexh]; // subtract the last reading:
  readings[readIndext] =  t;// read from the sensor:
  readings[readIndexh] =  h;// read from the sensor:
  totalt = totalt + readings[readIndext]; // add the reading to the total:
  totalh = totalh + readings[readIndexh]; // add the reading to the total:
  readIndext = readIndext + 1;// advance to the next position in the array:
  readIndexh = readIndexh + 1;// advance to the next position in the array:
  if (readIndext >= numReadings) {// if we're at the end of the array...
    readIndext = 0;// ...wrap around to the beginning:
  if (readIndexh >= numReadings) {// if we're at the end of the array...
    readIndexh = 0;// ...wrap around to the beginning:
  }

  }

  
  averaget = totalt / numReadings;// calculate the average:
  averageh = totalh / numReadings;// calculate the average:
  //delay(1);        // delay in between reads for stability
  tmax = max (t,readings [readIndext]);
  tmin= min (t,readings [readIndext]);
  hmax= max (h,readings [readIndexh]);
  hmin= min (h,readings [readIndexh]);
  String dataString= "";
  
  dataString+= String (day());
  dataString+= ("/");
  dataString+= String (month());
  dataString+= ("/");
  dataString+= String (year());
  dataString+= ("  ");
  dataString+= String (hour());
  dataString+= String (":");
  dataString+= String (minute());
  dataString+= String (":");
  dataString+= String (second());
  dataString+= ("  ");
  dataString+= String (averaget);
  dataString+= ("  ");
  dataString+= String (tmax);
  dataString+= ("  ");
  dataString+= String (tmin);
  dataString+= String (averageh);
  dataString+= ("  ");
  dataString+= String (hmax);
  dataString+= ("  ");
  dataString+= String (hmin);
  Serial.println(dataString);                   
delay (60000);
}
pero aquí tengo un error en el cálculo del total, que es el que me daría el promedio que ando buscando, y no se me ocurre como resolverlo.

Con este código me di cuenta del problema que hay con los intervalos de tiempo, ya que me parece que no es posible que tanto la búsqueda de máximos y mínimos para ambas variables (Temperatura y Humedad Relativa) no ocurre en todo el intervalo que se defina, sino que ocurre sobre los datos registrados según el intervalo definido (en este caso cada 2 minutos). Pese a esto, me parece que lo que hice con el código Smooting tiene la "ventajilla" que yo puedo definirle de cuantas repeticiones deseo el promedio, pero eso simplemente lo que hace es meter en memoria la cantidad de registros previos que se le defina y obtiene "primero" un Total (que es donde tengo un error) y luego divide dicho total por la cantidad de registros definidos para obtener el promedio, pero repito lo tengo malo, y no se me ha ocurrido una solución. Pero si me pudieras orientar un poco con respecto a tu código con while de cómo obtener un promedio, quizas me serviría mucho mejor que el que estaba intentando con el código de ejemplo smooting.

Nota:
En el while tuve que colocar un break al final para eliminar el "bucle infinito" y lograr solamente registros cada 2 minutos, pero eso es lo que genera el problema (resta precisión) para los máximos, mínimos y el promedio. Puesto que al salir del bucle infinito ya la comparación se hace sobre los registros que se hicieron cada vez que las lecturas pasan por dentro del bucle. Si hubiese una forma de crear los registros cada 2 minutos, pero que la comparación de máximos y mínimos y la obtención del promedio se hiciera, por ejemplo, cada segundo dentro del intervalo que se defina (en este caso específico 2 minutos, pero si fuesen 30 minutos, que también fuese una búsqueda del valor máximo y mínimo de dentro de esos 30 minutos, y que luego del registro, otra vez comience una NUEVA búsqueda de un máximo y un mínimo y un promedio para los siguientes 30 minutos "olvidaaaando" el valor que se registró en el evento anterior...

Gracias

---------- Actualizado después de 7 minutos ----------

En cualquier caso, algo que hace falta, es que el código "olvide" el máximo y mínimo del registro anterior y una vez que se registró un dato, se comience una nueva e independiente búsqueda de un valor máximo, un valor mínimo y un promedio, pues, haciendo numerosas pruebas con el código actual, el último valor máximo registrado se mantiene hasta que haya otro valor máximo superior (similar sucede con el mínimo), es decir, la búsqueda del valor máximo (y mínimo) está infinito y necesito idear algo, para que tanto el valor máximo y mínimo (y el promedio s se puede) se reinicien después de hacerse un registro de datos.
15/04/2016 #15

Avatar de Scooter

Pues fácil, haces dos variables de máximo, una dentro del bucle y otra fuera, cada vez que sales del bucle pisas la externa con la interna.
16/04/2016 #16


Eso no resuelve el problema que la búsqueda del valor se haga en todo el intervalo definido, o sí?
no comprendo como!
16/04/2016 #17

Avatar de Scooter

Pues claro que lo resuelve.
A ver haces tmax-def y tmax.
Tmax es la que se va pisando dentro del bucle, la empiezas de nuevo cada vez que empieces el bucle y tmax-def sólo la sobreescribe cada vez que acabas el bucle copiando el valor de tmax a tmax-def .


Enviado desde mi fnac 5.7 mediante Tapatalk
16/04/2016 #18


No, eso no lo resuelve, de hecho deja el mismo problema (con la agravante que más variables se han creado para llegar al mismo problema). El problema actual es que el valor máximo siempre es el último valor máximo registrado (en tu caso propones que se llame tmax-def), de esta manera en el próximo evento de 2 minutos, solamente se modificará tmax-def si el valor es mayor... y el problema continúa...
16/04/2016 #19

Avatar de Scooter

Yo no he dicho eso. Yo he dicho que cada minuto se pisa tmax-def sin condiciones.

Enviado desde mi fnac 5.7 mediante Tapatalk
16/04/2016 #20

Avatar de Nuyel

No entendí, yo use while (segundos) pero al final del bucle use --segundos; lo que reduce el valor y al terminar los x segundos que estaría analizando entonces se sale del while, por ello no iba un break, entu caso, veo que cambiaste a 120 segundos y con alarma, si lo harías así entonces puedes omitir la espera con millis y dejar que la alarma active la lectura.

Si se usa una interrupción externa temporizada, entonces no va ningún bucle para retrasar los segundos, solo que debes usar variables declaradas como globales (lo que ya esta) para escribir esos datos durante la rutina de interrupción.

Lo que podría cambiarse, seria en lugar de llamar "segundos" hacerlo "muestras", el tiempo seria con base a la alarma. ¿Cuántas muestras usarías? por que hacer el promedio es cosa simple solo agregamos una sigmaT y sigmaH, otra cosa es que no es recomendable que uses la Serial.println() dentro de una interrupción por tiempo si este es muy pequeño, o podría causar que no le alcance para transmitir el dato antes de que la interrupción se active nuevamente.

por lo pronto creare unas definiciones con #define y una función llamada resetValues() para los valores que deben ser reestablecidos en cada periodo para las muestras, ya dependerá de tu interrupción que se ejecuten cada determinado tiempo y con #define muestras cambias el numero de muestras que tomaras antes de procesar y enviar los datos.

No se si el siguiente código esta bien, seria que lo revises ya que no tengo DHT.h para siquiera intentar compilarlo.
Código:
#include "DHT.h"       
#define DHTTYPE DHT21  
#define DHTPIN 4       
DHT dht(DHTPIN, DHTTYPE);

#define muestras 120
#define tMaxVal (100.0)
#define tMinVal (0.0)
#define hMaxVal (100.0)
#define hMinVal (0.0)

float t, h, tmax = tMinVal, tmin = tMaxVal, hmax = hMinVal, hmin = hMaxVal;
float sigmaT = 0.0 sigmaH = 0.0, tavg = 0.0, havg = 0.0;
int numReadings = muestras;

void setup() {
   Serial.begin(9600);
  
  setSyncProvider (RTC.get); 
  //setTime(2,22,0,15,04,16); 

 if (timeStatus()!=timeSet){
  Serial.println ("No está el reloj");
  }else{
  Serial.println ("El reloj se sincronizo");
  }
 dht.begin();

 int horas = hour();
 int minutos = (minute()/2)*2+2; // Intervalos de registros cada 2 minutos.

  if (minutos == 60) {
     minutos = 0;
     horas   = hour()+1;
  }  

 Alarm.alarmOnce(horas, minutos, 0, AlarmStart);

 

  
}
void resetValues() {
  tmax = tMinVal;
  tmin = tMaxVal;
  hmax = hMinVal;
  hmin = hMaxVal;
  numReadings = muestras;    //reinicar cuenta de muestras
  sigmaT = 0.0;               //reiniciar suma de T
  sigmaH = 0.0;               //reiniciar suma de H
}

void loop() {
   Alarm.delay(1); // wait one second between clock display
}
void Registros(){   
 
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  if (t > tmax) tmax = t; //dado a que tMax inicia en cero, cualquier valor que sea superior al anterior lo sustituirá
  if (t < tmin) tmin = t; //dado a que tMin inicia en el valor más alto, cualquier valor inferior sustituye al ultimo registrado
  if (h > hmax) hmax = h;
  if (h < hmin) hmin = h;
  sigmaT += t;            //sumatoria de T
  sigmaH += h;            //sumatoria de H
  --numReadings;

if (numnumReadings == 0){ //esto solo deberia ejecutarse cuando se tenga todas las muestras
tavg = sigmaT/muestras;   //promedio de temperatura
havg = sigmaH/muestras;   //promedio de humedad

String dataString= "";
  
  dataString+= String (day());
  dataString+= ("/");
  dataString+= String (month());
  dataString+= ("/");
  dataString+= String (year());
  dataString+= ("  ");
  dataString+= String (hour());
  dataString+= String (":");
  dataString+= String (minute());
  dataString+= String (":");
  dataString+= String (second());
  dataString+= ("  ");
  dataString+= String (t);
  dataString+= ("  ");
  dataString+= String (tmax);
  dataString+= ("  ");
  dataString+= String (tmin);
  dataString+= ("  ");
  dataString+= String (h);
  dataString+= ("  ");
  dataString+= String (hmax);
  dataString+= ("  ");
  dataString+= String (hmin);
  dataString+= ("  ");
  //dataString+= String (tavg);
  //dataString+= ("  ");
  //dataString+= String (havg);
  Serial.println(dataString);

  resetValues() //reiniciar los registros para el siguiente periodo.
}
}


void AlarmStart() {
  
  Alarm.timerRepeat(120, Registros);        // Para un dato cada 2 minutos.
}
Por lo del Smoothing, el problema que veo es que al "buscar" los máximos y mínimos, en realidad no los buscas, simplemente asignas el mismo valor a ambos en lugar de realizar comparaciones, un pequeño inconveniente es que usas mucha memoria en almacenar toda la matriz (aunque igual creo que hay mucha libre aún) en datos que luego no vuelves a utilizar.
¿Tienes una mejor respuesta a este tema? ¿Quieres hacerle una pregunta a nuestra comunidad y sus expertos? Registrate

Buscar más temas sobre:
Lupa Arduino y Raspberry Pi

Cerrar
Foros de Electrónica » Diseño digital » Microcontroladores y sistemas embebidos » Arduino y Raspberry Pi

Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO ©2011, Crawlability, Inc.