#define __AVR_ATmega2560__
#define F_CPU 16000000UL
#include <stdint.h>
#include <avr/io.h>
#include <stdbool.h>
#include <util/delay.h>
#include <stdlib.h>
#include <avr/interrupt.h>
#include "usart.h"
/*
Use o circuito anterior. Usamos o conversor ADC para fazer
a leitura da tensão analógica no canal ADC1 (porta PF1), em intervalos de 1 s.
Quando a tensão lida for maior que o valor em PB[2:0], transmitimos pela USART0 a
mensagem “Tensão acima do permitido”2
. Deve ser enviada uma única mensagem,
cada vez que a tensão lida for maior que PB[2:0]. Se a tensão não retornar a um
valor menor que PB[2:0], depois de 5 s, o LED em PB7 acende. Ele é apagado quando
a tensão é menor ou igual a PB[2:0]. Use AVCC como tensão de referência. Escreva
o programa em C. Faça a simulação com o programa em https://wokwi.com.
Use um potenciômetro na entrada ADC1 para testar o circuito.
*/
#define led_pin PB7
#define botao1 PB2
#define botao2 PB1
#define botao3 PB0
#define pot PF1
void configuracao_TC0(void) {
// Configura o timer0 para gerar interrupções a cada 1,8 ms
/*
CS02:CS01:CS00 Prescaler Frequência do timer (para F_CPU = 16 MHz)
000 Sem clock Contador parado
001 1 16 MHz
010 8 2 MHz
011 64 250 kHz
100 256 62,5 kHz
101 1024 15,625 kHz
110 e 111 Reservado Não deve ser usado
*/
/* Queremos 1ms,
Logo, testaremos com N = 256 -> 16MHz/256 = 62.5kHz = 16us, necessários 1ms/16us = 62.5 = 62 */
TCCR0A = 0x02; // Modo CTC
TCCR0B = 0x04; // CS0[2:0]=100 N=256
TIMSK0 = 0x02; // Ativa OCIE0A (interrupção de comparação A)
OCR0A = 62;// // TOP (valor de comparação)
TCNT0 = 0x00; // Zera o contador
sei(); // Ativa as interrupções globais
}
volatile int tick_led, tick_usart, b1, b2, b3, tensao_ADC;
volatile bool flag_maior;
int main(void) {
USART0_configura();
configuracao_TC0();
configurar_ADC();
// Configura o pino do LED como saída e inicializa desligado
DDRB |= (1 << led_pin); // Configura PB7 como saída
PORTB &= ~(1 << led_pin); // Inicialmente, LED apagado
// Configura os botões como entrada com pull-up ativado
DDRB &= ~(1 << botao1); // Configura PB2 como entrada
DDRB &= ~(1 << botao2); // Configura PB1 como entrada
DDRB &= ~(1 << botao3); // Configura PB0 como entrada
// Adicionamos pull-up a essas portas
PORTB = PORTB | (1 << PORTB0);
PORTB = PORTB | (1 << PORTB1);
PORTB = PORTB | (1 << PORTB2);
while (1) {
// Loop principal vazio por enquanto
// A lógica de controle é feita nas interrupções
// O microcontrolador irá alternar o LED e ler os botões a cada interrupção
// Não há necessidade de código adicional aqui, a lógica é totalmente controlada pelas interrupções
}
}
// Interrupção do temporizador (TC0) chamada a cada 1ms
ISR(TIMER0_COMPA_vect) {
tick_usart++;
//
if (tick_usart == 1000) { //1s
comparacao();
tick_usart = 0;
}
if (tick_led >= 5 && flag_maior) {
led_on();
}
else if (tick_led >= 5 && !flag_maior) {
led_off();
}
}
void configurar_ADC(void) {
ADCSRA = 0x87; // Ativa o ADC (ADEN=1), desativa interrupção do ADC (ADIE=0) e define prescaler para 128 (ADPS[2:0]=111)
ADCSRB = 0x00; // Configura MUX[5] como 0 e ADTS[2:0] como 000 (nenhum gatilho de interrupção)
ADMUX = 01000001; // Configura a referência de tensão (REFS[1:0]=01) e o canal de entrada ADC1 (MUX[4:0]=0001)
}
void realizar_leitura_ADC(void) {
const float VREF = 5; // Define a tensão de referência (5V)
ADCSRA |= (1 << ADSC); // Inicia a conversão ADC
while (ADCSRA & (1 << ADSC)) {} // Espera a conversão ser concluída
tensao_ADC = ADC * (VREF / 1024.0); // Calcula a tensão correspondente ao valor ADC lido
}
// Função para alternar o estado do LED (piscar)
void led_on() {
PORTB |= (1 << led_pin); // Inverte o estado do LED (acende/apaga)
}
void led_off() {
PORTB &= ~(1 << led_pin); // Inverte o estado do LED (acende/apaga)
}
// Função para ler os botões e enviar os valores via USART
void comparacao() {
// Leitura dos botões (0 significa que o botão está pressionado)
uint8_t decimal;
b1 = !(PINB & (1 << botao1));
b2 = !(PINB & (1 << botao2));
b3 = !(PINB & (1 << botao3)); // faz a leitura dos botao;
decimal = (b1 | b2 << 1 | b3 << 2); // manda b1 pro bit 0, b2 pro bit 1 e b3 pro bit 2. Montando assim um decimal de 3 bits
realizar_leitura_ADC();
if (tensao_ADC > decimal) {
USART0_transmite_string_FLASH(PSTR("Tensão acima do permitido \n")); // Envia mensagem via USART
tick_led ++;
flag_maior = 1;
}
else {
flag_maior = 0;
USART0_transmite_string_FLASH(PSTR("Tensão OK \n")); // Envia mensagem via USART
}
}