As Limitações de Comunicação do Raspberry Pi
Existem várias formas de ligar sensores e outros dispositivos, cada uma com suas vantagens e desvantagens.
Sensores que só retornam uma informação do tipo sim/não (como um sensor de abertura) podem ser ligados facilmente a uma entrada digital. Não é o caso de sensores que precisam retornar um valor.
No caso de sensor de temperatura, uma opção simples e precisa é o LM35, que tem uma saída analógica. Infelizmente, o Raspberry Pi não tem um ADC.
As soluções seguintes são comunicações seriais padrão, como a serial assíncrona, SPI e I2C. O Raspberry possui suporte de hardware a estas comunicações (no caso da serial assíncrona, o Raspberry Zero W tem fortes limitações). Eu venho adquirindo um gosto pela comunicação I2C, por permitir facilmente a ligação de múltiplos dispositivos. Existem alguns sensores de temperatura com este tipo de comunicação (como o TMP1075 e o LM74) mas não tenho um aqui (vai para a lista de compras).
Existem ainda comunicações seriais que precisam ser implementadas por software, por não serem suportadas pelo hardware. Já vimos aqui o sensor de temperatura DS18B20 e o relógio DS1302. Dependendo de como é o protocolo, a comunicação pode ser complexa e exigir tempos pequenos e precisos (o que é complicado em um sistema operacional como o Linux). Como veremos, é aí que se encaixa o DHT11.
DHT11
O datasheet (que você pode baixar daqui) é bastante completo. Do ponto de vista de características de desempenho, ele opera com tensões de 3 a 5V e mede umidade e temperatura. A medida de temperatura pode ter um erro de até +/- 2°C, o que é bastante alto para algumas aplicações.
A comunicação é serial e bidirecional em um único pino. Para solicitar uma leitura, o mestre deve configurar o pino como saída e colocar o sinal em nível baixo por pelo menos 18ms. Em seguida, deve "virar" o pino para entrada (um pull-up vai colocar o sinal em nível alto). O DHT11 vai sinalizar a recepção do pedido, mantendo o sinal em nível zero por 80us. Em seguida o DHT11 vai enviar os 40 bits de resposta. Cada bit é composto de duas partes: primeiro um nível baixo por 50us e depois um nível alto por 26 a 28uS (se bit 0) ou 70uS (se bit 1). Estas temporizações não são muito ruins se você estiver usando um sistema dedicado e rápido, mas podem ser fatais se o seu sistema for lento ou se a rotina de leitura puder ser interrompida por coisas demoradas.
Os 40 bits devem ser interpretados como 5 bytes: 2 com a leitura de umidade, 2 com a leitura de temperatura e 1 de checksum. O primeiro byte das leituras é parte decimal e o segundo a parte inteira. O checksum é a somas dos quatro bytes anteriores. No DHT11 a parte decimal é sempre zero (existe um modelo com mais precisão, o DHT22 que usa o mesmo protocolo).
Um último cuidado é aguardar pelo menos 1 segundo antes da próxima leitura.
Do ponto de vista físico, o DHT11 possui quatro terminais:
Nos meus testes eu usei um "módulo", que contém o resistor de pullup e possui somente três terminais (atenção que outros módulos de três pinos podem ter os sinais em posição diferente):
DHT11 com Arduino
A conexão é trivial: Vcc em +5, GND no GND e Data na entrada digital 2 (poderia ser outro, basta acertar no código).
Seguindo a minha tradição, vamos implementar a leitura na raça para entender o protocolo:
/* * Teste do sensor DHT11 * * Daniel Quadros - 31/07/18 * https://dqsoft.blogspot.com */ static const int pinData = 2; static const int timeout = 200; // Resposta do sensor typedef struct { byte umidInt; byte umidDec; byte tempInt; byte tempDec; byte checksum; } RESPOSTA; // Iniciação void setup() { pinMode (pinData, INPUT); Serial.begin (9600); } // Laço Principal void loop() { RESPOSTA resp; delay (5000); // ler a cada 5 segundos if (leDHT11(&resp)) { Serial.print ("Temperatura "); Serial.print (resp.tempInt); Serial.print (","); Serial.print (resp.tempDec); Serial.print ("C umidade "); Serial.print (resp.umidInt); Serial.print (","); Serial.print (resp.umidDec); Serial.println ("%"); } else { Serial.println ("Falha na leitura"); } } // Efetua a leitura bool leDHT11 (RESPOSTA *pResp) { byte *pDados = (byte *) pResp; byte iByte, iBit; unsigned long to; // Solicita leitura pinMode (pinData, OUTPUT); digitalWrite (pinData, LOW); delay (20); digitalWrite (pinData, LOW); // Aguarda confirmar pinMode (pinData, INPUT); to = micros() + timeout; while (digitalRead(pinData) == HIGH) { if (micros() > to) { return false; } } while (digitalRead(pinData) == LOW) { if (micros() > to) { return false; } } while (digitalRead(pinData) == HIGH) { if (micros() > to) { return false; } } // Le os dados iByte = iBit = 0; while (iByte < 5) { // pulso inicial to = micros() + timeout; while (digitalRead(pinData) == LOW) { if (micros() > to) { return false; } } // valor do bit to = micros() + timeout; while (digitalRead(pinData) == HIGH) { if (micros() > to) { return false; } } pDados[iByte] = pDados[iByte] << 1; if (((micros() + timeout) - to) > 40) { pDados[iByte] |= 1; } // passa para o próximo bit if (++iBit > 7) { iBit = 0; iByte++; } } // Confere o checksum return (pDados[0]+pDados[1]+pDados[2]+pDados[3]) == pDados[4]; }
O resultado é algo como:
DHT11 com Raspberry
A conexão consiste em ligar o Vcc ao 3.3V, GND em GND e Data no pino 22 (GPIO25, também pode ser mudado no código).
Aqui eu vou usar a biblioteca para Python da Adafruit. Mas antes, vamos dar uma olhada sob o capô. A biblioteca está escrita em C e acessa o pino digital através de mapeamento de memória. Na hora de fazer a leitura a prioridade do processo é aumentada para minimizar a interferência dos demais processos. Possivelmente vai ter problemas se tiver muito mais coisa rodando no Pi ou se tiver alguma atividade alta de interrupções.
A instalação da biblioteca da Adafruit é descrita aqui; no Raspbian Scretch Lite eu precisei de alguns passos adicionais, pois o git não está instalado:
sudo apt-get update sudo apt-get install build-essential python-dev sudo apt-get install git git clone https://github.com/adafruit/Adafruit_Python_DHT.git
cd Adafruit_Python_DHT sudo python setup.py install
Fiz alguns testes com o exemplo no link acima e funcionou bem, mesmo quando tentei rodar outras coisas em paralelo.
Atualização 16/08/18: a versão atual no github resolve um problema do setuptools que eu tinha mencionado anteriormente.
Conclusão
O sensor DHT11 não é exatamente o que eu queria em termos de precisão e interface, mas funcionou de forma satisfatória. Futuramente pretendo testar outros sensores, como o DHT22 e o LM75.
Um comentário:
Rara publicação onde não se usa bibliotecas para demonstrar o uso de componentes, diferente da maioria dos blogs sobre o assunto.
Obrigado!
Postar um comentário