/*
* Calculadora - Com Biblioteca no Código.c
*
* Created: 13/11/2023 22:40:53
* Author : thiago rodrigues
*/
#define F_CPU 16000000 // Define a frequência do clock para 16 MHz
#include <avr/io.h> // Inclui o header para o hardware de I/O
#include <util/delay.h> // Inclui o header para as funções de delay
#include <stdlib.h> // Header para as funções atof e dtostrf
#define RS PB1 // Define o pino PB1 como RS (Register Select) do LCD
#define E PB0 // Define o pino PB0 como E (Enable) do LCD
// Definições dos pinos do sensor ultrassônico
#define PINO_TRIGGER PD2
#define PINO_ECHO PD3
//-----------------------------------------------------------------//
// Funções do LCD (pulso_E, envia_dados, Lcd_cmd, Lcd_out, Lcd_init)
//-----------------------------------------------------------------//
// Função para gerar um pulso no pino E, sinalizando ao LCD para ler os dados
void pulso_E() {
PORTB &= ~(1<<E); // Coloca o pino E em nível baixo
PORTB |= (1<<E); // Coloca o pino E em nível alto
PORTB &= ~(1<<E); // Coloca o pino E em nível baixo novamente
return;
}
// Função para enviar comandos ou dados para o LCD
void envia_dados(unsigned char comando) {
PORTD = ((comando & 0xF0) | (PORTD & 0x0F)); // Envia os 4 bits mais significativos
pulso_E(); // Gera um pulso no E para processar os dados
PORTD = (((comando << 4) & 0xF0) | (PORTD & 0x0F)); // Envia os 4 bits menos significativos
pulso_E(); // Gera um pulso no E para processar os dados
return;
}
// Função para enviar comandos para o LCD
void Lcd_cmd(unsigned char comando) {
_delay_ms(1); // Pequeno delay para garantir a execução do comando
PORTB &= ~(1<<RS); // Coloca o RS em nível baixo para indicar um comando
envia_dados(comando); // Envia o comando para o LCD
return;
}
// Função para posicionar o cursor e enviar texto para o LCD
void Lcd_out(char linha_lcd, char coluna_lcd, char *ponteiro) {
// Verifica se a linha e coluna estão dentro dos limites do LCD
if((linha_lcd > 0) && (linha_lcd < 3) && (coluna_lcd > 0) && (coluna_lcd < 41)) {
Lcd_cmd(128 + (coluna_lcd - 1) + ((linha_lcd - 1) * 64)); // Calcula a posição do cursor
while (*ponteiro) {
_delay_ms(1); // Delay para processamento de cada caractere
PORTB |= (1<<RS); // Coloca RS em nível alto para indicar dados (caractere)
envia_dados(*ponteiro++); // Envia o caractere para o LCD e incrementa o ponteiro
}
}
return;
}
// Função para inicializar o LCD
void Lcd_init() {
// Configura os pinos do LCD como saída e inicializa o LCD em modo 4 bits
DDRB |= ((1<<E) + (1<<RS));
DDRD |= ((1<<PD4)+(1<<PD5)+(1<<PD6)+(1<<PD7));
PORTB &= ~(1<<RS);
_delay_ms(15);
PORTD = ((0x30 & 0xF0) | (PORTD & 0x0F));
pulso_E();
_delay_ms(5);
pulso_E();
_delay_ms(1);
pulso_E();
_delay_ms(1);
PORTD = ((0x20 & 0xF0) | (PORTD & 0x0F));
pulso_E();
Lcd_cmd(0x28);
Lcd_cmd(0x08);
Lcd_cmd(0x01);
Lcd_cmd(0x06);
Lcd_cmd(0x0C);
}
//-----------------------------------------------------------------//
// Valor do parâmetro B do NTC
int B = 3950;
// Funções para USART (mantenha as mesmas)
void Inicia_USART(long unsigned int baud_rate)
{
int ubrr;
ubrr = ((F_CPU) / (8 * baud_rate)) - 1;
UBRR0H = (unsigned char)(ubrr >> 8);
UBRR0L = (unsigned char)ubrr;
UCSR0A |= (1 << U2X0);
UCSR0B |= ((1 << RXEN0) | (1 << TXEN0));
UCSR0C &= ~((1 << UMSEL01) | (1 << UMSEL00));
UCSR0C &= ~((1 << UPM01) | (1 << UPM00));
UCSR0C &= ~(1 << USBS0);
UCSR0C &= ~(1 << UCSZ02);
UCSR0C |= ((1 << UCSZ01) | (1 << UCSZ00));
UCSR0B |= (1 << RXCIE0); // Habilita a interrupção da recepção da USART
}
void enviar_dado(unsigned char data)
{
while (!(UCSR0A & (1 << UDRE0))); // Aguarda o buffer esvaziar
UDR0 = data; // Envia o dado
}
void enviar_string(const char *s) {
while (*s) {
enviar_dado(*s++);
}
}
// Configuração e leitura do ADC
void initADC() {
// Utiliza a tensão de referência interna (Vref)
ADMUX |= (1 << REFS1) | (1 << REFS0); // Altere esta linha
ADCSRA |= (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Liga o ADC e configura prescaler
}
// Função para ler um canal do ADC e retornar o valor
int readADC(int channel) {
ADMUX = (ADMUX & 0xF0) | (channel & 0x0F); // Seleciona o canal do ADC mantendo a configuração de tensão de referência
ADCSRA |= (1 << ADSC); // Inicia a conversão
while (ADCSRA & (1 << ADSC)); // Espera a conversão completar
return ADC;
}
// Funções para o sensor ultrassônico
void IniciaUltrassonico() {
// Configura os pinos do Trigger e Echo como saída e entrada, respectivamente
DDRD |= (1 << PINO_TRIGGER); // Trigger como saída
DDRD &= ~(1 << PINO_ECHO); // Echo como entrada
}
void PulsoTrigger() {
PORTD &= ~(1 << PINO_TRIGGER); // Garante que o Trigger está em nível baixo
_delay_us(2); // Espera 2us
PORTD |= (1 << PINO_TRIGGER); // Seta o Trigger para alto
_delay_us(10); // Espera 10us
PORTD &= ~(1 << PINO_TRIGGER); // Retorna o Trigger para baixo
}
unsigned long MedirEcho() {
// Inicia a medição quando o Echo fica em nível alto
unsigned long duracao = 0;
// Aguarda enquanto o Echo está em nível baixo
while (!(PIND & (1 << PINO_ECHO)));
// Conta o tempo enquanto o Echo está em nível alto
while (PIND & (1 << PINO_ECHO)) {
duracao++;
_delay_us(1);
}
return duracao;
}
//Cálculo do Nível
float distanciaMaxima = 210.0; // Distancia do sensor ao fundo do reservatório
float distanciaReferencia = 10.0; // Distancia do sensor ao nível máximo
float calcularNivel(float distanciaMedida) {
if (distanciaMedida > distanciaMaxima) {
return 0; // Evita valores negativos se a distância medida for maior que a máxima
}
if (distanciaMedida < distanciaReferencia) {
return 100; // Evita valores acima de 100%
}
return 100 * (distanciaMaxima - distanciaMedida) / (distanciaMaxima - distanciaReferencia);
}
//Cálculo da Temperatura
float calcularTemperatura() {
int adcVal = readADC(4); // Leitura do ADC no pino A4
float V_lida = adcVal * (5.0 / 1024.0); // Conversão do valor do ADC para tensão
float R_NTC = 10000.0 * ((5.0 / V_lida) - 1.0); // Cálculo da resistência do NTC
float T = 1.0 / ((1.0 / 298.15) + (1.0 / 3950.0) * log(R_NTC / 10000.0)) - 273.15; // Cálculo da temperatura
return T;
}
int main(void) {
Inicia_USART(9600);
initADC();
IniciaUltrassonico();
sei(); // Habilita interrupções globais
Lcd_init();
char buffer[50];
char temp[50];
char _nivel[50]; // Declare _nivel apenas uma vez
while (1) {
int AD4 = readADC(4); // Lendo do canal AD4
int V4_mV = (int)((float)AD4 * 5000.0 / 1024.0); // Tensão em milivolts para AD4
// Envia a tensão da porta A4
snprintf(buffer, sizeof(buffer), "Tensao A4: %d.%02d V\n", V4_mV / 1000, V4_mV % 1000);
enviar_string(buffer);
float T = calcularTemperatura();
int T_dec = (int)(T * 100); // Temperatura multiplicada por 100
// Envia a temperatura
snprintf(temp, sizeof(temp), "Temp: %d.%02doC\n", T_dec / 100, T_dec % 100);
enviar_string(temp);
// Cálculo da distância
PulsoTrigger();
unsigned long duracao = MedirEcho();
int distancia = (duracao * 0.0343) / 2; // Conversão da duração para distância
snprintf(buffer, sizeof(buffer), "Dist: %d cm\n", distancia);
enviar_string(buffer);
Lcd_out(1, 1, buffer);
// Cálculo do nível
float nivel = calcularNivel((float)distancia); // Chame calcularNivel aqui
int nivelInteiro = (int)nivel;
int nivelDecimal = (int)((nivel - nivelInteiro) * 100);
snprintf(_nivel, sizeof(_nivel), "Nivel: %d.%02d %%\n\n", nivelInteiro, nivelDecimal);
enviar_string(_nivel);
Lcd_out(2, 1, _nivel);
_delay_ms(500);
}
return 0;
}