Avançar para o conteúdo

O mundo é analógico, com ESP32

O mundo é analógico, então vamos aprender a ler estes sinais e transforma-los em algo útil. Usaremos um ESP32, porém qualquer microcontrolador que tenha porta i2c vai servir. O componente de interesse deste artigo é o ADS1115, um conversor analógico para digital de 16 bit.

Este componente é capaz de converter quatro canais analógicos entre 0 e (até) 6,144V em informação digital. Esta informação é então enviada para qualquer microcontrolador que se comunique via porta i2c. Tudo que você precisa é um Arduino (qualquer modelo, inclusive ESP32) e uma biblioteca da Adafruit.

A folha de dados (datasheet) do ADS1115 está neste link, este componente tem seis diferentes “fundos” de escala. Isto significa que por um lado a resolução dele pode ser bem grande, porém por outro o fundo de escala vai ser menor. Tudo na vida e na engenharia é uma troca.

Já mostrei vários projetos aqui no blog com entradas analógicas, como este aqui, porém sempre utilizando as entradas analógicas nativas dos microcontroladores. Até porque a maioria dos compatíveis com Arduino tem pelo menos 4-5 entradas analógicas. É bem difícil usar todas, mas se esta hora chegou, este artigo é para você.

O mundo é analógico

Eu fui no Google procurar tutoriais sobre o ADS1115, achei dois: este aqui e este aqui. É o que eu sempre faço (inclusive fica a dica). Quando pego um componente novo, sempre vou no Google para ver o que outras pessoas já fizeram com ele. Como usaram e o que implementaram.

O tutorial da ElectroNoobs usa a biblioteca ADS1X15 da Adafruit, então segui mais ele. Sempre que você ver um tutorial de Arduino usando biblioteca da Adafruit, pode confiar e usar. Claro que apenas usei o tutorial como base, obviamente dei meus toques e fiz minha própria lógica de controle e fluxo de processos.

Inclusive coloquei um LED no pino D0 do Xiao ESP32-C3 para piscar. Isto é para provar que meu código não é bloqueante, eu não uso delay() em lugar nenhum. Ou seja, eu consigo colocar várias coisas para “acontecer” ao mesmo tempo no código.

Hardware/Montagem

Como é de costume aqui no blog, minhas montagens são bem simples e diretas. Hoje teremos um pouco mais de componentes, visto que vamos ler duas entradas analógicas. Ainda teremos um LED (com um resistor de 10k em série) para ficar piscando.

Usaremos um Xiao ESP32-C3 da SeeedStudio, porém como já comentado você pode usar qualquer Arduino, literalmente. Basta que ele tenha uma porta de comunicação i2c, e praticamente todos os Arduinos tem. Vamos precisar de uma plaquinha de ADS1115, destas que você compra no Aliexpress.

Usaremos também um potenciômetro (qualquer valor entre 1k Ohm e 500k Ohm serve) e um LDR + resistor de 10k Ohm. Veja o diagrama esquemático completo abaixo, como sempre feito no Microsoft Paint para a maior clareza possível.

Diagrama esquemático do conversor ADS1115 com ESP32
Diagrama esquemático do conversor ADS1115 com ESP32

Abaixo deixo também fotos da montagem em protoboard. Eu usei uma de 400 pontos, bem pequena, pois a minha placa ESP32 permite isto.

ESP32-C3 na protoboard com ADS1115 e potenciômetro
ESP32-C3 na protoboard com ADS1115 e potenciômetro
ads1115 na protoboard com esp32
ADS1115 na protoboard com esp32

Firmware/Código

Conforme já comentado, usei dois sites como referência para fazer meu próprio código. Utilizei a IDE do Arduino versão “2.3.8 nightly” e a biblioteca “Adafruit ADS1X15”. Sobre a IDE do Arduino, qualquer versão acima da 1.8.X já serve, inclusive o WEB editor (online IDE).

O código completo está abaixo e também neste link do Github. Aproveite e use conforme precisar e gostar.

#include <Wire.h>
#include <Adafruit_ADS1X15.h>

#define LED D0 // This is pin 0 (first one) of my Xiao ESP32-C3
Adafruit_ADS1115 ads;
const float multiplier = 0.125F; // write here the value in mV of the ads.setGain you uncomment below
int16_t adc0, adc1, adc2, adc3;
long readTime= 0;
long LEDtime= 0;

void setup(void) 
{
  Wire.begin(6,7); // This is only necessary to some Arduinos and ESP32's, like
  // for example my Xiao ESP32-C3, which does not map the i2c in pins 4 and 5,
  // but on pins 6 and 7
  pinMode(LED, OUTPUT);
  Serial.begin(115200);
 
  // This is important. It defines the max voltage you are going to read in all analog channels
  // For example I uncommented GAIN_ONE, meaning I can only read signals up to +/- 4.096V

  // ads.setGain(GAIN_TWOTHIRDS);  //+/- 6.144V  1 bit = 0.1875mV (default)
  ads.setGain(GAIN_ONE);        //+/- 4.096V  1 bit = 0.125mV
  // ads.setGain(GAIN_TWO);        //+/- 2.048V  1 bit = 0.0625mV
  // ads.setGain(GAIN_FOUR);       //+/- 1.024V  1 bit = 0.03125mV
  // ads.setGain(GAIN_EIGHT);      //+/- 0.512V  1 bit = 0.015625mV
  // ads.setGain(GAIN_SIXTEEN);    //+/- 0.256V  1 bit = 0.0078125mV 
  ads.begin();
}
 
void loop(void) 
{
  if(millis() - readTime > 1000){ // do analog readings every 1000ms (1 second)
    readTime+= 1000;
    
    adc0 = ads.readADC_SingleEnded(0);
    adc1 = ads.readADC_SingleEnded(1);
    //adc2 = ads.readADC_SingleEnded(2); // Uncomment to read this channel
    //adc3 = ads.readADC_SingleEnded(3); // Uncomment to read this channel
    
    // You use the "multiplier" variable below to convert from integer to milivolts,
    // so instead of showing for example 65535 integers it shows 4096mV
    Serial.print("AIN0: "); Serial.println(adc0 * multiplier);
    Serial.print("AIN1: "); Serial.println(adc1 * multiplier);
    //Serial.print("AIN2: "); Serial.println(adc2 * multiplier); // Uncomment to use this input
    //Serial.print("AIN3: "); Serial.println(adc3 * multiplier); // Uncomment to use this input
    Serial.println(" ");
  }  
  if(millis() - LEDtime > 200){ // Just blinking an LED at 0,4 seconds full cycle
    LEDtime+= 200;
    digitalWrite(LED, !digitalRead(LED));
  }  
}

Alguns detalhes importantes valem ser mencionados: por exemplo a pinagem de cada Arduino. No meu caso em específico estou usando o Xiao ESP32-C3 da Seeed Studio, então o pino do LED, por exemplo, se chama “D0”. Já o i2c tem que ser declarado conforme abaixo:

 Wire.begin(6,7); // This is only necessary to some Arduinos and ESP32's, like
  // for example my Xiao ESP32-C3, which does not map the i2c in pins 4 and 5,
  // but on pins 6 and 7

Isto visto que a maioria dos Arduinos coloca o i2c nos pinos 4 e 5. Na minha placa eles ficam no D4 e D5, que correspondem aos pinos 6 e 7 do microcontrolador. Outro detalhe importante é o ganho do conversor analógico-digital ADS1115.

Como estou trabalhando com 3,3V, eu devo configurar o AD para funcionar entre 0V e 4,096V. Isso significa que eu poderia ler valores até 4,096V, porém só vou ler até 3,3V. A escala abaixo é de 2,048V, então não posso usa-la visto que vou até 3,3V. Descomente na parte do código abaixo apenas o ganho que vai usar:

// ads.setGain(GAIN_TWOTHIRDS);  //+/- 6.144V  1 bit = 0.1875mV (default)
  ads.setGain(GAIN_ONE);        //+/- 4.096V  1 bit = 0.125mV
  // ads.setGain(GAIN_TWO);        //+/- 2.048V  1 bit = 0.0625mV
  // ads.setGain(GAIN_FOUR);       //+/- 1.024V  1 bit = 0.03125mV
  // ads.setGain(GAIN_EIGHT);      //+/- 0.512V  1 bit = 0.015625mV
  // ads.setGain(GAIN_SIXTEEN);    //+/- 0.256V  1 bit = 0.0078125mV 

O meu código é não-bloqueante, eu uso o artifício abaixo para executar código de tempos em rempos. Isto garante que o microcontrolador pode fazer outras coisas enquanto não chega a hora de executar tal parte do código.

if(millis() - readTime > 1000){ // do analog readings every 1000ms (1 second)
    readTime+= 1000;

}

Considerações e testes

Copiando e colando o código completo acima na sua IDE do Arduino, conecte a placa ESP32 ao computador via USB. Então clique em “upload” no canto superior esquerdo da tela e aguarde uns instantes. Abra o monitor serial, indo em “Tools > Serial monitor”, você verá algo parecido com a imagem abaixo.

Monitor serial com ESP32 e ADS1115
Monitor serial com ESP32 e ADS1115

Veja que aparecem apenas os canais AIN0 e AIN1; para ver os outros dois, descomente as partes dos códigos abaixo:

//adc2 = ads.readADC_SingleEnded(2); // Uncomment to read this channel
    //adc3 = ads.readADC_SingleEnded(3); // Uncomment to read this channel

e também:

//Serial.print("AIN2: "); Serial.println(adc2 * multiplier); // Uncomment to use this input
    //Serial.print("AIN3: "); Serial.println(adc3 * multiplier); // Uncomment to use this input

Eu fiz dois vídeos ilustrando o funcionamento do experimento, um está logo no começo do artigo e o outro está abaixo. Aproveite! e em caso de dúvidas comente logo abaixo ou lá no Youtube.

Deixe um comentário

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