sexta-feira, 9 de dezembro de 2011

Frequencímetro via RS232 com ATmega8:

Neste exemplo de código vou demonstrar como ler frequência usando o ATmega8(pode ser adaptado para outros modelos como o ATmega328), como tem caráter apenas didático o range de frequência está de 500Hz a 32kHz(pois o simulador não vai conseguir passar disto) ,mas você pode melhorar o código e adequar a cada necessidade, o intuito aqui é só exemplificar como fazer um frequencímetro usando o AVR STUDIO (ele é grátis ).
O código fonte:


///************************************************************************/
//                             contador de pulsos - (frequencimetro)
//  Version    : 1.0
//  microcontrolador : AVR ATMega8
//  Autor        : Aguivone
//  descrição  : captura de sinais
//  data : 09/12/2011.
//
//************************************************************************/
#define F_CPU 16000000UL  // 16 MHz deve vir antes das interrupçoes
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <util/delay.h>
#include <string.h>

int amostra1, amostra2 ;
int dig1='0';
int dig2='0';
int dig3='0';
int dig4='0';
int dig5='0';
int valor_lido=0;
int  frequencia;
int tem_interrupcao=0;
int estouro = 0;

/////////////////////////////////////////////////Funções usadas/////////////////////////////////////////////
void inicializa_timer1(void)
{
    //TIMSK = 0x21; //Habilita interrupção de captura do timer1 , e habilita interrupção de estouro do contador1
    TIMSK = 0x20; //Habilita interrupção de captura do timer1 , e habilita interrupção de estouro do contador1
    TCCR1A=0X00;//desabilita geração de pulsos 
    TCNT1=0x00;//zera contagem; 
    OCR1A =0x00;//desabilita comparadores 
    OCR1B =0x00;//desabilita comparadores
    TCCR1B=0x41;//filtro de ruido desabilitado(atrasa 4 ciclos),habilita interrupção na borda de subida,preescaler div por 1 
    /*
    pra outros valores basta mudar o ultimo digito para:
    1-dividido por 1
    2-dividido por 8
    3-dividido por 64
    4-dividido por 256
    5-dividido por 1024

    obs: o registrador ICR1 só pode ser zerado no modo de geração de pulso.
    ou seja é melhor zerar o TCNT1, pois quando o conteudo deste for copiado ele será zerado tambem.
    */


}
///////////////////////////////////////////////funçoes usadas pela usart////////////////////////////////////////////////

void serial_inicializa(unsigned int BAUD)
{
unsigned int valor = F_CPU/16/BAUD-1; //é recomendavel ver o data sheet para ter certeza se está formula irá funcionar na sua mcu
/* baud rate */
UBRRH = (unsigned char)(valor>>8);
UBRRL = (unsigned char)valor;
UCSRA = 0X20;
/* habilita receiver and transmitter buffers */
UCSRB = 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 */
UCSRC = 0X86;
}
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
       {
           while ( !( UCSRA & (1<<UDRE)) ); //espera transmitir para enviar um novo
           UDR =frase[indice];
           indice++;
       }
}
void put_serial(int carac)
{
           while ( !( UCSRA & (1<<UDRE)) ); //espera transmitir para enviar um novo
           UDR = carac;
}


void converte(int quant)//converte int para 3 caracter numerico
{
   dig1='0';
   dig2='0';
   dig3='0';
   dig4='0';
   dig5='0';
   if(quant > 0)
       {
       while(quant>=10000)
        {
         quant=quant-10000;
         dig1++;
         }
       while(quant>=1000)
        {
         quant=quant-1000;
         dig2++;
         }
       while(quant>=100)
        {
         quant=quant-100;
         dig3++;
         }
       while(quant>=10)
        {
         quant=quant-10;
        dig4++;
         }
       while(quant>=1)
        {
           quant=quant-1;
         dig5++;
         }
      }
      }

//////////////////////////interrupções do timer1 ///////////////////////////////////
ISR(TIMER1_CAPT_vect)
{///quando a interrupção é ativada e o vetor de interrupção é zerado 
       unsigned char sreg;
       cli();//disabilita as interrupçoes
       TCNT1 = 0;//zera contador 
       sreg = SREG;//salva o valor dos flags de interrupçoes.
       valor_lido = ICR1;
       tem_interrupcao = 1;
       SREG = sreg;//restaura o valor das interrupçoes globais (consequentemente habilita as interrupçoes novamente)
}
//////////////////////////////////////////////função principal///////////////////////////////////////////
int main(void)
{
           DDRC = 0xFF;  //inicializa portd
           PORTC = 0;
           inicializa_timer1();
           serial_inicializa(9600);
           sei();
           for(;;)
            {//obs : no laço for não pode ficar sem nenhuma acão,deve ser coisa do compilador

                  if(tem_interrupcao == 1)
                  {
                     frequencia=16000000/valor_lido;//veja que vai ser arredondado para dar o resultado em inteiros.
                     converte(frequencia);
                     put_serial(dig1);
                     put_serial(dig2);
                     put_serial(dig3);
                     put_serial(dig4);
                     put_serial(dig5);             
                     put_serial(*"\n"); //pula linha 
                     put_serial(*"\r"); //retorna ao inicio da linha
                     estouro =0;
                  }
                  tem_interrupcao=0;

                 
            }            
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
A simulação: