terça-feira, 26 de abril de 2016

O código do sensor AMF16 - Lendo tensões AC com o PIC12F675.

             Olá, hoje vou disponibilizar o código do sensor AMF16 (descrito aqui: http://microcontroladores-c.blogspot.com.br/2015/12/medindo-tensao-ac-com-o-sensor-amf-16.html , ainda tenho algumas pcbs que eu havia mandado fazer para este projeto vendo pelo preço que paquei RS = 10,00, caso alguém se interesse), vamos começar pelo o esquemático do circuito:
             O algoritmo usado verifica as tensões e joga em um vetor acumulador e ao encontrar uma decida do sinal por meio de comparações de valores,a probabilidade de ser um pico de tensão é muito grande,veja na figura a seguir como isso ocorre(supondo haver somente 3 pontos pra identificar o pico de tensão AC):
             Todas as especificações estão no manual que montei deem uma olhada neste link http://microcontroladores-c.blogspot.com.br/2015/12/medindo-tensao-ac-com-o-sensor-amf-16.html,
             O microcontrolador usado é o PIC 12F675 como ele não tem serial, foi usado o artificio de emular uma serial,ele apenas envia os dados num intervalo pré definido, sendo então o sinal elétrico convertido em luz através do optoacoplador para que seja ligado diretamente a um microcontrolador secundário sem risco de queimar.

O código fonte:
/*
 *                                    voltimetro via serial          
 *
 * Compilador : MPlabXC8
 * Microcontrolador: 12F675
 * Autor: aguivone
 * Versão: 1
 * Data :  15/09/2015
 */
#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        // Oscillator Selection bits (HS oscillator: High speed crystal/resonator on GP4/OSC2/CLKOUT and GP5/OSC1/CLKIN)
#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
//#define  TIME_BAUD  202//4800 bps - 20MHZ
//#define  BAUD_RX    198//4800 bps - 20MHZ 

#define  TX  GP2//configura o pino que será TX
#define  RX  GP1//configura o pino que será RX

#define  TAM_MAX  10//tamanho maximo do vetor de amostragem(numero de pontos)
#define  NUM_MED  6//numero de intens para formar a media dos picos
//#define  TEMPO_ENVIO  110//(aprox. 15ms)tempo para enviar os dados(em tempo de rotina))
//#define  TEMPO_ENVIO  1100//(aprox. 150ms)tempo para enviar os dados(em tempo de rotina))
#define  TEMPO_ENVIO  7000//(aprox. 1s)tempo para enviar os dados(em tempo de rotina))

int vetor[TAM_MAX+1];
int tensao=0;
char flag_libera=0;

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 serial/////////////////////////////////////////////////////////////
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
}
///é interessante observar que está rotina irá trabalhar melhor se for 
///usado na rotina de interrupção de estado no pino, aqui vou deixar na rotina principal por 
// ser um exemplo simples
char ler() {
    int contagem = 0;
    char RX_dados = 0X00;
    if (RX == 0)//tem dados pra ler
    {
        RX_dados = 0X00;
        while (contagem < 8) //recebe dados + stop bit
        {
            __delay_us(BAUD_RX); //compensa algum delay na recepção 
            if (RX == 1) {
                RX_dados = (RX_dados | 0X80); //seta bit mais significativo (MSB)
            }
            RX_dados = RX_dados >> 1;
            contagem++;
        }
        contagem = 0;
        while ((RX == 0) && (contagem < 4)) {
            contagem++; //time out para não travar,tempo de 4 bits
            __delay_us(TIME_BAUD);
        }
    }
    return (RX_dados);
}

void escreve_frase(char *frase) {
    int tam_frase = strlen(frase);
    int contagem = 0;
    while (contagem < tam_frase)           
    {
        escreve_char(frase[contagem]);
        contagem++;
    }

}

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_char('-');
}
void gira_vetor()
{
    int aux=0;
    while(aux<TAM_MAX)
    {
        vetor[aux] = vetor[aux+1];
        aux++;
    } 
}


//////////////////////////////////////////////////////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(300);//debounce e tempo para preparar hardware
    //logo a frequencia de interrupção é 250khz
    char tempo_media = 0;
    int tempo_de_envio = 0;
    int flag=0;
    for(;;)
    {  //
        __delay_us(1); //para garantir uma leitura estavel
        vetor[TAM_MAX] = ler_adc_un();
        if((flag_libera == 1))
        {
             if(vetor[TAM_MAX]<vetor[0])//localizou o pico de tensão
            {
                int valor =0;
                int aux=0;
                while(valor<TAM_MAX)
                {//procura o maior valor
                    if(aux < vetor[valor])
                    {
                        aux = vetor[valor];
                    }
                   valor++;  
                }
              tensao = aux + tensao;//sempre pega a média da leitura de pico atual pela anterior
              if(tempo_media >= NUM_MED)
              {
                 tensao =tensao/(NUM_MED + 2);//sempre pega a média da leitura de pico atual pela anterior
                 if(tempo_de_envio >= TEMPO_ENVIO)
                 {
                  long_to_char(tensao);
                  tempo_de_envio = 0;
                 }
                 tempo_media =0;
              }
              else
              {
              tempo_media++;
              }
              flag_libera=0;
            }   
        }
        else
        {//flag de liberação desligado
           if(vetor[TAM_MAX] > vetor[0])//localizou o inicio de subida
            {
               flag_libera=1;
            }
        }            
        gira_vetor();        
        tempo_de_envio++;        
    }//loop infinito
}


//NOTAS DE PARAMETRIZAÇÃ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