#include <util/delay.h>
#include <avr/io.h>
enum DHT_Type {
DHT22,
DHT11
};
// Escolher o tipo de sensor no circuito
#define _type DHT22
// ========================================================================
// PINOS LCD
// ========================================================================
// LCD - Pinos de controle
#define CONTR_LCD PORTA
#define RS PA1
//#define RW PA3
#define E PA5
// LCD - Pinos de dados (8 bits)
#define DADOS_LCD PORTC
#define nibble_dados 1
// Definição do Sensor DHT
#define DHT_PIN PH5
#define LED PG2
#define pulse_enable() _delay_us(1); set_bit(CONTR_LCD, E); _delay_us(1); clr_bit(CONTR_LCD, E); _delay_us(45);
// ========================================================================
// Macros para o trabalho com bits
// ========================================================================
#define set_bit(y,bit) (y|=(1<<bit)) // Coloca em 1 o bit x da variável Y
#define clr_bit(y,bit) (y&=~(1<<bit)) // Coloca em 0 o bit x da variável Y
#define cpl_bit(y,bit) (y^=(1<<bit)) // Troca o estado lógico do bit x da variável Y
#define tst_bit(y,bit) (y&(1<<bit)) // Retorna 0 ou 1 conforme leitura do bit
char* itoa(int value, char* str, int base);
uint8_t dht_read(uint8_t dht, enum DHT_Type type);
void led_control(int temperature);
// REVER AONDE ESTÁ ESSA FUNÇÃO
uint8_t dht_mount_byte()
{
uint8_t b = 0x0;
for (uint8_t i = 0; i < 8; i++)
{
while(~(PINH >> DHT_PIN) & 0x1);
switch(_type)
{
case DHT22: // DHT22 espera 50us
_delay_us(50);
case DHT11: // DHT11 espera 30us
_delay_us(30);
}
if ((PINH >> DHT_PIN) & 0x1) b = (b<<1)|(0x01);
else b = (b<<1);
while((PINH >> DHT_PIN) & 0x1);
}
return b;
}
// ========================================================================
// LCD - Enviar caracteres/instruções
// ========================================================================
void lcd_cmd(unsigned char c, char cd)
{
// cd : indica se instrução (0) ou caractere (1)
if(cd == 0)
clr_bit(CONTR_LCD,RS);
else
set_bit(CONTR_LCD,RS);
// Primeiro nibble de dados - 4 MSB
#if (nibble_dados)
// Compila o código para os pinos de dados do LCD nos 4 MSB do PORT
DADOS_LCD = (DADOS_LCD & 0x0F) | (0xF0 & c);
#else
// Compila o código para os pinos de dados do LCD nos 4 LSB do PORT
DADOS_LCD = (DADOS_LCD & 0xF0) | (c >> 4);
#endif
pulse_enable();
// Segundo nibble de dados - 4 LSB
#if (nibble_dados)
// Compila o código para os pinos de dados do LCD nos 4 MSB do PORT
DADOS_LCD = (DADOS_LCD & 0x0F) | (0xF0 & (c << 4));
#else
// Compila o código para os pinos de dados do LCD nos 4 LSB do PORT
DADOS_LCD = (DADOS_LCD & 0xF0) | (0x0F & c);
#endif
pulse_enable();
// Se for instrução de retorno ou limpeza espera LCD estar pronto
if((cd == 0) && (c < 4)) _delay_ms(2);
}
// ========================================================================
// LCD - Inicializacao do LCD com via de dados de 4 Bits
// ========================================================================
void lcd_init_4bits()
{
// Como o LCD será só escrito, R/W é sempre zero.
clr_bit(CONTR_LCD,RS); // RS em zero indicando que o dado para o LCD será uma instrução
clr_bit(CONTR_LCD,E); // Pino de habilitação em zero
// Tempo para estabilizar a tensão do LCD, após VCC ultrapassar 4.5 V (na prática pode ser maior)
_delay_ms(20);
// Interface de 8 bits
#if (nibble_dados)
DADOS_LCD = (DADOS_LCD & 0x0F) | 0x30;
#else
DADOS_LCD = (DADOS_LCD & 0xF0) | 0x03;
#endif
pulse_enable(); // Habilitação respeitando os tempos de resposta do LCD
_delay_ms(5);
pulse_enable();
_delay_us(200);
pulse_enable();
// Interface de 4 bits
// Deve ser enviado duas vezes (a outra está abaixo)
#if (nibble_dados)
DADOS_LCD = (DADOS_LCD & 0x0F) | 0x20;
#else
DADOS_LCD = (DADOS_LCD & 0xF0) | 0x02;
#endif
pulse_enable();
// Interface de 4 bits 2 linhas
// Aqui se habilita as 2 linhas
lcd_cmd(0x28,0);
// São enviados os 2 nibbles (0x2 e 0x8)
lcd_cmd(0x08,0); // Desliga o display
lcd_cmd(0x01,0); // Limpa todo o display
lcd_cmd(0x0C,0); // Mensagem aparente cursor inativo não piscando
lcd_cmd(0x80,0); // Inicializa cursor na primeira posição a esquerda
}
// ========================================================================
// LCD - Escrita no LCD
// ========================================================================
void lcd_write(char *c)
{
for (; *c!=0;c++) lcd_cmd(*c,1);
}
// Protótipo da função itoa()
char* itoa(int value, char* str, int base)
{
// Verifica se a base é suportada (apenas base 10 é implementada aqui)
if (base != 10) {
*str = '\0';
return str;
}
// Inicializa o índice para a string resultante
int i = 0;
// Armazena o sinal do número (positivo ou negativo)
int is_negative = 0;
// Caso o número seja zero, adiciona '0' à string e encerra
if (value == 0) {
str[i++] = '0';
str[i] = '\0';
return str;
}
// Se o número for negativo, armazena o sinal e transforma em positivo
if (value < 0) {
is_negative = 1;
value = -value;
}
// Loop para converter o número em string reversa
while (value != 0) {
int rem = value % 10; // Calcula o dígito menos significativo
str[i++] = rem + '0'; // Converte o dígito em caractere e armazena
value /= 10; // Remove o dígito menos significativo
}
// Adiciona o sinal '-' se o número for negativo
if (is_negative) {
str[i++] = '-';
}
// Adiciona o terminador de string
str[i] = '\0';
// Inverte a string resultante
int start = 0;
int end = i - 1;
while (start < end) {
char temp = str[start];
str[start] = str[end];
str[end] = temp;
start++;
end--;
}
return str;
}
int main()
{
// Configurar portas de saida do LCD
DDRA = 0xFF; // Configura todas as portas A como saída para o LCD
DDRC = 0xFF; // Configura todas as portas C como saída para o LCD
DDRG |= (1 << LED); // Configura o pino PG2 como saída para o LED
// Inicializar LCD
lcd_init_4bits();
// Buffer para armazenar a temperatura como texto
// char temperature_text[16];
// Mostrar a mensagem "Olá Mundo"
// lcd_cmd(0x80, 0);
// lcd_write("Olá mundo");
//int temp; // Declarando a variável temp antes de usá-la
while (1)
{
int result = dht_read(DHT_PIN, _type);
if (result != 0)
{
lcd_cmd(0x01, 0); // Limpa o display
_delay_ms(2);
lcd_cmd(0x80, 0); // Posiciona o cursor na primeira linha
lcd_write("Erro: ");
char buffer[2];
itoa(result, buffer, 10);
lcd_write(buffer);
}
_delay_ms(500); // Aguarda 2 segundos antes de fazer a próxima leitura
}
}
// Função para ler o valor digital do sensor DHT22
uint8_t dht_read(uint8_t dht, enum DHT_Type type)
{
uint8_t dht_data[5] = {0, 0, 0, 0, 0};
// Configurando o pino como saída
DDRH |= (1 << dht);
// Enviando sinal de inicialização
PORTH &= ~(1 << dht);
_delay_ms(18);
// switch(_type)
// {
// case DHT22:
// _delay_us(1000);
// break;
// case DHT11:
// _delay_us(18);
// break;
// }
PORTH |= (1 << dht);
_delay_us(1);
// switch(_type)
// {
// case DHT22:
// _delay_us(40);
// break;
// case DHT11:
// _delay_us(20);
// break;
// }
DDRH &= ~(1 << dht); // Configurando o pino como entrada
// Esperando resposta do sensor
uint8_t timeout_counter = 0;
while (PINH & (1 << dht))
{
if (++timeout_counter > 100)
{
return 1; // Erro de timeout
}
_delay_us(1);
}
timeout_counter = 0;
while (!(PINH & (1 << dht)))
{
if (++timeout_counter > 100)
{
return 2; // Erro de timeout
}
_delay_us(1);
}
timeout_counter = 0;
while (PINH & (1 << dht))
{
if (++timeout_counter > 100)
{
return 3; // Erro de timeout
}
_delay_us(1);
}
// Lendo os dados do sensor
for (uint8_t i = 0; i < 5; ++i)
{
uint8_t byte = 0;
for (uint8_t j = 0; j < 8; ++j)
{
timeout_counter = 0;
while (!(PINH & (1 << dht)))
{
if (++timeout_counter > 100)
{
return 4; // Erro de timeout
}
_delay_us(1);
}
_delay_us(30); // Espera para determinar se o bit é 0 ou 1
if (PINH & (1 << dht))
{
byte |= (1 << (7 - j)); // Bit é 1
timeout_counter = 0;
while (PINH & (1 << dht))
{
if (++timeout_counter > 100)
{
return 5; // Erro de timeout
}
_delay_us(1);
}
}
}
dht_data[i] = byte;
}
// Verificando a soma de verificação
if ((uint8_t)(dht_data[0] + dht_data[1] + dht_data[2] + dht_data[3]) != dht_data[4])
{
return 6; // Erro de checksum
}
uint16_t temperature;
uint8_t temperature_decimal;
// Calculando temperatura e umidade
switch (type)
{
case DHT22:
// Unir parte inteira e decimal
temperature = ((uint16_t)dht_data[2] & 0x7f) << 8 | dht_data[3];
// humidity = ((uint16_t)dht_data[0] << 8) | dht_data[1];
// Atribuir aos decimais
temperature_decimal = temperature / 10;
// humidity_decimal = humidity / 10;
// Corrigir sinal da temperatura
if ((uint16_t)dht_data[2] & 0x80) temperature_decimal *= -1;
break;
case DHT11:
// Unir parte inteira e decimal
temperature = ((uint16_t)dht_data[2]);
// humidity = (uint16_t)dht_data[0] + dht_data[1] * 0.1;
// Atribuir aos decimais
temperature_decimal = ((float)temperature);
// humidity_decimal = ((float)humidity);
// Corrigir sinal da temperatura
if (dht_data[3] & 0x80)
{
temperature = -1-temperature;
}
temperature += (dht_data[3] & 0x0f) * 0.1;
break;
}
// Exibindo os valores lidos
lcd_cmd(0x01, 0); // Limpa o display
_delay_ms(2);
lcd_cmd(0x80, 0); // Posiciona o cursor na primeira linha
lcd_write("Temp: ");
lcd_cmd(0x86, 0); // Posiciona o cursor após "Temp: "
char buffer[8];
itoa(temperature / 10, buffer, 10);
lcd_write(buffer);
lcd_write(".");
itoa(temperature % 10, buffer, 10);
lcd_write(buffer);
lcd_write(" C");
// lcd_cmd(0xC0, 0); // Posiciona o cursor na segunda linha
// lcd_write("Umid: ");
// lcd_cmd(0xC6, 0); // Posiciona o cursor após "Umidade: "
// itoa(humidity / 10, buffer, 10);
// lcd_write(buffer);
// lcd_write(".");
// itoa(humidity % 10, buffer, 10);
// lcd_write(buffer);
// lcd_write(" %");
led_control(temperature_decimal);
return 0; // Sucesso
}
// Função para controlar o LED com base na temperatura
void led_control(int temperature)
{
if (temperature < 34 || temperature > 45) {
// Temperatura fora do intervalo, liga o LED
PORTG |= (1 << LED);
} else {
// Temperatura dentro do intervalo, desliga o LED
PORTG &= ~(1 << LED);
}
}