Introdução
Este artigo aborda o monitoramento de temperatura e umidade utilizando o sensor DHT11 e a placa Franzininho C0, com a exibição dos valores obtidos em um display OLED. Vamos realizar a configuração inicial da Franzininho C0 com a ferramenta CubeMX e depois adaptar o código conforme necessário.
Componentes necessários
- 1 Franzininho C0
- 1 Módulo DHT11
- 1 Display OLED ssd1306
Esquemático para montagem circuito
| Componentes | Pinos |
| Display | SDA: C14SCL: B6GNDVCC |
| DHT11 | Sinal (s): A4GNDVCC |
Funcionamento DHT11
Processo de Comunicação:
Quando o MCU envia um sinal de início, o DHT11 muda do modo de baixo consumo de energia para o modo de operação, aguardando que o MCU complete o sinal de início. Uma vez concluído, o DHT11 envia um sinal de resposta com 40 bits de dados que incluem as informações de umidade relativa e temperatura para o MCU.
Sinal de Início para o DHT:
Normalmente, o barramento de dados está em um nível de tensão alta. Quando o MCU começa a se comunicar com o DHT11, ele baixa essa tensão de alta para baixa e mantém assim por pelo menos 18ms. Isso garante que o DHT11 detecte o sinal do MCU. Depois disso, o MCU aumenta novamente a tensão e espera entre 20 a 40μs para receber a resposta do DHT11.

Resposta do DHT ao MCU:
Assim que o DHT detecta o sinal de início, ele envia um sinal de resposta de baixo nível de tensão, que dura 80μs. Em seguida, o DHT muda a tensão do barramento de dados de baixo para alto e mantém assim por 80μs para se preparar para enviar os dados.
Durante a transmissão de dados do DHT para o MCU, cada bit de dados começa com um nível de baixa tensão de 50μs, e a duração do sinal de alta tensão seguinte determina se o bit de dados é “0” ou “1”.

Formato dos dados:
8 bits de dados integrais de umidade relativa (RH) + 8 bits de dados decimais de umidade relativa (RH) + 8 bits de dados integrais de temperatura (T) + 8 bits de dados decimais de temperatura (T) + 8 bits de soma de verificação (check-sum).
Para mais informações acesse o datasheet: https://www.mouser.com/datasheet/2/758/DHT11-Technical-Data-Sheet-Translated-Version-1143054.pdf
Configuração CubeMX
- Abra STM32Cube , crie um novo projeto e selecione o microcontrolador de destino “STM32C011F6P6”.
- Vá para a página de configurações de relógio e em HCLK digite 48 MHz para a frequência de saída desejada do sistema. Pressione a tecla “Enter” e deixe o aplicativo resolver os divisores/multiplicadores PLL necessários para atingir a taxa de clock desejada. Depois volte para a página de configuração dos pinos, selecione “Trace and Debug” e habilite “Serial Wire.
- Configure a interface I2C. Selecione o pino C14 como SDA e o pino PB6 como SCL. Clique em “Connectivity” > I2C1 e habilite o I2C. As demais configurações, para esse exemplo, podemos deixar padrão.
- Selecione o pino PA4 como saída, ajuste o output level como “high”, o mode como “output push pull” e o speed como “very high”. Também renomeie o nome do pino como dht.
- Em seguida, vamos configurar o TIM3 com um tempo de 1us. Para isso, selecione o Clock Source como “Internal Clock” e o Preescaler como 48-1, de forma que a frequência passe a ser 1Mhz.
- Por fim, gere o código em “Project” > “Generate Code”.
Implementação do código
- Para começar, faça o download dos arquivos da biblioteca para o display OLED. Está disponível em: Repositório da biblioteca OLED para Franzininho C0.
- Após baixar os arquivos os inclua em seu projeto:

- Abra o arquivo main.c
- Inclua as seguintes bibliotecas:
#include "stdio.h"
#include "string.h"
#include "ssd1306.h"
#include "ssd1306_fonts.h"- Crie as variáveis para guardar os valores de temperatura e umidade:
uint16_t temperatura, umidade;- Crie a função para leitura do DHT11:
void dht11(uint16_t *temperatura, uint16_t *umidade)
{
//Variáveis para execução de cálculos da função.
uint16_t tempcalc, umidcalc;
//Configurações para seleção da direção do Pino 'dht11' como saída digital:
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = dht_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(dht_GPIO_Port, &GPIO_InitStruct);
//Sinal em nivel lógico 0 - Conforme Datasheet.
HAL_GPIO_WritePin(dht_GPIO_Port, dht_Pin, GPIO_PIN_RESET);
//Tempo mínimo de 18ms - Conforme Datasheet.
HAL_Delay(20); //Configura para 20ms
//Sinal em nivel lógico 1 - Conforme Datasheet.
HAL_GPIO_WritePin(dht_GPIO_Port, dht_Pin, GPIO_PIN_SET);
//Configurações para seleção da direção do Pino 'dht11' como entrada digital:
GPIO_InitStruct.Pin = dht_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(dht_GPIO_Port, &GPIO_InitStruct);
//Lógica Principal:
//Seta contador Timer 3 para 0.
__HAL_TIM_SET_COUNTER(&htim3, 0);
//Variáveis Auxiliares.
uint16_t ler[2];
uint16_t dados[42];
uint8_t bits[40];
uint16_t temph = 0;
uint16_t umidh = 0;
//Lógica Para Captura do Tempo Alto dos Dados.
for(int i = 0; i < 42; i++)
{
while(HAL_GPIO_ReadPin(dht_GPIO_Port, dht_Pin) == GPIO_PIN_RESET);
ler[0] = __HAL_TIM_GET_COUNTER(&htim3);
while(HAL_GPIO_ReadPin(dht_GPIO_Port, dht_Pin) == GPIO_PIN_SET);
ler[1] = __HAL_TIM_GET_COUNTER(&htim3);
dados[i] = ler[1] - ler[0];
}
//Definindo bits conforme tempos do datasheet.
for(int i = 0; i < 40; i++)
{
if((dados[i+2] >=20) && (dados[i+2] <=32))
{
bits[i] = 0;
}
else if((dados[i+2] >=65) && (dados[i+2] <=75))
{
bits[i] = 1;
}
}
//Cálculo da temperatura e umidade determinado pelos bits.
for(int i = 0; i < 8; i++)
{
temph += bits[i+16] << (7 - i);
umidh += bits[i] << (7 - i);
}
//Atribuição dos valores calculados nas variáveis
tempcalc = temph;
umidcalc = umidh;
*temperatura = tempcalc;
*umidade = umidcalc;
}
Essa função realiza a leitura de temperatura e umidade a partir de um sensor DHT11 seguindo o que foi indicado no funcionamento do sensor descrito no artigo:
- Configuração inicial: Define o pino do sensor DHT11 como saída, envia um sinal de baixo por 20ms e então muda o pino para entrada.
- Leitura dos dados: Utiliza um timer (TIM3) para medir tempos entre transições de nível lógico no pino do sensor, capturando os tempos altos dos dados enviados pelo DHT11.
- Decodificação dos dados: Com base nos tempos medidos, determina se cada bit dos dados recebidos é um 0 ou um 1, seguindo os intervalos especificados pelo datasheet do DHT11.
- Cálculo de temperatura e umidade: A partir dos bits recebidos, calcula os valores de temperatura e umidade.
- Retorno dos valores: Armazena os valores calculados nas variáveis temperatura e umidade, que são passadas por referência para a função.
- Crie a função para exibição no display:
void Display_Data(uint16_t *temperatura, uint16_t *umidade) {
char temp_str[16];
char hum_str[16];
// Formatando as strings de temperatura e umidade manualmente
sprintf(temp_str, "Temp: %dC", (int)*temperatura);
sprintf(hum_str, "Umid: %d%%", (int)*umidade);
// Limpar o display
ssd1306_Fill(Black);
// Definir o cursor e escrever a string de temperatura
ssd1306_SetCursor(4, 4);
ssd1306_WriteString(temp_str, Font_11x18, White);
// Definir o cursor e escrever a string de umidade
ssd1306_SetCursor(4, 24);
ssd1306_WriteString(hum_str, Font_11x18, White);
// Atualizar o display
ssd1306_UpdateScreen();
}
- Modifique a função principal int main:
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
MX_TIM3_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start(&htim3); //Inicializa Timer 3 -> '1us'
ssd1306_Init();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
dht11(&temperatura, &umidade);
Display_Data(&temperatura, &umidade);
HAL_Delay(5000); // Aguarda 5 segundos antes de fazer uma nova leitura
}
/* USER CODE END 3 */
}
No int main, estamos realizando o seguinte:
- Inicialização Geral com HAL_Init() e SystemClock_Config().
- Inicialização dos Periféricos com MX_GPIO_Init(), MX_I2C1_Init(), MX_TIM3_Init().
- Inicializações Específicas com HAL_TIM_Base_Start(&htim3) e ssd1306_Init().
- No Loop Infinito é chamado a função dht11() para ler a temperatura e umidade do sensor e depois é chamado Display_Data() para exibição dos dados de temperatura e umidade no display OLED. É aguardado 5 segundos antes de realizar uma nova leitura.
Gravação
Ao finalizar o código, partiremos para gravação. Nessa etapa você pode utilizar o ST-Link seguindo as conexões da imagem abaixo e clicando em “run” no STM32CubeIde.
Ou você pode optar por utilizar um cabo USB e gravar conforme explicado no seguinte tutorial: gravar-franzininho-c0-via-stm32cubeprogrammer
Funcionamento
Conclusão
Neste artigo, demonstramos como monitorar temperatura e umidade usando o sensor DHT11 e a placa Franzininho C0, exibindo os valores obtidos em um display OLED. O processo envolveu a configuração do hardware utilizando o STM32CubeMX e a implementação do código necessário para leitura e exibição dos dados.
Através deste projeto, aprendemos a implementar a comunicação com o sensor DHT11, entendendo seu protocolo de transmissão de dados e como decodificar os sinais recebidos e a utilizar um display OLED para exibir as leituras de temperatura e umidade, formatando e atualizando as informações de maneira eficiente.






