16 de dez de 2012

PK2Lab - Como adquirir sua placa.

E ai galera, mais um ano que finda, com muitas coisas boas para serem comemoradas e muitas histórias a serem contadas, para mim particularmente foi uma ano de conquistas e abertura de novos horizontes espero que todos possam compartilhar do mesmo sentimento!

Apresento a vocês o novo site da minha empresa JL Audio Manutenção Eletrônica, através do qual serão comercializados os produtos por mim desenvolvidos, entre eles a placa PK2Lab e o Curso de microcontroladores PIC.

 

Site

 

Todo o processo de compra pode ser efetuado pelo próprio site, onde é possível ainda simular o valor de frete.

Para compras em maior quantidade, empresas  ou instituições de ensino, enviar  e-mail para contato@jlaudioeletronica com o assunto PK2Lab, para ter acesso a descontos especiais.

Para facilitar o acesso do hardware ao aluno ou hobbysta, o valor da placa pode ser parcelado em até 18 vezes no cartão de crédito, tornando a tecnologia acessível a todos.

Tire seus projetos da tela do PC… crie realmente aplicações reais em tempo real !

É isso ai, grande abraço a todos, um feliz Natal e um próspero Ano Novo!

Em 2013 teremos vários projetos bacanas envolvendo muitos periféricos interessantes… até breve!

Jean Carlos

PK2Lab Team! @2012

 

27 de out de 2012

Expansão de I/O - 74HC595

Pessoal, continuando com os posts relacionados aos CI’s de expansão de I/O, apresento a vocês o CI 74HC595, tal como o CI 74LS164, consiste em um conversor serial paralelo de 8 bits (Shift Register) porém com características que ao meu ver o tornam muito mais interessante que o 74164.

74595

Uma das características que o tornam tão especial é o fato de possuir dois registradores para manuseio dos dados, sendo:

  • Shift Register
    Armazena as informações transferidas serialmente como registrador temporário, a cada pulso de clock no pino SRCLK este registrador é carregado bit a bit conforme o nível lógico disponível no pino SER (Entrada Serial).
  • Storage Register
    Este registrador é carregado com as informações disponíveis no registrador  Shift Register quando o pino RCLK é pulsado com um nível lógico alto (Latch), ou seja, podemos manusear o envio dos bits um a um e ao término habilitamos o latch. Isto nos trás uma vantagem enorme na simplificação do hardware, pois no caso do uso do 74164 teríamos que providenciar um mecanismo eletrônico que durante a atualização dos dados apagasse o display para evitar que a serialização fosse percebida.

Além desses dois registradores, o 74595 possui um pino que habilita a operação do mesmo (OE), sendo que quando garantimos um nível alto neste pino temos todas as saídas configuradas como tri-state, ou seja, não drena e nem fornece corrente alguma ao circuito, portando fica configurada como alta impedância.

Outra característica importante é que este CI é capaz de trabalhar com cargas de +- 6ma sendo suficiente para por exemplo, alimentarmos pequenos leds para uso em painéis de IHMs diretamente pelos I/Os do CI.

Lógica de operação:

Diagrama temporal

Aqui podemos observar o funcionamento deste CI passo a passo!


Exemplo de uso

Para exemplificar o uso deste componente, vamos criar uma aplicação junto a PK2Lab, que consiste num contador de 0 à 99 com o uso de dois displays de sete segmentos conectados aos shift registers 74595 em cascata (Daisy Chain), assim podemos criar posteriormente projetos maiores como por exemplo um relógio com horas, minutos e segundos… tendo apenas como limite a sua imaginação!

Esquema:

Esquema

Podemos observar que além dos pinos de alimentação, são utilizados apenas 3 pinos de I/O para controlar os dois displays, e mesmo aumentando a quantidade de CIs, continuamos utilizando apenas 3 pinos, esta é a grande vantagem de se utilizar a comunicação serial para transferência de dados.

DSC01053

Poderíamos ainda ter utilizado os pinos de Reset e Operational Enable para controlar mais algumas funcionalidades, porém no exemplo não foram implementadas ficando estas a cargo do leitor caso queira implementar.


Software

A parte de software deste exemplo já foi explorado anteriormente nos outros posts, apenas temos o acréscimo de um pino de latch que fará com que os dados previamente setados no Shift Register sejam transferidos para os pinos do CI acionando os segmentos dos displays.

Uma prática interessante que podemos adotar ao construir software é o cuidado utilizado ao criar nomes de variáveis dentro de funções, por exemplo, podemos criar uma função chamada Display() e utiliza-lá em muitos projetos com grande facilidade, basta apenas que as variáveis internas desta função utilizem características próprias da função de origem, neste exemplo podemos observar que foi criada a função SN74HC595() e todas as variáveis internas desta função começam com SN74HC595_ seguido do nome da variável propriamente dito, a primeira vista temos a impressão de que o programa fica carregado, porém, facilita muito o inter-relacionamento das variáveis como um todo.

Outro ponto interessante é a chamada recorrente de funções, na linha abaixo podemos ver que chamamos a função display() duas vezes dentro da função SN74HC595().

SN74HC595(Display(Unidade), Display(Dezena));

Com esta única linha de comando montamos os dois bytes referentes aos dígitos de dezena e unidade e enviamos serialmente essas informações.

/******************************************************************************

                      JL Audio Manutenção Eletrônica

Data: 10/2012
Autor: Jean Carlos
Projeto: Registrador de deslocamento SN74HC595
Microprocessador: PIC18F4520
Clock do processador: 8MHz
Estação de desenvolvimento: PK2Lab V 1.1
Compilador: MikroC PRO V 4.60.0.0
Versão atual: 1.0
Descrição:

          Demonstração do uso de shift register para expansão de I/O


*******************************************************************************/
// Inicializações do programa

// Configuração do LCD da placa PK2Lab V.1.1

sbit LCD_RS at RB2_bit;
sbit LCD_EN at RB3_bit;
sbit LCD_D4 at RB4_bit;
sbit LCD_D5 at RB5_bit;
sbit LCD_D6 at RB6_bit;
sbit LCD_D7 at RB7_bit;

sbit LCD_RS_Direction at TRISB2_bit;
sbit LCD_EN_Direction at TRISB3_bit;
sbit LCD_D4_Direction at TRISB4_bit;
sbit LCD_D5_Direction at TRISB5_bit;
sbit LCD_D6_Direction at TRISB6_bit;
sbit LCD_D7_Direction at TRISB7_bit;

//******************************************************************************
// Variáveis Globais

short Contador = 0;       // Variável para contagem de 0 a 99.
short Dezena   = 0, Unidade = 0;

#define Latch      PORTC.B0
#define Clock      PORTC.B1
#define Ser_Out  PORTC.B2

//******************************************************************************
// Rotinas Auxiliares
//******************************************************************************
// Driver de display de 7 segmentos, número a ser impresso é passado como
// argumento da função.

unsigned char Display(unsigned char no)
{
    unsigned char Pattern;
    unsigned char SEGMENT[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,
                                                0x7D,0x07,0x7F,0x6F};

    Pattern = SEGMENT[no];             // Segmento a retornar
    return (Pattern);
}

void SN74HC595(char SN74HC595_Display1, char SN74HC595_Display2)
{
short SN74HC595_Aux;                 // Variável local de controle do laço for
for(SN74HC595_Aux = 0; SN74HC595_Aux < 8; SN74HC595_Aux ++)
    {
     if( SN74HC595_Display1 & 0b10000000)  Ser_Out = 1;// Máscara o sétimo bit
     else Ser_Out = 0;                      // e verifica se é zero ou um.
     SN74HC595_Display1 = SN74HC595_Display1 << 1; // Rotaciona o próximo bit
     Clock = 1;                                // Pulsa o clock para envio do bit
     Delay_us(1);
     Clock = 0;
    }
Ser_Out = 0;                               // Mantém a linha de dados em nivel baixo
 
  for(SN74HC595_Aux = 0; SN74HC595_Aux < 8; SN74HC595_Aux ++)
    {
     if( SN74HC595_Display2 & 0b10000000)  Ser_Out = 1;// Máscara o sétimo bit
     else Ser_Out = 0;                   // e verifica se é zero ou um.
     SN74HC595_Display2 = SN74HC595_Display2 << 1; // Rotaciona o próximo bit
     Clock = 1;                             // Pulsa o clock para envio do bit
     Delay_us(1);
     Clock = 0;
    }
Ser_Out = 0;                             // Mantém a linha de dados em nivel baixo
 
Latch = 1;
Delay_us(1);
Latch = 0;
}

 

//******************************************************************************
//Rotina Principal

void main()
{
TRISA    = 0b00000000;
PORTA  = 0b00000000;
TRISB    = 0b00000000;
PORTB  = 0b00000000;
TRISC    = 0b00000000;
PORTC  = 0b00000000;
TRISD    = 0b00000000;
PORTD  = 0b00000000;
TRISE    = 0b00000000;
PORTE  = 0b00000000;
ADCON1 = 0X0F;            // Entradas digitais.
OSCCON.B5 = 1;            // Ajusta oscilador interno para 8MHz
OSCCON.B4 = 1;            // Ajusta oscilador interno para 8MHz

Lcd_Init();
Lcd_Cmd(_Lcd_Cursor_Off);
Lcd_Cmd(_LCD_CLEAR);
Lcd_Out(1,1,"***  PK2Lab  ***");
Lcd_Out(2,1,"Shift  SN74HC595");
Sound_Init(&PORTE,0);
Sound_Play(1000,200);
Delay_ms(100);
Sound_Play(1000,200);

while(1)
{
Dezena  = Contador / 10;
Unidade = Contador % 10;
SN74HC595(Display(Unidade), Display(Dezena));
Delay_ms(200);
Contador ++;
if(Contador == 100)
   {
   Contador = 0;
   Sound_Play(1000,200);
   Delay_ms(100);
   Sound_Play(1000,200);
   Delay_ms(100);
   Sound_Play(1000,200);
   while(1){};          // Trava o programa até ser pressionado o reset
   }
  
}//while(1)
}//main


Download do código

Abaixo podemos observar os sinais de controle que foram capturados no analisador lógico, o primeiro sinal é referente ao pino de DADOS, o segundo é o clock e por fim temos o pino de habilitação de transferência(Latch) que é onde efetivamente carregamos os novos valores nos displays.

Analisando as informações podemos ver o número “00” no display, onde os dois pulsos baixos iniciais correspondem aos segmentos “g”  e “.” (ponto decimal) apagados e os outros segmentos acesos.

Analisador

Protótipo montado

Montagem

 

Vídeo do projeto

Bom pessoal, é isso, grande abraço a todos e ótimos projetos!!!

12 de set de 2012

Expansão de I/O - 74HC164

 

Dando prosseguimento ao último post, venho apresentar um componente bem conhecido dos entusiastas da eletrônica digital, trata-se do circuito integrado SN74HC164, um conversor de dados serial para paralelo de 8 bits também conhecido por registrador de deslocamento ou apenas shift register, sendo este componente facilmente encontrado no mercado brasileiro.

ic164(1)

SN74HC164

Este Ci possui um pino para entrada de dados, sendo esta entrada disponibilizada por meio de uma porta AND (entradas A e B), o que facilita o controle de entrada dos dados.

Lógica

Além dos pinos de entrada de dados, A e B, podemos encontrar um pino para entrada do sinal de clock, podendo operar até 25MHz com a alimentação de 5V, um pino de /CLR que recebe a função de limpar todas as saídas do shift register além dos 8 pinos de saída, pinos estes que podem fornecer uma corrente máxima de 25mA o que já é suficiente para acender de forma eficiente um LED, porém devemos atentar para o fato da corrente máxima admissível entre VDD e VSS que é de 50mA não seja ultrapassada.

Lógica de operação:

TimeChart

Como podemos observar, este CI não possui um pino para controle de ativação das saídas, ou seja, assim que enviarmos o conteúdo dos bits serialmente, estas informações aparecerão nos pinos de saída de forma indesejável, podendo causar danos ao hardware ou mão funcionamento do mesmo. Uma alternativa ao SN74HC164 é o circuito integrado CD4094 que abordaremos em um próximo post.


Exemplo de Uso

Neste exemplo vamos utilizar o SN74HC164 para adicionar 8 LEDs à placa PK2Lab utilizando apenas 2 pinos do microcontrolador, neste caso não será utilizado o pino de reset e o mesmo deverá ser conectado ao VCC, este recurso seria interessante no caso de controlarmos displays de 7 segmentos onde teríamos a possibilidade de efetuar o apagamento de todos os dígitos simultaneamente ao aplicarmos um nível lógico baixo no pino 9.

Esquema

Caso seja necessário aumentar a quantidade de saídas podemos interligar mais de um shift register em cascata, basta interligarmos o pino 13 (MSB) ao pino de entrada de dados do próximo SN74HC164, assim sucessivamente.

Esquema 2

Um exemplo de utilização em cascata deste componente pode ser visto na placa DE-DP011, comercializada pela Sure Electronics, que consiste de um conjunto de cinco shift registers serializados para a apresentação de 40 Leds.

Sure Foto

Abaixo podemos observar o funcionamento desta placa em uma IHM, fornecendo indicação visual sobre distância e tensão de bateria.

Esquema DE-DP011

Para nosso exemplo utilizaremos apenas um CI e 8 Leds para simular um PORT auxiliar, para isto vamos usar o primeiro esquema apresentado neste post.

Foto_1


Software

O Software desenvolvido para este exemplo consiste basicamente de uma função que irá transmitir os dados a serem exibidos no “PORTAux” e uma rotina principal que incrementa uma variável contador a cada 100ms, mostrando o valor de forma binária nos Leds conectados ao SN74HC164.

Para a utilização de mais de um CI cascateado, basta efetuar a chamada da função na mesma proporção de CIs utilizados.

/******************************************************************************

                      JL Audio Manutenção Eletrônica

Data: 09/2012
Autor: Jean Carlos
Projeto: Registrador de deslocamento SN74HC164
Microprocessador: PIC18F4520
Clock do processador: 8MHz
Estação de desenvolvimento: PK2Lab V 1.1
Compilador: MikroC PRO V 4.60.0.0
Versão atual: 1.0
Descrição:

          Demonstração do uso de shift register para expansão de saídas


*******************************************************************************/
// Inicializações do programa

// Configuração do LCD da placa PK2Lab V.1.1

sbit LCD_RS at RB2_bit;
sbit LCD_EN at RB3_bit;
sbit LCD_D4 at RB4_bit;
sbit LCD_D5 at RB5_bit;
sbit LCD_D6 at RB6_bit;
sbit LCD_D7 at RB7_bit;

sbit LCD_RS_Direction at TRISB2_bit;
sbit LCD_EN_Direction at TRISB3_bit;
sbit LCD_D4_Direction at TRISB4_bit;
sbit LCD_D5_Direction at TRISB5_bit;
sbit LCD_D6_Direction at TRISB6_bit;
sbit LCD_D7_Direction at TRISB7_bit;

//******************************************************************************
// Variáveis Globais

unsigned short contador = 0; // Variavel para contagem de 0 a 255.
char txt[4];                 // Variavel para conversão de dados.

//******************************************************************************
// Rotinas Auxiliares

#define Clear    PORTC.B0
#define Clock    PORTC.B1
#define Ser_Out  PORTC.B2

void SN74HC164(char SN74HC164_Value)
{
short SN74HC164_Aux;                 // Variável local de controle do laço for
for(SN74HC164_Aux = 0; SN74HC164_Aux < 8; SN74HC164_Aux ++)
    {
     if( SN74HC164_Value & 0b10000000)  Ser_Out = 1;  // Máscara o sétimo bit…
     else Ser_Out = 0;                      // e verifica se é zero ou um.
     SN74HC164_Value = SN74HC164_Value << 1;        // Rotaciona o próximo bit
     Clock = 1;                                 // Pulsa o clock para envio do bit
     Delay_us(1);
     Clock = 0;
    }
Ser_Out = 0;                                 // Mantém a linha de dados em nível baixo
}

//******************************************************************************
//Rotina Principal

void main()
{
TRISA = 0b00000000;
PORTA = 0b00000000;
TRISB = 0b00000000;
PORTB = 0b00000000;
TRISC = 0b00000000;
PORTC = 0b00000000;
TRISD = 0b00000000;
PORTD = 0b00000000;
TRISE = 0b00000000;
PORTE = 0b00000000;
ADCON1 = 0X0F;            // Entradas digitais.
OSCCON.B5 = 1;            // Ajusta oscilador interno para 8MHz
OSCCON.B4 = 1;            // Ajusta oscilador interno para 8MHz

Lcd_Init();
Lcd_Cmd(_Lcd_Cursor_Off);
Lcd_Cmd(_LCD_CLEAR);
Lcd_Out(1,1,"***  PK2Lab  ***");
Lcd_Out(2,1,"Shift  SN74HC164");
Delay_ms(1000);
Lcd_Out(2,1,"Contador:       ");


while(1)
{
ByteToStr(Contador, txt);   // Converte o byte numa string para impressão no LCD
Lcd_Out(2, 11, txt);
SN74HC164(Contador);      // Envia os dados para o SN74HC164
Delay_ms(100);                 // Delay entre incrementos
Contador ++;                     // Incremento da variável em uma unidade
}//while(1)
}//main

//**********************************************************************************************

Abaixo podemos observar os níveis lógicos capturados através do analisador lógico da própria PK2Lab. O pino de dados está conectado ao CH1 e o pino de clock está conectado ao CH2. Nesta captura podemos observar o valor do contador igual a 1.

Logic Analiser

Na tela abaixo podemos verificar a captura do contador igual a 128, podemos notar que o formato de envio dos dados é enviando primeiro o bit menos significativo (LSB).

Logic Analiser_128

Bom pessoal, segue o vídeo do projeto em funcionamento, qualquer dúvida ou sugestão deixem um comentário pois será muito bem vindo!

Código do projeto

2 de ago de 2012

Expansão de I/O - 74HC165

Quando precisamos utilizar um grande número de pinos de I/O em um microcontrolador e não os dispomos, podemos fazer uso de vários recursos, dentre eles a técnica de multiplexação de pinos ou a utilização de registradores de deslocamento.

A última técnica foi utilizada neste projeto com o intuito de demonstrar como conectar cinco teclas e um encoder rotativo (potenciômetro sem fim) ao microcontrolador utilizando apenas 3 pinos de I/O.

74HC165

74HC165

O circuito integrado 74HC165, consiste de um conversor paralelo serial de 8 bits que pode funcionar em uma frequência máxima de operação de 10MHz, possui dois pinos de clock, sendo um deles atribuído para inibição do mesmo possui ainda, um pino responsável pelo carregamento  das informações contidas em suas entradas para um latch interno que é transferido posteriormente de forma serial a cada pulso de clock.

Portanto, para transferirmos a informação contida em suas entradas, precisamos primeiramente carregar estas informações e  depois aplicar 8 pulsos de clock.

Neste exemplo conectamos um encoder rotativo com push-botton e mais 4 chaves tact, onde a cada 1ms obtemos seus estados que ficam armazenados na variável Teclas_8bits.

Encoder

O esquema abaixo utiliza um CI 74HC165 conectado ao hardware escolhido.

Esquema

Podemos efetuar a conexão de mais de um CI 74HC165 para obtermos um maior número de I/Os disponíveis, no exemplo abaixo podem se ver a utilização de dois CIs contendo o total de 16 chaves tacts.

2x74hc165


Software

O software responsável pela leitura do 74HC165 consiste basicamente de um loop for para deslocar os bits e armazenar os valores na variável que irá conter os estados das entradas, neste processo efetuamos o uso de lógica digital para trabalhar os bits da variável, isto é feito dentro da rotina SN74165_8bits().

unsigned char SN74165_8bits()
{
char count;
char bitval;
char teclas_8bits = 0;
Clock = 1;
Load = 0;
Load = 1;
Clock = 0;
for(count=0; count<8; count++)
   {
    bitval = Ser_in;
    teclas_8bits |= (bitval << (7-count));
    Clock = 1;
    Clock = 0;
   }
return(teclas_8bits);
}

Na linha abaixo podemos observar a aplicação de diversos recursos disponibilizados pelo compilador, para que seja possível maximizar a eficiência do código gerado, sendo a utilização de agrupamentos de operadores e a análise de mais de uma condição na mesma linha de comando.

teclas_8bits |= (bitval << (7-count));


Análise dos sinais de controle

Utilizando a ferramenta de Analisador Lógico disponível na placa PK2Lab podemos observar o funcionamento do código e obter os tempos de clock e load aplicados no CI.

Captura 1


Nesta tela acima podemos observar os sinais Load no canal 1, o sinal Clock no canal 2 e a resposta do CI 74HC165 através do sinal Ser_in no canal 3, neste caso os bits dos dois últimos pinos estão em nível alto.

Captura 2

Nesta tela podemos ver o primeiro e último pino em nível alto.

Na aba de trigger, o ajuste [ Ch1=\ ] indica  que o sinal começará a ser capturado quando o pino Load, passar do nível alto para o nível baixo, ou seja, o sinal de trigger ou disparo é sensível a borda de descida.


DSC00948

Código do projeto

17 de jul de 2012

Relógio LCD com números grandes

Durante o desenvolvimento do projeto de um robô de sumô para a disciplina de projeto integrado II do curso de Engenharia de Controle e Automação, me deparei com a necessidade de mostrar informações numa tela de LCD caractere de 20X4, porém uma grande limitação destes displays facilmente encontrados a venda no comércio é o tamanho efetivo do caractere.

Pensando nisto busquei um artigo que havia me deparado na internet, em que o programador utilizava mais de um caractere para a construção dos dígitos a serem exibidos. O artigo em questão pode ser visto aqui.

Utilizando a técnica descrita anteriormente, aqui mesmo neste blog  foram criados alguns caracteres especiais que formam os dez algarismos utilizados para a criação deste relógio que apresento hoje a vocês.

Caracteres Especiais

A junção de quatro destes caracteres especiais formam um numeral decimal que ocupa o lugar de seis caracteres do display com exceção dos dois últimos caracteres que formam os pontos para divisão dos dígitos do relógio.

Para a base de tempo utilizamos o RTC PCF8583 contido na placa PK2Lab, que nos retorna de forma serial as informações referentes a hora, minutos e segundos e ainda gera um sinal de clock de 1Hz  para a atualização dos dados no display a cada segundo.

O microcontrolador escolhido para este exemplo é o PIC18F4520, por ser o microcontrolador escolhido pela Microchip como substituto natural ao PIC16F877 sendo a pinagem totalmente compatível com os microcontroladores da linha 16F, portanto os pinos de comunicação I2C também seguem esta regra, consequentemente a placa tem que estar com os jumpers na posição 16F e não na posição 18F como usual.

1

Os pinos de enables dos leds devem estar dasabilitados para não influenciarem na comunicação serial I2C.

O programa foi desenvolvido utilizando a ferramenta MikroC PRO e foi baseado no código exemplo do RTC que acompanha a placa, apenas foram feitas algumas modificações para a inserção do código que gera os caracteres maiores no LCD.

Para este projeto foi utilizado o oscilador interno de 8MHz do microcontrolador, é importante observar que por default o microcontrolador opera com uma frequência de 1MHz e é necessário que sejam setados dois bits do registrador OSCCON para configurar a frequência de 8MHz.

OSCCON.B5 = 1;            // Ajusta oscilador interno para 8MHz
OSCCON.B4 = 1;            // Ajusta oscilador interno para 8MHz

Foram criadas algumas funções para conversão e exibição dos números no LCD.

void Caracter_Especial()         

Cria os caracteres especiais na CGRAM do display LCD

void Converte_Numeros(char numero,char lin, char col)

Efetua a conversão dos numeros do RTC para os digitos grandes

void Display_Time()

Mostra os digitos na tela do display LCD

void ZERO(char linha, char coluna)

Prepara os caracteres especias para exibição dos digitos grandes

void PONTOS(char linha, char coluna)

Prepara os caracteres especiais para exibição dos pontos


O resultado pode ser visto abaixo:

DSC00926

 

 

Código do projeto

19 de jun de 2012

Conversor Digital Analógico R2R

 

Conversores Digitais

Durante muito tempo fiquei intrigado com a eletrônica no que diz respeito a conversão de grandezas entre o mundo real e o mundo digital. No mundo real, as grandezas podem ser analisadas de forma contínua, já no mundo digital, onde temos a representação de grandezas em formado binário (temos apenas bits que podem valer 0 ou 1) estas grandezas devem ser discretizadas, ou seja, tanto o tempo (amostragem) quanto a amplitude (quantização) devem ser analisados.

O processo de amostragem do sinal consiste em obter instantâneamente o valor do sinal a ser processado em intervalos regulares, sendo que a frequência destes intervalos definem a taxa de amostragem do conversor.

Para que a resposta de um conversor digital possa ser substâncialmente eficiente em relação a entrada (conversor AD) ou a saída (conversor DA), se faz necessário que se respeite o teorema de Nyquist, que diz que a frequência de amostragem deve ser de pelo menos duas vezes maior que a maior frequência a ser amostrada. Um exemplo prático da aplicação desta teoria pode ser observada em aparelhos reprodutores de CD em que normalmente se informa a taxa de seu conversor interno que é de 44100Hz, ou seja mais de 2 vezes a maior frequência audível ao ser humano que está na faixa dos 20000Hz.

Harry Nyquist (1889–1976)

Harry Nyquist (1889–1976)


Conversor DA R2R

Neste projeto vamos efetuar a implementação de um conversor Digital Analógico utilizando um método muito eficiente de conversão que utiliza apenas dois valores de resistores, facilitando a construção e calibração do mesmo. Este conversor pode ser montado em um protoboard resistor por resistor ou comprado em um único package já contendo todos os resistores devidamente ajustados, este componente é conhecido como rede R2R. (R2R network)

Bourns-4610X-R2R-103LF

A placa PK2Lab, possui conectores de expansão que possibilitam a conexão de placas externas, como por exemplo a placa fornecida pela Mikroelektronica que consiste um em conversor DA R2R completo que pode fornecer uma corrente máxima de 20mA em sua saída.

Placa

Nesta placa podemos observar a utilização de resistores de dois valores distintos, sendo 47K e 100K representando respectivamente R e 2R conforme o esquema abaixo:

Esquema

Pode-se observar ainda a utilização de um amplificador do tipo Rail-to-Rail da Microchip operando como buffer de saída, está etapa pode ser obtida à partir de um simples amplificador operacional.

buffer

A vantagem de se utilizar amplificadores do tipo Rail-to-Rail, é o fato de a saída do sinal poder trabalhar praticamente no limite dos níveis de alimentação do operacional, isto é muito bem vindo quando trabalhamos com tensões de 3V por exemplo.

Até aqui temos o nosso hardware do conversor DA implementado, e para demonstrar o funcionamento do mesmo na prática, vamos gerar uma forma de onde senoidal podendo servir de base para um gerador de funções digital.

Para tanto, vamos utilizar uma tabela no microcontrolador que conterá os valores a serem aplicados na rede R2R do conversor DA para obtenção da senoide.

Esta tabela pode ser gerada contendo todos os pontos que formam a senoide completa de 0 a 2 pi de forma direta ponto a ponto, como mostrado no programa picseno1, ou utilizando a função de cosseno para gerar metade da senoide, sendo a outra metade é obtida através do espelhamento da primeira que será apresentada implementado no programa picsen2.

 

coseno

Função Cosseno

seno

Função Seno obtida da junção da função cosseno direta e espelhada

 

A função cosseno que será usada para criar a tabela pode ser implementada no MikroC PRO utilizando uma função interna do compilador.

cosE3 (ângulo em graus)

Esta função retorna o valor do cosseno do ângulo passado como parâmetro multiplicado por 1000 e arredondado para um valor inteiro aproximado. Exemplo: cosE3(45) resulta em 707 que corresponde a 0.707 valor do cosseno de 45°.

Para definir a frequência de saída do gerador, podemos utilizar a fórmula abaixo que leva em consideração a quantidade de pontos de amostra e a frequência desejada para definirmos o tempo de delay para a amostragem do sinal.

Valor_Delay = 1/(frequência * 360)

Como utilizamos 360 pontos para criar a nossa forma de onda, obtivemos um resultado muito bom, mesmo sem a utilização de filtro passa baixa na saída.

Fotos do projeto:

foto (2)

foto (1)

 

 


Programa picsen1.c

/******************************************************************************

                      JL Audio Manutenção Eletrônica

Data: Junho 2012
Autor: Jean Carlos
Projeto: Gerador Senoidal
Microprocessador: PIC18F4550
Clock do processador: 48MHz
Estação de desenvolvimento: PK2Lab V 1.1
Compilador: MikroC PRO V 4.60.0.0
Versão atual:
Descrição:

          Gerador de sinal senoidal utilizando tabela de referencia


*******************************************************************************/
// Inicializações do programa

// Configuração do LCD da placa PK2Lab V.1.1

sbit LCD_RS at RB2_bit;
sbit LCD_EN at RB3_bit;
sbit LCD_D4 at RB4_bit;
sbit LCD_D5 at RB5_bit;
sbit LCD_D6 at RB6_bit;
sbit LCD_D7 at RB7_bit;

sbit LCD_RS_Direction at TRISB2_bit;
sbit LCD_EN_Direction at TRISB3_bit;
sbit LCD_D4_Direction at TRISB4_bit;
sbit LCD_D5_Direction at TRISB5_bit;
sbit LCD_D6_Direction at TRISB6_bit;
sbit LCD_D7_Direction at TRISB7_bit;

//******************************************************************************
// Variáveis Globais

char amostra;
char tabela_Seno[] =
{127, 130, 133, 136, 140, 143, 146, 149, 152, 155, 158, 161, 164, 167, 170, 173,
176, 179, 182, 185, 187, 190, 193, 195, 198, 201, 203, 206, 208, 211, 213, 215,
217, 220, 222, 224, 226, 228, 230, 232, 233, 235, 237, 238, 240, 241, 242, 244,
245, 246, 247, 248, 249, 250, 251, 252, 252, 253, 253, 254, 254, 254, 254, 255,
255, 254, 254, 254, 254, 253, 253, 252, 252, 251, 250, 250, 249, 248, 247, 246,
244, 243, 242, 240, 239, 237, 236, 234, 232, 231, 229, 227, 225, 223, 221, 219,
216, 214, 212, 209, 207, 204, 202, 199, 197, 194, 191, 189, 186, 183, 180, 177,
175, 172, 169, 166, 163, 160, 157, 154, 150, 147, 144, 141, 138, 135, 132, 129,
125, 122, 119, 116, 113, 110, 107, 104, 100, 97, 94, 91,88, 85, 82, 79, 77, 74,
71, 68, 65, 63, 60, 57, 55, 52, 50, 47, 45, 42, 40, 38, 35, 33, 31, 29, 27, 25,
23, 22, 20, 18, 17, 15, 14, 12, 11, 10, 8, 7, 6, 5, 4, 4, 3, 2, 2, 1, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,1, 1, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 16, 17,
19, 21, 22, 24, 26, 28, 30, 32, 34, 37, 39, 41, 43, 46, 48, 51, 53, 56, 59, 61,
64, 67, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96,99,102, 105, 108, 111, 114, 118,
121, 124, 127 };

//******************************************************************************
//Rotina Principal


void main()
{
TRISA     = 0b00000000;
PORTA   = 0b00000000;
TRISB     = 0b00000000;
PORTB   = 0b00000000;
TRISC     = 0b00000000;
PORTC   = 0b00000000;
TRISD     = 0b00000000;
PORTD   = 0b00000000;
TRISE     = 0b00000000;
PORTE   = 0b00000000;
ADCON1 = 0X0F;                                           // Entradas digitais.

Lcd_Init();
Lcd_Cmd(_Lcd_Cursor_Off);
Lcd_Cmd(_LCD_CLEAR);
Lcd_Out(1,1,"***  PK2Lab  ***");
Lcd_Out(2,1,"Gerador Senoidal");

while(1)
{
  for(amostra = 0; amostra <= 256; amostra++)
     {
     PORTD = Tabela_Seno[amostra];
     delay_us(65);                                       // Delay = 1/(Freq*256)
     }                                                   // Para 60Hz --> 1/(60*256) = 65us
}
}


Programa picsen2.c

/******************************************************************************

                      JL Audio Manutenção Eletrônica

Data: Junho 2012
Autor: Jean Carlos
Projeto: Gerador Senoidal 60Hz
Microprocessador: PIC18F4550
Clock do processador: 48MHz
Estação de desenvolvimento: PK2Lab V 1.1
Compilador: MikroC PRO V 4.60.0.0
Versão atual:
Descrição:

          Este circuito gera uma senoide de 60Hz com 180 Amostras


*******************************************************************************/
// Inicializações do programa

// Configuração do LCD da placa PK2Lab V.1.1

sbit LCD_RS at RB2_bit;
sbit LCD_EN at RB3_bit;
sbit LCD_D4 at RB4_bit;
sbit LCD_D5 at RB5_bit;
sbit LCD_D6 at RB6_bit;
sbit LCD_D7 at RB7_bit;

sbit LCD_RS_Direction at TRISB2_bit;
sbit LCD_EN_Direction at TRISB3_bit;
sbit LCD_D4_Direction at TRISB4_bit;
sbit LCD_D5_Direction at TRISB5_bit;
sbit LCD_D6_Direction at TRISB6_bit;
sbit LCD_D7_Direction at TRISB7_bit;

//******************************************************************************
// Variáveis Globais

char sample;
char array[181];

//******************************************************************************
//Rotina Principal


void main() {
TRISA     = 0b00000000;
PORTA   = 0b00000000;
TRISB     = 0b00000000;
PORTB   = 0b00000000;
TRISC     = 0b00000000;
PORTC   = 0b00000000;
TRISD     = 0b00000000;
PORTD   = 0b00000000;
TRISE     = 0b00000000;
PORTE   = 0b00000000;
ADCON1 = 0X0F;                                                           // Entradas digitais.

Lcd_Init();
Lcd_Cmd(_Lcd_Cursor_Off);
Lcd_Cmd(_LCD_CLEAR);
Lcd_Out(1,1,"***  PK2Lab  ***");
Lcd_Out(2,1,"Gerador Senoidal");
Delay_ms(1000);
 
  for (sample = 0; sample <= 180; sample++)                   // 181 amostras de 0 a pi
  {                                                                                
    array[sample] = (255l * (1000 + cosE3(sample)))/2000;

  }

  while(1)
  {
    for (sample = 0; sample <= 180; sample++)                 // Amostras de 0 a pi
    {

      PORTD = array[sample];                                          // Delay = 1/(Freq*360)
      Delay_us(46);                                                          // Para 60Hz 46.29us

    }
        
    for (sample = 179; sample > 0; sample—)                    // Amostras de pi a 2pi
    {
      PORTD = array[sample];
      Delay_us(46);
    }
  }
}

29 de abr de 2012

Teclado Matricial

 

Dentre as várias maneiras de interagirmos com o hardware em uma IHM (Interface Homem Máquina) uma das formas mais comuns é através do pressionamento de chaves e botoeiras para que o programa possa então executar uma tarefa específica.

Hoje vamos interfacear um teclado matricial, como o encontrado em telefones celulares e calculadoras, onde temos várias chaves conectadas ao microcontrolador de maneira eficiente a fim de não despediçarmos pinos do hardware.

foto

Para efetuar a conexão de uma tecla ao microcontrolador, podemos citar a maneira mais simples que utiliza apenas uma tecla e um resistor de Pull-up ou Pull-down conforme o nível de tensão que desejarmos quando ocorrer o pressionamento da tecla.

Chave HI-LO_1

Porém nesta configuração precisamos um pino para cada tecla conectada ao microcontrolador, o que caracteriza o desperdício de hardware, porém isto pode ser resolvido  com  implementação de uma simples matriz, onde conseguimos maximizar a utilização dos pinos de forma eficiente.

No esquema abaixo podemos observar a utilização das linhas e colunas que formam a matriz.

 

Capturar

 

O número máximo de chaves para esta implementação pode ser obtida através da equação abaixo:

                 N°teclas = Colunas x Linhas

O funcionamento do teclado matricial consiste em energizar apenas uma única linha por vez e efetuar a leitura das colunas para verificar o pressionamento de alguma das teclas, quando detectado um nível alto em alguma das colunas durante o rastreamento se torna possível a identificação da tecla pressionada. Para que não haja erros de leituras durante este processo, se faz necessário o uso de resistores de pull-down para garantir um nível baixo nas colunas que não estão sendo ativas pelo pressionamento de tecla.

Função para escaneamento de teclado

Para efetuar a leitura do teclado matricial, vamos criar uma função que retornará o valor da tecla pressionada em hexadecimal ou o valor 0xFF caso nenhuma tecla tenha sido pressionada.No nosso exemplo utilizaremos um teclado matricial de [4x3] que foi adquirido através do site www.goodluckbuy.com.

Assim que a função é chamada, colocamos um nivel alto na primeira linha e efetuamos a leitura das quatro colunas, caso alguma coluna responda nivel alto, retornamos da função com o valor correspondente a matrizagem, vejamos como fica o código:


#define Coluna_1  PORTD.B0
#define Coluna_2  PORTD.B1
#define Coluna_3  PORTD.B2

#define Linha_1    PORTD.B6
#define Linha_2    PORTD.B5
#define Linha_3    PORTD.B4
#define Linha_4    PORTD.B3

char Le_Teclado()         // Função que efetua a leitura do teclado matricial
{
Coluna_1 = 1;
Coluna_2 = 0;
Coluna_3 = 0;
Delay_ms(1);
if(Linha_1) return 1;
if(Linha_2) return 4;
if(Linha_3) return 7;
if(Linha_4) return 10;
 
Coluna_1 = 0;
Coluna_2 = 1;
Coluna_3 = 0;
Delay_ms(1);
if(Linha_1) return 2;
if(Linha_2) return 5;
if(Linha_3) return 8;
if(Linha_4) return 0;
 
Coluna_1 = 0;
Coluna_2 = 0;
Coluna_3 = 1;
Delay_ms(1);
if(Linha_1) return 3;
if(Linha_2) return 6;
if(Linha_3) return 9;
if(Linha_4) return 11;
 
return 255;
}


Este código  mostra como efetuar uma leitura “simples” do teclado matricial, porém dependendo do hardware utilizado pode apresentar problemas de estabilidade efetuando leituras falsas ou deixando de apresentar um pressionamento.

MikroC PRO

O compilador MikroC PRO, possui internamente uma biblioteca própria para uso com teclados matriciais e que torna o processo de escaneamento uma tarefa simples. Podem ser utilizadas as configurações [4x1] , [4x2] , [4x3] ou [4x4].

Keypad_Init()

Efetua a inicialização do teclado matricial, esta função requer que seja declarado anteriormente uma variável chamada keypadPort que define o PORT onde será conectado o nosso hardware do teclado.

char keypadPort at PORTD;  

Keypad_Key_Press()

Efetua a leitura de uma tecla pressionada, retornando o valor da tecla (1 –16) ou 0 caso nenhuma tecla seja pressionada.

Keypad_Key_Click()

Efetua a leitura de uma tecla pressionada, retornando o valor da tecla (1 –16) ou 0 caso nenhuma tecla seja pressionada, porém é uma função com propriedades de bloqueio, ou seja, quando chamada, aguarda o pressionamento da tecla, bloqueando o processo do programa durante a espera do pressionamento da tecla.

Notem que esta biblioteca do MikroC PRO, embora nos ajude a interfacear o teclado não retorna o valor direto das teclas e sim a posição dela na matriz.

Vejamos como ficou o nosso código completo utilizando o compilador MikroC PRO.

/******************************************************************************

                            JL Audio – www.esquemas .org

Data: 04/2012
Autor: Jean Carlos
Projeto: Teclado Matricial
Microprocessador: PIC18F4550
Clock do processador: 48MHz
Estação de desenvolvimento: PK2Lab V 1.1
Compilador: MikroC PRO V 4.60.0.0
Versão atual: 1.0
Descrição:
                 Implementação de leitura de teclado matricial na
                 placa PK2Lab, através de biblioteca do MikroC PRO.

*******************************************************************************/
// Inicialização do teclado no PORTD

char keypadPort at PORTD;

// Configuração do LCD da placa PK2Lab V.1.1

sbit LCD_RS at RB2_bit;
sbit LCD_EN at RB3_bit;
sbit LCD_D4 at RB4_bit;
sbit LCD_D5 at RB5_bit;
sbit LCD_D6 at RB6_bit;
sbit LCD_D7 at RB7_bit;

sbit LCD_RS_Direction at TRISB2_bit;
sbit LCD_EN_Direction at TRISB3_bit;
sbit LCD_D4_Direction at TRISB4_bit;
sbit LCD_D5_Direction at TRISB5_bit;
sbit LCD_D6_Direction at TRISB6_bit;
sbit LCD_D7_Direction at TRISB7_bit;

//******************************************************************************
// Variáveis Globais

char tecla, tecla_antiga = 0;

//******************************************************************************
// Rotinas Auxiliares

//******************************************************************************
//Rotina Principal

void main()
{
TRISA     = 0b00000000;
PORTA    = 0b00000000;
TRISB     = 0b00000000;
PORTB    = 0b00000000;
TRISC     = 0b00000000;
PORTC    = 0b00000000;
PORTD    = 0b00000000;
TRISE     = 0b00000000;
PORTE    = 0b00000000;
ADCON1  = 0X0F;          // Entradas digitais.


Keypad_Init();          // Inicializa o Teclado Matricial

Lcd_Init();
Lcd_Cmd(_Lcd_Cursor_Off);
Lcd_Cmd(_LCD_CLEAR);
Lcd_Out(1,1,"***  PK2Lab  ***");
Lcd_Out(2,2,"Tecla Press:");
Delay_ms(100);

while(1)
{

tecla = Keypad_Key_Press();      // Efetua leitura do teclado
 
if(tecla != 0)
{
  switch (tecla)                          // Efetua conversão para impressão
      {
      case  1: tecla = 49; break; // 1
      case  2: tecla = 50; break; // 2
      case  3: tecla = 51; break; // 3
      case  4: tecla = 65; break; // A
      case  5: tecla = 52; break; // 4
      case  6: tecla = 53; break; // 5
      case  7: tecla = 54; break; // 6
      case  8: tecla = 66; break; // B
      case  9: tecla = 55; break; // 7
      case 10: tecla = 56; break; // 8
      case 11: tecla = 57; break; // 9
      case 12: tecla = 67; break; // C
      case 13: tecla = 42; break; // *
      case 14: tecla = 48; break; // 0
      case 15: tecla = 35; break; // #
      case 16: tecla = 68; break; // D
      }
  if(tecla != tecla_antiga)       // Atualiza a ultima tecla pressionada
    {
    tecla_antiga = tecla;
    }
  Lcd_Chr(2,15,tecla);            // Imprime a tecla pressionada no LCD
}
}//while(1)
}//main


Abaixo o vídeo do projeto funcionando!

Bom projetos a todos e até a próxima!

1 de abr de 2012

Sensor Ultra-Sônico


Sensores de ultra som são componentes muito úteis no desenvolvimento de projetos microcontrolados por serem fáceis de implementar e ter uma resposta linear diretamente proporcional a distância em que se encontra de um determinado objeto.
Veremos agora como funciona o sensor de ultrasom DYP-ME007 que pode  ser adquirido diretamente da China através do site www.goodluckbuy.com

Sensor ultra1

O Sensor de ultrasom pode detectar objetos a distâncias que variam entre 2 e 350cm de distância com uma precisão de 3mm, sendo que o modelo testado retornou uma precisão de 2mm.
A detecção de distância é feita através do disparo de um pulso de nível alto com duração de 10us no pino de Trigger do sensor, assim que ele detectar este sinal, emite uma sequencia de 8 pulsos na frequência de 40KHz, frequência esta que define o termo Ultra-sônico utilizado na nomenclatura. Após este som emitido “Bater” em algum objeto, retorna e é capturado pelo microfone do sensor para processamento das informações.

Sensor

A distância “D” corresponde a real distância do objeto, como o sensor recebe a informação de distância de emissão e recepção, obtêm duas vezes a distância real, como a velocidade do som no ar a temperatura média de 25°C é de 340m/s, facilmente se obtém a relação de distância em milímetros através da equação:
Distância = Velocidade * Tempo
2 * Distância = 340 * Tempo
Distância = 170 * Tempo
 
Todos estes cálculos são efetuados diretamente pelo sensor DYP-ME007 que ao final entrega no pino Echo um pulso ativo correspondente a distância real do objeto como mostra a figura abaixo:
 
Temporização
 
Para se transformar o tempo (us) retornado pelo sensor  em distância(mm), basta dividir valor do tempo por 58.
Este valor é obtido da seguinte relação:
Um metro corresponte a um pulso de aproximadamente 5764us, transformando em cm temos 57,64cm que arredondamos para 58 para facilitar os cálculos no microcontrolador.

Teste de funcionamento.

Este sensor possui quatro pinos de conexão sendo:
VCC – Alimentação de 5V (Consumo médio de 20ma)
GND – Alimentação GND
Trigger- Pino para disparo de leitura (10ms)
Echo – Pino de retorno de informações referente a distância medida
Out – Este pino NÃO deverá ser conectado

Podemos detectar a largura de pulso do sensor de várias maneiras, porém a maneira mais elegante de se fazer isto com microcontroladores PIC, é utilizando o módulo CCP na função CAPTURE.
Para isto temos que conhecer um pouco mais sobre este módulo interno do microcontrolador.
O módulo CCP utiliza os Timers internos do microcontrolador como base de tempo, neste caso específico do modo CCP que é o CAPTURE, é utilizado o TIMER1 incrementando a cada us.
Desta forma quando o módulo CCP detecta a borda alta correspondente ao pino ECHO do sensor, ativa a contagem do TIMER,(incrementeado a cada us) e muda a configuração da borda de sensibilidade para baixa, aguardando assim o término do pulso referente a distância, com isto conseguimos saber qual o período do pulso entrege pelo sensor em já em us.
Após esta informação ser processada temos que alterar novamente a borda de sensibilidade para alta afin de estarmos prontos para uma nova informação proveniente so sensor.
Através do uso deste módulo, trabalhamos apenas com interrupções liberando o microcontrolador para outras tarefas tornando o programa mais eficiente.


Abaixo segue o programa exemplo da placa PK2Lab para uso com estes sensores.
/******************************************************************************
                      JL Audio Manutenção Eletrônica
Data: 01/2012
Autor: Jean Carlos
Projeto: Sensor de distância DYP-ME007
Microprocessador: PIC18F4550
Clock do processador: 8MHz
Estação de desenvolvimento: PK2Lab V 1.1
Compilador: MikroC PRO V 4.60.0.0
Versão atual:
Descrição:

          Este projeto demonstra o uso do sensor de distancia DYP-DM007
          Com a placa PK2Lab, o valor referente a distância entre o
          objeto e o sensor é exibido no display LCD.

          Trigger -> RC0
          Echo    -> RC2 -> Entrada do módulo CCP1

          O resultado da captura é salvo em CCPR1H e CCPR1L
          Para efetuar este projeto, iremos configurar o TMR1 como contador
          sincrono,para ser incrementado pela fonte de clock externo que é
          o cristal de 8MHz conectado a placa PK2Lab(Sem PLL).

          8MHz -> (Fosc/4)2MHz -> Prescaler 2:1 -> 1MHz (1uS)
          Para calcular a distancia em centimetros, usamos a formula abaixo:


*******************************************************************************/
// Configuração do LCD da placa PK2Lab V.1.1

sbit LCD_RS at RB2_bit;
sbit LCD_EN at RB3_bit;
sbit LCD_D4 at RB4_bit;
sbit LCD_D5 at RB5_bit;
sbit LCD_D6 at RB6_bit;
sbit LCD_D7 at RB7_bit;

sbit LCD_RS_Direction at TRISB2_bit;
sbit LCD_EN_Direction at TRISB3_bit;
sbit LCD_D4_Direction at TRISB4_bit;
sbit LCD_D5_Direction at TRISB5_bit;
sbit LCD_D6_Direction at TRISB6_bit;
sbit LCD_D7_Direction at TRISB7_bit;


//******************************************************************************
// Definições e  Variáveis Globais

#define Trigger RC0_bit
char txt[4];                  // Usado para conversão de dados em string
char Tempo_H, Tempo_L, Distancia_cm;
unsigned int Periodo;         // Variável que armazena o período do Pulso ECHO

//******************************************************************************
// Funções Auxiliares

void interrupt()
{
if(CCP1IF_bit && CCP1CON.B0)  // Captura por CCP1 e borda configurada como subida...
{
  CCP1IF_bit  = 0;            // Limpa a flag para nova captura
  CCP1IE_bit  = 0;            // Desabilita interrupção por periféricos(CCP1)
  CCP1CON     = 4;          // Configura a borda de captura para DESCIDA. (ESTE EVENTO CAUSARIA INTERRUPÇÃO ERRÔNEA)
  CCP1IE_bit  = 1;            // Habilita interrupção por periféricos(CCP1)
  TMR1H       = 0;             // Zera registradores do TMR1 para contagem de tempo
  TMR1L       = 0;
  TMR1ON_bit  = 1;          // Habilita contagem de tempo.
}

else if(CCP1IF_bit)
      {
       CCP1IF_bit  = 0;        // Limpa a flag para nova captura
       TMR1ON_bit  = 0;      // Desabilita contagem de tempo.
       CCP1IE_bit  = 0;        // Desabilita interrupção por periféricos(CCP1)
       CCP1CON     = 5;      // Configura a borda de captura para SUBIDA. (ESTE EVENTO CAUSARIA INTERRUPÇÃO ERRÔNEA)
       CCP1IE_bit  = 1;       // Habilita interrupção por periféricos(CCP1)
       Tempo_H     = CCPR1H;  // Carrega valores de tempo capturado(Neste caso em us)
       Tempo_L     = CCPR1L;
      }

}
Pulso()                       // Gera o Pulso de trigger para o sensor ultra som.
{
Trigger = 1;
Delay_us(10);
Trigger = 0;
}

//******************************************************************************
//Rotina Principal

void main()
{
TRISC  = 0b00000100;         // Entrada CCP1
PORTC  = 0b00000000;
INTCON = 0b11000000;         // Liga interruptores GIE e PEIE
TMR1IE_bit = 0;              // Desabilita interrpções de TMR1
CCP1IE_Bit = 1;              // Habilita interrupções por CAPTURA(CCP1)
CCP1CON    = 5;              // Configura módulo CCP1 para CAPTURA e borda de SUBIDA.

T1CKPS1_bit = 0;             // Prescaller TMR1 2:1
T1CKPS0_bit = 1;
TMR1CS_bit  = 0;             // Clock selecionado -> OSC/4
TMR1ON_bit  = 0;             // Timer -> 1 = Habilita contagem

Lcd_Init();
Lcd_Cmd(_Lcd_Cursor_Off);
Lcd_Cmd(_LCD_CLEAR);
Lcd_Out(1,1,"***  PK2Lab  ***");
Lcd_Out(2,1,"Distancia:    cm");
Delay_ms(100);

while(1)
{
Pulso();                                 // Dispara leitura de distância.
Delay_ms(100);                     // Intervalo entre leituras.
Periodo = (Tempo_H<<8)+ Tempo_L;   // Obtenção do período relativo ao ECHO
Distancia_cm = Periodo/58;    // Conversão da distância informada para cm

                  //------------------------------------------------------------------------------------//
                  // Um Pulso de 58us corresponde a uma distância de 1cm  //
                  //------------------------------------------------------------------------------------//


// Distância MINIMA 3cm e MAXIMA 3m

if((Distancia_cm < 3)||Distancia_cm >300) Lcd_Out(2,12,"---");
else
    {
    byteToStr(Distancia_cm, txt);   // Converte texto para impressão
    Lcd_Out(2,12,txt);                   // Imprime valores no display
    }
}
}