// Nome: Kauana Quintana Fort
// Matrícula: 202110738
#define __ATmega2560__ // Define que estamos utilizando o ATmega2560
#define __AVR_ATmega2560__ // Define que estamos utilizando o ATmega2560
#ifndef F_CPU
#define F_CPU 16000000UL // Define a frequência do microcontrolador (16 MHz)
#endif
#include <stdint.h> // Bibliotecas para tipos inteiros fixos
#include <avr/io.h> // Bibliotecas para controle de I/O do microcontrolador
#include <avr/pgmspace.h> // Para trabalhar com strings armazenadas em memória flash
#include <stdbool.h> // Para uso de tipo bool
#include <stdint.h> // Inclusão de tipos inteiros de 8, 16 e 32 bits
#include <util/delay.h> // Para uso de delays
#include <stdlib.h> // Funções padrões de C
#include <avr/interrupt.h> // Bibliotecas para interrupções
#include "usart.h" // Biblioteca para configuração da comunicação USART
/* Descrição do funcionamento:
O código faz a leitura de uma tensão analógica a partir do canal ADC1 (pino PF1) a cada 1 segundo.
Se a tensão for maior que o valor configurado nos pinos PB[2:0], uma mensagem será transmitida via USART0.
Se a tensão permanecer maior que esse limite por 5 segundos, o LED no pino PB7 será aceso.
A tensão de referência utilizada é AVCC (5V), e um potenciômetro é usado para variar a tensão no ADC1. */
uint8_t estado_pin0 = 0; // Valor do pino PB0 (botão)
uint8_t estado_pin1 = 0; // Valor do pino PB1 (botão)
uint8_t estado_pin2 = 0; // Valor do pino PB2 (botão)
float valor_pino0, valor_pino1, valor_pino2, valor_total_pinos; // Valores dos pinos PB0, PB1, PB2 e soma dos valores
float tensao_ADC = 0; // Variável para armazenar a tensão lida do ADC
uint8_t contador1 = 0, contador2 = 0; // Contadores para controlar o envio de mensagens e acendimento do LED
/* Função para configurar os pinos do microcontrolador */
void configurar_pinos(void) {
DDRB |= (1 << DDB7); // Configura PB7 como saída (para controle do LED)
PORTB &= ~(1 << PORTB7); // Desliga o LED em PB7 inicialmente
DDRB &= ~(1 << DDB0); // Configura PB0 como entrada (botão)
PORTB |= (1 << PORTB0); // Ativa o resistor de pull-up interno em PB0
DDRB &= ~(1 << DDB1); // Configura PB1 como entrada (botão)
PORTB |= (1 << PORTB1); // Ativa o resistor de pull-up interno em PB1
DDRB &= ~(1 << DDB2); // Configura PB2 como entrada (botão)
PORTB |= (1 << PORTB2); // Ativa o resistor de pull-up interno em PB2
}
/* Tabela de Configuração do ADC:
| Parâmetro | Valor | Descrição |
|-----------------|------------|----------------------------------------------------|
| **Referência de Tensão (REFS)** | 01 | Usa AVCC (5V) como referência de tensão |
| **Canal de Entrada (MUX)** | 0001 | Canal de entrada ADC1 (pino PF1) |
| **Prescaler (ADPS)** | 111 | Prescaler de 128, para obter 125 kHz de clock |
| **Ativar o ADC (ADEN)** | 1 | Ativa o ADC |
*/
/* Tabela de Modos de Referência de Tensão:
| Modo de Referência | REFS[1:0] | Descrição |
|--------------------|-----------|--------------------------------------------------------|
| AVCC | 01 | Usa AVCC (5V) como referência de tensão |
| Interna (1.1V) | 10 | Usa a referência interna de 1.1V |
| Interna (VBG) | 11 | Usa a referência interna de 2.56V |
*/
/* Para escolher o modo de referência, você deve considerar:
- Se o seu sistema utiliza 5V como tensão de referência, utilize AVCC (5V).
- Se o seu sistema precisar de uma referência mais estável ou precisa de uma tensão mais baixa, use a referência interna de 1.1V ou 2.56V.
- Certifique-se de que o pino de Vref esteja conectado corretamente dependendo do modo de referência escolhido.
MUX[4:0] Canal de Entrada Pino no ATmega2560
000000 ADC0 PF0 (Port F, Pino 0)
000001 ADC1 PF1 (Port F, Pino 1)
000010 ADC2 PF2 (Port F, Pino 2)
000011 ADC3 PF3 (Port F, Pino 3)
000100 ADC4 PF4 (Port F, Pino 4)
000101 ADC5 PF5 (Port F, Pino 5)
000110 ADC6 PF6 (Port F, Pino 6)
000111 ADC7 PF7 (Port F, Pino 7)
001000 ADC8 PG0 (Port G, Pino 0)
001001 ADC9 PG1 (Port G, Pino 1)
001010 ADC10 PG2 (Port G, Pino 2)
*/
/* Função para configurar o ADC (Conversor Analógico-Digital) */
void configurar_ADC() {
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)
}
/* Função para realizar a leitura do ADC e converter o valor para tensão */
void realizar_leitura_ADC() {
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 principal onde o código roda em loop */
int main(void) {
configurar_pinos(); // Configura os pinos de entrada e saída
configurar_ADC(); // Configura o ADC para leitura de tensão
USART0_configura(); // Configura a comunicação USART
while (1) {
// Leitura dos estados dos botões PB0, PB1 e PB2
estado_pin0 = PINB & (1 << PINB0); // Leitura do pino PB0
estado_pin1 = PINB & (1 << PINB1); // Leitura do pino PB1
estado_pin2 = PINB & (1 << PINB2); // Leitura do pino PB2
// Verifica se os botões estão pressionados
valor_pino0 = (estado_pin0 == 0x00) ? 0x01 : 0x00; // Se PB0 pressionado, valor_pino0 = 1
valor_pino1 = (estado_pin1 == 0x00) ? 0x02 : 0x00; // Se PB1 pressionado, valor_pino1 = 2
valor_pino2 = (estado_pin2 == 0x00) ? 0x04 : 0x00; // Se PB2 pressionado, valor_pino2 = 4
valor_total_pinos = valor_pino0 + valor_pino1 + valor_pino2; // Soma dos valores dos pinos (para o limite da tensão)
realizar_leitura_ADC(); // Realiza a leitura da tensão no ADC
// Se a tensão lida for maior que o valor total dos pinos e ainda não enviou mensagem
if ((tensao_ADC > valor_total_pinos) && (contador1 == 0)) {
USART0_transmite_string_FLASH(PSTR("Tensão acima do permitido \n")); // Envia mensagem via USART
contador1 = 0x01; // Marca que já enviou a mensagem
} else {
if (tensao_ADC > valor_total_pinos) {
contador2++; // Contador para o tempo de 5 segundos
} else {
contador1 = 0; // Reseta contador1 se a tensão cair abaixo do limite
contador2 = 0; // Reseta contador2 se a tensão cair abaixo do limite
}
}
// Se o contador2 atingir 5, acende o LED no pino PB7
if (contador2 >= 5) {
PORTB |= (1 << PORTB7); // Liga o LED
} else {
PORTB &= ~(1 << PORTB7); // Desliga o LED
}
_delay_ms(1000); // Aguarda 1 segundo para realizar a próxima leitura
}
return 0;
}