Hoy voy a describir el pequeño montaje realizado para toma de medidas de temperatura de forma continua, y su posterior tratamiento y representación en el PC. El sensor de temperatura utilizado es un LM35, se trata de un sensor de bajo coste, con una precisión aceptable (0.5ºC aproximadamente) y de fácil utilización. Dicho sensor sólo necesita ser alimentado con una tensión de entre 4 y 30 V, conexión a tierra, y en la tercera patilla podemos medir una señal de tensión que se corresponde con la temperatura según la siguiente relación:

La idea detrás de este montaje es la de medir continuamente la temperatura y transmitirla por USB de modo que se muestre en una gráfica elaborada en C#. Además de mostrar los valores medidos, se aplicará un filtro pasa-bajo para suavizar la señal, obteniendo una estimación más precisa de la temperatura actual. También se realizan in-situ varias medidas que se promedian antes de ser enviadas por el USB, con el fin de compensar y eliminar ruidos electrónicos tanto del LM35 como del ADC del Arduino.

La misión del filtro pasa-bajo es, de forma muy resumida, bloquear las variaciones de alta frecuencia (debidas principalmente a ruido electrónico), dejando pasar únicamente las fluctuaciones de temperatura más lentas (que se deben a la variación de la temperatura real). Matemáticamente se calcula usando la siguiente expresión:

donde el factor se calcula a partir de la frecuencia de corte:

 

El esquema de conexiones y el código usado en Arduino son los siguientes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Declaracion de variables
float tempC;      // Temperatura final
int tempPin = 0;  // Definimos la entrada en pin A0
 
void setup()
{
    // Abre puerto serial y lo configura a 115200 bps
    pinMode(tempPin, INPUT);  
    Serial.begin(115200);
}
void loop()
{
    // Lee el valor desde el sensor
    int lectura = 0;
    for(int i = 0; i < 32; i++) lectura += analogRead(tempPin);           lectura >> 5;
    // Convierte el valor a temperatura
    tempC = (5.0 * lectura/32.0 * 100.0)/1024.0; 
    // Envia el dato al puerto serial
    Serial.println(tempC);
    // Espera 0.1 s para iniciar de nuevo
    delay(100);
}

Por otro lado, el código del programa que muestra los datos gráficamente es:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
public partial class Form1 : Form
{
    // Declaración de constantes
    public const double fc = 0.5;
    public const double dt = 0.1;
    public const double pi = 3.141592654;
    double alfa = (2 * pi * fc * dt) / (1 + 2 * pi * fc * dt);
 
    double y_viejo = 0;
    SerialPort serialport;
    write_invoker invoker;
 
    public Form1()
    {
        InitializeComponent();
        invoker = new write_invoker(this.write);
 
        // Iniciamos el puerto serie
        serialport = new SerialPort("COM3");
        serialport.BaudRate = 115200;
        serialport.Parity = Parity.None;
        serialport.StopBits = StopBits.One;
        serialport.DataBits = 8;
        serialport.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
        serialport.Open();
    }
 
    private void write(double xi)
    {
        // Calculamos el valor filtrado
        double promedio = alfa * xi + (1 - alfa) * y_viejo;
        y_viejo = promedio;
        // Mostramos los valores en la gráfica y lo escribimos
        chart.Series[0].Points.AddY(xi);
        chart.Series[1].Points.AddY(promedio);
        current.Text = promedio.ToString("N1") + " ºC";
    }
    delegate void write_invoker(double xi);
 
    private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
    {
        // Leemos el dato, y lo procesamos
        double xi = 0;
        string datos = ((SerialPort)sender).ReadLine().Trim('\r');
        bool exito = double.TryParse(datos, NumberStyles.Float, CultureInfo.InvariantCulture, out xi);
        if(exito) this.BeginInvoke(invoker, xi);
    }
 
    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        serialport.Close();     // Cierra el puerto serie
    }
}

Por último, os dejo una captura de pantalla con un ejemplo de captura de datos:

Monitor de temperatura

 

Podemos observar que las medidas realizadas (en azul claro) son bastante estables, ya que el dispositivo toma 32 lecturas seguidas y las promedia, eliminando efectos de ruido. Además, se ha utilizado una frecuencia de filtrado muy baja, para exagerar el efecto de promediado (en azul oscuro) y que éste se pueda distinguir sin problema. En este caso casi no es necesario aplicar el filtro pasa bajos.