Páginas

sexta-feira, 9 de setembro de 2016

Projetos - Gerando Senoides com o PIC - Parte 1

Finalmente resolvi tirar essa postagem da gaveta de rascunhos e compartilhar um projeto de bancada que me foi útil na ocasião e pode também ser para outros. O Gerador de Onda Senoidal faz o que o nome diz, fornece um sinal tipo senoide modificada com resolução e frequência ajustáveis a nível de projeto. É possível também gerar outras formas de onda utilizando o mesmo conceito descrito e o Módulo de Tensão de Referência. Já falei sobre esse periférico do PIC aqui no blog quando utilizei ele em conjunto com o Comparador Analógico no projeto do Termômetro Bargraph. Agora vou mostrar como é possível gerar uma senoide ou outra forma de onda qualquer utilizando o VREF.

Conceitos Básico e recursos do PIC:
Muitos PICs, e outros microcontroladores em geral, possuem um módulo VREF que é um periférico bem versátil. É basicamente um conversor digital-analógico (CDA) e como tal, converte um valor binário em um nível tensão DC no pino de I/O do PIC. No caso do PIC, é possível escolher entre 26 valores distintos entre 0 e 5 Volts.

A arquitetura do módulo VREF é baseada em uma associação com 16 resistores multiplexados. Um divisor de tensão controlado pelo bit <VRR>  permite o módulo trabalhar com duas escalas (ranges) de tensões. Cada divisão (high e low) pode assumir 16 valores diferentes.

figura 01 - Diagrama do Módulo de Tensão de Referência. 
- retirado do datasheet do pic -

Como se pode ver na figura, escrevendo um valor binário entre 0000 e 1111 nos bits VR0 a VR3 do registrador VCON, você faz a multiplexação dos resistores que ficarão ativos e com isso, altera o valor da tensão de saída.
Quando programando em C no MPLAB e com o compilador CCS, o controle é feito utilizando a função SETUP_VREF(arg1| arg2 | arg3)que recebe 3 argumentos.
Argumento1: VREF_HIGH / VREF_LOW / FALSE- indica qual escala (range) deve ser usado. Alto  ou baixo ou ainda se o módulo ficará desligado (false).
Argumento2: VREF_A2 - determina onde a tensão de saída do módulo será disponível interna ou externamente. Nesse exemplo, VREF estará disponível no pino A2.
Argumento3: Neste argumento deve ser passado um valor numérico de entre 0 e 15, que corresponde ao valor nos bits de controle <VR3:0>. O Efetivo valor da tensão DC é dado pelas equações mostradas abaixo.
Quando na escala alta (VREF_HIGH) o valor da tensão de saída é dado pela equação:


Quando na escala baixa (VREF_LOW), o valor da tensão é dado agora pela equação:


Note que o módulo também utiliza VDD e VSS como alimentação e portanto, variações ou flutuações em VDD/VSS  irão refletir em VREF. Com base nas equações mostradas criei uma tabela onde calculei todos os valores que VREF pode assumir para um valor de VDD igual a 5 volts. Uma outra limitação é o fato que alguns pontos dos dois ranges são coincidentes, e portanto, não é possível ter 32 pontos de resolução mas apenas 26.

A tabela abaixo mostra todos as 32 tensões possíveis que podemos obter utilizando VDD = 5 Volts.

figura 02 - Valores possíveis de VREF para ambos os ranges


Lógica do Projeto: Uma vez que não estamos realmente gerando uma senoide pura, mas sim uma senoide modificada ou digitalizada. Configuramos VREF para fornecer a mínima tensão desejada na saída, fazemos um delay para que a tensão se estabilize, em seguida mudamos os argumentos da função SETUP_VREF() para aumentar a tensão de saída para o próximo valor, repetimos o processo até atingimos o valor máximo desejado e então fazemos o caminho inverso, diminuindo a tensão à cada delay. A figura abaixo ilustra um caso particular, onde foram usados 5 patamares distintos.
figura 03 - Senoide modificada, n=5
Aumentando o número de pontos, aumentamos a resolução e mais próximo vamos chegando da forma de uma senoide pura. Quanto a frequência da senoide, basta perceber que é preciso passar por todos os pontos, tanto de subida quanto de descida, no intervalo de tempo definido pelo período T=1/f.  Nesse projeto eu queria obter a máxima resolução bem como e a máxima excursão da amplitude do sinal de saída e portanto os intervalos foram calculados para se obter uma senoide com frequência de 1 kHz (que era o que eu precisava na hora pra testar um outro projeto). Formas de onda diferentes e frequências maiores podem ser alcançadas, porém é preciso ficar atento às limitações do componente e principalmente com o tempo de estabilização necessário do módulo VREF.

Software: Primeiro é feito a configuração dos registradores de controle do periférico em seguida, um laço garante a geração da senoide ad infinitum. O código abaixo foi escrito por meu colega Eng. Heitor M. Couto em 2014 na época, estudante de graduação e meu estagiário.

NOTA: Conforme o datasheet, quando configurado no modo de tensão de referência, o pino RA2 trabalha como uma saída de alta impedância. Antes de usa-lo é preciso configurá-lo como ENTRADA e conectar ao pino apenas cargas de alta impedância ligada ao pino. 

void main() 

   SET_TRIS_A(0b00000100);  //pino RA2 como ENTRADA!!!
   setup_comparator(NC_NC_NC_NC);//desabilita o módulo comparador

   for(;;)
   {
      senoide();
   }
}

void senoide(void)

   setup_vref(VREF_LOW | VREF_A2 | 9);//1,87
   delay_us(245);
   setup_vref(VREF_HIGH | VREF_A2 | 5);//2,03
   delay_us(82);
   setup_vref(VREF_LOW | VREF_A2 | 10);//2,08
   delay_us(165);
   setup_vref(VREF_HIGH | VREF_A2 | 6);//2,18
   delay_us(167);
   setup_vref(VREF_LOW | VREF_A2 | 11);//2,29
   delay_us(84);
   setup_vref(VREF_HIGH | VREF_A2 | 7);//2,34
   delay_us(257);
   setup_vref(VREF_LOW | VREF_A2 | 12);//2,5
   delay_us(267);
   setup_vref(VREF_HIGH | VREF_A2 | 9);//2,656
   delay_us(92);
   setup_vref(VREF_LOW | VREF_A2 | 13);//2,708
   delay_us(190);
   setup_vref(VREF_HIGH | VREF_A2 | 10);//2,81
   delay_us(199);
   setup_vref(VREF_LOW | VREF_A2 | 14);//2,916
   delay_us(104);
   setup_vref(VREF_HIGH | VREF_A2 | 11);//2,96
   delay_us(333);
   setup_vref(VREF_LOW | VREF_A2 | 15);//3,125
   delay_us(385);
   setup_vref(VREF_HIGH | VREF_A2 | 13);//3,28
   delay_us(489);
   setup_vref(VREF_HIGH | VREF_A2 | 14);//3,437
   delay_us(1149);
   setup_vref(VREF_HIGH | VREF_A2 | 15);//3,59
   delay_us(1149);
   //até aqui é 90°
   setup_vref(VREF_HIGH | VREF_A2 | 14);//3,437
   delay_us(489);
   setup_vref(VREF_HIGH | VREF_A2 | 13);//3,28
   delay_us(385);
   setup_vref(VREF_low | VREF_A2 | 15);//3,125
   delay_us(333);
   setup_vref(VREF_HIGH | VREF_A2 | 11);//2,96
   delay_us(104);
   setup_vref(VREF_LOW | VREF_A2 | 14);//2,916
   delay_us(199);
   setup_vref(VREF_HIGH | VREF_A2 | 10);//2,81
   delay_us(190);
   setup_vref(VREF_LOW | VREF_A2 | 13);//2,708
   delay_us(92);
   setup_vref(VREF_HIGH | VREF_A2 | 9);//2,656
   delay_us(267);
   setup_vref(VREF_LOW | VREF_A2 | 12);//2,5
   delay_us(257);
   setup_vref(VREF_HIGH | VREF_A2 | 7);//2,34
   delay_us(84);
   setup_vref(VREF_LOW | VREF_A2 | 11);//2,29
   delay_us(167);
   setup_vref(VREF_HIGH | VREF_A2 |6);//2,18
   delay_us(165);
   setup_vref(VREF_LOW | VREF_A2 | 10);//2,08
   delay_us(82);
   setup_vref(VREF_HIGH | VREF_A2 |5);//2,03
   delay_us(245);
   //ATÉ AQUI 180°
   
   setup_vref(VREF_LOW | VREF_A2 | 9);//1,87
   delay_us(245);
   setup_vref(VREF_HIGH | VREF_A2 | 3);//1,718
   delay_us(82);
   setup_vref(VREF_LOW | VREF_A2 | 8);//1,667
   delay_us(166);
   setup_vref(VREF_HIGH | VREF_A2 |2);//1,5625
   delay_us(168);
   setup_vref(VREF_LOW | VREF_A2 | 7);//1,4583
   delay_us(85);
   setup_vref(VREF_HIGH | VREF_A2 | 1);//1,4063
   delay_us(260);
   setup_vref(VREF_LOW | VREF_A2 | 6);//1,25
   delay_us(365);
   setup_vref(VREF_LOW | VREF_A2 | 5);//1,0417
   delay_us(398);
   setup_vref(VREF_LOW | VREF_A2 | 4);//0,8333
   delay_us(455);
   setup_vref(VREF_LOW | VREF_A2 | 3);//0,625
   delay_us(572);
   setup_vref(VREF_LOW | VREF_A2 | 2);//,04167
   delay_us(1330);
   setup_vref(VREF_LOW | VREF_A2 | 1);//0,2083
   delay_us(1330);
   //Até aqui 270°
   
   setup_vref(VREF_LOW | VREF_A2 | 2);//,04167
   delay_us(572);
   setup_vref(VREF_LOW | VREF_A2 | 3);//0,625
   delay_us(455);
   setup_vref(VREF_LOW | VREF_A2 | 4);//0,8333
   delay_us(398);
   setup_vref(VREF_LOW | VREF_A2 | 5);//1,0417
   delay_us(365);
   setup_vref(VREF_LOW | VREF_A2 | 6);//1,25
   delay_us(260);
   setup_vref(VREF_HIGH | VREF_A2 | 1);//1,4063
   delay_us(85);
   setup_vref(VREF_LOW | VREF_A2 | 7);//1,4583
   delay_us(168);
   setup_vref(VREF_HIGH | VREF_A2 |2);//1,5625
   delay_us(166);
   setup_vref(VREF_LOW | VREF_A2 | 8);//1,667
   delay_us(82);
   setup_vref(VREF_HIGH | VREF_A2 | 3);//1,718
   delay_us(245);
   //Até aqui 360°
}

Hardware: A saída do módulo é feita no pino RA2/AN2, no caso do 16F628A corresponde ao pino 1 do CI. É preciso lembrar que o PIC não tem capacidade de corrente suficiente para a maioria das aplicações e portanto é preciso utilizar um driver ou buffer na saída para alimentar a sua carga. Se você não precisa de muita corrente, um simples transistor tipo BC ou BD com a base ligada através de um resistor de alto valor ao pino RA2 deve ser suficiente. Se o seu projeto necessita de mais corrente é mandatório o uso de mais estágios de amplificação filtros que podem melhorar a forma de onda, reduzindo as componentes harmônicas de alta frequência que sempre estão presentes quando se faz chaveamentos desse tipo.

A senoide gerada possui um nível DC incorporado, já que só podemos excursionar o sinal gerado pelo PIC entre 0V e 5V. Isso pode ser contornado utilizando fontes simétricas no circuito de amplificação.

Utilização: Para utilizar o circuito basta compilar o código, gravar no chip, uma vez alimentado, o circuito já começa a funcionar e fica gerando o sinal eternamente. Para melhorar esse projeto O primeiro refinamento é incluir uma interface com LCD e pelo menos dois botões para visualizar e fazer a seleção da frequência de forma mais simples e não ter que ficar recompilando toda vez que precisar fazer alguma mudança. Isso vai exigir uma abordagem diferente também no código. As constantes usadas na rotina delay_us()são transformadas em variáveis calculadas em uma rotina à parte que irá receber os argumentos via interface.

Quando chegar nesse ponto, já fica ridiculamente fácil incluir também outras formas de onda e construir um pequeno gerador de funções.

Na parte 2, vou mostrar as imagens obtidas com o código acima no osciloscópio e a análise no domínio da frequência da senoide gerada. Gostou, não gostou, achou um erro no projeto? deixe um comentário.

sexta-feira, 12 de junho de 2015

Carro movido a água - A falácia

Resolvi escrever esse post depois de ver inúmeros vídeos circulando pela internet, primeiro de "inventores populares" oferecendo a oportunidade de rodar milhares de quilômetros com o seu automóvel utilizando apenas 1 litro de água. Logo esses videos caseiros viraram matéria de jornais, daqueles bem ruizinhos mesmo, pois como vou mostrar é fácil desmascarar esse charlatanismo. Por fim, já tem gente oferecendo comercialmente os kits de conversão de fácil instalação no seu automóvel.

ÁGUA OU HIDROGÊNIO - O MILAGRE DA HIDRÓLISE - OU AQUELA EXPERIÊNCIA QUE VOCÊ FEZ NA QUINTA-SÉRIE.
Existe uma pequena confusão sobre o tal carro movido a água que algumas pessoas não se dão conta. Apesar de ser abastecido com água, o combustível no caso é o gás Hidrogênio H2, formado por duas moléculas do átomo de Hidrogênio. O gás é obtido fazendo a eletrólise da água, processo no qual ao passar uma corrente elétrica por uma solução aquosa, quebramos a molécula de água em seus componentes básicos Hidrogênio e Oxigênio. É exatamente como aquelas experiências que você fazia na quinta série, utilizando alguns fios, algumas pilhas, tubos de ensaio, água e sal. 

A FALÁCIA.
Para desmascarar de uma vez por todas essa falácia, vou usar como base um vídeo no youtube. Observe nos comentários do vídeo que realmente existem pessoas que acreditam que o feito do cidadão é possível e que quem não acredita ou argumenta contra é considerado "limitado" por achar que as leis da física não podem ser mudadas, blá, blá, blá. Ou ainda aqueles que dizem que essa tecnologia é antiga e todos que de certa forma a reinventam são mortos... conspiração.




Voltando ao vídeo. Perceba que é dito que:
O carro rodou 1.000 km com 1,5 litros de água destilada.

Agora, para efeitos de simplificação das contas, vou assumir que:
1) O Hidrogênio foi obtido DE GRAÇA, nenhum custo financeiro ou energético foi necessário para a sua obtenção.
2) O veículo usado como base será o mesmo do vídeo, que eu identifiquei como sendo um Chery S-18.
3) Não existe atrito, desgaste, forças resistivas ou outras que possam roubar potência, ou seja, toda energia da queima dos combustíveis citados será aproveitada para o MOVIMENTO do veículo e que o gasto de energia para deslocar o veículo é o mesmo independente do combustível utilizado (o que parece bem obvio).


O primeiro ponto que eu vou mostrar é que o rendimento do hidrogênio não é assim tão incrível a ponto de 1 litro de água ser capaz de mover um veículo por uma distância tão grande. Vou mostrar ainda que não é preciso ser um gênio para resolver esse problema, todas os cálculos são resolvidos com regra-de-três.

A QUÍMICA DO PROCESSO.
Não confundir átomos com moléculas. O gás queimado é o gás hidrogênio (H2) que é uma molécula formada por DOIS átomos de hidrogênio.

Uma molécula de água, a famosa H2O tem 1 átomo de oxigênio e 2 átomos de hidrogênio. 
Como a densidade de água é de 1:1 sabemos que 1 litro de água pesa exatamente 1 kg, mas a maior parte da massa que compõe a água se deve ao Oxigênio. Para achar quantas gramas de hidrogênio é possível extrair de um litro de água precisamos fazer algumas contas.
Se você não se lembra do segundo grau, pode consultar o São Google e confirmar que:

1 mol de água pesa 18 gramas (16 g de Oxigênio e 2 g de Hidrogênio)
em 1 litro (1000 gramas) de água teremos 62,5 mols de moléculas o que dá também 62,5 mols de hidrogênio (gás).

O hidrogênio tem massa molecular de 2,02 gramas/mol, logo em 1000 litro de água é possível extrair 125 gramas de H2.

Outro dado tabelado é a energia calorífica do H2 que é de 120.10^6 Joules/kg.
Logo no nosso litro de água, se queimarmos todo o H2 disponível, será possível extrair 15.10^6 Joules.  

Legal, então sabemos agora que em 1 litro de água, podemos extrair no máximo 15.10^6 J de energia (isso sem levar em consideração que foi necessário gastar energia para extrair o hidrogênio da água). Mas será essa quantidade suficiente para mover um carro popular por 1.000 km? para responder essa pergunta e mostrar que tudo é uma farsa, vamos ver alguns dados da gasolina e do veículo.

A GASOLINA
A gasolina tem densidade de 0,73g/L ou seja, 1 litro de gasolina pesam 730 gramas.
Outro dado (tabelado) é a energia calorífica da gasolina que é de 42,5.10^6 J/kg.

Considerando os dados que obtive do Chery S-18, o mais otimista de todos foi o que considerava o consumo do automóvel como sendo de 15,1 km/L de gasolina na estrada.

Com o consumo médio de 15,1 km/L para rodar os 1.000 km seriam necessários 66,22 litros de gasolina. E esse volume de gasolina corresponde a 48,33 kg do combustível (regra de três com a densidade).

Então se 1 kg de gasolina fornecem 42,5 .10^6 J , os 48,33 kg necessários para percorrer os 1.000 km fornecem 2.054,03 .10^6 Joules.

Ou seja, fazendo todas as simplificações possíveis, seria necessário 2.054 .10^6 Joules para mover o carro por 1.000 km, que é uma quantidade de energia bem maior (136 vezes maior) que a fornecida pela queima do hidrogênio presente em 1 litro de água, que como vimos, é de apenas 15 .10^6 Joules.

Além disso, a simplificação 1) diz que não gastamos nada para obter o hidrogênio é a que mais pesa, uma vez que para se extrair o hidrogênio de água, vamos gastar a mesma quantidade de energia que ele vai devolver em sua queima (novamente, desprezando todo tipo de perda, resistência ou atrito.)

OUTROS CASOS:
Se você procurar mais, vai ficar ainda com mais raiva vendo que a quantidade de pessoas que tem propagando essas mentiras. Nesse outro, ainda mais mentiroso, eles vão além e dizem que o carro rodou 2.000 km com menos de 1 litro de água. Não sendo o bastante, ainda chamaram uns calouros de engenharia elétrica, pra corroborar a mentira. É tanta desinformação que reparem o que a repórter fala à partir dos 2:25 min do vídeo.... "...em apenas uma molécula de H2O são várias partículas partículas do gás que se transformam em combustível". Nota-se total desconhecimento de química básica, confundindo termos como partículas (átomos) e moléculas. Como vimos, cada molécula de H20 fornece uma (e não várias) moléculas de H2 que é o combustível.




Conclusão. Não compre kit de conversão seja chines, americano ou brasileiro. Não acredite em quem disse que teve resultado. Não compartilhe tudo que você lê ou escuta sem antes fazer o mínimo de verificação, jornalistas dificilmente sabem algo (principalmente ciência) com o mínimo de profundidade necessária, então como se pode ver pelos vídeos, é muito fácil enganá-los e convence-los a fazer propaganda gratuita de algo que beira o estelionato. Lembre-se a burrice se propaga com uma velocidade muito maior que a sabedoria.

Fontes:
http://www.carrosnaweb.com.br/fichadetalhe.asp?codigo=1213
http://www.antoniolima.web.br.com/arquivos/podercalorifico.htm

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