segunda-feira, 11 de março de 2013

Frequencimetro Atmega328(até 100khz) - Divisor de frequencia virtual

Olá postei anteriormente aqui um frequencimentro usando o ATmega328 porem ele media valores de até 10khz(quando passava disto ficava instavel,veja o post http://microcontroladores-c.blogspot.com.br/2013/03/frequencimetro-com-atmega328-usando-icp1.html ),para sanar o problema do range sem ter que recorrer a um divisor de frequência implementei no firmware o que eu chamo de "divisor de frequencia virtual",com isso consegui ler valores até 100Khz, alem de colocar um filtro contra ruidos e leitura erradas veja como ficou :




O código fonte:


//************************************************************************
//            usando o modo captura de pulsos para ler frequencia(range 1 a 100KHZ)
//  Version    : 1.2
//  microcontrolador : AVR ATMega328
//  Autor        : Aguivone
//  descrição  : captura de eventos externos  
//  data : 11/03/2013.
//
//************************************************************************
#define F_CPU 16000000UL  //  deve vir antes das interrupçoes
#include <avr/io.h>
#include <avr/interrupt.h>
#include <string.h>
#include <util/delay.h>
#include <string.h>

/////////////////////////declaração da variaveis ///////////////////////////////////
int flag_inte=0;
long estouro = 0,lido_estouro=0;
long lido;
long filtro;

long leitura[6];
int ler=0;

//////////////////////////interrupções do timer1 ///////////////////////////////////
#define liga_pino(x,y) x |= _BV(y)
#define desliga_pino(x,y) x &= ~(_BV(y))
#define alterna_pino(x,y) x ^= _BV(y)


ISR(TIMER1_OVF_vect )
  {                    //interrupção overflow
       estouro= estouro + 65535;
  }  
ISR(TIMER1_CAPT_vect)
{              //interrupção de captura de eventos externos.
          if(flag_inte< 2)
          {
          flag_inte++;
          TCNT1 = 0;//zera timer 
          TIFR1 = 0XF0; //limpa interrupcão pendente
          estouro = 0 ;
          lido = 0;
          filtro = 1;
          }
          else
          {
              lido = estouro + ICR1;
              if(lido >35000)// em testes de bancada vi que abaixo desse valor o avr fica impreciso
              {
              flag_inte++;
              if(ler < 6)
                   {//enquanto menor que 6 pega leitura
                             // em 1 segundo temos 15999693 ciclos ao inves de 16000000(segundo simulação do proteus)
                          //logo para calcular a frequencia basta:
                          lido = 15999693 / lido;
                          if(filtro > 1)
                          {
                           lido = lido * filtro ;  
                          }
                    leitura[ler] = lido;
                       flag_inte = 0;
                    ler++;
                  }
              }
              else
              {
               filtro++;
              }                             
          }           
          
}
///////////////////////////////////////////////funçoes usadas pela usart////////////////////////////////////////////////

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;
    UBRR0H = (unsigned char)(velocidade>>8);
    UBRR0L = (unsigned char)velocidade;
    UCSR0B = 0X18;//não vou habilitar nenhuma interrupção da porta serial
    /* 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(1);//tempo para garantir o envio
}
void impri_serial(const char frase[20])
{
      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++;
       }
}

void int_to_char(long quant)
{

       char convert_char5='0';
       char convert_char6='0';
       char convert_char7='0';
       char  convert_char8='0';
       char convert_char9='0';

      
       while(quant>=10000)
        {
           quant=quant-10000;
         convert_char5++;
         }

       while(quant>=1000)
        {
         quant=quant-1000;
         convert_char6++;
         }
       while(quant>=100)
        {
         quant=quant-100;
         convert_char7++;
         }
       while(quant>=10)
        {
         quant=quant-10;
        convert_char8++;
         }
       while(quant>=1)
        {
           quant=quant-1;
         convert_char9++;
         }
          escreve_caracter(convert_char5);
          escreve_caracter(convert_char6);
          escreve_caracter(convert_char7);
          escreve_caracter(convert_char8);
          escreve_caracter(convert_char9);

} 
  
/////////////////////////////////////////////////Funções usadas/////////////////////////////////////////////

void inicializa_modo_captura(void)
{
   TCCR1A = 0X00;//não tem uso para o modo captura de eventos externos
   TCCR1B = 0x01;//filtro desabilitado de ruido habilitado,captura na borda de descida do sinal, clock interno/1
   TCCR1C = 0X00;//não tem uso para o modo captura de eventos externos
   TIMSK1 = 0x21; //habilita interrupção de estouro de timer e de captura

}

//opcional vai depender da aplicação

long  filtro_de_ruido(int val)
{
 long valor;
//comparação de 3 valores pelo menos 2 leituras devem ser iguais 
                  if((leitura[val] == leitura[val+1])||(leitura[val] == leitura[val+2]))
                  {//ok
                      valor =  leitura[val]; 
                  }
                  else
                  {
                         if(leitura[val+1] == leitura[val+2])
                                  {//ok
                              
                                     valor =  leitura[val+1];                            
                                  }                      
                  }
                  return(valor);
}

//////////////////////////////////////////////função principal///////////////////////////////////////////
int main(void)
{
            DDRD = 0X1E;
            DDRB = 0x00;  //inicializa portb como  entrada
            PORTB = 0XFF;//desabilita pull-ups
            DDRC = 0xFF;  //inicializa portC como saida
            PORTC = 0;//limpa as portas logicas.
            inicializa_modo_captura();
            RS232_inicializa(9600);
            impri_serial("Inicializado...\n\r");
            sei(); // habilita interrupções
            desliga_pino(PORTC,0);
            desliga_pino(PORTC,1);
            ler = 0;
           for(;;)
            {
              if(ler >= 6 )
               {
                  cli();
                  long compara1,compara2;
                  compara1 = filtro_de_ruido(0);
                  compara2 = filtro_de_ruido(3);
                  //se de 6 amostras pelo menos 4 forem iguais
                      if((compara1 == compara2)&&(compara1 > 0))//filtra leitura errada
                      {
                          impri_serial("-> ");
                          int_to_char(compara1);//isso garante melhor performace
                          impri_serial("\n\r");
                      }
                  flag_inte = 0;
                  ler=0;
                  _delay_ms(100);                  
                  sei(); 
               }
          
            }//laço for
}//main

Um comentário :

  1. Atenção desabilite as optimizações do compilador para funcionar.

    ResponderExcluir

olá,digite aqui seu comentário!