#define __AVR_ATmega2560__
#define F_CPU 16000000UL
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "usart.h"
void configura_pinos()
{
// PB2, PB2 e PB0 como entrada com resistor pull-up
DDRB &= ~(1 << DDB2);
PORTB |= (1 << PORTB2);
DDRB &= ~(1 << DDB1);
PORTB |= (1 << PORTB1);
DDRB &= ~(1 << DDB0);
PORTB |= (1 << PORTB0);
// PB7 como saida
DDRB |= (1 << DDB7);
PORTB &= ~(1 << PORTB7);
// Entrada tri-state para o ADC PF1
DDRF &= ~(1 << DDF1);
PORTF &= ~(1 << PORTF1);
}
void inicializa_ADC()
{
/* Configuramos o ADC usando os registradores
ADCSRA e ADCSRB. O bit ADEN aciona o módulo conversor.
Segundo o datasheet, para operação com 10 bits
de precisão o módulo conversor necessita de um
clock entre 50KHz e 200KHz. Sendo o clock principal
de 16MHz, usando os bits ADPSx, selecionamos um divisor
de 128, conseguindo assim um clock final de 125KHz no ADC */
ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
ADCSRB = 0;
}
/* Realiza uma leitura no canal selecionado pelo argumento,
variando do pinos F0 (canal 0) até F7 (canal 7).
A tensão de referência é mantida constante em AVCC
durante a aplicação. A função assume que o pino referente
ao canal selecionado já foi previamente configurado como uma
entrada tri-state */
uint16_t leitura_ADC(uint8_t canal)
{
/* Os bits REFSx configuram a seleção da tensão de
referência (VREF) para o conversor, e os bits
menos significativos (LSBs) selecionam o canal.
Nessa aplicação selecionamos uma tensão de referência
de AVCC e o canal é selecionado pelo argumento da função */
ADMUX = (1 << REFS0) | canal;
// Uma conversão é iniciada setando o bit ADSC
ADCSRA |= (1 << ADSC);
/* Enquanto a conversão estiver em progresso, o bit
ADSC será lido como 1, quando a conversão se concluir
o bit será alterado para 0 pelo hardware, então aguardamos
até que isso aconteça */
while (ADCSRA & (1 << ADSC))
{
continue;
}
/* O resultado da conversão é escrito pelo módulo
no registrador ADC, então retornamos seu valor */
return ADC;
}
int main()
{
configura_pinos();
USART0_configura();
inicializa_ADC();
uint8_t contador_5s = 0;
uint8_t mensagem_enviada = 0;
while (1)
{
_delay_ms(1000);
contador_5s++;
uint8_t valor_dip = !(PINB & (1 << PINB2));
valor_dip |= !(PINB & (1 << PINB1)) << 1;
valor_dip |= !(PINB & (1 << PINB0)) << 2;
float tensao = leitura_ADC(1) * (5.0 / 1024);
if (tensao <= valor_dip) {
PORTB &= ~(1 << PORTB7);
mensagem_enviada = 0;
contador_5s = 0;
}
else if (!mensagem_enviada) {
USART0_transmite_string_RAM("Tensao acima do permitido\r\n");
mensagem_enviada = 1;
}
if(contador_5s == 5) {
contador_5s = 0;
PORTB |= (1 << PORTB7);
}
}
return 0;
}