ÍNDICE DE CONTEÚDO
- Franzininho C0 – Primeiros passos com Arduino
- Franzininho C0: Blink LED com Delay e com Interrupção no Arduino
- Leitura de um botão e acionamento de um LED no Arduino com a Franzininho C0
- Controle de intensidade de um LED com PWM no Arduino usando a Franzininho C0
- Franzininho C0: Comunicação serial no Arduino
- Franzininho C0: Conexão de display OLED SSD1306 via I2C usando Arduino IDE
- Franzininho C0: Automação do Acendimento de LED com Sensor LDR usando Arduino IDE
- Franzininho C0: Controlando o Duty Cycle de um PWM com um Potenciômetro Usando Arduino
- Franzininho C0: Monitoramento da Qualidade do Ar com Sensor MQ135 usando Arduino
- Franzininho C0: Detecção de chuva usando Arduino
- Franzininho C0: Monitoramento de Temperatura e Umidade com Sensor DHT11
Introdução
Neste tutorial, vamos utilizar a Franzininho C0 em conjunto com o sensor DHT11, que mede a temperatura e a umidade do ambiente, e um LED para sinalização, criando um sistema de monitoramento de temperatura e umidade. Este projeto será desenvolvido utilizando a IDE do Arduino.
Sensor DHT11
O sensor DHT11 é um dispositivo projetado para medir com precisão a temperatura e a umidade do ambiente, por meio de uma saída digital. Embutido em seu encapsulamento, há um microcontrolador de 8 bits, que contribui para a alta performance do módulo.
A principal característica do DHT11 é o elemento resistivo NTC, que é responsável pela medição precisa da temperatura. Com isso, o sensor demonstra uma resposta rápida às variações ambientais, além de possuir uma ótima capacidade de resistir a interferências externas.
O dispositivo opera em uma faixa de medição de temperatura de 0 a 50ºC e em uma faixa de umidade de 20 a 80%.
Embarcados Experience 2024: Evento Presencial
Participe do Embarcados Experience 2024 em São Paulo. Conhecimento técnico, palestras, workshops e oportunidade de networking com profissionais experientes.
Materiais necessários
- Franzininho C0
- Protoboard
- Sensor DHT11
- Jumpers
Pinout da Franzininho C0
Para definir os pinos utilizados, precisamos consultar o pinout da placa:
Acesse a documentação completa em:
https://docs.franzininho.com.br/docs/franzininho-c0/franzininho-c0-board
Circuito
Conecte a Franzininho C0 à protoboard. Em seguida, conecte os pinos GND e 3,3 V na protoboard para fornecer energia aos demais dispositivos.
Vamos começar com o sensor, que possui 4 pinos: VCC, Data, NC e GND. A identificação de cada pino é mostrada na Figura 2.
Siga os passos abaixo para conectá-lo à placa:
- Conecte o terminal VCC do sensor ao trilho de 3,3 V da protoboard.
- Conecte o terminal data do sensor a um dos pinos digitais da Franzininho C0 (por exemplo, PA5).
- O terminal NC não será utilizado
- Conecte o terminal GND do sensor ao trilho de GND da protoboard.
Código
Para criar um sistema de monitoramento de temperatura e umidade usando a Franzininho C0, utilizaremos o código a seguir. Esse código é baseado no exemplo desenvolvido por Daniel Quadros em seu blog.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
/* Baseado no teste do sensor DHT11 * Por: Daniel Quadros - 31/07/18 * https://dqsoft.blogspot.com/2018/08/sensor-de-umidade-e-temperatura-dht11.html */ static const int DHTPIN = PA5; static const int timeout = 200; static const int LED = PB6; // Resposta do sensor typedef struct { byte umidInt; byte umidDec; byte tempInt; byte tempDec; byte checksum; } RESPOSTA; // Iniciação void setup() { pinMode (DHTPIN, INPUT); pinMode (LED, OUTPUT); // Conecta a UART aos pinos ligados à USB Serial.setRx(PA_10_R); Serial.setTx(PA_9_R); Serial.begin (115200); } // Laço Principal void loop() { RESPOSTA resp; delay (5000); // lê 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 ("%"); if (resp.tempInt>= 30 || resp.umidInt<= 60){ digitalWrite(LED, HIGH); } else{ digitalWrite(LED, LOW); } } 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 (DHTPIN, OUTPUT); digitalWrite (DHTPIN, LOW); delay (20); digitalWrite (DHTPIN, LOW); // Aguarda confirmar pinMode (DHTPIN, INPUT); to = micros() + timeout; while (digitalRead(DHTPIN) == HIGH) { if (micros() > to) { return false; } } while (digitalRead(DHTPIN) == LOW) { if (micros() > to) { return false; } } while (digitalRead(DHTPIN) == HIGH) { if (micros() > to) { return false; } } // Le os dados iByte = iBit = 0; while (iByte < 5) { // pulso inicial to = micros() + timeout; while (digitalRead(DHTPIN) == LOW) { if (micros() > to) { return false; } } // valor do bit to = micros() + timeout; while (digitalRead(DHTPIN) == 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]; } |
Obs.1: Antes da IDE iniciar o carregamento do programa, a Franzininho C0 deve executar o bootloader, caso contrário ocorrerá um erro.
Explicação do Código
Por conta das limitações de memória do microcontrolador STM32C0, da Franzininho C0, a leitura dos dados do sensor DHT11, que normalmente é feita com o auxílio de uma biblioteca, precisou ser implementada de forma mais enxuta. Por isso, utilizamos o código desenvolvido por Daniel Quadros.
Antes da função setup(), definimos as variáveis globais do programa. As variáveis DHTPIN e LED correspondem aos pinos da placa conectados ao sensor DHT11 e ao LED, respectivamente. A variável timeout define o período para a leitura dos dados.
1 2 3 |
static const int DHTPIN = PA5; static const int timeout = 200; static const int LED = PB6; |
Em seguida, temos a estrutura RESPOSTA, que contém os atributos para armazenar os valores de umidade (umidInt e umidDec) e temperatura (tempInt e tempDec) lidos pelo sensor, divididos em parte inteira e parte decimal. Há também o campo checksum, que será utilizado para verificar a integridade dos dados.
1 2 3 4 5 6 7 8 9 |
// Resposta do sensor typedef struct { byte umidInt; byte umidDec; byte tempInt; byte tempDec; byte checksum; } RESPOSTA; |
No setup(), inicializamos o pino do DHT11 (DHTPIN) como entrada e o pino do LED (LED) como saída. Também configuramos a comunicação serial definindo os pinos UART da Franzininho C0 e 115200 de baud rate, isso é feito para visualizar os dados no monitor serial do Arduino.
1 2 3 4 5 6 7 8 9 10 |
// Iniciação void setup() { pinMode (DHTPIN, INPUT); pinMode (LED, OUTPUT); // Conecta a UART aos pinos ligados à USB Serial.setRx(PA_10_R); Serial.setTx(PA_9_R); Serial.begin (115200); } |
Na função leDHT11() é feita a leitura e armazenamento dos dados do sensor. A função tem como argumento pResp, um ponteiro para uma estrutura RESPOSTA, onde os dados lidos serão armazenados. O retorno da função é booleano, então ela irá retornar true se a leitura for bem-sucedida, ou false se houver um erro.
No início da função o ponteiro pDados, do tipo byte, aponta para a mesma área de memória de pResp. As variáveis do tipo byte iByte e iBit são definidas para uso posterior. Como também a variável to.
1 2 3 4 5 |
bool leDHT11 (RESPOSTA *pResp) { byte *pDados = (byte *) pResp; byte iByte, iBit; unsigned long to; ...} |
O pino DHTPIN é alterado para funcionar como saída, isso é feito para que um sinal de início de comunicação ao sensor seja enviado. Assim, com digitalWrite(DHTPIN, LOW) definimos o DHTPIN como nível baixo, sinalizando ao sensor que o microcontrolador está pronto para receber dados. Um delay de 20 milissegundos é necessário para garantir que o sensor reconhecerá a solicitação de leitura.
1 2 3 4 5 6 7 |
{ ... // Solicita leitura pinMode (DHTPIN, OUTPUT); digitalWrite (DHTPIN, LOW); delay(20); digitalWrite (DHTPIN, LOW); ... } |
Depois, o DHTPIN volta a ser configurado como entrada para começar a receber a resposta do sensor. A variável to é definida como o tempo atual em microssegundos (micros()) somado ao valor do timeout, definido no início do código como 200.
O to é usado como limite de tempo para evitar que o código fique preso dentro do loop caso o sensor não responda.
O código então verifica três estados sequenciais:
- Espera pela mudança de nível alto para baixo: O primeiro while(digitalRead(DHTPIN) == HIGH) aguarda que o pino mude de estado alto (HIGH) para baixo (LOW). O sensor DHT11 deve responder com um pulso de nível baixo logo após a solicitação de leitura. Se o pino não mudar antes de atingir o tempo de timeout, a função retorna false, indicando uma falha na leitura.
- Espera pela mudança de nível baixo para alto: O segundo while(digitalRead(DHTPIN) == LOW) aguarda que o pino mude de estado baixo (LOW) para alto (HIGH). Isso indica que o sensor DHT11 está pronto para enviar os dados. Novamente, se o pino não mudar antes do timeout, a função retorna false.
- Espera pela mudança de nível alto para baixo: É o último bit de sincronização inicial. Se o pino não mudar antes do timeout, a função retorna false.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
{ ... // Aguarda confirmar pinMode (DHTPIN, INPUT); to = micros() + timeout; while (digitalRead(DHTPIN) == HIGH) { if (micros() > to) { return false; } } while (digitalRead(DHTPIN) == LOW) { if (micros() > to) { return false; } } while (digitalRead(DHTPIN) == HIGH) { if (micros() > to) { return false; } } ... } |
Finalmente, é feita a leitura dos dados. Primeiramente, iByte e iBit são iniciados com zero. O iByte é responsável por controlar qual byte da resposta está sendo lido, enquanto iBit controla qual bit do byte está sendo manipulado.
1 2 |
// Le os dados iByte = iBit = 0; |
O laço while (iByte < 5) é feito para executar até que todos os 5 bytes (ou 40 bits) de dados do sensor tenham sido lidos. Novamente to é utilizado como limite de tempo.
Dentro desse loop temos while (digitalRead(DHTPIN) == LOW) que aguarda até que DHTPIN mude de nível lógico baixo para alto, sinalizando o início de cada bit.
1 2 3 4 5 6 7 8 |
while (iByte < 5) { // pulso inicial to = micros() + timeout; while (digitalRead(DHTPIN) == LOW) { if (micros() > to) { return false; } } |
Em seguida, o laço while (digitalRead(DHTPIN) == HIGH) é usado para aguardar a transição do DHTPIN de nível lógico alto para baixo. Antes desse laço, o valor de to é atualizado com o objetivo de medir o tempo em que o pino permanece em HIGH, o que ajudará a determinar se o bit lido é 0 ou 1.
1 2 3 4 5 6 7 |
// valor do bit to = micros() + timeout; while (digitalRead(DHTPIN) == HIGH) { if (micros() > to) { return false; } } |
Na linha seguinte deslocamos todos os bits do byte atual (pDados[iByte]) uma posição à esquerda. Logo, se por exemplo, o byte atual fosse 00000001, após o deslocamento se tornaria 00000010.
1 |
pDados[iByte] = pDados[iByte] << 1; |
Feito isso, com a estrutura condicional fica definido que:
- Se o tempo que o pino permaneceu em HIGH foi maior que 40 microssegundos, o bit é 1.
- Caso contrário, o bit é 0.
É preciso prestar atenção que aqui é feita uma operação OR bit a bit, com pDados[iByte] |= 1. Logo, se o tempo foi maior que 40 microssegundos, o código adiciona 1 na posição menos significativa do byte que está sendo construído.
1 2 3 |
if (((micros() + timeout) - to) > 40) { pDados[iByte] |= 1; } |
Após ler cada bit, iBit é incrementado. Quando iBit chegar a 8 (indicando que todos os 8 bits do byte foram lidos), iByte é incrementado para passar ao próximo byte, e iBit é zerado.
1 2 3 4 5 6 |
// passa para o próximo bit if (++iBit > 7) { iBit = 0; iByte++; } } |
Por último é feito uma verificação da integridade dos dados recebidos do sensor DHT11. Lembrando que pDados é do tipo de RESPOSTA, logo é formado pelos 5 bytes de dados:
- pDados[0]: Parte inteira da umidade.
- pDados[1]: Parte decimal da umidade.
- pDados[2]: Parte inteira da temperatura.
- pDados[3]: Parte decimal da temperatura.
- pDados[4]: Checksum (soma de verificação).
1 2 3 |
// Confere o checksum return (pDados[0]+pDados[1]+pDados[2]+pDados[3]) == pDados[4]; } |
Por fim, na função loop(), declaramos uma variável resp do tipo RESPOSTA, que será utilizada para armazenar os dados do sensor. Esses dados serão lidos a cada 5 segundos.
1 2 3 4 |
void loop() { RESPOSTA resp; delay (5000); // lê a cada 5 segundos ...} |
Em uma estrutura condicional, leDHT11(&resp) é chamada para ler os dados do sensor e armazená-los na variável resp. Se a leitura for bem-sucedida, a função retorna true, e o código dentro do if é executado. Se a leitura falhar, a função retorna false, e o bloco else é executado.
No bloco if, exibimos no monitor serial do Arduino os valores de temperatura e umidade, seguidos das unidades Celsius e porcentagem (%), respectivamente. Se o valor de temperatura ou umidade exceder o intervalo estabelecido, o LED do Franzininho C0 é acionado para alertar o usuário sobre um comportamento que necessita de atenção.
No bloco else, uma mensagem “Falha na leitura” é exibida no monitor serial para indicar o erro.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
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 ("%"); if (resp.tempInt>= 30 || resp.umidInt<= 60){ digitalWrite(LED, HIGH); } else{ digitalWrite(LED, LOW); } } else { Serial.println ("Falha na leitura"); } |
Ao executar o código, o monitor serial exibe a temperatura e a umidade detectadas pelo DHT11. Para alterar esses valores, você pode assoprar o sensor com ar quente, o que fará com que a temperatura aumente. No entanto, tome cuidado para não danificar o sensor.
Conclusão
Neste projeto, implementamos um sistema de monitoramento de temperatura e umidade utilizando a Franzininho C0, o LED integrado da placa, e um sensor DHT11. O sensor DHT11 é responsável por detectar as condições ambientais, enquanto o LED sinaliza quando determinados limites de temperatura e umidade são atingidos, proporcionando uma solução eficiente para monitoramento em tempo real.
Desafio
Neste desafio, você irá atualizar o projeto de monitoramento de temperatura e umidade, adicionando recursos visuais e sonoros para o operador. Esse aprimoramento incluirá a integração de um buzzer e um LED RGB, que mudará de cor conforme as condições ambientais.
O funcionamento será o seguinte:
- LED verde: indica que a temperatura e a umidade estão dentro dos parâmetros normais
- LED laranja: sinaliza que os valores estão em um intervalo que requer atenção
- LED vermelho: alerta para um valor crítico, acionando o buzzer como alerta sonoro.