Lectura de un TMP36, curiosidad

Hola,
He leído varias veces, que de estos medidores de temperatura analógicos, tipo el TMP36, hay que intentar escapar, y he sufrido su inestabilidad con frecuencia, mayor, cuantas más cositas se ponen en el circuito.

Pues bien, buscando ideas para realizar un ajuste de reloj por pulsadores (ya volveré al ataque con dudas al respecto, pero antes prefiero pelearme unas horas con ello), he encontrado un trozo de código para leer un TMP36 en el que he visto dos cosas que me parecen curiosas, y al menos la primera, para mí, es novedad (llevo muy poco, y sé nada de electrónica, así que casi todo lo es).

 // use pins A0 and A2 to power the TMP36 sensor:
   pinMode(A0, OUTPUT);
  pinMode(A2, OUTPUT);
  // set A0 low, and A2 high:
  digitalWrite(A0, LOW);
  digitalWrite(A2, HIGH);

}


void loop()
{
  // Display time centered on the upper line
  lcd.setCursor(0, 0);
  lcd.print(rtc.getTimeStr());
 
  // Display abbreviated Day-of-Week in the lower left corner
  lcd.setCursor(0, 1);
  lcd.print(rtc.getDOWStr(FORMAT_SHORT));
 
  // Display date in the lower right corner
  lcd.setCursor(6, 1);
  lcd.print(rtc.getDateStr());
 
// read the sensor:
  int sensorVal = analogRead(A1);
  // convert to voltage:
  float voltage = 5.0 * sensorVal / 1024.0;
  // convert to degrees celsius:
  float temperature = (voltage - 0.5) * 100;
  // read the trim pot:
  float trimPotValue = analogRead(A3)/1023.0;
 
  // filter the sensor's result:
  float currentEstimate = filter(temperature, trimPotValue, lastEstimate);
  // print the result:
  lcd.print("               C");
  lcd.setCursor(11, 0);
  lcd.print(currentEstimate);
  // save the current result for future use:
  lastEstimate = currentEstimate;
  delay (1000);
}


// filter the current result using a weighted average filter:
float filter(float rawValue, float weight, float lastValue) {
  // run the filter:
  float result = weight * rawValue + (1.0-weight)*lastValue;
  // return the result:
  return result;


  // Wait one second before repeating :)
  delay (1000);
}

Primero:
parece que en vez de alimentar de 5V y GND, lo hace desde A2 y A0, poniéndolos antes en HIGH y LOW. Pregunta: ¿es algo habitual?¿da ventajas?
También pensaba que los A0...A5 siempre eran entradas. De hecho en la documentación no he visto nada como que puedan usarse como salidas y asignarles HIGH o LOW.

Segundo:
lee la temperatura en A1, y usa la lectura de A3 (en principio parece que no hay nada conectado ahí), para filtrar la señal (usa un filtro con la medida anterior, la actual y ese valor entre 0 y 1 leído de A3 -divide lo recibido por 1023-
He realizado en Excel una simulación simple y parece que filtra bien.
Pregunta: ¿se suelen usar estos filtrados?¿pensáis que A3 estará al aire, dando así medidas aleatorias?

Gracias.

Primero:
parece que en vez de alimentar de 5V y GND, lo hace desde A2 y A0, poniéndolos antes en HIGH y LOW. Pregunta: ¿es algo habitual?¿da ventajas?
También pensaba que los A0...A5 siempre eran entradas. De hecho en la documentación no he visto nada como que puedan usarse como salidas y asignarles HIGH o LOW.

Da ventajas? Solo la posibilidad de activarlo y desactivarlo cuando lo requieras, pero esta puesto por setup que es lo mismo que conectarlo a 5V y GND entonces a mi me parece una pavada.
A0 .. A5 son entradas analógicas, y pueden usarse digitalmente (Input o Outpus).

Segundo:
lee la temperatura en A1, y usa la lectura de A3 (en principio parece que no hay nada conectado ahí), para filtrar la señal (usa un filtro con la medida anterior, la actual y ese valor entre 0 y 1 leído de A3 -divide lo recibido por 1023
He realizado en Excel una simulación simple y parece que filtra bien.
Pregunta: ¿se suelen usar estos filtrados?¿pensáis que A3 estará al aire, dando así medidas aleatorias

En A3 tiene un preset o potenciómetro ajustable. De modo que no conecta a A1 donde esta el sensor TMP36 y luego mide en A3. Son dos cosas distintas.
El filtro parece ser una variante simple del promedio móbil. Búscalo porque da muy buenos resultados.
En el promedio móbil cada muestra se va restando y sumando por la cantidad de muestras en curso.
Da valores muy estables y sigue bastante bien la variable.

surbyte:
En A3 tiene un preset o potenciómetro ajustable. De modo que no conecta a A1 donde esta el sensor TMP36 y luego mide en A3. Son dos cosas distintas.

Gracias.
Lo que no acabo de pillar al 100% es lo que he anotado.

A ver si he entendido bien:
La salida del TMP36 a A1
La salida de un potenciómetro a A3
Lee A1 y usa el valor de A3 para dar más o menos o peso a la función “suavizadora”
¿Es así?

A ver si esta noche lo pruebo en el reloj que estoy montando. Espero que cuando lo comente sea para exponer cómo ha quedado, y no para pedir SOS en algún atasco.

si. Fijate que el valor de trimpot no es nunca mayor que 1 va de 0 a 1.
Por ende

float result = weight * rawValue + (1.0-weight)*lastValue;

Si vale 0 pot a GND => result =lastvalue
si vale 1 pot a 5V => result = rawvalue

Lo implemente, y aun asi la variabilidad era grande. Parece que procede de la fuente de alimentacion.
Es una china de 9v. Lo he alimentado de un cargador de 5v y las medidas son muy estables.
Ahora he sustituido el filtrado por un promedio de las ultimas 10 lecturas realizadas.

prueba con este filtro y me cuentas luego Moving-Avarage-Filter–Arduino-Library
Lo usas asi con tu ejemplo

#include <MovingAverageFilter.h>  // https://github.com/sebnil/Moving-Avarage-Filter--Arduino-Library-

MovingAverageFilter movingAverageFilter(20); // pon aquí la cantidad de muestras que desees no superes 100

void setup() {
	Serial.begin(115200);		// ajustar la velocidad en baudios
}

void loop() {

	// Display time centered on the upper line
	lcd.setCursor(0, 0);
	lcd.print(rtc.getTimeStr());
	 
	// Display abbreviated Day-of-Week in the lower left corner
	lcd.setCursor(0, 1);
	lcd.print(rtc.getDOWStr(FORMAT_SHORT));
	 
	  // Display date in the lower right corner
	lcd.setCursor(6, 1);
	lcd.print(rtc.getDateStr());
	 
	// convert to voltage:
	float voltage = 5.0 * analogRead(A1) / 1023.0;
	// convert to degrees celsius:
	float temperature = (voltage - 0.5) * 100;
    n++;
    Serial.print("n= ");		// print the sample number
	Serial.println(n, DEC);
	Serial.println("Ejecuto el filtro...");
	output = movingAverageFilter.process(temperature);		// here we call the fir routine with the input. The value 'fir' spits out is stored in the output variable.
	Serial.println(output);		// just for debugging or to understand what it does, print the output value
	
	lcd.print("               C");
  	lcd.setCursor(11, 0);
  	lcd.print(output);
  	delay(1000);
}

Gracias. He mirado el codigo y esencialmente es lo mismo que he programado, aunque algo mas elegante.
He estado pensando en mejorarlo excluyendo del calculo, cuando ya se han alcanzado el maximo de lecturas consideradas, el maximo y el minimo.

Aunque de momento tengo en el proyecto (se trata de un reloj con ajuste por pulsadores) algun otro punto de interes preferente. Espero poder dedicarle un par de ratos y rematarlo para poderlo comentar aqui.

Por favor!!! no puedes decir que es el mismo. Lo has probado?

surbyte:
Por favor!!! no puedes decir que es el mismo. Lo has probado?

No lo he probado, pero lo voy a hacer. Mañana, lo aseguro. Sólo le he echado un ojo al código de la librería.
Hay muchas muchas cosas de C que se me escapan, y de ahí seguramente que no haya sabido apreciar los matices.

De momento, se me acaba el tiempo de jugar con Arduino por hoy. Toca el tiempo de la familia.

Pongo el código de lo mío

// Filtra la temperatura, haciendo el promedio de los 10 últimos valores
float calculatemp(float tempi[10]) {
    int i=0, numvalores=0;
    float sumatemp=0;
    for (i=0;i<10;i++){
         if (tempi[i]<65000){
             numvalores++;
             sumatemp=sumatemp+tempi[i];
         }
    }
    if (numvalores>0){return sumatemp/(numvalores*1.00);}
    else {return 0;}
}

Y aquí cómo defino el array inicial y hago la llamada

En el setup:
float tempi[]={65535.0,65535.0,65535.0,65535.0,65535.0,65535.0,65535.0,65535.0,65535.0,65535.0};
byte contador=0;

En el loop:

tempi[contador]=temp;
      contador++;
      if (contador==10){contador=0;}
      float tempc=calculatemp(tempi);

Prueba realizada. El resultado es el mismo en estado "estacionario" (después de que se hayan realizado todos los ciclos de medida). Ya no sé apreciar si hay ventajas a la hora de procesar.

Pongo, desde el arranque, la salida al serie de la medida, la calculada con "mi media", y la calculada con la librería. Ambas para 10 medidas.

ACTIVA EL LCD
T(C) read: 17.45  T(C) calc_chema: 17.45 T(C) cal_guay: 1.74
T(C) read: 17.94  T(C) calc_chema: 17.69 T(C) cal_guay: 3.54
T(C) read: 18.91  T(C) calc_chema: 18.10 T(C) cal_guay: 5.43
T(C) read: 17.45  T(C) calc_chema: 17.94 T(C) cal_guay: 7.17
T(C) read: 17.45  T(C) calc_chema: 17.84 T(C) cal_guay: 8.92
T(C) read: 17.94  T(C) calc_chema: 17.86 T(C) cal_guay: 10.71
T(C) read: 17.94  T(C) calc_chema: 17.87 T(C) cal_guay: 12.51
T(C) read: 19.89  T(C) calc_chema: 18.12 T(C) cal_guay: 14.50
T(C) read: 19.40  T(C) calc_chema: 18.26 T(C) cal_guay: 16.44
T(C) read: 18.91  T(C) calc_chema: 18.33 T(C) cal_guay: 18.33
T(C) read: 18.91  T(C) calc_chema: 18.48 T(C) cal_guay: 18.48
T(C) read: 17.94  T(C) calc_chema: 18.48 T(C) cal_guay: 18.48
T(C) read: 17.94  T(C) calc_chema: 18.38 T(C) cal_guay: 18.38
T(C) read: 17.94  T(C) calc_chema: 18.43 T(C) cal_guay: 18.43
T(C) read: 20.38  T(C) calc_chema: 18.72 T(C) cal_guay: 18.72
T(C) read: 18.91  T(C) calc_chema: 18.82 T(C) cal_guay: 18.82
T(C) read: 17.45  T(C) calc_chema: 18.77 T(C) cal_guay: 18.77
T(C) read: 18.91  T(C) calc_chema: 18.67 T(C) cal_guay: 18.67
T(C) read: 17.94  T(C) calc_chema: 18.52 T(C) cal_guay: 18.52
T(C) read: 17.94  T(C) calc_chema: 18.43 T(C) cal_guay: 18.43

imposible que tu cálculo y la rutina de promedio mobil te den los mismos valores.
Muestrame el código por favor!

Que es una media movil, no? No tiene mayor misterio. El codigo esta puesto dos mensajes mas arriba, y esta tambien en el codigo del proyecto de reloj que colgue ayer tarde.

Ok. yo no veo tu ultimo código (veo un par de modificaciones o correcciones) y como respondo muchos post, cuando le tengo que dedicar tiempo demás adivina que? No lo hago.
A menos que la librería que te propuse no sea lo que yo esperaba, las dos respuestas no pueden ser idénticas.
Tu promedio, es un promedio standard de 10 muestras. El móbíl no es igual a un promedio standard.
Tampoco veo código alguno que tenga estos carteles

T(C) read: 17.94  T(C) calc_chema: 17.86 T(C) cal_guay: 10.71

Lo siento. Pongo la información creo que completa.
La librería, antes de utilizarla, la ojeé, y lo que vi fue una simple media móvil: nada más.

Arduino Uno.
Sensor TMP36GTz conectado a A0

Código de un sketch que realiza medidas (simple: ciclo de medidas, visualización, delay y nada más)

//Temperatura analógica en A0
int lec_analog;
unsigned long conta=0;

#include <MovingAverageFilter.h> //librería media movil. Recomendada por surbyte
MovingAverageFilter movingAverageFilter(10);//se define el número de medidas a incluir en la media movil

//tempi define e inicializa el array de 10 para hacer la media de temperaturas
//contador controla la posición del array de temperaturas en que debe entrar el último valor leido
float tempi[]={65535.0,65535.0,65535.0,65535.0,65535.0,65535.0,65535.0,65535.0,65535.0,65535.0};
int contador=0;

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

void loop() {
  conta++;
  Serial.print(conta);
  Serial.print (" - ");
  //Lee la señal de temperatura
  lec_analog = analogRead(A0);
  delay(100);
  //Calcula el valor en la función
  float temp=TMP36GT(lec_analog);
  //Mete el valor en su sitio del array de los últimos 10 valores
  tempi[contador]=temp;
  contador++;
  if (contador==10){contador=0;}
  float tempc=calculatemp(tempi); //Es el cálculo de la media móvil de 10 valores según mi función
  float output = movingAverageFilter.process(temp);

  Serial.print("T leida: ");
  Serial.print(temp);
  Serial.print("  T calc. propio: ");
  Serial.print(tempc);
  Serial.print(" T calc. libreria: ");
  Serial.println(output);
  delay(2000);

}

float TMP36GT(int lectura){        
  //750 mV a 25ºC y 10 mV/ºC
  //reference, 5000 si se usa referencia a 5V, 1100 si se usa referencia interna
  float reference=1100;
  float mvolt;
  float temp;
  mvolt=((lectura*reference)/1023.0);
  temp=(mvolt/10.0)-50.0;
  return (temp);                
                                               
}

// Filtra la temperatura, haciendo el promedio de los 10 últimos valores
float calculatemp(float tempi[10]) {
    int i=0, numvalores=0;
    float sumatemp=0;
    for (i=0;i<10;i++){
         if (tempi[i]<65000){
             numvalores++;
             sumatemp=sumatemp+tempi[i];
         }
    }
    if (numvalores>0){return sumatemp/(numvalores*1.00);}
    else {return 0;}
}

Salida al puerto serie. Se ve cómo, a partir del ciclo 10 se igualan.

1 - T leida: 13.98  T calc. propio: 13.98 T calc. libreria: 1.40
2 - T leida: 19.03  T calc. propio: 16.51 T calc. libreria: 3.30
3 - T leida: 14.52  T calc. propio: 15.84 T calc. libreria: 4.75
4 - T leida: 20.43  T calc. propio: 16.99 T calc. libreria: 6.80
5 - T leida: 18.60  T calc. propio: 17.31 T calc. libreria: 8.66
6 - T leida: 16.24  T calc. propio: 17.13 T calc. libreria: 10.28
7 - T leida: 20.65  T calc. propio: 17.63 T calc. libreria: 12.34
8 - T leida: 12.26  T calc. propio: 16.96 T calc. libreria: 13.57
9 - T leida: 19.57  T calc. propio: 17.25 T calc. libreria: 15.53
10 - T leida: 17.31  T calc. propio: 17.26 T calc. libreria: 17.26
11 - T leida: 19.89  T calc. propio: 17.85 T calc. libreria: 17.85
12 - T leida: 20.32  T calc. propio: 17.98 T calc. libreria: 17.98
13 - T leida: 14.95  T calc. propio: 18.02 T calc. libreria: 18.02
14 - T leida: 19.35  T calc. propio: 17.91 T calc. libreria: 17.91
15 - T leida: 16.13  T calc. propio: 17.67 T calc. libreria: 17.67
16 - T leida: 18.60  T calc. propio: 17.90 T calc. libreria: 17.90
17 - T leida: 19.35  T calc. propio: 17.77 T calc. libreria: 17.77
18 - T leida: 14.09  T calc. propio: 17.96 T calc. libreria: 17.96

Esto esta mal para comenzar

temp=(mvolt/10.0)-50.0;

debe ser

temp=(mvolt-500.0)/10.0;

mira acá Using a Temp Sensor por cualquier duda
Centigrade temperature = [(analog voltage in mV) - 500] / 10

Gracias por la corrección, aunque las dos expresiones son TOTALMENTE equivalentes, y en otros aspectos tengo duda, pero no en éste.

Vaya que ando mal. Y de nuevo tienes razón, son equivalentes.

Hola, intenta esto, es bastante simple el código a ver que tal...

int Sensor=A0;

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

void loop ()
        {
            int lectura = analogRead(Sensor);
            float voltaje = 5.0 /1024 * lectura ; // Atencion aqui
            float temp = voltaje * 100 -50 ; 
            Serial.println(temp) ; delay(1000); }

Espero te sirva, Saludos.

Pero eso ya lo hace, ademas divides por 1024 y esto te da 4,9951171875 cuando el ad entrega 1023 cuentas.
No se divide por 1024.
Es cierto que son 1024 pasos pero van de 0 a 1023. Entonces se divide por 1023.

Justamente esto le da valores con mucha variación.

Muchas gracias chicos, en especial a surbyte, por el tiempo perdido.
Con el tema he sacado varias cosas en claro, sobre todo entrar en el desarrollo de las medias móviles y otros medios de suavizar señales por software

Considero mi tiempo demasiado precioso para seguir peleando de momento con este sensor (tanto más no querría que perdáis el vuestro con esto).

Si esto fuera un proyecto para entregar, no dudéis en que me dejaría de historias, me gastaría un par de euros, y pondría un DHT22, o un ds18b20, pero estas cositas las uso como medio de aprendizaje, y no me importaría dedicarle más adelante un tiempo a seguir el tema, con calma, e intentar sacar alguna conclusión.

Seguiré haciendo alguna prueba, con tranquilidad, para intentar aislar la causa de la inestabilidad (que parte de la propia lectura que el Arduino hace en A0 del sensor), y si obtengo alguna conclusión, la “postearé”.

La idea será registrar de algún modo un índice de la variabilidad de medidas en un tiempo determinado, quizá una desviación estándar (varias horas, restando una medida independiente que pueda considerar estable), e irlo comparando modificando algunas variables, una a una.

  • tipo de conexiones utilizadas (diferencia entre protoboard y otros)
  • el pin al que se conecta (cambiar de A0 a A1, A2,…)
  • la placa Arduino a que se conecta
  • concurrencia de otros elementos en el circuito que puedan interferir.

Seguiremos informando. Gracias.