Avançar para o conteúdo

Jeito fácil de medir temperatura

E se eu te disser que existe um jeito fácil de medir temperatura – sem contato?. É exatamente sobre este tipo de sensor que vamos falar no artigo de hoje. Mais especificamente do sensor MLX90614 da empresa Melexis.

O modelo que eu comprei é o MLX90614BCC, direto deste link do Aliexpress, Ou deste outro link. Este é um sensor de temperatura sem contato, capaz de medir entre -70ºC e +380ºC sem encostar no objeto.

MLX90614BCC
Sensor MLX90614 para medir temperatura sem contato

Ele possui ainda um sensor de temperatura “ambiente”, interno ao seu encapsulamento. Este sensor é capaz de medir entre -40ºC e +125ºC. É usado, entre outras coisas, para a própria compensação do sensor de temperatura sem contato. Todas as informações aqui presentes sobre o sensor foram retiradas do seu datasheet, deste link.

Ele se comunica primáriamente via porta i2c, portanto tem pinos de SDA e SCL. Seu encapsulamento TO-39 conta ainda com pinos de alimentação para 3V3 e GND, além de campo de visão de 35º. A informação “gradient compensated” significa que o sensor mede sua temperatura interna para compensar fontes de calor que estejam esquentando o corpo do próprio sensor.

Abaixo está a página do datasheet que trata do código de aquisição do sensor. Eu marquei em vermelho o modelo que tenho em bancada, que você poode comprar nos links acima.

Escolha do modelo do sensor de temperatura
Escolha do modelo do sensor de temperatura

Segundo o próprio datasheet, quando mais fechado o ângulo de leitura (5º ou 10º por exemplo) maior o efeito do “self-heating”, encapsulamento esquentando. E imagino que maior o preço do sensor, visto que o “gradient compensated” comentado acima torna-se mandatório. Então por mais que um ângulo pequeno permita leituras mais direcionadas, também vem acompanhando de um custo maior.

Ainda sobre como ler os dados do sensor, além da porta i2c ele ainda pode ter uma saída PWM do valor lido. Neste caso a porta i2c ficaria desabilitada, mas eu não testei isso. Neste artigo vamos focar apenas na comunicação i2c, utiliando uma biblioteca da Adafruit para o software IDE do Arduino.

Como este sensor faz leituras?

Você já deve estar se perguntando como este sensor consegue fazer leituras de temperatura sem contato, certo?. Pois bem, a base do sensor é um sensor infravermelho, que portanto ignora luz visível. Segundo seu datasheet ele até tem filtros físicos na frente do sensor infravermelho. Servem para ignorar qualquer outro comprimento de onda que possa chegar na frente do sensor.

Este sensor é calibrado de fábrica com um “corpo negro” com emissividade bem próxima de 1. Este corpo negro é posicionado na frente do sensor de modo a ocupar toda sua área útil de medição. Um corpo negro com emissividade próxima de 1 é basicamente um objeto “o mais escuro possível” que absorve e re-emite toda energia térmica que recebe.

Este sensor é tão avançado que possui leitura do sensor infravermelho interno em 17 bit. Isso é muita coisa para um conversor analógico-digital, especialmente um montado dentro de um sensor. Ele conta ainda com um DSP (“digital signal processor”, processador digital de sinais), que é um “microcontrolador” especializado em operações matemáticas de sinais analógicos.

Tem um conceito importante que até mesmo eu demorei a entender sobre este sensor. Um termômetro daqueles de medir a temperatura da nossa testa sempre tem uma distância de leitura recomendada. Não dá para apontar o termômetro para uma pessoa a três metros de distância e esperar medir temperatura de forma precisa.

Já o sensor que vamos testar hoje, o MLX90614 é especificado não por distância, mas sim somente por ângulo de abertura. Isto vem de encontro justamente ao corpo negro da calibração citado acima. Este sensor é calibrado de fábrica para o tal corpo negro numa temperatura conhecida, a uma distância tal que ocupe toda área do sensor.

Isto significa que se quisermos por exemplo fazer um termômetro destes de medir febre, precisaremos executar uma nova calibração do sensor. Assim como outras aplicações (temperatura ambiente, temperatura de geladeira, etc) precisarão cada uma de sua calibração. Então nas fotos e no vídeo que acompanham este artigo você verá temperaturas que nem sempre serão precisas com a realidade.

O hardware necessário

Já falamos aqui no blog sobre diversos sensores de temperatura, como este, este aqui e ainda este. Porém é a primeira vez que vamos falar de um que faz leituras sem contato. Inclusive é um dos sensores (no geral) mais caros que eu já testei, na casa dos US$8.

Porém sua forma de ligação é bem similar a vários módulos de Arduino que já testei aqui: apenas a porta i2c (SDA e SCL) e VCC + GND. Um detalhe importante é sua alimentação e controle, em termos de níveis de sinais. O diagrama esquemático do módulo que achei aqui monstra a presença de um regulador de tensão para 3,3V. O mesmo diagrama também mostra a presença de resistores de pull-up no SDA e SCL, no próprio sensor.

Então você até pode alimentar o módulo com 5V, porém os pinos do i2c precisam ser 3,3V. No caso do nosso tutorial de hoje eu vou controla-lo com um ESP32-C6, que já é nativamente 3,3V. Eu inclusive conectei o 3,3V direto no pino VIN (que é a entrada do regulador de tensão) e funcionou normal.

Nosso experimento vai contar com “algumas coisinhas a mais”: teremos um LED que vai ficar piscando em tempos aleatório (só por diversão). Teremos também um pequeno display de 0.49″ (polegadas) para mostrar temperatura em tempo real. Já falamos sobre este display aqui no meu outro blog. Abaixo está o diagrama esquemático do experimento para medir temperatura, bem como uma foto dele montado na protoboard.

Diagrama esquemático do sensor MLX90614 + OLED + ESP32
Diagrama esquemático do sensor MLX90614 + OLED + ESP32
sensor de temperatura em protoboard
Sensor de temperatura em protoboard

A montagem foi feita toda em uma pequena protoboard de 400 pontos. Isto foi possível pois eu usei um módulo Xiao ESP32-C6 feito pela SeeedStudio. A placa PCI eu mesmo fiz, ela acomoda todos os pinos um uma única linha da protoboard. Mais detalhes aqui. A placa que fiz é bem visível no desenho do esquemático acima.

Detalhe importante: para este experimento de medir temperatura você deve utilizar uma placa ESP32. Pode ser de qualquer modelo disponível, pois todos trabalham com 3,3V e possuem porta i2c. Mas não pode ser Arduino UNO, etc, já já te explico porque.

O firmware/código

Para nosso experimento eu resolvi incrementar um pouco o resultado. Além de ler o sensor de temperatura MLX90614, vamos mostrar sua leitura em um pequeno display de 0.49 polegadas. Ainda vai ter um LED piscando em intervalos aleatórios, usando a função de números aleatórios nativa do ESP32.

Exatamente devido a este gerador de números aleatórios que você deve usar um ESP32, não um Arduino UNO, Nano, Mega, etc. Claro que se você se sentir confiante pode remover do código toda parte de números aleatórios. Aí sim pode usar outros tipos de placas no experimento.

Todo o código deste experimento de medir temperatura está neste Github, aproveite. Também disponibilizei o código abaixo, para ser mais fácil de você copiar e colar. Logo após ele eu vou explicar alguns passos e partes importantes do código, com calma.

/***************************************************
  MLX90614 sensor library
  Written by Limor Fried/Ladyada for Adafruit Industries.
  BSD license.
  OLED display info from here https://fritzenlab.net/2025/01/03/tiny-0-49-oled-display/
 ****************************************************/

#include <Adafruit_MLX90614.h>
#include <Arduino.h>
#include <U8g2lib.h>
#include <Wire.h>
#include <esp_system.h> // Required for esp_random()

#define LED 2

U8G2_SSD1306_64X32_1F_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
Adafruit_MLX90614 mlx = Adafruit_MLX90614();

float t= 0;
uint32_t sensorTime = 0;
uint32_t ledTime = 0;
bool ledStatus = false;
const char* varToPrint = " ";
uint32_t ledPreviousMillis = 0;

// Avoids modulo bias using rejection sampling
uint32_t randomBounded(uint32_t bound) {
  if (bound == 0) return 0;  // avoid division by zero

  uint32_t x;
  const uint32_t limit =
    UINT32_MAX - ((UINT32_MAX + 1ULL) % bound);

  // Reject values in the incomplete top interval so every output
  // has exactly the same probability (avoids modulo bias).
  do {
    x = esp_random();
  } while (x >= limit);  // Retry until unbiased

  return x % bound;
}

// Returns a random number in the range [minVal, maxVal)
uint32_t randomRange(uint32_t minVal, uint32_t maxVal) {
  if (maxVal <= minVal) return minVal;  
  return minVal + randomBounded(maxVal - minVal);
}

void setup() {
  pinMode(LED, OUTPUT);
  u8g2.begin();
  // Setting the display i2c clock to 100kHz is necessary for the MLX90614
  // sensor to work, since it communicates on that speed only. 
  // Otherwise the 0.49" OLED display would use 400kHz.
  u8g2.setBusClock(100000);
  u8g2.setFont(u8g2_font_10x20_tf);
  Serial.begin(115200);
  while (!Serial);

  Serial.println("MLX90614 + OLED");

  if (!mlx.begin()) {
    Serial.println("Error connecting to MLX sensor. Check wiring.");
    while (1);
  };

  Serial.print("Emissivity = "); Serial.println(mlx.readEmissivity());
  Serial.println("================================================");
  Wire.setClock(100000); // this is only necessary at power up, later
  // "u8g2.setBusClock(100000);" above assumes and corrects the issue
  ledTime = randomRange(80, 800);
}

void loop() {

  if(millis() - sensorTime > 1000){
    sensorTime += 1000;
    t= mlx.readObjectTempC();
    /*Serial.print("Ambient = "); Serial.print(mlx.readAmbientTempC());
    Serial.print("*C\tObject = "); Serial.print(t); Serial.println("*C");
    Serial.println();*/
    
    u8g2.clearBuffer();			
    // String() constructor with decimal-places argument — Arduino String reference
    // https://www.arduino.cc/reference/en/language/variables/data-types/string/
    String tempStr = String(t, 1) + "C";
    u8g2.setCursor(0, 20);
    varToPrint = tempStr.c_str();
    u8g2.drawStr(5, 20, varToPrint);
    // this print is just to get the printable string width, 
    // it helped me and Claude.ai pick the best font
    //Serial.println(u8g2.getStrWidth(varToPrint));
    u8g2.sendBuffer();	
  }

  if(millis() - ledPreviousMillis > ledTime){
    ledPreviousMillis = millis();
    ledTime = randomRange(80, 800);
    ledStatus = !ledStatus;
    digitalWrite(LED, ledStatus);
    Serial.println(ledTime);  
  }
}

Para começar, no setup() eu preciso baixar a frequência do clock do display OLED para 100kHz. Isto porque o OLED trabalha por padrão em 400kHz, porém o sensor MLX90614 trabalha até 100kHz (de acordo com seu datasheet). Eu faço isso assim:

u8g2.setBusClock(100000);

Já dentro do loop() principal, eu faço um IF que é executado a cada 1000ms (1 segundo). É aqui que é feita a leitura do sensor de temperatura:

if(millis() - sensorTime > 1000){

O sensor MLX90614 é lido assim:

t= mlx.readObjectTempC();

Depois eu pego a variável “t” e concateno com a letra “C”, para que seja mostrada temperatura no display da seguinte forma: “23.2C”. A função de “desenhar Strign” no display aceita apenas variável char*, então eu preciso converter de Sring para char*:

varToPrint = tempStr.c_str();
    u8g2.drawStr(5, 20, varToPrint);

Esta parte do código fica executando a cada um segundo, sem parar e sem bloquear o restante do código. Além disso eu tenho um LED piscando no pino D2 (GPIO 2). seu tempo de piscada é obtido de forma aleatória, entre 80ms e 800ms. Para isso eu criei uma função chamada “randomRange(de, até)”, que obtém o número aleatório através da função nativa “esp_random()”.

ledTime = randomRange(80, 800);

Já havíamos comentado sobre números aleatórios no ESP32 neste artigo do meu outro blog. Basicamente o ESP32 tem uma máquina interna de números aleatórios. Ela pode ser “incrementada” com seeds (sementes) tanto do módulo WiFi como de entrada analógica. Não usaremos nenhum dos dois aqui.

Diferente de placas como o Arduino UNO, onde os números são pseudo-aleatórios, aqui no ESP32 são aleatórios de verdade.

Como medir temperatura sem contato?

Copie o código completo acima (ou do GitHub), cole na sua IDE do Arduino. A versão do software IDE do Arduino que estou usando é 2.3.8, porém qualquer uma acima da 1.8.x serve. O ideal é que seja a mais atualizada possível. Conecte sua placa ESP32 ao computador via cabo USB. Agora clique em “->” “Upload” no canto superior esquerdo da tela.

Ao fim do upload tudo já deve estar funcionando: o LED piscando de forma “estranha” e o display de 0.49 polegadas mostrando temperatura neste formato: “21.9C”. Agora faça alguns experimentos de medir temperatura: aproxime a palma ou as costas da sua mão do sensor, coisa de 3-5 centímetros.

Caso você esteja tomando café ou até mesmo algo gelado, aproxime a xícara/copo do sensor. Observe que a variação da leitura é quase instantânea. Só não é mais rápida pois nosso código só atualiza o display a cada um (1) segundo.

Medir temperatura de xícara com café
Medir temperatura de xícara com café

Fiz um vídeo sobre este experimento, falando de todos os detalhes e segredos. Para assisti-lo vá até lá no início deste artigo, no primeiro parágrafo. Lá você vai conseguir tirar todas as suas dúvidas. Caso ainda restem, pode comentar abaixo ou então lá no Youtube do FritzenLab mesmo. Até a próxima pessoal!.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *