DS18B20 – Como alterar a resolução do sensor

DS18B20 e ajuste de resolução

Como já devem ter notado, eu gosto muito do sensor DS18B20 quando o assunto é medição de temperatura. E os motivos para isto são simples:

  • Uso do protocolo One-Wire, o que facilita muito o projeto tanto na parte de hardware(ligações) quanto na parte de software(sketches simples);
  • Qualidade construtiva, permitindo o uso do DS18B20 em várias situações, inclusive mergulhado em líquidos;
  • É bonito 😀 😀 ;
  • É preciso nas leituras de temperatura.

Hoje vamos falar justamente da precisão do DS18B20. Este sensor permite o ajuste de resolução em 9, 10, 11 ou 12 bits. Por padrão ele vem com uma resolução de 12 bits.

Resolução?

É a resolução que permite uma leitura em determinada precisão, quanto maior a resolução, maior a precisão de leitura. E então somos levados a pensar que o melhor é sempre utilizar a maior resolução. Mas não é bem assim que funciona. O tempo gasto na leitura da temperatura é proporcional ao número de bits utilizados, e inversamente proporcional à precisão obtida. Confuso? Vamos ver em uma tabela que certamente vai ajudar:

Dados do datasheet do DS18B20

ResoluçãoPrecisãoTempo de Conversão (Leitura)
9 bits0,5 Graus93,75 ms
10 bits0,25 Graus187,5 ms
11 bits0,125 Graus375 ms
12 bits0,0625 Graus750 ms

Observem que a precisão dobra conforme aumentamos a resolução em 1 bit, assim como o tempo de leitura também dobra. Em um projeto mais ou menos sério o ideal é balancearmos a necessidade de precisão com o tempo gasta no leitura. Usando minha ideia como exemplo, utilizar 12 bits de resolução parece adequado, pois não temos problema com a alta precisão (0.065C) e o tempo de leitura(750ms) também não chega a ser um problema, mesmo sendo 5 sensores(o tempo de leitura é por sensor). Mas notem que estou utilizando um Arduino exclusivamente para isso.

Se eu quiser aproveitar melhor o Arduino, o que farei provavelmente, pode ser que este tempo de leitura se torne inadequado para outras necessidades, lembrem-se que durante a execução de delay(1000) o Arduino não faz mais nada além de esperar. Então eu precisaria considerar melhor a precisão que eu REALMENTE necessito, e ajustar a resolução de modo a melhor atender minhas necessidades.

Os objetivos justificam as resoluções 😀

Vejam, meu objetivo é medir a temperatura da água para fins de comprovação da eficiência de um aquecedor solar. Aumentos de temperatura abaixo de 1 grau Celsius não tem muito interesse, concordam? Então podemos concluir que para minha necessidade uma resolução de 9 bits atende perfeitamente, e eu ainda fico com um tempo de leitura de 93,75ms, bem menor que 750ms.

Claro que tudo depende do que você quer fazer. Se sua necessidade é alta precisão, vai de resolução de 12 bits, se sua necessidade é uma leitura o mais rápido possível, utilize resolução de 9 bits. Não esqueça de considerar o número de sensores utilizados, pois 10 sensores * 750ms resultam em 7,5 segundos no total, utilizando resolução de 12 bits.

Resolução tecnicamente falando.

Galera, recorram ao datasheet sempre que possível, pode consultar o datasheet do DS18B20 clicando aqui ou aqui. A pequena análise abaixo foi feita com base neste documento.

Internamente o sensor DS18B20 possui um tipo de memória chamada scratchpad e uma mini EEPROM. O scratchpad possui 8 bytes, sendo que os bytes 0 e 1 armazenam a temperatura lida. Os bytes 2 e 3 são utilizado para definirmos um alarme quando determinada temperatura for atingida, máxima e mínima respectivamente. Já o byte 4 é registro de configuração(ou configuration register). É aqui que vamos definir a resolução que queremos de nosso sensor. Os bytes 5, 6 e 7 são reservados, sem uso no momento. Ainda podemos considerar um nono byte (ou byte 8), que armazena o CRC.

Já a mini-EEPROM esta diretamente relacionada aos bytes 2,3 e 4, armazenando o mesmo tipo de informação. Os leitores deste blog certamente já sabem que a EEPROM é uma memória não volátil, ou seja, os valores nela armazenados não são apagados quando “desligamos” nosso sensor, e também já sabem que a EEPROM normalmente é uma memória lenta. O motivo da EEPROM espelhando os dados é muito simples: no scratchpad o sensor lê rapidamente os valores, como os limites do alarme e a resolução a utilizar, porém estas informações só valem enquanto o sensor esta energizado. Sendo assim, o sensor lê a EEPROM na inicialização e copia os dados para o scratchpad.

DS18B20 Scratchpad e EEPROM

Relacionamento entre o scratchpad e a EEPROM do DS18B20

Podemos setar os valores do scratchpad apenas, e ao “desligarmos” o DS18B20 e “ligarmos” novamente teremos os valores default. Para que a mudança seja definitiva temos que gravar a informação na EEPROM. Um detalhe interessante é que não podemos escrever apenas no byte 2, ou apenas no 3, ou apenas no 4, temos que escrever os 3 bytes para que o sensor armazene estes valores.

Configuration Register

Como falamos, o registro de configuração consiste em apenas um byte, e o “layout” do byte é o seguinte:

DS18B20 Configuration Register

Layout do Configuration Register do DS18B20

Vejam que os únicos bits que nos interessam são os bits 5 e 6. Os outros bits não importam, pois o sensor sempre os lê com os valores indicados na imagem acima. Vamos ver como manipular os bits 5 e 6 para ajustar a resolução, e consequentemente a precisão e tempo de conversão.

Valores de R0 e R1

R1R0Resolução (bits)Tempo(ms)PrecisãoHEX
00993,750,50x1F
0110187,50,250x3F
10113750,1250x5F
11127500,06250x7F

Mamão com açucar essa tabela hein? Principalmente pelo valor em hexadecimal no último campo.

Mais teoria?

Afff, chega por enquanto. Poderíamos falar ainda sobre o uso do alarme. Ou ainda uma explicação mais detalhada sobre os comandos aceitos pelo DS18B20, mas para um pouco de teoria.

Para aprendermos como ajustar a resolução vamos utilizar um Arduino, um resistor de 4,7k ohms e apenas um sensor. O esquema de ligação é o seguinte:

DS18B20 com Arduino

Esquema de ligação entre DS18B20 e Arduino

Código de exemplo

Vamos utilizar o sketch de exemplo que vem com a interface IDE do Arduino. Basta ir em Arquivos –> Exemplos –> OneWire –> DS18x20_Temperature

Procurem pelo seguinte código. Aqui pra mim ele estava na linha 67:

delay(1000);     // maybe 750ms is enough, maybe not

A resolução “default” do DS18B20 é 12 bits. Pelo datasheet vemos que o tempo de conversão é de 750ms. Eu não falei antes, mas 750ms é o tempo máximo de conversão. Na prática o tempo é menor, e 750ms é um número de segurança, considerando as piores condições. Notem que o sketch de exemplo ainda põe uma margem considerável de tempo(+250ms) para que a conversão ocorra. Faça upload do sketch, acesse o “Monitor serial” e você deverá obter um output similar ao abaixo:

DS18B20 Output

Exemplo de saida do sensor DS18B20

Esta saída nos diz várias informações, mas nada a respeito do que tratamos neste post. Vamos incrementar essa saida?

Visualizando o tempo real de leitura.

Insiram no código, logo acima de delay(1000), o seguinte código:

    float inicio = millis();
    ds.write(0x44);        // start conversion, use ds.write(0x44,1) with parasite power on at the end
    while (ds.read() == 0){
      
    }
    float fim = millis();
    Serial.print("O tempo gasto com a leitura foi de: ");
    Serial.print(fim - inicio);
    Serial.println(" milesegundos");

Imediatamente acima deste código que inseriram, apaguem o ds.write(0x44); . Reparem que no trecho de código acima ele já existe, e é aqui que deve estar para nosso teste. Refaçam o upload e observem a nova saida obtida:

DS18B20 Output com tempo

Saida do DS18B20 indicando tempo gasto na conversão

Vejam que interessante, embora a resolução atual fixe o tempo máximo de conversão em 750ms, e o sketch ainda acrescenta 250ms por segurança, na verdade gastamos na faixa de 600ms com uma resolução de 12 bits. Podemos eliminar o delay(1000) de nosso código que não haveria problemas. Vamos mantê-lo apenas para facilitar a visualização na console serial. A linha contendo while (ds.read() == 0){} faz com que o sketch pause somente até que a conversão termine. Se quiserem entender porque, o datasheet responde, mas eu também posso responder 😀 , baste deixar sua dúvida nos comentários.

Finalmente: Alterando a resolução

Aleluia, finalmente vou mostrar como alterar a resolução.

Insiram ao final do sketch a seguinte função:

void setResolution(byte resolucao) {
  byte addr[8];
  ds.search(addr); // address on 1wire bus
  ds.reset();             // rest 1-Wire
  ds.select(addr);        // select DS18B20

  ds.write(0x4E);         // write on scratchPad
  ds.write(0x00);         // User byte 0 - Unused
  ds.write(0x00);         // User byte 1 - Unused
  switch (resolucao) {
    case 12:
      ds.write(0x7F);         // set up en 12 bits (0x7F)
      break;
    case 11:
      ds.write(0x5F);         // set up en 11 bits (0x5F)
      break;
    case 10:
      ds.write(0x3F);         // set up en 10 bits (0x3F)
      break;
    case 9:
      ds.write(0x1F);         // set up en 9 bits (0x1F)
      break;
  }

  ds.reset();             // reset 1-Wire
}

E para completar, insira a seguinte linha dentro do setup(){}:

setResolution(9); // apenas 9, 10, 11 ou 12

Eu espero que tenham entendido o que fizemos, mas em todo caso vai uma explicação 😀

A função setResolution(byte resolucao){} recebe o valor que desejamos para nossa resolução. No código da função identificamos o sensor e enviamos a instrução 0x4E com um ds.write. Esta instrução diz ao DS18B20 que vamos escrever no scratchpad. Falamos sobre ele acima, e se prestaram atenção vão se lembrar que eu disse que o scratchpad aceita escrita nos 3 bytes configuráveis, mas de uma só vez. Portanto, após ds.writte com a instrução 0x4E, escrevemos  duas vezes com 0x00, e finalmente vamos escrever um valor para setar a resolução. Como passamos a resolução como parâmetro da função, vamos utilizar uma declaração switch e enviar o valor hexadecimal correspondente.

Em setup fazemos a chamada da função passando como parâmetro o valor 9. Vamos ver como fica? Não esqueçam de fazer upload novamente 😉

DS18B20 9 bits Resolution

Saida do DS18B20 com resolução de 9 bits

Reparem que a temperatura aumentou em saltos de 0,5 graus celsius(segurei o sensor) e o tempo de leitura foi de aproximadamente 76ms, abaixo do máximo declarado de 93,75.

Vamos fazer os testes com as outras resoluções:

DS18B20 10 bits Resolution

Saida do DS18B20 com resolução de 10 bits

 

DS18B20 11 bits Resolution

Saida do DS18B20 com resolução de 11 bits

Interessante não é?

Pessoal, o objetivo do post foi cumprido. Pelas funções disponíveis no datasheet faltou alguma coisa, como o uso de alarmes e a escrita para a EEPROM, ou mesmo algumas gambiarras (eu prefiro workaround 🙂 ) para acelerar ainda mais a leitura, mas se prestaram atenção no post eu sei que conseguem chegar a essas artimanhas. Um abraço a todos e até a próxima.

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

vinte − 12 =