Conversor analógico digital ADS1115 e sensor LM35 17

Muitos projetos dependem da aquisição de variáveis ambiente para controle, automação ou algum tipo de tomada de decisão, e dentro destas variáveis podemos citar a temperatura como uma das que mais se destacam. Existem inúmeros sensores/transdutores com foco na medição de temperatura, cada um com suas características, qualidade e em alguns casos, dificuldades de uso. Dentro da categoria “analógico” o LM35 é um dos modelos mais comuns, visto sua exatidão, simplicidade de uso e amplo range de medição.  Apesar da sua simplicidade, obter medições com alto grau de reprodutibilidade (e também resolução) pode se tornar um desafio em microcontroladores com conversor Analógico Digital (ADC) de 8 ou 10 bit.

Conversor AD ADS1115

Neste artigo mostraremos como obter excelentes medições utilizando um conversor externo de 16 bits, o conversor analógico digital 4 canais ADS1115.

Conversor analógico digital ADS1115 de 16 bits

O conversor analógico digital ADS1115 é um ADC do tipo Sigma/Delta com resolução de 16 bit e com comunicação I2C, bastante versátil e interessante para projetos que demandem mais resolução e exatidão, mas que não necessitem de uma alta taxa de amostragem.

Conversor Analógico Digital ADS1115

Principais características

  • Alimentação entre 2V e 5,5V
  • Amostragem de 8 a 860 samples por segundo
  • Referência interna de tensão com elevada exatidão inicial
  • PGA interno – Ganho programável via software
  • MUX interno
  • Configuração Single-ended ou Differential
  • Pode atuar como comparador de tensão ou de janela
  • Permite a utilização de até 4 dispositivos no mesmo barramento I2C

Em uma comparação direta com o ATmega328P, os 6 bits a mais de resolução proporcionam 64x mais resolução, são 1024 gradações (10 bit) contra 65536 gradações (16 bit). Em uma aplicação real mais variáveis irão entrar em jogo, mas já dá para perceber que poderemos medir valores muito menores com este conversor.

Devido ao seu amplo range de alimentação o conversor pode ser utilizado desde um microcontrolador alimentado com 5V até dispositivos alimentados com 3,3V como uma NodeMCU ou mesmo uma Raspberry Pi.

Além da resolução muito maior podemos tirar proveito de outro artifício muito interessante, o PGA, ou “Programmable Gain Amplifier”, ou “Amplificador de Ganho Programável”. Basicamente é um circuito que permite amplificar o sinal na entradas analógicas para aproveitar ao máximo o range do ADC, com todo este controle sendo feito digitalmente via registradores internos acessados pela I2C. Configurando o PGA podemos trabalhar com sinais entre +/-256mV até +/-6.144V (range padrão).

O ADS1115 possui um MUX interno permitindo escolher entre 4 canais single-ended ou 2 canais diferenciais. Ok, mas o que isso quer dizer? Talvez você já esteja familiarizado com a configuração single-ended, visto que está presente no ADC interno da maioria dos microcontroladores. Nesta configuração o sinal é referenciado diretamente o GND do circuito e a entrada analógica em si precisa de apenas uma via de sinal. Na configuração diferencial o ADC irá converter um sinal diferencial, ou seja a diferença de potencial entre dois pontos, semelhante ao que acontece com um multímetro. Nesta configuração são necessárias duas entradas que serão conectadas aos pontos de interesse, além do GND que também deve ser comum para evitar que se exceda os limites do componente.

Uma observação importante, nunca o sinal na entrada deve exceder a tensão de “Vcc + 0,3V” ou “GND – 0,3V”. Apesar do componente possui proteções internas, ao exceder estes níveis você colocará em risco o dispositivo. De maneira resumida, o sinal não pode ser maior que a alimentação e nem ser negativo em referência ao terra.

O ADS1115 possui um pino “ADDR” responsável por configurar o endereço do dispositivo no barramento I2C. O Mais interessante é que com apenas um único pino conseguimos 4 endereços diferentes. No total podemos obter até 16 canais single-ended ou 8 diferenciais em um único barramento I2C.

ADDR conectado a:

Endereço (binário)

Endereço (hexadecimal)

GND

1001000

48h

VDD

1001001

49h

SDA

1001010

4Ah

SCL

1001011

4Bh

Endereçamento ADS1115

Indico a leitura do datasheet para conhecer mais sobre as características deste conversor analógico digital (ADC).

O sensor de temperatura LM35

O sensor de temperatura LM35 é um sensor de temperatura de precisão com saída analógica proporcional a temperatura em grau Celsius.

Possui um fator de escala de 10mV/°C, ou seja, cada 1°C de variação desencadeia uma variação de 10mV em sua saída. Veja, a variação é bem pequena e justamente por isso pode-se perder muita resolução se tentarmos utilizar o ADC do Arduino Nano ou Uno em sua configuração padrão com referência de tensão em Vcc.

Possui uma ótima exatidão de 0,5°C à 25°C, podendo chegar a 1°C nos extremos da escala (onde geralmente não costumamos utilizar).

O componente possuir apenas 3 terminais se assemelhando muito a um transistor bipolar. Sua alimentação pode variar entre 4V até 30V.

LM35

Indico darem uma olhada no datasheet do componente para conhecer mais sobre suas características e também alguns circuitos indicados pelo fabricante.

Principais materiais utilizados

Montagem do circuito com ADS1115

O circuito é bastante minimalista e simples de ser montado em uma protoboard. Deve-se conectar o pino SDA ao pino A4 e o pino SCL ao pino A5. Além disso devemos conectar o pino ADDR ao GND (endereço 48h). O pino VDD deve ser conectado a linha de 5V e o GND ao GND.

Circuito Arduino ADS1115

Programa de teste do ADS1115

O código também é bastante simples e está bem comentado. Mas antes de começar temos que instalar a biblioteca. Você pode utilizar o “Gerenciador de Biblioteca” e instalar a libraryAdafruit ADS1x15”, ou então baixá-la neste link e realizar a instalação manualmente.

Os principais passos para uso são

  • Criar uma instância da classe “Adafruit_ADS1115” já indicando o endereço do dispositivo;
  • Dentro do Setup, modificar o ganho caso necessário, inicializar o conversor;
  • Dentro do Loop, chamar a função de leitura (single-ended ou diferencial)

O código é bastante explicativo, veja a seguir.

/********************************************************************************
 * ADS1115_LM35_01 - Medicao de temperatura com LM35 e conversor analogico digital ADS1115 (16 bit)
 * ------------------------------------------------------------------------------
 * https://github.com/agaelema/ADS1115_and_LM35
 * developed by: Haroldo Amaral - [email protected]
 * 2017/11/18 - v 1.0
 ********************************************************************************/
#include <Wire.h>
#include <Adafruit_ADS1015.h>

/* possibilidades/niveis de acordo com a resolução */
#define   ADC_16BIT_MAX   65536

/* cria instância do conversor analogico digital ADC */
Adafruit_ADS1115 ads(0x48);

/*
 * Variaveis
 */
float ads_bit_Voltage;
float lm35_constant;


void setup(void) 
{
  /* inicializa a serial */
  Serial.begin(9600);

  /* aguarda a serial estar disponível */
  while (!Serial);

  /* imprime o nome do arquivo com data e hora */
  Serial.println(F("\r\n"__FILE__"\t"__DATE__" "__TIME__));

  /*
   * configura o ganho do PGA interno do ADS1115
   * - Sem configurar ele inicia automaticamente na escala de +/- 6.144V
   * - lembre-se de não exceder os limites de tensao nas entradas
   * - - VDD+0.3v ou GND-0.3v
   */
  ads.setGain(GAIN_TWOTHIRDS);  // 2/3x gain +/- 6.144V  1 bit = 3mV      0.1875mV (default)
//  ads.setGain(GAIN_ONE);        // 1x gain   +/- 4.096V  1 bit = 2mV      0.125mV
//  ads.setGain(GAIN_TWO);        // 2x gain   +/- 2.048V  1 bit = 1mV      0.0625mV
//  ads.setGain(GAIN_FOUR);       // 4x gain   +/- 1.024V  1 bit = 0.5mV    0.03125mV
//  ads.setGain(GAIN_EIGHT);      // 8x gain   +/- 0.512V  1 bit = 0.25mV   0.015625mV
//  ads.setGain(GAIN_SIXTEEN);    // 16x gain  +/- 0.256V  1 bit = 0.125mV  0.0078125mV

  /* inicializa o ADC */
  ads.begin();

  /* modifique este valor de acordo com o ganho selecionado */
  float ads_InputRange = 6.144f;

  /* no range de +-6.144V, 187.502uV/bit */
  ads_bit_Voltage = (ads_InputRange * 2) / (ADC_16BIT_MAX - 1);

  /* LM35 - tensão por grau Celsius - 10mV/oC */
  lm35_constant = 10.0f / 1000;


  /*
   * imprime o valor da tensao por bit
   * - ADS1115 (de acordo com o ganho do PGA)
   * - Arduino Nano/Uno com referencia em Vcc
   * - Arduino Nano/Uno com referencia interna de 1.1V
   */
  Serial.println();
  Serial.print("ADS volt/bit: ");   Serial.print(ads_bit_Voltage * 1000, 4);     Serial.println(" mV/bit");
  Serial.println();
  Serial.println();

  /* imprime a primeira linha com identificacao dos dados */
  Serial.println("ADS RAW \tADS Temp.");

  /* seta a referencia interna */
  analogReference(INTERNAL);
}

void loop(void) 
{
  /* variaveis apra armazenar o valor RAW do adc */
  int16_t ads_ch0 = 0;
  int16_t nano_ch0_0 = 0;           // usando referencia de Vcc (5V)
  int16_t nano_ch0_1 = 0;           // usando referencia interna (1.1V)
  /* variaveis para armazenar o resultado em tensao */
  float ads_Voltage_ch0 = 0.0f;
  /* variaveis para armazenar a temperatura */
  float ads_Temperature_ch0 = 0.0f;

  /********************************************
   * ADS1115 - 16bit ADC
   * - le o ADC
   * - converter o valor RAW em tensao
   * - calcula a temperatura
   ********************************************/
  ads_ch0 = ads.readADC_SingleEnded(0);
  ads_Voltage_ch0 = ads_ch0 * ads_bit_Voltage;
  ads_Temperature_ch0 = ads_Voltage_ch0 / lm35_constant;

  /* imprime os resultados */
  Serial.print(ads_ch0);    Serial.print("\t\t");   Serial.print(ads_Temperature_ch0, 3);       Serial.print("\t\t");
  Serial.println();
  
  delay(200);
}

O resultado será apresentado no serial monitor com os dados RAW e com o valor já convertido em temperatura.

COMPARANDO OS RESULTADOS

A título de curiosidade realizei um comparativo coletando amostras utilizando o conversor analógico digital ASD1115 e também o conversor interno da placa Nano. Basicamente montei o esquema acima, adicionei um fio conectando a saída do LM35 a entrada A0 da placa Nano e então aqueci brevemente o sensor com meus dedos.

Note que existem três traçados na figura abaixo. Em azul temos as medições com o ADS1115, note como a resolução a mais permite um traçado sem a presença de variações bruscas, diferente do que notamos nos outros dois traçados. Em laranja temos a medição direta com o ADC interno e em verde temos uma média de 16 leituras sequenciais para suavizar as amostras e reduzir o ruído.

Bastante diferente o resultado não é!? Achou o resultado do conversor interno com muito ruído? Poderia ser pior pois neste caso configurei o código para utilizar a referência interna de 1,1V e com isso melhorar a margem dinâmica, em 5V o resultado teria muito mais ruído. Mas isso é bastante normal nos conversores internos dos microcontroladores. Só o fato de utilizar conversores externos já minimiza muito o ruído, tanto é que em aplicações de exatidão geralmente são utilizados conversores externos.

Desconsidere o pequeno offset entre as temperatura pois isso pode ser compensado em software. O ruído também poderia ser minimizado aumentando o tamanho da média, mas veja, isso não é muito prático e nem eficiente. Você precisa tomar N amostras a mais para então calcular a média, tudo isso toma mais tempo e consome mais energia. Em diversos casos vale a pena utilizar um conversor com mais resolução.

Se quiser reproduzir esse teste é só utilizar o código abaixo, lembrando de conectar a saída do sensor também ao pino A0 da placa Nano. Tente modificar o tamanho da média através da variável “repeat” para ver o resultado. Utilize o “Serial Plotter” para visualizar os dados.

/********************************************************************************
 * ADS1115_LM35_02 - Comparacao resultado conversor analogico digital ADS1115 e ADC interno ATmega
 * - conectar a saida do LM35 as entradas A0 do ADS1115 e do Arduino
 * - utilizar a referencia interna no arduino (nano/uno) de 1.1v
 * ------------------------------------------------------------------------------
 * https://github.com/agaelema/ADS1115_and_LM35
 * developed by: Haroldo Amaral - [email protected]
 * 2017/11/18 - v 1.0
 ********************************************************************************/

#include <Wire.h>
#include <Adafruit_ADS1015.h>

/* possibilidades/niveis de acordo com a resolução */
#define   ADC_10BIT_MAX   1024
#define   ADC_16BIT_MAX   65536

/* cria instância do ADC */
Adafruit_ADS1115 ads(0x48);

/*
 * Variaveis
 */
float ads_bit_Voltage;
float nano_bit_Voltage_5v0;
float nano_bit_Voltage_1v1;
float lm35_constant;


void setup(void) 
{
  /* inicializa a serial */
  Serial.begin(9600);

  /* aguarda a serial estar disponível */
  while (!Serial);

  /*
   * configura o ganho do PGA interno do ADS1115
   * - Sem configurar ele inicia automaticamente na escala de +/- 6.144V
   * - lembre-se de não exceder os limites de tensao nas entradas
   * - - VDD+0.3v ou GND-0.3v
   */
  ads.setGain(GAIN_TWOTHIRDS);  // 2/3x gain +/- 6.144V  1 bit = 3mV      0.1875mV (default)
//  ads.setGain(GAIN_ONE);        // 1x gain   +/- 4.096V  1 bit = 2mV      0.125mV
//  ads.setGain(GAIN_TWO);        // 2x gain   +/- 2.048V  1 bit = 1mV      0.0625mV
//  ads.setGain(GAIN_FOUR);       // 4x gain   +/- 1.024V  1 bit = 0.5mV    0.03125mV
//  ads.setGain(GAIN_EIGHT);      // 8x gain   +/- 0.512V  1 bit = 0.25mV   0.015625mV
//  ads.setGain(GAIN_SIXTEEN);    // 16x gain  +/- 0.256V  1 bit = 0.125mV  0.0078125mV

  /* inicializa o ADC */
  ads.begin();

  /* modifique este valor de acordo com o ganho selecionado */
  float ads_InputRange = 6.144f;

  /* no range de +-6.144V, 187.502uV/bit */
  ads_bit_Voltage = (ads_InputRange * 2) / (ADC_16BIT_MAX - 1);
  /* range de 0 a 5V em 10 bit, 4.88mV/bit */
  nano_bit_Voltage_5v0 = 5.0f / (ADC_10BIT_MAX - 1);
  /* referencia interna de 1.1V em 10 bit, 1.07mV/bit */
  nano_bit_Voltage_1v1 = 1.1f / (ADC_10BIT_MAX - 1);

  /* LM35 - tensão por grau Celsius - 10mV/oC */
  lm35_constant = 10.0f / 1000;

  /* seta a referencia interna */
  analogReference(INTERNAL);
}

void loop(void) 
{
  /* variaveis apra armazenar o valor RAW do adc */
  int16_t ads_ch0 = 0;
  int16_t nano_ch0_0 = 0;           // usando referencia de Vcc (5V)
  int16_t nano_ch0_1 = 0;           // usando referencia interna (1.1V)
  /* variaveis para armazenar o resultado em tensao */
  float ads_Voltage_ch0 = 0.0f;
  float nano_Voltage_ch0_0 = 0.0f;
  float nano_Voltage_ch0_1 = 0.0f;
  /* variaveis para armazenar a temperatura */
  float ads_Temperature_ch0 = 0.0f;
  float nano_Temperature_ch0_0 = 0.0f;
  float nano_Temperature_ch0_1 = 0.0f;

  /********************************************
   * ADS1115 - 16bit ADC
   * - le o ADC
   * - converter o valor RAW em tensao
   * - calcula a temperatura
   ********************************************/
  ads_ch0 = ads.readADC_SingleEnded(0);
  ads_Voltage_ch0 = ads_ch0 * ads_bit_Voltage;
  ads_Temperature_ch0 = ads_Voltage_ch0 / lm35_constant;

  uint16_t  i;
  /********************************************
   * ATmega328P (Nano/UNO) - 10bit ADC
   * - le o ADC
   * - converter o valor RAW em tensao
   * - calcula a temperatura
   ********************************************/
  nano_ch0_0 = analogRead(0);
  nano_Voltage_ch0_0 = nano_ch0_0 * nano_bit_Voltage_1v1;
  nano_Temperature_ch0_0 = nano_Voltage_ch0_0 / lm35_constant;

  /*
   * calcula a media de N conversoes
   */
  uint16_t repeat = 16;
  for (i = 0; i < repeat; i++)
  {
    nano_ch0_1 += analogRead(0);      // soma N resultados
  }
  nano_ch0_1 /= repeat;               // divide o somatorio
  nano_Voltage_ch0_1 = nano_ch0_1 * nano_bit_Voltage_1v1;
  nano_Temperature_ch0_1 = nano_Voltage_ch0_1 / lm35_constant;

  /* 
   *  imprime os resultados 
   *  - utilize o "Plotter Serial" para visualizar os dados
   */
  
  Serial.print(ads_Temperature_ch0, 3);       Serial.print(',');
  Serial.print(nano_Temperature_ch0_0, 3);    Serial.print(',');
  Serial.print(nano_Temperature_ch0_1, 3);
  
  Serial.println();

  delay(200);
}

Chegamos ao final deste artigo. Você pode acessar os arquivos deste projeto no meu Github. Qualquer dúvida sinta-se a vontade de deixar seus comentários.

Gostou do post com conversor analógico digital ADS1115? Ajude-nos a melhorar o Blog comentando abaixo sobre este tutorial. 

Faça seu comentário

Acesse sua conta e participe

17 Comentários

  1. Ótima explicação, Haroldo! A ideia da comparação por meio de gráfico foi genial. Parabéns!

  2. boa noite, e se eu colocar mais um sensor, o que tenho que modificar no código?

    1. Olá, Augusto!

      Você teria que duplicar as linhas relacionados ao sensor!

      Você pode seguir alguns tutoriais aqui do nosso blog pra isso:
      https://www.makerhero.com/blog/sensor-de-temperatura-ds18b20-arduino/
      https://www.makerhero.com/blog/temperatura-pressao-bmp180-arduino/

      Abraços!
      Diogo – EquipeF MakerHero

  3. Haroldo, gostei muito da matéria, mas estou realizando curso em linguagem C com micro PIC18F4550. O AD1115 seria compatível com o P18F4550. Estou com um pouco de dificuldade para usar a biblioteca I2C. Poderia ajudar?, no que se refere a maior chance de estar errado na comunicação.

  4. Olá Haroldo, estou tentando plotar uma onda senoidal de 30 Hz com o ADS1115, ( devidamente escalonada de 0 à 5 V) através do plotter serial. Mas não sei porque meu sinal distorce com menos de 5 Hz. Acho estranho porque estou usando a frequencia de amostragem máxima do meu conversor (obedecendo o critério de nyquist) e transmitindo a 9600bps. Por que ocorre essa distorção com uma freqencia menor que 5 Hz??

  5. Obrigado Haroldo pela postagem.
    Mas uma duvida se colocou. Onde obteve aquela segunda imagem ( do conversor interno). Não foi naturalmente no “serial monitor”, rs…

    Saudações
    A. Magalhães

    1. Grato António.

      O Serial monitor consegue plotar o gráfico, mas como queria controlar o resultado utilizei o Excel. Copiei e colei as leituras na planilha e plotei o gráfico.

  6. Bom dia! Sou novo no mundo da programação, esta é a primeira vez que faço o uso do ADS1115 e estou tendo dificuldades em fazer com que ele leia as 4 portas Analógicas. Poderia me dar alguma dica de como fazer isso. Desde já, obrigado.

    1. Olá Marcelo!

      Sugiro você dar uma olhada na comunicação I2C, que é usada por ele.

      Neste post, falam sobre comunicação I2C e como ver alguns erros possíveis:
      https://www.arduinoecia.com.br/2015/04/arduino-lcd-16×2-modulo-i2c-rtc-ds1307.html

      Abraços!

      André – Equipe MakerHero

  7. Boa tarde, estou fazendo um projeto em que uso dois sensores, comparo as temperaturas deles e com essa informação controlo um servo motor. Como seria o código com esses dois sensores?

    1. Olá Christiano!

      Você deve primeiro ler os valores dos sensores e controlar o servo separadamente.

      Você pode seguir alguns tutoriais aqui do nosso blog pra isso:
      https://www.makerhero.com/blog/sensor-de-temperatura-ds18b20-arduino/
      https://www.makerhero.com/blog/temperatura-pressao-bmp180-arduino/
      https://www.makerhero.com/blog/potenciometro-controlando-servo-motor/
      https://www.makerhero.com/blog/micro-servo-motor-9g-sg90-com-arduino-uno/

      Você já deu uma olhadinha no nosso fórum? Pode ser interessante tirar eventuais dúvidas por lá https://www.makerhero.com/forum/

      Abraços!

      André Rocha – Equipe MakerHero

  8. Haroldo, excelente matéria! Poderia eu esclarecer umas dúvidas? Segundo seu texto: “Configurando o PGA podemos trabalhar com sinais entre +/-256mV até +/-6.144V (range padrão).” e, em outra parte, “nunca o sinal na entrada deve exceder a tensão de “Vcc + 0,3V” ou “GND – 0,3V”.” Uma afirmação parece oposta a outra, não? Estou precisando medir uma tensão que pode variar de -4 a +4 V. É possível com o ADS1115? É no modo “Single Ended” ou no diferencial?

    Obrigado!

    1. Olá Renato, apesar de parecerem contraditórias elas fazem sentido. O sinal nas entradas nunca pode ser negativo em relação ao GND ou superar o valor de Vcc. Se você configurar o ADC no modo single-endded, será possível ler apenas valores positivos de tensão, mas se você configurar no modo diferencial, você consegue ler polaridades positivas e negativas em relação a entrada diferencial, mas mesmo assim o sinal da entrada não é negativo e relação ao GND.

      O que você pode fazer é condicionar seu sinal para que toda escala entre -4 e 4V seja representada de forma positiva, por exemplo entre 0 e 5V.

  9. Ola, Nao entendi direito para que serve o setGain, como sei qual usar? No meu caso estou usando o Esp8266 12e. Ele nao é 5V. Poderia me explicar melhor? Abraços!

    1. Anderson, o “setGain” modifica o ganho de um amplificador que existe na entrada do ADS1115. Ele permite que você converta sinais ainda menores sem perder resolução.

      Por exemplo, no ganho 16x o sinal de entrada máximo deverá ser de +/- 0.256V, onde cada bit equivale a 0.0078125mV.

      Por padrão você pode manter o ganho em 1x, mas não poderá ultrapassar os 3.3v da alimentação.

      Abraço

  10. Boa tarde. Gostaria de ligar um sensor de pressão mpxv5004dp no ads115. A saída do sensor é uma tensão que varia de 0 à 5v. Posso conectar essa tensão na entrada analógica do ads1115?

    No datasheet eu vi que trabalha com entrada entre -0,3v a +0,3v, ai fiquei com essa dúvida.

    Abraços

    1. Boa tarde José.

      Você pode conectar sem problemas, o “Absolute Maximum Ratings” para a entrada é de “GND – 0.3 a VDD + 0.3”. O principal ponto é que as entrada nunca devem ultrapassar em 0.3V os rails de alimentação.

      Abraço