Vamos trabalhar com medição de tensão e corrente usando o ATmega328P, como ele possui um sensor de temperatura interno a gente já mata dois coelhos com um tiro só.
A primeira coisa que se deve fazer é configurar o hardware pra isso, é preciso estar atento a entrada Aref(referência analógica), para não ter problemas na configuração faça assim: coloque o pino Avcc ligado ao +5V,o pino Aref ligado um capacitor de 100nf que estará com o outro teminal ligado ao terra(dessa forma ele funciona como um filtro, o que reduz e muito ruídos),nunca ligue este pino ao GND pois pode inutilizar este chip para a função de leitura de tensão. Para este exemplo vou usar um cristal de 16Mhz e um circuito com o max232 para enviar os dados a um PC.
Para fazer a leitura de tensão de 0 a 55V usei um divisor resistivo igual o da figura abaixo:
Ou seja a razão de saída é 11:1(se entra 55V sai 5V na saída), no código deixei uma linha comentada para o caso de alguém querer usar para medir de 0 a 5V.Na simulação do proteus não deu certo colocar o divisor resistivo então optei por usar 2 potenciômetro para conseguir um resultado aproximado.Outro detalhe é que na simulação o sensor interno não é simulador então lá ele assume valor 0 o que acaba resultado em -65°C.
A equação para medir a temperatura foi retirada deste site http://www.embarcados.com.br/arduino-uno-sensor-de-temperatura/ .
O código fonte:
//*********************************************************************************************************** // Usando o conversor analógico/digital // // no gravador configurar os fuses assim: // EXTENDED 0XFF // HIGH 0XD8 - neste modo funciona com qualquer valor de cristal usei um de 16Mhz // LOW 0XC7 // LOKBITS 0XFF - sem proteção // // // versão : 1.1 // descrição : Voltimetro e leitor de temperatura // Autor : Aguivone // microcontrolador : ATmega328P // compilador : AVR-GCC / Atmel AVR Studio 6.1 // Data do projeto : 07/08/2014 // Data de atualização : 07/08/2015 - adicionado leitura de temperatura e melhoria para ler tensão //************************************************************************************************************* #include <avr/io.h> #include <string.h> #include <stdio.h> #include <util/delay.h> #include <avr/interrupt.h> #include <avr/pgmspace.h>// AVRJazz Mega328 SPI I/O ////////////////////////funçoes auxiliares///////////////////////////// #define alterna_pino(x,y) x ^= _BV(y) #define LED PD2 #define TENSAO PC2 char caracter; void RS232_inicializa(unsigned int BAUD) { unsigned int velocidade = F_CPU/16/BAUD-1; //veja que na simulação do proteus dá erros nas velocidade diferentes de 9600 mas na pratica funciona. UCSR0A = 0X20; /* habilita receiver and transmitter buffers */ UBRR0H = (unsigned char)(velocidade>>8); UBRR0L = (unsigned char)velocidade; UCSR0B = 0X98;//deve se habilitar somente a interrupção de recepção para não travar o microcontrolador /* 8 bits , 1 stop bit, assincrono , sem paridade,modo nornal */ UCSR0C = (1<<USBS0)|(3<<UCSZ00); } void escreve_caracter(unsigned char carac) { _delay_loop_1(1);//tempo para estabilizar tensão while ( !( UCSR0A & (1<<UDRE0)) ); //espera transmitir para enviar um novo UDR0 = carac; while ( !( UCSR0A & (1<<UDRE0)) ); //espera transmitir desabilita a transmissão _delay_loop_1(2);//tempo para garantir o envio } void impri_serial(const char frase[80]) { unsigned int indice=0; unsigned int tamanho = strlen(frase); while(indice<=tamanho)///veja que o programa pode travar se aqui não tiver as duas aspas { escreve_caracter(frase[indice]); indice++; } } //////////////////////////interrupções requerida para usar a recepção serial/////////////////////////////////// ISR(USART_RX_vect) { caracter = (char)UDR0; escreve_caracter(caracter); } ///long para char void long_to_char(unsigned int quant, int inicio) { char texto[6]; texto[1] = '0'; texto[2] = '0'; texto[3] = ','; texto[4] = '0'; texto[5] = '0'; if(quant>9999)//valor maior que 100V { texto[1] = 'F'; texto[2] = 'A'; texto[3] = 'L'; texto[4] = 'H'; texto[5] = 'A'; } else { while(quant>=1000) { quant=quant-1000; texto[1]++; } while(quant>=100) { quant=quant-100; texto[2]++; } while(quant>=10) { quant=quant-10; texto[4]++; } while(quant>=1) { quant=quant-1; texto[5]++; } } int cont = inicio; while(cont<=5) { escreve_caracter(texto[cont]); cont++; } } ////////////rotina de leitura de tensão ///////////////////////////////// void ler_adc() { ADCSRA |= _BV(ADSC);//inicia conversão analogico/digital while ( (ADCSRA & _BV(ADSC)) );//espera terminar leitura float valor = ADC; //valor = ((ADC*50)/102);//mede de 0 a 5V valor = ((ADC*50)/102)*11;//mede de 0 a 55V - colocando um resitor de 10K e outro de 1K(entre o pino de entrada e gnd) long_to_char(valor,1); return; } void ler_temperatura() { ADCSRA |= _BV(ADSC);//inicia conversão analogico/digital while ( (ADCSRA & _BV(ADSC)) );//espera terminar leitura float valor = ADC; // a formula é temperatura = (ADC - 324,31)/1,22 , mas vou arrendondar para 324 if(valor < 324) { //temperatura negativa valor = (324.31-valor)/1.22;; escreve_caracter('-'); } else { //temperatura positiva valor = (valor-324.31)/1.22;; escreve_caracter('+'); } long_to_char(valor,4); return; } void inicializa_adc(int valor) { if(valor == 0)///Modo ler tensão { ADMUX = 0X42;// vai usar o pino PC2 como entrada, justificado a direita e com capacitor externo no pino de referencia(estabiliza leitura) ADCSRA = 0XA7;//habilita o conversor adc clock dividido por 128(para 16MHZ - pois o range deve ser de 50-200khz) e trigger ADCSRB = 0X41;//habilita o comparador e o trigger usará a saida dele DIDR0 = 0XFB;////desabilita entrada analógica(reduz consumo), deixa apenas PC2 como analógica } if(valor == 1)///Modo ler temperatura { //deve ser alterado somente esses dois registradores pois ADMUX = 0XC8;// sensor de temperatura, justificado a direita e capacitor externo no pino de referencia //ADCSRA = 0XA7;//habilita o trigger e o conversor adc clock dividido por 128(para 16MHZ - pois o range deve ser de 50-200khz) ADCSRB = 0X41;//habilita o comparador e o trigger usará a saida dele //DIDR0 = 0XFF;////desabilita entrada analógica(reduz consumo) } } ////////////////////função principal///////////////////////////////////// int main(void) { //////////////////inicializa port D ///////////////////////////////////////////////////////////////////// DDRD = 0XFE; //inicializa portD,4 a 7 entrada DDRC = 0x18;//configura port C como entradas exceto C3 e C4 PORTD = 0x00;//desabilita pull ups DDRB = 0x2F;//configura port B PORTB = 0x02;//inicia com o pino de reset e desliga wiznet em nivel alto RS232_inicializa(9600); inicializa_adc(0); sei();//habilita interrupções impri_serial("Lendo tensão e temperatura ... \n\r"); /////////////////////////////////////////////////////// for(;;) { impri_serial("Tensão = "); ler_adc(); inicializa_adc(1);//ler temp _delay_ms(50);//estabilizar tensão impri_serial(" Temp = "); ler_temperatura(); impri_serial(". \n\r "); inicializa_adc(0);//volta a ler tensão //não sei por que em alguns terminais seriais o valor não é impresso, //mas na simulação e em um aplicativo que fiz mostra normalmente _delay_ms(500); alterna_pino(PORTD,LED);//led }//chave do laço infinito (for) }//chave de main
A Simulação:
Saída no terminal serial:
link para baixar o terminal serial: https://drive.google.com/file/d/0Bx9JeN0dmzXxNFhxMVFLQ2NPWHc/view?usp=sharing
Nenhum comentário :
Postar um comentário
olá,digite aqui seu comentário!