#include <stdint.h> /* usamos os tipos uint8_t e uint16_t */
#define __AVR_ATmega2560__ /* programa para o microcontrolador ATMega2560 */
#include <avr/io.h> /* definições das entradas e saídas */
#ifndef F_CPU // Se não definida a frequência de relógio do sistema
#define F_CPU 16000000UL // defina a frequência de 16 MHz
#endif // F_CPU
#include <util/delay.h> // usamos _delay_ms()
#include "usart.h" // declaração dos procedimentos com a USART0
/**
* @brief Configuramos o ADC para realizar leituras no canal ADC5. Consideramos a frequência de relógio do sistema de
* 16 MHz. Usaremos os 10 bits do conversor. Usamos a fonte de referência de 1,1 V
*/
void ADC_configura(void) {
ADCSRA = 0x87; // ADEN=1 ADSC=0 ADATE=0 ADIE=0 ADIF=0 ADPS[2:0]=111
ADCSRB = 0x00; // ACME=0 MUX[5]=0 ADTS[2:0]=000
ADMUX = 0x85; // REFS[1:0]=10 ADLAR=0 MUX[4:0]=00101
}
/**
* @brief Seleciona o canal de leitura do ADC. Neste procedimento, selecionamos um canal entre 0 e 7.
* @param canal Um canal entre 0 (ADC0) e 7 (ADC7)
* @todo Modificar o procedimento para aceitar os canais de 0 (ADC0) a 15 (ADC15)
*/
void ADC_altera_canal(uint8_t canal) {
/** @todo verificar se o número do canal está entre 0 e 7 */
ADMUX = (ADMUX & (0xE0)) | canal; // MUX[4:0]= 00CCC, onde CCC é o canal
}
/**
* @brief Realizamos uma leitura no conversor AD.
* @return uint16_t resultado da conversão: um valor entre 0 e 1023.
*/
uint16_t ADC_medida(void) {
ADCSRA |= (1 << ADSC); // fazendo ADSC=1 em ADCSRA, iniciamos uma nova conversão
while (ADCSRA & (1 << ADSC)) // enquanto ADSC=1, a conversão está em andamento
;
return ADC; // retorna o valor do canal convertido
}
/**
* @brief Realiza a leitura dos canais ADC4 e ADC1, calcula a tensão lida e retorna a diferença de tensão entre os
* canais ADC4 e ADC1.
* @return float diferença de tensão entre os canais ADC4 e ADC1.
*/
float diferenca_tensao_adc4_adc1(void) {
const float VREF = 1.1; // tensão de referência do conversor
const float C_CONVERSOR = VREF / 1024.0; // constante para converter o valor do ADC para tensão
uint16_t leitura_canal_4; // leitura do canal 4 do ADC
uint16_t leitura_canal_1; // leitura do canal 1 do ADC
float tensao_ADC4; // tensão lida no canal 4
float tensao_ADC1; // tensão lida no canal 1
float diferenca_tensao; // diferença de tensão ADC4-ADC1
// realizamos a leitura dos canais
ADC_altera_canal(4); // escolhemos o canal ADC4 para leitura
leitura_canal_4 = ADC_medida(); // realizamos a leitura do canal ADC4
ADC_altera_canal(1); // escolhemos o canal ADC1 para leitura
leitura_canal_1 = ADC_medida(); // realizamos a leitura do canal ADC1
// calculamos a diferença entre ADC4 e ADC1
tensao_ADC4 = C_CONVERSOR * (float)leitura_canal_4; // encontramos a tensão lida no canal 4
tensao_ADC1 = C_CONVERSOR * (float)leitura_canal_1; // encontramos a tensão lida no canal 1
diferenca_tensao = tensao_ADC4 - tensao_ADC1; // calculamos a diferença de tensão ADC4-ADC1
return diferenca_tensao;
}
/**
* @brief Transmite pela USART0 o valor em ponto flutuante da diferença de tensão lida nos canais anlógicos ADC4 e ADC1.
* @param diferenca_tensao diferença de tensão nos canais analógicos ADC4 e ADC1: ADC4-ADC1.
*/
void transmite_diferenca_adc4_adc1(const float diferenca_tensao) {
char buffer[10]; // buffer para a string com a diferença de tensão
// transmitimos a diferença entre as leituras ADC4 e ADC1
dtostrf(diferenca_tensao, 6, 2, buffer); // dtostrf não é uma função padrão ISO-C
USART0_transmite_string_RAM(buffer); // transmitimos a string com o valor da dif. tensão
USART0_transmite_string_FLASH(PSTR("\r\n")); // transmitimos uma nova linha
}
/**
* @brief Procedimento principal. Configuramos o sistema e a cada 2 segundos realizamos a leitura dos canais analógicos
* ADC4 e ADC1. Calculamos a tensão e a diferença de tensão nos canais: ADC4-ADC1. Este valor, da diferença de
* tensão, é enviado pela USART0.
* @return int Este procedimento não retorna.
*/
int main(void) {
float diferenca_tensao; // diferença de tensão ADC4-ADC1
// configuramos o sistema
ADC_configura(); // configuramos o conversor AD
USART0_configura(); // configuramos a USART0
// A cada 2 s lemos ADC4 e ADC1, calculamos a diferença ADC4-ADC1 e transmitimos pela USART0.
while (1) {
_delay_ms(2000); // esperamos 2 s
diferenca_tensao = diferenca_tensao_adc4_adc1(); // lemos ADC4 e ADC1 e calculamos a diferença ADC4-ADC1
transmite_diferenca_adc4_adc1(diferenca_tensao); // transmitimos a diferença de tensão
}
return 0;
}