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%.
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.
/* 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.
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.
// 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.
// 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.
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.
{ ...
// 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.
{ ... // 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.
// 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.
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.
// 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.
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.
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.
// 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).
// 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.
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.
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.





