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