terça-feira, 9 de agosto de 2016

Gerando sinais analógicos com o PIC(onda triangular e dente de serra).

Olá,
      As vezes precisamos converter dados digitais em sinais analógicos apesar de alguns microcontroladores terem esta opção já inclusa podemos também recorrer a chips dedicado para esta função como os chips da "analog devices" os AD5601/AD5611/AD5621 que são de 8,10 e 12 bits respectivamente.
      O circuito montado no proteus foi este a seguir:
     Observe que coloquei uma porta serial para saber o qual valor eu estava sendo enviado, o voltímetro 'lê'  a tensão que estava saindo a cada incremento no chip.O código fonte ficou dividido em duas partes; uma gera onda dente de serra e o outro gera uma onda triangular, veja na imagem abaixo os prints da tela:

As formas de ondas em azul são os pacotes SPI que foram enviados ,em verde o clock gerado a cada transmissão de pacotes e em vermelho o momento em que o pino de "slave select " é ativado. Na figura a seguir é visto como é feito o cálculo para o chip AD5601, para calcular para os outros chips segue o mesmo raciocínio ou seja pega o valor de 5V e divide pelo números de resolução(incrementos) do chip ou seja 255 incrementos para o AD5601,1024 para o AD5611 e 4096 incrementos para o AD5621.
O código fonte fica :


/*
 *                                Usando comunicação SPI  com ADS601/ADS611/ADS621     
 *
 * Compilador : MPlabXC8
 * Microcontrolador: 16F1947
 * Autor: aguivone
 * Versão: 1
 * Data :  09/08/2016
 */
#include <xc.h>
#include <stdio.h>
#include "serial16F1947.c"
#include "SPI.c"
#define _XTAL_FREQ 16000000  //usado para rotinas de  delays
#define LED               LATAbits.LATA0
#define LER_LED           PORTAbits.RA0


//
///////////configuração dos fuses bits/////////////////////////////////////////////
// CONFIG1
#pragma config FOSC = HS        // Oscillator Selection (HS Oscillator, High-speed crystal/resonator connected between OSC1 and OSC2 pins)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = ON        // Internal/External Switchover (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)

// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config VCAPEN = OFF     // Voltage Regulator Capacitor Enable (VCAP pin functionality is disabled)
#pragma config PLLEN = OFF      // PLL Enable (4x PLL disabled)
#pragma config STVREN = OFF     // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will not cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)
//////////////////////////////////////////////////////////////////////////////////

//************************************************************************************/
//VARIAVEIS GLOBAIS
//************************************************************************************/
bit flag_led=0;
////variaveis da porta serial
char   gcCaracter;
//*******************************************************************************/
//===================================================================================
//Função:    _interrupcoes
//Descrição: usada para tratar as interrupções geradas pelo microcontrolador.
//===================================================================================
void interrupt interrupcoes(void)//vetor de interrupção
 {
      if(RC1IF)//verifica interrupção da serial na COM1
    {//interrupção da serial
        gcCaracter = RC1REG;   
        escreve_RS232(gcCaracter,0);//finaliza string
        RC1IF = 0;//  limpa flag de interrupção de recepção
    }
    /*if(RC2IF)//verifica interrupção da serial na COM2
    {//interrupção da serial
        gcCaracter = RC2REG;
        escreve_RS232(gcCaracter,1);//finaliza string
        RC2IF = 0;//  limpa flag de interrupção de recepção
    }*/
}

//===================================================================================
//Função:    _config_CPU
//Parâmetros: não tem
//Retorno:   não tem retorno.
//Descrição: inicializa os registradores do microcontrolador.
//===================================================================================
void config_CPU()
{
    //configura portas logicas
    TRISA = 0X00;
    TRISB = 0X00;
    TRISC = 0x80;
    TRISD = 0x00;
    TRISE = 0x00;
    TRISF = 0x00;//todos entrada e ainda são as entrasas analogicas
    TRISG = 0x04;
    // inicializa portas logicas configuradas como saida para 0
    LATA = 0;
    LATB = 0;
    LATC = 0;
    LATD = 0;
    LATE = 0;
    LATF = 0;
    LATG = 0;
    inicializa_RS232(9600,1,0);//modo de alta velocidade inicializa COM1
    //inicializa_RS232(9600,1,1);//modo de alta velocidade inicializa COM2
    PEIE = 1;//habilita interrupção de perifericos do pic
    GIE = 1; //GIE: Global Interrupt Enable bit  
    __delay_ms(100);
    
}

void Envia_pacote(unsigned long valor,int modo,int tipo)//valor,modo de operação,tipo do sensor
{
    switch(tipo)
    {
        case 0:
        {
           valor = valor << 6; //8 bits - ADS601
        }break;
        case 1:
        {
            valor = valor << 4;//10 bits - ADS611
        }break;
        case 2:
        {
            valor = valor << 2;//12 bits - ADS621
        }break;
    }
     valor =  valor & 0B0011111111111111;//zera os 2 primeiros bits
     switch(modo)
    {//modos do power down
        case 1:
        {
           valor  = valor + 0X4000;//1K ligado ao gnd 
        }break;
        case 2:
        {
           valor  = valor + 0X8000;//100K ligado ao gnd 
        }break;
        case 3:
        {
           valor  = valor + 0XC000; //three state
        }break;
    }
    escreve_SPI(((unsigned char)(valor>>8)),(unsigned char)valor ,1,0);//byte1 , byte2,numero de bytes a ser enviado(0 = 1 e 1 = 2),tipo de ligação ao terra 
    
}

void main(void) 
{
    config_CPU(); 
    imprime_RS232("Imprimindo: COM 1!\r\n",0); 
    imprime_RS232("Digite um caracter:\r\n",0);
    inicializa_spi_mestre(0);
    long tensao,tempo=0;
    for(;;)
    { 
         ///////////////simulação do trecho 1(onda dente de serra)//////////////
            imprime_RS232("Valor enviado = ",0);
            long_to_char_RS232(tempo,5,0,0);
            Envia_pacote(tempo,0,0); //8 bits - ADS601  o valor a ser colocado deve ser de 0 a 255.
           // Envia_pacote(tensao,0,1); //10 bits - ADS611  o valor a ser colocado deve ser de 0 a 1024.
           // Envia_pacote(tensao,0,2); //12 bits - ADS601  o valor a ser colocado deve ser de 0 a 4096.
            __delay_ms(200);//tempo de cada degrau
            imprime_RS232("\r\n",0);
            if(tempo > 245)
            {
                tempo = 0;
            }
             tempo = tempo + 10;
            ////////////////fim do trecho 1//////////////////////
///////////////simulação do trecho 2(onda triangular)////////////// /* //descomente esta linha para gerar a onda senoidal mas o trecho 1 deve ser comentado if(tempo > 254) { tensao--; if(tensao == 0) { tempo =0; } } else { tensao++; } Envia_pacote(tensao,0,0); __delay_ms(1);//tempo de cada degrau *///descomente esta linha para gerar a onda senoidal mas o trecho 1 deve ser comentado ////////////////fim do trecho 2////////////////////// tempo++; } }

código dos includes externos
--------------------------------------------
"serial16F1947.c"
/*
 *                          FUNÇOES USADAS NA SERIAL
 *
 * Compilador :      MPlabXC8
 * Microcontrolador: 16F1947
 * Autor:            Aguivone
 * Versão:           1
 * Data de criação:  21 de agosto de 2014.
 */

#include <xc.h>
#include <stdio.h>
#include <string.h> //para usar funçoes de string deve se adicionar este header
#define _XTAL_FREQ 16000000//usado para rotinas de  delays

//===================================================================================
//Função:    _inicializa_RS232
//Parâmetros: unsigned long ulVelocidade
//          : unsigned int uiModo
//          : porta serial(1 ou 0) 
//Retorno:   não tem retorno.
//Descrição: usada para iniciar a porta serial.
//===================================================================================
void inicializa_RS232(unsigned long ulVelocidade,unsigned int uiModo,int porta)
{//// por padrão é usado o modo 8 bits e sem paridade, mas se necessario ajuste aqui a configuração desejada.
    // verifique datasheet para ver a porcentagem de erro e se a velocidade é possivel para o cristal utilizado.
    unsigned long valor;
    if(porta == 0)
    {
        RC1STA = 0X90;//habilita porta serial,recepção de 8 bit em modo continuo,assincrono.        
            if(uiModo == 1)
            {//modo = 1 ,modo alta velocidade
             TX1STA = 0X24;//modo assincrono,trasmissao 8 bits.
             valor =(((_XTAL_FREQ/ulVelocidade)-16)/16);//calculo do valor do gerador de baud rate
            }
            else
            {//modo = 0 ,modo baixa velocidade
             TX1STA = 0X20;//modo assincrono,trasmissao 8 bits.
             valor =(((_XTAL_FREQ/ulVelocidade)-64)/64);//calculo do valor do gerador de baud rate
            }
        SP1BRG = valor;
        RC1IE = 1;//habilita interrupção de recepção
        TX1IE = 0;//deixa interrupção de transmissão desligado(pois corre se o risco de ter uma interrupção escrita e leitura ao mesmo tempo)

    }
    else
    {
       RC2STA = 0X90;//habilita porta serial,recepção de 8 bit em modo continuo,assincrono.
        if(uiModo == 1)
        {//modo = 1 ,modo alta velocidade
         TX2STA = 0X24;//modo assincrono,trasmissao 8 bits.
         valor =(((_XTAL_FREQ/ulVelocidade)-16)/16);//calculo do valor do gerador de baud rate
        }
        else
        {//modo = 0 ,modo baixa velocidade
         TX2STA = 0X20;//modo assincrono,trasmissao 8 bits.
         valor =(((_XTAL_FREQ/ulVelocidade)-64)/64);//calculo do valor do gerador de baud rate
        }
    SP2BRGL = valor;
    SP2BRGH = valor<<8;
    RC2IE = 1;//habilita interrupção de recepção
    TX2IE = 0;//deixa interrupção de transmissão desligado(pois corre se o risco de ter uma interrupção escrita e leitura ao mesmo tempo)
    }
    
}
//===================================================================================
//Função:    _escreve1_RS232
//Parâmetros: char cValor, int porta
//Retorno:   não tem retorno.
//Descrição: usada para escrever 1 caracter.
//===================================================================================
 void escreve_RS232(char cValor,int porta)
{
     if(porta == 0)
    {
        TX1IF = 0;//limpa flag que sinaliza envio completo.
        TX1REG = cValor;
        while(TX1IF ==0);//espera enviar caracter
    }
    else
    {
        TX2IF = 0;//limpa flag que sinaliza envio completo.
        TX2REG = cValor;
        while(TX2IF ==0);//espera enviar caracter
    }
     __delay_us(50);
}
 
//===================================================================================
//Função:    _imprime_RS232
//Parâmetros: const char ccFrase[], int porta
//Retorno:   não tem retorno.
//Descrição: usada para escrever uma string(vetor de caracteres).
//===================================================================================
 void imprime_RS232(const char ccFrase[],int porta)
{
     unsigned char indice = 0;
     unsigned char tamanho = strlen(ccFrase);     
      while(indice < tamanho ) ///veja que o programa pode travar se aqui não tiver as duas aspas
       {
           escreve_RS232(ccFrase[indice],porta);
           indice++;
       }
}
//===================================================================================
//Função:    _long_to_char_RS232
//Parâmetros: unsigned long  ulQuant, -> valor a ser impresso na serial
//            int iTam,-> numero de caracter que deve ser impresso
//Retorno:   não tem retorno.
//Descrição: converte um long ou int em uma sequencia de caracteres.
//===================================================================================
void long_to_char_RS232(unsigned long  ulQuant,int iTam,int virgula,int porta)
{
        char cTexto[7];
        int  iValor = 0;
        if(virgula == 0)
        { virgula = 20;//dessa forma nunca será usado a virgula
        }
        while(iValor < 6 )
        {
             cTexto[iValor]='0';
             iValor++;
        }        
         while(ulQuant>=10000)
            {
             ulQuant=ulQuant-10000;
             cTexto[5]++;
             }
         while(ulQuant>=1000)
            {
             ulQuant=ulQuant-1000;
             cTexto[4]++;
             }
          while(ulQuant>=100)
            {
             ulQuant=ulQuant-100;
             cTexto[3]++;
             }
           while(ulQuant>=10)
            {
             ulQuant=ulQuant-10;
             cTexto[2]++;
             }
           while(ulQuant>=1)
            {
             ulQuant=ulQuant-1;
             cTexto[1]++;
             }
        iValor = iTam ;
          while(iValor != 0 )
           {
              escreve_RS232(cTexto[iValor],porta);
              iValor--;
              if(virgula == iValor){ escreve_RS232(',',porta);}
           }
}
------------------------------------------------------------------------------------
"SPI.c"

/*
 * File:   SPI.c
 * Author: aguivone
 *
 * Created on 14 de Julho de 2016, 14:54
 */
#include <xc.h>
#define _XTAL_FREQ 16000000  //usado para rotinas de  delays

#define SPI1_SS            LATCbits.LATC2 //configura pino de Slave selected
#define SPI2_SS            LATCbits.LATC0 //configura pino de Slave selected


unsigned char ler_SPI( unsigned char dado,int porta_spi)
{//le um byte
  unsigned char TempVar;
  unsigned char Retorno;
  if(porta_spi == 0)
  {
    SPI1_SS    = 1;
    __delay_us(5);
    TempVar = SSP1BUF;        // limpa BF
    SSP1BUF = dado;           // escreve no buffer o codigo da solicitação
    while (!SSP1STATbits.BF);//espera terminar o envio
    TempVar = SSP1BUF;        // limpa BF
    SSP1BUF = 0X00;           // envia um dado qualquer somente para fazer a leitura
    while (!SSP1STATbits.BF);
     SPI1_SS    = 0;
     Retorno = SSP1BUF;
  }
  else
  {
     SPI2_SS    = 1;
    __delay_us(5);
    TempVar = SSP2BUF;        // limpa BF
    SSP2BUF = dado;           //escreve no buffer o codigo da solicitação
    while (!SSP2STATbits.BF);//espera terminar o envio
    TempVar = SSP1BUF;        // limpa BF
    SSP2BUF = 0X00;           // envia um dado qualquer somente para fazer a leitura
    while (!SSP2STATbits.BF);
     SPI2_SS    = 0;
     Retorno = SSP2BUF;
  }
  return (Retorno);       // byte lido
}


void escreve_SPI( unsigned char byte0,unsigned char byte1 ,int num_byte,int porta_spi)
{//geralmente o primeiro byte tambem é chamado de opcode
   unsigned char TempVar;
   if(porta_spi == 0)
   {//usa a SPI 1
        SPI1_SS = 0;//verifique se o hardware funciona deste modo ou é invertido
        __delay_us(5);
        TempVar = SSP1BUF;        // limpa BF
        SSP1BUF = byte0;           // escreve no buffer
        while ( !SSP1STATbits.BF ); //espera terminar o envio
        if(num_byte == 1)
        {
            TempVar = SSP1BUF;        // limpa BF
            SSP1BUF = byte1;           // escreve no buffer o byte 2
            while (!SSP1STATbits.BF );//espera terminar o envio
        }
        SPI1_SS = 1;
   }
   else
   {//usa a SPI 2
       SPI2_SS    = 0;//verifique se o hardware funciona deste modo ou é invertido
        __delay_us(5);
        TempVar = SSP2BUF;        // limpa BF
        SSP2BUF = byte0;           // escreve no buffer
        while (!SSP2STATbits.BF); //espera terminar o envio
        if(num_byte == 1)
        {
            TempVar = SSP2BUF;        // limpa BF
            SSP2BUF = byte1;           // escreve no buffer
            while (!SSP2STATbits.BF);
        }
        __delay_us(5);
        SPI2_SS = 1;
   }
}
 void inicializa_spi_mestre(int tipo)//inicialica modo mestre - 0-habilita somente spi1 , 1- habilita spi2 e 2- habilita os 2 spi  
{  
     if((tipo == 0)||(tipo == 2))
     {
       // SSP1CON1 = 0X20; //habilita pinos de spi // FOSC/4 //clock em nivel 0
       // SSP1CON1 = 0X21; //habilita pinos de spi // FOSC/16 //clock em nivel 0
        SSP1CON1 = 0X22; //habilita pinos de spi // FOSC/64 //clock em nivel 0
       // SSP1STAT = 0X40; //pega amostras no meio do byte e a trasmissão será na borda de subida
        SSP1STAT = 0X40; //pega amostras no meio do byte e a trasmissão será na borda de descida
        SPI1_SS = 1;//inicia em nivel alto para AD5601/AD5611/AD5621
     }
     if((tipo == 1)||(tipo == 2))
     {
        SSP2CON1 = 0X21; //habilita pinos de spi // FOSC/16 //clock em nivel 0
        SSP2STAT = 0XC0; //pega amostras no fim do byte e a trasmissão será na borda de subida
        SPI2_SS = 0;
     }
}

segunda-feira, 8 de agosto de 2016

Balança óptica com o PIC 12F675.

          Olá, hoje vou apenas lançar uma ideia para que vocês usem em seus projetos ou mesmo para aprender mais sobre como usar sensores ópticos.Este projeto pode ser montado usando receptores como fotodiodo,fototransistor  e LDR(fotoresistor) como sensores de proximidades.O principio de funcionamento é bem simples, se baseia na variação de distancia entre um diodo emissor de luz(pode ser de qualquer espectro de luz que o sensor aceite) e o elemento sensor.
        Um detalhe que influencia no resultado final são as sapatas usadas como elemento sensor(pode ser de borracha, espuma ou qualquer outro elemento que apresente a propriedade mecânica de ser elástico).Neste projeto como eu queria algo mais sensível usei espumas(tipo de colchoes), veja que a variação de unidades lidas vão depender da curva característica das sapatas de apoio e também da capacidade de flambar(sofrer flexão) do material usado como base.
       A opção de usar um fotodiodo é devido a seu maior tempo de resposta embora que o uso de LDR seja uma boa opção devido a sua característica de varia a resistência numa faixa maior do que os fotodiodos, o capacitor de 100nF é para filtrar pequenos ruídos que possam afetar a leitura.O esquemático elétrico é visto a seguir:

         Observe que este projeto é uma aplicação do exemplo apresentado anteriormente aqui no blog("emulando uma porta serial" ), para comunicar com o PC é necessário usar um CI para fazer o "casamento" das tensões(popular MAX232).O software para usar  a porta serial pode ser qualquer aplicativo que "leia" a porta serial de seu pc. As configurações da seria são 9600b/s, 8 bits de dados, sem paridade, 1 bit de stop.Todo o circuito funciona com 5V, veja o vídeo de demonstração:
         
O código fonte:            
            Agora vamos para a parte lógica desta balança veja as linhas de código fonte a seguir:
/*
 *                                    balança óptica          
 *
 * Compilador : MPlabXC8
 * Microcontrolador: 12F675
 * Autor: aguivone
 * Versão: 1
 * Data :  05/08/2016
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>//para trabalhar com string
#include <xc.h>
#define _XTAL_FREQ 20000000  

/////////////////////////////////////////////////////////configuraçôes//////////////////////////////////////////////////
// CONFIG
#pragma config FOSC = HS        ////High speed para o cristal
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-Up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF     // GP3/MCLR pin function select (GP3/MCLR pin function is digital I/O, MCLR internally tied to VDD)
#pragma config BOREN = OFF      // Brown-out Detect Enable bit (BOD disabled)
#pragma config CP = OFF         // Code Protection bit (Program Memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)

///parametros da porta serial emulada////////////////////////////////////////////////////////////////
#define  TIME_BAUD  97//9600 bps - 20MHZ
#define  BAUD_RX    95//9600 bps - 20MHZ 
/////para simulação do proteus descomentar esta linha e comentar as 2 anteriores
//#define  TIME_BAUD  202//4800 bps - 20MHZ
//#define  BAUD_RX    200//4800 bps - 20MHZ 

#define  TX  GP2//configura o pino que será TX
#define  RX  GP1//configura o pino que será RX
#define  BOTAO  GP3//configura o pino como entrada, botão setar nova referencia 

///variaveis globais usada neste projeto
long tensao=0;
char flag_libera=0;
long tensao_anterior=0;
long variacao=0;
long referencia=0;
bit  flag_sinal=0;

///usado para converter tensão.
int ler_adc_un()
{
        int ultensao;
        PIR1bits.ADIF = 0;//limpa flag
        ADCON0bits.GO = 1; //inicia conversão
        while (PIR1bits.ADIF == 0); //espera finalizar leitura
        ultensao = (ADRESH << 8) | ADRESL;
        return(ultensao);
}

/////////////////////Funçoes utilizadas pela porta serial emulada ///////
void escreve_char(char dados) {
    int contagem = 0;
    TX = 0;
    while (contagem < 8) //envia dados + stop bit
    {
        __delay_us(TIME_BAUD);
        if ((dados & 0X01) == 0X01) //testa bit menos significativo (LSB)
        {
            TX = 1;
        } else {
            TX = 0;
        }
        dados = dados >> 1; //rotaciona bit
        contagem++;
    }
    __delay_us(TIME_BAUD); //tempo do ultimo bit
    TX = 1; //volta pra nivel alto (fim de transmissão de caracter)
    __delay_us(TIME_BAUD); //stop bit
}
//imprime uma cadeia de caracteres
void escreve_frase(char *frase) {
    int tam_frase = strlen(frase);
    int contagem = 0;
    while (contagem < tam_frase)           
    {
        escreve_char(frase[contagem]);
        contagem++;
    }

}

//usado para converter um numero em string 
void long_to_char(int ulQuant)
{
        char cTexto[4]={'0','0','0','0'};
         while(ulQuant>=1000)
            {
             ulQuant=ulQuant-1000;
             cTexto[3]++;
             }
          escreve_char(cTexto[3]);
          while(ulQuant>=100)
            {
             ulQuant=ulQuant-100;
             cTexto[2]++;
             }
          escreve_char(cTexto[2]);
           while(ulQuant>=10)
            {
             ulQuant=ulQuant-10;
             cTexto[1]++;
             }
          escreve_char(cTexto[1]);
           while(ulQuant>=1)
            {
             ulQuant=ulQuant-1;
             cTexto[0]++;
             }
          escreve_char(cTexto[0]);
          escreve_frase(" \r\n");
}
// pega referência para calcular a variação somente na descida do sinal
void pega_ref(void)
{
    referencia = 0;
    for(int val=0;val<5;val++)
    {
      referencia = referencia + ler_adc_un();
      __delay_ms(100);
    }
    referencia = referencia/5;//tira media
    escreve_frase("Referencia:");
    long_to_char(referencia);
    escreve_frase("\r\n");
}
///////////////////////////////////////Rotina principal////////////////////////////////////////////////
void main(void) {
    CMCON = 7;//desabilita comparadores
    ANSEL = 0X31;//usa AN0 como entrada analogica e usa o clock interno do chip(2 a 6 us)
    WPU = 0X00;//desabilita pull ups
    TMR0 = 0;
    ADCON0 = 0X80;//justificado a esquerda , ref ligado ao vdd,usando AN0
    OSCCAL = 0XFF;//configura o oscilador interno para frequencia maxima(4mhz)
    OPTION_REG = 0X81;//pull up desabilitado/preescaler ligado ao timer0(dividido por 4)
    PIR1 = 0X00; //desabilita interrupções não necessaria
    TRISIO = 0X03;//configura gp0 e gp1 como entrada
    INTCON = 0XC0;//desabilita interrupção do timer 0 e habilitainterrupção global e de perifericos
    ADCON0bits.ADON = 1;//liga modulo de conversão
    __delay_ms(100);//debounce e tempo para preparar hardware
    //logo a frequencia de interrupção é 250khz
    escreve_frase("inicializando... \r\n");//a primeira escrita é sempre perdida(ainda não sei o porque)
    escreve_frase("Pesagem optica \r\n");
    //inicializa pegando um valor de referencia
    pega_ref();//pega referencia
    for(;;)
    {  //
        __delay_ms(100);//como tem um intevalo grande tira ruidos pontuais 
            if(BOTAO == 0)
            {
               pega_ref();//pega nova referencia
               __delay_ms(500);//debounce 
            }
            tensao = ler_adc_un();
            if(tensao_anterior >tensao)
            {
                variacao = tensao_anterior - tensao;
                flag_sinal=1;//indica que o sinal está descendo
            }
            else
            {
                variacao = tensao - tensao_anterior; 
                flag_sinal=0;//indica que o sinal está subindo
            }
            if(variacao > 3)//verifica variação se é maior que 3 (filtro)
            {
                if((referencia > tensao)&&(flag_sinal==1))//o valor sempre terá que ser menor que o de referencia(pois o led aproxima mais do sensor))
                {///se for maior pode ser ruidos(no momento de desdetecção) 
                    escreve_frase("Valor lido =");
                    long_to_char(tensao); 
                    escreve_frase("Variacao = ");
                    long_to_char(referencia - tensao);
                }
                 tensao_anterior = tensao;  
            }
    }//loop infinito
}//main


//NOTAS DE PARAMETRIZAÇÃO(sugestão):

//***********************************************************************************************************
//oscilador interno do pic 12F675(testado fisicamente )//////////////////////////////////////////////////////
// configure assim o fuse do oscilador interno => #pragma config FOSC = INTRCIO
// configure assim o fuse do cristal de 4MHZ => #pragma config FOSC = XT
//
//#define  TIME_BAUD  14//19200 bps - 4MHZ - usando cristal 
//#define  TIME_BAUD  16//19200 bps - 4MHZ - usando oscilador interno
//#define  BAUD_RX    12//19200 bps - 4MHZ - osc. interno - recepção não fica confiavel 

//#define  TIME_BAUD  68//9600 bps - 4MHZ - usando oscilador interno
//#define  BAUD_RX    58//9600 bps - 4MHZ - cristal 4MHZ - recepção funcionou bem(houve pouquissimo erros) - no proteus esse valor não funciona
//#define  BAUD_RX    60//9600 bps - 4MHZ - recepção funcionou bem(houve pouquissimo erros)

//#define  TIME_BAUD  175//4800 bps - 4MHZ 
//#define  BAUD_RX    165//4800 bps - 4MHZ - recepção funcionou muito bem(100% confiavel fisicamente, mas no proteus apresenta falhas)


//*************************************************************************************************
// oscilador com cristal de 20MHZ (testado fisicamente funcionou ok)
// configure assim o fuse do cristal => #pragma config FOSC = HS
//#define  TIME_BAUD  45//19200 bps - 20MHZ
//#define  BAUD_RX    42//19200 bps - 20MHZ 

//#define  TIME_BAUD  97//9600 bps - 20MHZ
//#define  BAUD_RX    95//9600 bps - 20MHZ 

//#define  TIME_BAUD  202//4800 bps - 20MHZ
//#define  BAUD_RX    198//4800 bps - 20MHZ 
         
Obrigado a todos que acompanham minhas postagens, e até a próxima pessoal!