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!

Nenhum comentário :

Postar um comentário

olá,digite aqui seu comentário!