quarta-feira, julho 17, 2013

Sensor de Temperatura DS18B20 ligado ao Arduino - parte 2

Existe uma biblioteca específica para o DS18S20, a "Dallas Temperature Control Library", descrita aqui. Neste post vamos fazer algumas experiências com ela.


Instalação

Esta biblioteca não inclui a comunicação 1-wire, para isto ela usa a OneWire que vimos no post anterior. A instalação é semelhante à da OneWire,  basta expandir o zip no subdiretório libraries do diretório onde são gravados os sketches.  Precisei renomear o subdiretório, pois a IDE não aceita espaços e caracteres alfanuméricos.

Primeiro Teste

Mantendo a montagem do post anterior, abri o exemplo Tester, alterei a porta para 10 e executei. A saída está abaixo:

Dallas Temperature IC Control Library Demo
Locating devices...Found 3 devices.
Parasite power is: ON
Found device 0 with address: 289C7BB504000041
Setting resolution to 9
Resolution actually set to: 9
Found device 1 with address: 281D25DC040000A8
Setting resolution to 9
Resolution actually set to: 9
Found device 2 with address: 28274CB6040000E3
Setting resolution to 9
Resolution actually set to: 9
Requesting temperatures...DONE
Temperature for device: 0
Temp C: 21.00 Temp F: 69.80
Temperature for device: 1
Temp C: 21.50 Temp F: 70.70
Temperature for device: 2
Temp C: 21.50 Temp F: 70.70


Como a saída mostra, através da biblioteca conseguimos descobrir quantos dispositivos estão conectados, se eles são alimentados pela linha de dados e quais os seus endereços. Podemos também controlar a resolução (número de bits do ADC) e disparar a leitura em vários dispositivos com uma única chamada.

O Uso da Biblioteca

Vamos examinar o código do exemplo (simplificado abaixo):

  1. #include <OneWire.h>  
  2. #include <DallasTemperature.h>  
  3.   
  4. #define ONE_WIRE_BUS 10  
  5. #define TEMPERATURE_PRECISION 9  
  6.   
  7. // Setup a oneWire instance to communicate with any OneWire devices  
  8. OneWire oneWire(ONE_WIRE_BUS);  
  9.   
  10. // Pass our oneWire reference to Dallas Temperature.   
  11. DallasTemperature sensors(&oneWire);  
  12.   
  13. int numberOfDevices; // Number of temperature devices found  
  14. DeviceAddress tempDeviceAddress;  
  15.   
  16. void setup(void)  
  17. {  
  18.   // start serial port  
  19.   Serial.begin(9600);  
  20.   Serial.println("Dallas Temperature IC Control Library Demo");  
  21.   
  22.   // Start up the library  
  23.   sensors.begin();  
  24.     
  25.   // Grab a count of devices on the wire  
  26.   numberOfDevices = sensors.getDeviceCount();  
  27.     
  28.   // locate devices on the bus  
  29.   Serial.print("Locating devices...");  
  30.     
  31.   Serial.print("Found ");  
  32.   Serial.print(numberOfDevices, DEC);  
  33.   Serial.println(" devices.");  
  34.   
  35.   // report parasite power requirements  
  36.   Serial.print("Parasite power is: ");   
  37.   if (sensors.isParasitePowerMode()) Serial.println("ON");  
  38.   else Serial.println("OFF");  
  39.     
  40.   // Loop through each device, print out address  
  41.   for(int i=0;i<numberOfDevices; i++)  
  42.   {  
  43.     // Search the wire for address  
  44.     if(sensors.getAddress(tempDeviceAddress, i))  
  45.  {  
  46.   Serial.print("Found device ");  
  47.   Serial.print(i, DEC);  
  48.   Serial.print(" with address: ");  
  49.   printAddress(tempDeviceAddress);  
  50.   Serial.println();  
  51.     
  52.   Serial.print("Setting resolution to ");  
  53.   Serial.println(TEMPERATURE_PRECISION, DEC);  
  54.     
  55.   // set the resolution to TEMPERATURE_PRECISION bit (Each Dallas/Maxim device is capable of several different resolutions)  
  56.   sensors.setResolution(tempDeviceAddress, TEMPERATURE_PRECISION);  
  57.     
  58.    Serial.print("Resolution actually set to: ");  
  59.   Serial.print(sensors.getResolution(tempDeviceAddress), DEC);   
  60.   Serial.println();  
  61.  }else{  
  62.   Serial.print("Found ghost device at ");  
  63.   Serial.print(i, DEC);  
  64.   Serial.print(" but could not detect address. Check power and cabling");  
  65.  }  
  66.   }  
  67.   
  68. }  
  69.   
  70. // function to print the temperature for a device  
  71. void printTemperature(DeviceAddress deviceAddress)  
  72. {  
  73.   float tempC = sensors.getTempC(deviceAddress);  
  74.   Serial.print("Temp C: ");  
  75.   Serial.print(tempC);  
  76.   Serial.print(" Temp F: ");  
  77.   Serial.println(DallasTemperature::toFahrenheit(tempC)); // Converts tempC to Fahrenheit  
  78. }  
  79.   
  80. void loop(void)  
  81. {   
  82.   // call sensors.requestTemperatures() to issue a global temperature   
  83.   // request to all devices on the bus  
  84.   Serial.print("Requesting temperatures...");  
  85.   sensors.requestTemperatures(); // Send the command to get temperatures  
  86.   Serial.println("DONE");  
  87.     
  88.     
  89.   // Loop through each device, print out temperature data  
  90.   for(int i=0;i<numberOfDevices; i++)  
  91.   {  
  92.     // Search the wire for address  
  93.     if(sensors.getAddress(tempDeviceAddress, i))  
  94.  {  
  95.   // Output the device ID  
  96.   Serial.print("Temperature for device: ");  
  97.   Serial.println(i,DEC);  
  98.     
  99.   // It responds almost immediately. Let's print out the data  
  100.   printTemperature(tempDeviceAddress); // Use a simple function to print out the data  
  101.  }   
  102.  //else ghost device! Check your power requirements and cabling  
  103.    
  104.   }  
  105. }  

Ok, não parece muito complicado. Os métodos possuem nomes e parâmetros simples, mesmo sem olhar a documentação dá para entender o código.

Abrindo o Capô

Uma olhada no código fonte da biblioteca trouxe algumas surpresas. A biblioteca não mantém nenhuma informação sobre a rede 1-wire (exceto o pino onde ela está ligado). Em quase todo acesso ela enumera os dispositivos conectados, o que parece desnecessário. Poderia ser útil caso dispositivos sejam conectados ou desconectados durante a execução, porém aí esbarramos em um outro problema. As funções usadas no exemplo se referem aos dispositivos pela sua ordem de enumeração, o que mudaria neste caso.

O disparo da leitura "simultaneamente" também pode apresentar problemas. Caso esteja sendo usada a alimentação pelo pino de dados, a biblioteca espera um tempo fixo (conforme a precisão programada). Se a alimentação é independente, é testado se a conversão terminou em apenas um dos sensores. Portanto, teremos problemas se os sensores estiverem configurados com precisões diferentes ou apresentarem tempos de resposta diferente.

Concluindo
Esta biblioteca é bem prática para projetos rápidos, desde que todos os sensores estejam configurados iguais e tenham desempenho semelhante e não haja alteração dinâmica na rede.

Se quisermos algo mais sofisticado ou seguro, vamos precisar escrever a nossa própria biblioteca. É o que pretendo tentar no futuro.

8 comentários:

janainajocs disse...

Bom dia, estou tentando utilizar o DS18B20 já montado testei diversos programas inclusive este que você apresentou e obtenho apenas temperaturas negativas -2032 ºC que totalmente incompatível já que a temperatura deveria estar na faixa de 20ºC. Já testei diversas montagem e programas e todos me dão uma temperatura negativa totalmente fora da faixa. Você tem alguma ideia do que pode ser?
Aguardo retorno.

Daniel Quadros disse...

O programa localizou o DS18B20 e mostrou o endereço? Você tentou o programa da parte 1 e ele identificou corretamente o modelo do chip? Se sim para as duas coisas, eu desconfiaria que o DS18B20 está pifado (você testou com mais de um?).

Unknown disse...

Como posso fazer para o sensor analisar durante 1 minuto se ouve alteração >=6 graus para mais nesse 1 minuto e fazer determinado comando que eu vou criar. É possível isso?

Daniel Quadros disse...

Rafael: Quem fará isto é o Arduino, não o sensor. Por exemplo, o seu programa pode ler a temperatura, dar um delay de 1 minuto, ler de novo e comparar as duas temperaturas. Isto pode ser suficiente se a sua temperatura está sempre subindo, mas se ela estiver oscilando pode ser melhor você usar uma média móvel e ficar monitorando continuamente.

Unknown disse...

Como eu faço para salvar o dado de 1 minuto para comparar depois?

Daniel Quadros disse...

Rafael: float tempC = sensors.getTempC(deviceAddress); salva na variável tempC a temperatura informada pelo dispositivo de endereço deviceAddress. Se você não conhece a linguagem C e a programação do Arduino, recomendo você dar uma estudada nelas primeiro.

LUCIO disse...

Fiz uma ligação em “modo normal” de vários sensores (mais especificamente 4 sensores) DS18B20. Coloquei-os medindo a mesma posição no quarto, porém mostraram valores diferentes entre si. A diferença não é muito grande (em torno de meio grau celsius). Gostaria de saber se isso tem algo a ver com o resistor utilizado (4,7 kohm) e se eu poderia melhorar a precisão da medida usando resistores diferentes para cada sensor.

Daniel Quadros disse...

Lúcio, o resistor está relacionado à comunicação e não afeta a precisão. Segundo o datasheet, a precisão no pior caso é justamente esta que você observou +/- 0,5 C. Além disso, se você estiver usando a resolução de 9 bits o bit menos significativo da leitura corresponde também a 0,5C. Você pode experimentar aumentar a resolução para 10, 11 ou 12 bits. Isto vai aumentar o tempo de leitura e não vai melhorar a precisão em si, mas o valor lido será mais fiel. Por exemplo, imagine que o valor lido está oscilando entre 20,9 e 21,1 (devido à precisão). Trabalhando com 9 bits a leitura só poderá oscilar entre 20,5 e 21, pois não tem como reportar um valor intermediário.