Páginas

sexta-feira, 9 de janeiro de 2015

Frequencímetro microprocessado com PIC


[REVISADO]
Mais um projeto envolvendo microcontroladores PIC. Ele que já foi montado e testado no proto-board mas infelizmente não tive tempo de montar a placa final. A princípio é um circuito muito simples exigindo o mínimo de componentes externos além do microprocessador graças aos recursos do PIC, mais especificamente, do módulo do Timer 1 (TMR1) ativando os recursos de incremento externo e modo assíncrono. O circuito apresentado é capaz de medir frequências entre 10 Hz e 50 MHz, mesmo com o PIC trabalhando com o Clock de 4 MHz.


Esquema Frequencímetro com PIC 16F628A e LCD


A medida do sinal é feita quase que diretamente no pino do processador e o resultado é exibido em um display de LCD 16X2 com resolução de 5 dígitos. É possível modificar o programa para se ter uma resolução maior e/ou o circuito para exibir o resultado em diplays de 7 segmentos, porém, dependendo da quantidade de dígitos que o projetista deseja exibir, pode ser necessário a adição de um CI decodificador (BCD-7seg) ou de um PIC com maior número de pinos para fazer a multiplexação dos displays.

Lógica de Funcionamento:
O funcionamento do frequencímetro é baseado em "janelas de amostragem", que são intervalos de tempo muito pequenos (na casa dos milissegundos) onde é feito a contagem dos pulsos. Em seguida extrapola-se o valor dessa contagem para o tempo de 1 segundo. Ou seja, não contamos todos os pulsos que chegam durante um segundo inteiro.
Para cada faixa de frequência que se deseja medir, devemos escolher o tempo de amostragem adequado. Para frequências maiores (ordem de MHz), deve usar intervalos menores, já medições em faixas de frequências menores (ordem de kHz) deve-se utilizar intervalos de amostragem maiores.

É possível fazer no programa, um sistema de "auto-range", onde programa determina a faixa de frequência de acordo com o sinal na entrada. Isso é obtido fazendo a amostragem dos pulsos começando pela escala mais baixa (intervalo de amostragem maior), caso a contagem estoure, o resultado é desprezado e é feita uma nova amostragem na escala seguinte (intervalo de amostragem menor) até que a contagem dos pulsos no sinal de entrada não estoure durante a amostragem.
Dividir o intervalo de medição em faixas pode ser útil para uma exibição melhor do resultado, principalmente quando se usa poucos dígitos.

Exemplo:
O primeiro range (faixa ou intervalo de medição) corresponde a um janelamento de 1 segundo (JANELA=1000 ms). Logo vamos contar quantos pulsos recebemos do sinal de entrada durante um segundo. Caso a contagem do TMR1 estoure (ultrapasse 65535) significa que o sinal possui uma frequência maior que 65 kHz e neste caso o programa muda a janela para 500 ms e faz uma nova amostragem, se durante essa nova amostragem a contagem estourar novamente, significa que o sinal de entrada possui uma frequência maior que 131 kHz e deve-se utilizar um intervalo de amostragem menor ainda. O programa trabalha nesse loop, reduzindo o tempo de amostragem até que a contagem do TMR1 não exceda 65535, quando isso acontecer, basta fazer a conta de extrapolação dos pulsos e exibir o resultado.

O Hardware:
O sinal de entrada é ligado ao pino de incremento externo do TMR1, para testes de bancada é possível ligar diretamente a entrada ao pino através de um resistor limitador, na prática é necessário utilizar algum circuito para adequar o sinal da entrada (amplitude, impedância de saída) a níveis seguros para o PIC. Existem diversos projetos na internet de circuitos de condicionamento de sinal e proteção. O projetista deve selecionar o circuito para cada caso, lembrando que: A amplitude máxima do sinal suportável pelo processador é de 5 V. Aconselho o uso de acoplamento óptico para evitar interferências e isolar eletricamente o sinal de entrada do processador.

O software:
O firmware foi escrito em C. Utilizando o compilador CCS e o MPLAB.
As funções são bem simples, segue abaixo uma breve explicação de delas.

Função de amostragem 
int16 amostragem(int16 janela)
{ int16 TEMP=0;              //inicializa variavel TEMP
output_low(RB7);           
SET_TRIS_B(0b11000000);    //inicia o janelamento por                                          //hardware.
set_timer1(0);
delay_ms(janela);          //Aguarda por X milissegundos                                        //enquanto o TMR1 recebe a                                          //contagem.
TEMP=get_timer1();         //Captura o valor da contagem na                                    //variável no TMR1 e passa para a                                    //variável TEMP.
output_low(RB7);           //encerra o janelamento por                                          //hardware.
SET_TRIS_B(0b01000000);
return TEMP;               //Repassa o valor da contagem
}
O "janelamento por hardware" é opcional e é feito ligando se o pino RB7 juntamente com a entrada do sinal. Quando não estamos amostrando o sinal de entrada, o pino RB7 força a entrada do sinal para nível baixo, quando queremos fazer a contagem colocamos o pino RB7 como entrada (alta impedância) e com isso o TMR1 só é incrementado dentro desta rotina. 


Função BINÁRIO-BCD
//CONVERTE UM VALOR BINÁRIO PURO DE UMA VARIÁVEL
//EM 4 DÍGITOS BCD
void binario_BCD(int16 TEMP) // formato 012.34 
{ digits[0]=((TEMP/10000))+0X30;     //soma 30H para a
digits[1]=((TEMP/1000)%10)+0X30;   //adequar a ROM do LCD
digits[2]=((TEMP/100)%10)+0X30;    // 30H = 0, 31H= 1,...
digits[3]=((TEMP/10)%10)+0X30;
digits[4]=((TEMP)%10)+0x30; //
}
No caso de se trabalhar com display de LCD, pode-se passar o valor diretamente em binário e a rotina se encarrega de fazer a conversão, devendo o programador apenas ajustar a vírgula (parte decimal),  eu prefiro transformar tudo em caractere para se manter a compatibilidade em caso de uso de displays de 7-segmentos.

Rotina de Interrupção por estouro de contagem do TIMER1
#INT_TIMER1 //interrupção do timer1
void inter_timer1(void)
{ FAIXA++;
if(FAIXA>7){FAIXA=0;}
}
A rotina acima ocorre sempre que o valor da contagem dos pulsos do sinal de entrada excede 65.535. Neste caso, a variável FAIXA é incrementada, o que altera o janelamento para um valor menor em outra parte do programa com é visto abaixo. 


void main()
{setup_oscillator(OSC_4MHZ);   //pic16f628A possui cristal interno
SETUP_COMPARATOR(NC_NC_NC_NC);  //comparadores desligados
SETUP_VREF(FALSE);              //tensão de referência desligada
SETUP_TIMER_2(T2_DISABLED,0,1); //TMR2 desabilitado
SET_TRIS_A(0b00000000);
SET_TRIS_B(0b01000000);
lcd_init();                   //invoca rotina de inicialização LCD
lcd_gotoxy(1,1);
ENABLE_INTERRUPTS(INT_TIMER1); //habilita interrupção TMR1
ENABLE_INTERRUPTS(GLOBAL);     //chave geral das interupções
FAIXA = 0;                     //carrega com valor incial

SETUP_TIMER_1(T1_EXTERNAL|T1_DIV_BY_1); //configura TMR1

while(true)
{ delay_ms(1000);
switch (FAIXA)
{case 0:{JANELA=500;     //tempo de amostragem 500 ms
 FREQUENCIA=amostragem(JANELA);
 if(FREQUENCIA==0){FAIXA=7; break;}
 if(FREQUENCIA<30000)
 { binario_BCD(FREQUENCIA*2);
imprime_LCD();
faixa_0(); // 655,35 hz = 655,35 kHz
break;
 }
else
{FAIXA=1;
JANELA=250;
break;
}
break;}
case 1:{JANELA=250;          //tempo de amostragem 250 ms
FREQUENCIA=amostragem(JANELA);
if(FREQUENCIA==0){FAIXA=7; break;}
if(FREQUENCIA<15000)
{ binario_BCD(FREQUENCIA*4);
imprime_LCD();
faixa_0();
break;
}
else
{ FAIXA=2;
JANELA=200;
break;
}
break;
}
...
  }
}

A rotina acima, que não está completa, é o loop principal no qual o programa fica rodando, ela é chamada na função main após as instruções de inicialização do PIC. O caso zero, corresponde à faixa de medida mais baixa (variável FAIXA=0) que corresponde a um janelamento de 500 ms. Se a contagem for menor que 30.000 pulsos, o valor a ser exibido é simplesmente o número de pulsos multiplicado por 2. Se a contagem for maior que 30.000 pulsos, a contagem é desprezada, a variável faixa é incrementada e na próxima passagem pela função o programa irá pular para o caso 1 que utiliza uma janela de 250 ms e assim por diante. 

As rotinas abaixo fazem a exibição do resultado no LCD, nas três situações possíveis. Não confundir com a variável FAIXA (falta criatividade as vezes pra nomear variáveis e rotinas).
void faixa_0(void)
{   printf(lcd_putc,"%c%c.%c%c%c.%c%c%c Hz",digits[0],digits[1],digits[2],digits[3],digits[4]);
}

void faixa_2(void)
{ printf(lcd_putc,"ERRO: f > 60MHZ",);
}

void faixa_1(void)
{ printf(lcd_putc,"ERRO: sem sinal",);

}

Os arquivos para o projeto podem ser obtidos no link abaixo.

Considerações: 
1) Lembrar de setar o TMR1 para trabalhar com incrementos externos, modo assíncrono e sem prescaler. É possível medir frequências até 50 MHz com esse circuito sem muitos problemas.  
2)Para testar o frequencímetro pode-se montar um circuito oscilador composto de um CI 555, um capacitor e um potenciômetro ou trimpot. Se você tiver um cristal e algumas portas lógicas é possível montar um oscilador para a frequência nominal do cristal. 
3) Em muitos casos o circuito de entrada precisa amplificar o sinal que queremos, pois o mesmo pode estar em uma amplitude muito baixa e o PIC não irá conseguir fazer a contagem dos pulsos, Em outros casos, o sinal de entrada precisará ser atenuado (se o intuito for, por exemplo, medir a frequência da rede elétrica), Fica a cargo do projetista escolher e projetar seu próprio circuito de entrada. 

Circuito para teste do frequencímetro

4) É possível transformar o frequencímetro em um capacímetro ou em um indutímetro com pouquíssimas modificações.
Se tiver alguma dúvida ou sugestão sobre o projeto deixe um comentário que você será respondido.
5) Senha do arquivo: dnail.org

7 comentários:

  1. Respostas
    1. Prezado testei o link e os arquivos estão funcionando normalmente.

      Excluir
  2. Muito obrigado meu amigo, você é incrível. Único projeto que encontrei que consegui reproduzir. Obrigado por compartilhar e documentar.

    ResponderExcluir