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