domingo, 8 de dezembro de 2019

Medidor do fator de potência com o PIC 18F4550 - Wattímetro e frequêncímetro.

Olá pessoal!

    Neste exemplo os conceitos abordados serão:
  • Uso do conversor analógico digital
  • Implementação da comunicação em 4 bits utilizando LCD(funciona para 16X2 ou 4X20).
  • Leitura de tensão AC e DC .
  • Medir o fator de potência.
     A intenção é criar um voltímetro,amperímetro,wattímetro,frequencímetro e medidor do fato de potência que por consequência deve ler tensão e corrente DC E AC.O programa se torna extenso mas se for entendido por partes ficará mais fácil o que cada bloco de código faz.
      Para o amperímetro é usado um resistor de 1 R ligado a uma carga(neste caso foi usado uma associação indutor e resistor para ter defasagem das senoides, para o voltímetro foi usado um divisor de tensão que mede até 30V porém não fica tão preciso devido ao numero de bits do conversor AD interno(10 bits).Para o Wattímetro é usado apenas os dados de tensão e corrente para fornecer a potencia instantânea, já para o caso de tensão DC a potencia media é feita ao longo do tempo(pois pode haver variações de tensão e corrente).O circuito montado para testes e simulação é mostrado na figura a seguir:
    Figura 1 - Esquemático geral(elaboração própria)

        Para medir o fator de potencia poderia ter sido feito internamente, com o microcontrolador, porém montar um simples circuito detector de zero com uma porta XOR é uma solução interessante, pois então só é preciso pegar a forma de onda que é proporcional a defasagem do sinal na saida da porta XOR. Porém durante os testes foi observado que esta porta XOR gera dois pulsos, e que o segundo é do momento que as ondas descem, o que gera imprecisão devido ao tempo de decaimento da tensão na saída da porta, na figura 2,em amarelo sinal de saída de XOR, em azul a tensão em vermelho a corrente do circuito.Com este circuito interno foi utilizado apenas uma porta do microcontrolador para medir a largura do sinal(período) e do pulso(fator de potência), por meio das interrupções do ccp1.

                                   Figura 2 - Sinais lidos no circuito de detecção de zero(elaboração própria)
   
      Outra observação é que para simular no proteus, ora se usa a fonte DC, ora se usa a fonte AC em simulações separadas, para alternar entre o modo AC e DC basta apertar o botão de seleção,na figura a seguir é mostrado as simulações  AC e DC.No modo AC a tensão e corrente medida são as de pico, para converter para RMS(que é a mostrada nos multímetros), basta dividir por raiz de 2, conforme figura AC ,figura 4.
          Figura 3 - Modo DC(elaboração própria)

Figura 4 - Modo AC (elaboração própria)

O circuito funcionando é visto na figura 5, veja que ele tem 2 botões sendo um para reset do microcontrolador e outro para alternar os modo de funcionamento. 
                                         Figura 5 - foto do protótipo implementado(elaboração própria)

O código fonte:

/* 
 * Author: Aguivone Moretti Fógia
 * descrição: Multimetro que mede fator de potencia
 * freq.de clock: 20MHZ
 * data:08/12/2019 
 * testado fisicamente.
 */
#include "MCC18_18F4550.h"
#include "tempo_20mhz.h"
#include "LCD_4bits.h"
unsigned char Buffer_lcd[16]; // variavel usada pelo LCD
//variaveia globais para cpp1////////////////////////////////
unsigned int tempo_pulso=0;
unsigned int periodo=0;
unsigned char estado_amostras=0;
unsigned int tempo_ccp1=0;
//variaveis globais para ADC
unsigned char modo_tensao=0;//padrão CC
unsigned char descarta_FP=0;
float PM[5];//pega os ultimos 5 valores para potencia media DC
//defines usados
#define sin1_FP PORTCbits.RC4
#define sin2_FP PORTCbits.RC5
#define BOT_SEL PORTEbits.RE2
#define LED_STATUS PORTEbits.RE1
#define LED_MODO   PORTEbits.RE0 //sinaliza modo AC e pisca a cada pulso de clock
//equações usadas
#define EQ_TENSAO (float)((lido_adc*35.2)/1023) //para divisor de 10K - 1K - Máx: 33V
#define EQ_CORRENTE (float)((lido_adc*5.0)/1023)
#define EQ_FP (float)((90.0*tempo_pulso)/periodo) //fator de potencia
#define EQ_FREQ  (float)((1/(0.0000002*periodo*2.0))/8)//para 20Mhz - divide por 8 pois o T1CON está assim//frequencia
unsigned char sinal_FP= ' ';
////prototipos de funções ///////////////////////
void Inic_Regs (void);
void Read_ADC_DC(void);
void Read_ADC_CA(void);
void high_isr (void);
void Tela_inicial(unsigned char modo);
void verifica_botao(void);
//void low_isr (void);
//vetor de interrupção de alta prioridade
#pragma code high_vector=0x08
void interrupt_at_high_vector(void)
{
    _asm GOTO high_isr _endasm        //desvia programa para rotina de tratamento da interrupção
}
#pragma code 
//*****************************
//Rotina de tratamento de interrupção (ISR)
#pragma interrupt high_isr 
void high_isr (void)
{
   if(PIR1bits.CCP1IF)
    {
        if(estado_amostras==0)
        {//prepara contagem
           TMR1L =0;//Zera timer 1
           TMR1H =0;//Zera timer 1           
           if((sin2_FP)&&(sin1_FP))//se os dois estiver em um indica que está na descida do sinal e isso gera imprecisão
           {//descarta
               estado_amostras=0;               
           }
           else
           {//sinal subindo               
               if(sin1_FP)
                   {sinal_FP= '-';}
               else{sinal_FP= '+';}
               CCP1CON = 0X04;//captura a cada borda de descida
               estado_amostras=1;
           }            
           
        }
        else
        {
            if(estado_amostras==1)
            {//borda de descida - pega valor do pulso
                tempo_pulso =((((unsigned int)CCPR1H)<<8)|CCPR1L);
                estado_amostras = 2;
                CCP1CON = 0X05;//captura a cada borda de subida 
                _delay_ms(1);//
                if((sin2_FP==0)||(sin1_FP==0))//se os dois estiver em zero indica que está na descida do sinal e isso gera imprecisão
                           {//sinal invalido  
                             estado_amostras = 0;
                           }
            }
            else
            {//fim de coleta
                if(estado_amostras == 2)
                {   
                 periodo =((((unsigned int)CCPR1H)<<8)|CCPR1L);
                 estado_amostras=3;//pra sinalizar fim de amostragem  
                 PIE1bits.CCP1IE = 0;//não precisa mais das interrupçõe do CCP1
                 PORTDbits.RD3 = 0;
                }
            }
        }        
        PIR1bits.CCP1IF = 0;//limpa flag   
    }
    
}
/////rotina principal/////////////////////////////
void main() 
{
  Inic_Regs();
  inicializa_LCD();
  Tela_inicial('D');
  modo_tensao=0;
  while(1)
   { 
     verifica_botao();
     if(modo_tensao)//modo AC
     {
        Read_ADC_CA();
        tempo_ccp1=0; 
        estado_amostras=0;//libera nova coleta     
        PIE1bits.CCP1IE = 1;//liga interrupcão do ccp1
        while(tempo_ccp1<100)//demora em media 100ms
         { 
           if(estado_amostras==3)
               {//tem coleta mostra o valor 
                   float temp;
                   unsigned int parte_inteira;                //declaração de variável local
                   unsigned int parte_decimal;                //declaração de variável local 
                   if(descarta_FP == 0)
                   {
                    temp=EQ_FP;//pois divide por (2*semicilo)
                   }
                   else
                   {
                    temp=0;//tensão ou corrente sem leitura   
                   }
                    parte_inteira = (int)temp;            //pega parte inteira do valor
                    parte_decimal =(unsigned int)((temp - parte_inteira) * 10);    //resgata parte fracionária do valor ,2 casa decimais
                    sprintf(Buffer_lcd,"%c%u.%u",sinal_FP,parte_inteira,parte_decimal);        //converte valor em string e armazena no vetor buf    
                    impri_lcd(4,'3');
                    if(descarta_FP == 0)
                   {
                     temp=(EQ_FREQ);//para 20Mhz - divide por 8 pois o T1CON está assim
                     
                   }
                   else
                   {
                    temp=(EQ_FREQ*2);//tensão ou corrente sem leitura -> onda fica igual a corrente ou a tensão  
                   }                   
                   parte_inteira = (int)temp;            //pega parte inteira do valor
                   parte_decimal =(unsigned int)((temp - parte_inteira) * 10);    //resgata parte fracionária do valor ,2 casa decimais
                   sprintf(Buffer_lcd,"%u.%u",parte_inteira,parte_decimal);        //converte valor em string e armazena no vetor buf    
                   impri_lcd(3,'4'); //frequencia
                   _delay_ms(250);//lê a cada 0.5s
                   PIE1bits.CCP1IE = 1;//liga interrupcão do ccp1
                   _delay_us(10);//espera tempo para CCP1 se preparar
                   estado_amostras=0;//libera nova coleta
               }
               if(estado_amostras==2)
               {
                    if((sin2_FP==0)||(sin1_FP==0))//se os dois estiver em um indica que está na descida do sinal
                        //(do segundo sinal) e isso gera imprecisão 
                           {//sinal invalido  
                             estado_amostras = 0;
                           }

               }
           _delay_ms(1);
           tempo_ccp1++;
       }//fim do laçõ ccp1
       PIE1bits.CCP1IE = 0;//desliga interrupcão do ccp1 pra garantir
     }
     else//modo DC
     {
         Read_ADC_DC(); 
     }     
    _delay_ms(500);
    LED_STATUS=~LED_STATUS;
  }//fim do while 
  }//fim do laço main

/////////////////////////////////////////////////////////////////////////////////

void verifica_botao(void)
{
     if(!BOT_SEL)//testa botão de seleção -> AC/DC
     {
            _delay_ms(200);//debouce
            if(!BOT_SEL)
            {
               if(modo_tensao)
               {//modo DC
                   Tela_inicial('D');
                   modo_tensao=0;
                   LED_MODO =0;   
                   PIE1bits.CCP1IE = 0;//desliga interrupcão do ccp1
               }
               else
               {//modo AC
                   Tela_inicial('A');
                   LED_MODO =1;
                   modo_tensao=1;
                   estado_amostras=0;//libera nova coleta     
                   PIE1bits.CCP1IE = 1;//liga interrupcão do ccp1
               }
               _delay_ms(200);//debouce
            }
     }
}
 void Inic_Regs(void)
{
    TRISA = 0x03;            //PORTA saida, exceto RA0(tensão) e RA1(corrente) será usado para entradas analogicas
    TRISB = 0x00;            //PORTB saida
    TRISC = 0x34;            //PORTC saida e pino c2 entrada ccp1,pino C4 e C5 informa sinal do fator de potencia 
    TRISD = 0x00;            //PORTD saida
    TRISE = 0x04;            //PORTE saida,botão no RE2
    PORTA = 0x00;            //limpa PORTA
    PORTB = 0x00;            //limpa PORTB
    PORTC = 0x00;            //limpa PORTC
    PORTD = 0x00;            //limpa PORTD:
    PORTE = 0x00;            //limpa PORTE
//********************************************************************
    ADCON0 = 0X01;          //liga modulo analogico digital e configura entrada de sinal para o pino RA0(AN0)
    ADCON1=0b00001011;          // Vref- seta ao Vss e  Vref+ ao Vdd , somente Ra0 ate Ra4 analogico
    //ADCON2 = 0b101101010;    // justificado a direita     // clk Fosc/32
       ADCON2=0b10101001;
    // tempo de aquisição 12TAD(assim funciona pra qualquer cristal, porem fica mais lento, se precisar deve ser ajustado)
    INTCON=0b11000000;//liga interrupção de periferico e geral
    T3CON = 0;//mantem o ccp1 e ccp2 ligado ao timer1
    T1CON = 0b10110001;//modo de 16bits - fosc/dividido por 8 - timer ligado (lé no maximo500khz para clock de 8MHZ))
    CCP1CON = 0b00000101;//captura a cada borda de subida
    IPR1= 0X05;//coloca estouro de timer  e ccp1 como alta prioridade
    PIR1bits.CCP1IF = 0;//limpa flag do ccp1
    PIE1bits.CCP1IE = 1;//liga interrupcão do ccp1
    PIE1bits.TMR1IE = 0;//deixa interrupção de timer desligado(não vai prescisar))
 }
 //configura tela inicial
 void Tela_inicial(unsigned char modo)
{    
    if(modo == 'A') 
    {
        sprintf(Buffer_lcd,"Vrms=      V  -> AC ");
        impri_lcd(0,'1');
        sprintf(Buffer_lcd,"Vp=     V  Ip=     A");
    }else
    {
        sprintf(Buffer_lcd,"Multimetro    -> DC ");
        impri_lcd(0,'1');
        sprintf(Buffer_lcd,"Vdc=     V Idc=    A");  
    }
  impri_lcd(0,'2'); 
  sprintf(Buffer_lcd,"Fp=        Pi=     W");
  impri_lcd(0,'3');
  sprintf(Buffer_lcd,"F=      hz Pm=     W");
  impri_lcd(0,'4');  
} 
 //faz leitura de amostras em corrente continua
void Read_ADC_CA(void)
{       
       unsigned int lido_adc;
       float temp,tensao;
       unsigned int parte_inteira;                //declaração de variável local
       unsigned int parte_decimal;                //declaração de variável local
       unsigned int hist_leitura[5]={0,0,0,0,0};//pega 5 amostras para não estourar a variavel
       unsigned char fim_captura=245;//esse valor pede pra encontrar quando a onda está subindo
       unsigned int num_de_tentativas = 0;
       descarta_FP=0;//libera leitura do fator de potencia
       //////////Lê tensão////////////////////
        ADCON0 = 0X01; //RA0
        _delay_us(40);//espera tensão estabilizar 
        hist_leitura[0] = 0XFFFF;//coloca valor maximo para garantir 
        while((fim_captura == 245)&&(modo_tensao==1))
        {
            ADCON0bits.GO = 1; //RA1 habilita conversão         
             while (ADCON0bits.DONE == 1); //espera finalizar leitura
            hist_leitura[1] =  (((int)ADRESH)<<8)|(ADRESL);
             if((hist_leitura[1]>hist_leitura[0])&&(hist_leitura[1]<10))//pra garantir que está no começo da onda 
                {
                   fim_captura = 0;//finalizou processo onda está subindo
                }
            hist_leitura[0]= hist_leitura[1];//recebe valor atual
            verifica_botao();
            num_de_tentativas++;
            if(num_de_tentativas>1000)//anti travamento
            {
                fim_captura = 253;//indica que não leu tensão
            }
        }
        while((fim_captura < 250)&&(modo_tensao==1))
        {
            ADCON0bits.GO = 1; //RA1 habilita conversão         
            while (ADCON0bits.DONE == 1); //espera finalizar leitura
            hist_leitura[fim_captura] =  (((int)ADRESH)<<8)|(ADRESL);
            if(fim_captura == 0)
            {
                if(hist_leitura[0]<hist_leitura[4])
                {
                   fim_captura = 252;//finalizou processo 
                   lido_adc = ((hist_leitura[4]+hist_leitura[3]+hist_leitura[2])/3);//tira uma média das 3 ultimas amostras
                }
            }
            else
            {
                if(hist_leitura[fim_captura]<hist_leitura[fim_captura-1])
                {
                    unsigned char conta = 0;
                     lido_adc =0;
                    while(conta<5)//0 a 4
                    {
                        if(conta != fim_captura)//ignora valor atual
                        {
                            lido_adc =  lido_adc + hist_leitura[conta];
                        }
                        conta++;
                    }
                     lido_adc = lido_adc/4;//tira media
                    fim_captura = 252;//finalizou processo 
                }
            }            
            if(fim_captura<250)
            {
                fim_captura++;
                if(fim_captura > 4)
                {
                    fim_captura = 0; 
                }
            }
           verifica_botao(); 
        }
        if(fim_captura == 253)
        {
          temp = 0;
          descarta_FP=1;
        }else
        {
         temp = EQ_TENSAO ;         
        }
    //*******************************************************************
        if(temp < 0)                    //valor é menor que 0?
        { temp = temp * (-1);        //inverte o sinal de float
        }
    //*******************************************************************
        parte_inteira = (int)temp;            //pega parte inteira do valor
        tensao =temp;
    //*******************************************************************
        parte_decimal =(unsigned int)((temp - parte_inteira) * 100);    //resgata parte fracionária do valor ,2 casa decimais
        Tela_inicial('A');//limpa campos
        sprintf(Buffer_lcd,"%u.%u",parte_inteira,parte_decimal);        //converte valor em string e armazena no vetor buf    
        impri_lcd(3,'2'); 
        temp=(tensao/1.4142);
        parte_inteira = (int)temp;            //pega parte inteira do valor        
    //*******************************************************************
        parte_decimal =(unsigned int)((temp - parte_inteira) * 100);    //resgata parte fracionária do valor ,2 casa decimais
        sprintf(Buffer_lcd,"%u.%u",parte_inteira,parte_decimal);        //converte valor em string e armazena no vetor buf    
        impri_lcd(5,'1'); 
        
        //////////Lê corrente////////////////////        
        hist_leitura[0]=0;
        hist_leitura[1]=0;
        hist_leitura[2]=0;
        hist_leitura[3]=0;
        hist_leitura[4]=0;
        ADCON0 = 0X05; ///liga RA1  
        _delay_us(40);//espera tensão estabilizar 
        fim_captura = 245;
        hist_leitura[0] = 0XFFFF;//coloca valor maximo para garantir 
        num_de_tentativas=0;
         while((fim_captura == 245)&&(modo_tensao==1))
        {
            ADCON0bits.GO = 1; //RA1 habilita conversão         
            while (ADCON0bits.DONE == 1); //espera finalizar leitura
            hist_leitura[1] =  (((unsigned int)ADRESH)<<8)|(ADRESL);
             if((hist_leitura[1]>hist_leitura[0])&&(hist_leitura[1]<10))//pra garantir que está no começo da onda
                {
                   fim_captura = 0;//finalizou processo onda está subindo
                }
            hist_leitura[0]= hist_leitura[1];//recebe valor atual
            verifica_botao();
            num_de_tentativas++;
            if(num_de_tentativas>1000)//anti travamento
            {
                fim_captura = 253;//indica que não leu tensão
            }            
        }
        while((fim_captura < 250)&&(modo_tensao==1))
        {
            ADCON0bits.GO = 1; //RA0 habilita conversão         
            while (ADCON0bits.DONE == 1); //espera finalizar leitura
            hist_leitura[fim_captura] =  (((int)ADRESH)<<8)|(ADRESL);
            if(fim_captura == 0)
            {
                if(hist_leitura[0]<hist_leitura[4])
                {
                   fim_captura = 252;//finalizou processo 
                   lido_adc = ((hist_leitura[4]+hist_leitura[3]+hist_leitura[2])/3);//tira uma média das 3 ultimas amostras
                }
            }
            else
            {
                if(hist_leitura[fim_captura]<hist_leitura[fim_captura-1])
                {
                    unsigned char conta = 0;
                     lido_adc =0;
                    while(conta<5)//0 a 4
                    {
                        if(conta != fim_captura)//ignora valor atual
                        {
                            lido_adc =  lido_adc + hist_leitura[conta];
                        }
                        conta++;
                    }
                     lido_adc = lido_adc/4;//tira media
                    fim_captura = 252;//finalizou processo 
                }
            }            
            if(fim_captura<250)
            {
                fim_captura++;
                if(fim_captura > 4)
                {
                    fim_captura = 0; 
                }
            }
            verifica_botao();
        }
        if(fim_captura == 253)
        {
          temp = 0;
          descarta_FP=1;
        }else
        {
         temp = EQ_CORRENTE;  
        }               
    //*******************************************************************
        if(temp < 0)                    //valor é menor que 0?
        { temp = temp * (-1);        //inverte o sinal de float
        }
    //*******************************************************************
        parte_inteira = (int)temp;            //pega parte inteira do valor        
    //*******************************************************************
        parte_decimal =(unsigned int)((temp - parte_inteira) * 100);    //resgata parte fracionária do valor ,2 casa decimais
        sprintf(Buffer_lcd,"%u.%u",parte_inteira,parte_decimal);        //converte valor em string e armazena no vetor buf    
        impri_lcd(14,'2');
        temp = tensao*temp;
        parte_inteira = (int)temp;            //pega parte inteira do valor 
        parte_decimal =(unsigned int)((temp - parte_inteira) * 10);//somente uma casa decimal
        sprintf(Buffer_lcd,"%u.%u",parte_inteira,parte_decimal);        //converte valor em string e armazena no vetor buf    
        impri_lcd(14,'3'); 
        //potencia media ac
        temp = temp/2;
        parte_inteira = (int)temp;            //pega parte inteira do valor 
        parte_decimal =(unsigned int)((temp - parte_inteira) * 10);//somente uma casa decimal
        sprintf(Buffer_lcd,"%u.%u",parte_inteira,parte_decimal);        //converte valor em string e armazena no vetor buf    
        impri_lcd(14,'4');

}
//faz leitura de amostras em corrente continua
void Read_ADC_DC(void)
{
       unsigned int lido_adc;
       float temp,tensao;
       unsigned int parte_inteira;                //declaração de variável local
       unsigned int parte_decimal;                //declaração de variável local
       unsigned int amostras[5];
       //////////Lê tensão////////////////////
        ADCON0 = 0X01;//RA0 
        _delay_us(40);//espera tensão estabilizar
        lido_adc = 0;
        while(lido_adc<5)
        {
        ADCON0bits.GO = 1; //RA0
        while (ADCON0bits.DONE == 1); //espera finalizar leitura
        amostras[lido_adc] =  (((unsigned int)ADRESH)<<8)|(ADRESL);
        lido_adc++;
        }
        temp = amostras[0] +amostras[1] +amostras[2] +amostras[3] +amostras[4];
        lido_adc =(unsigned int)temp/5;
        temp = EQ_TENSAO;  
        Tela_inicial('D');//limpa campos
    //*******************************************************************
        if(temp < 0)                    //valor é menor que 0?
        { temp = temp * (-1);        //inverte o sinal de float
        }
    //*******************************************************************
        parte_inteira = (int)temp;            //pega parte inteira do valor
        tensao =temp;
    //*******************************************************************
        parte_decimal =(unsigned int)((temp - parte_inteira) * 100);    //resgata parte fracionária do valor ,2 casa decimais
        sprintf(Buffer_lcd,"%u.%u",parte_inteira,parte_decimal);        //converte valor em string e armazena no vetor buf    
        impri_lcd(4,'2');
        
        //////////Lê corrente ////////////////////
       ADCON0 = 0X05; ///liga RA1        
        _delay_us(40);//espera tensão estabilizar
       lido_adc = 0;
        while(lido_adc<5)
        {
        ADCON0bits.GO = 1; //RA0
        while (ADCON0bits.DONE == 1); //espera finalizar leitura
        amostras[lido_adc] =  (((unsigned int)ADRESH)<<8)|(ADRESL);
        lido_adc++;
        }
        temp = amostras[0] +amostras[1] +amostras[2] +amostras[3] +amostras[4];
        lido_adc =(unsigned int)temp/5;
        temp = EQ_CORRENTE;       
    //*******************************************************************
        if(temp < 0)                    //valor é menor que 0?
        { temp = temp * (-1);        //inverte o sinal de float
        }
    //*******************************************************************
        parte_inteira = (int)temp;            //pega parte inteira do valor        
    //*******************************************************************
        parte_decimal =(unsigned int)((temp - parte_inteira) * 100);    //resgata parte fracionária do valor ,2 casa decimais
        sprintf(Buffer_lcd,"%u.%u",parte_inteira,parte_decimal);        //converte valor em string e armazena no vetor buf    
        impri_lcd(15,'2');
        temp = tensao*temp;
        parte_inteira = (int)temp;            //pega parte inteira do valor 
        parte_decimal =(unsigned int)((temp - parte_inteira) * 10);//somente uma casa decimal
        sprintf(Buffer_lcd,"%u.%u",parte_inteira,parte_decimal);        //converte valor em string e armazena no vetor buf    
        impri_lcd(14,'3');        
        PM[3]= PM[4];
        PM[2]= PM[3];
        PM[1]= PM[2];
        PM[0]= PM[1];
        PM[4]= temp+ PM[0]+PM[1]+ PM[2]+ PM[3];
        tensao =temp;
        temp= PM[4]/5;//potencia media reaproveitando variavel
        PM[4]=tensao;
        parte_inteira = (int)temp;            //pega parte inteira do valor 
        parte_decimal =(unsigned int)((temp - parte_inteira) * 10);//somente uma casa decimal
        sprintf(Buffer_lcd,"%u.%u",parte_inteira,parte_decimal);        //converte valor em string e armazena no vetor buf    
        impri_lcd(14,'4');
}

Arquivo MCC18_18F4550_H.h


/* 
 * File:   main_lcd.c
 * Author: aguivone
 * descrição: como usar display lcd no modo 4 bits
 * freq.de clock: 20MHZ
 * data:31/10/2019 
 * não esquecer de coloca o arquivo MCC18_18F4550.h
 */
#include <stdio.h>
#include <p18f4550.h>    
#include <string.h>
#include <delays.h>

#ifndef __MCC18_18F4550___H
#define    __MCC18_18F4550___H

// CONFIG1L
#pragma config PLLDIV = 1       // PLL Prescaler Selection bits (No prescale (4 MHz oscillator input drives PLL directly))
#pragma config CPUDIV = OSC1_PLL2// System Clock Postscaler Selection bits ([Primary Oscillator Src: /1][96 MHz PLL Src: /2])
#pragma config USBDIV = 1       // USB Clock Selection bit (used in Full-Speed USB mode only; UCFG:FSEN = 1) (USB clock source comes directly from the primary oscillator block with no postscale)

// CONFIG1H
#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator (HS))
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF       // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)

// CONFIG2L
#pragma config PWRT = OFF       // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOR = OFF        // Brown-out Reset Enable bits (Brown-out Reset disabled in hardware and software)
#pragma config BORV = 3         // Brown-out Reset Voltage bits (Minimum setting 2.05V)
#pragma config VREGEN = OFF     // USB Voltage Regulator Enable bit (USB voltage regulator disabled)

// CONFIG2H
#pragma config WDT = OFF        // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))
#pragma config WDTPS = 32768    // Watchdog Timer Postscale Select bits (1:32768)

// CONFIG3H
#pragma config CCP2MX = ON      // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
#pragma config PBADEN = ON      // PORTB A/D Enable bit (PORTB<4:0> pins are configured as analog input channels on Reset)
#pragma config LPT1OSC = OFF    // Low-Power Timer 1 Oscillator Enable bit (Timer1 configured for higher power operation)
#pragma config MCLRE = ON       // MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled)

// CONFIG4L
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = OFF        // Single-Supply ICSP Enable bit (Single-Supply ICSP disabled)
#pragma config ICPRT = OFF      // Dedicated In-Circuit Debug/Programming Port (ICPORT) Enable bit (ICPORT disabled)
#pragma config XINST = OFF      // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))

// CONFIG5L
#pragma config CP0 = OFF        // Code Protection bit (Block 0 (000800-001FFFh) is not code-protected)
#pragma config CP1 = OFF        // Code Protection bit (Block 1 (002000-003FFFh) is not code-protected)
#pragma config CP2 = OFF        // Code Protection bit (Block 2 (004000-005FFFh) is not code-protected)
#pragma config CP3 = OFF        // Code Protection bit (Block 3 (006000-007FFFh) is not code-protected)

// CONFIG5H
#pragma config CPB = OFF        // Boot Block Code Protection bit (Boot block (000000-0007FFh) is not code-protected)
#pragma config CPD = OFF        // Data EEPROM Code Protection bit (Data EEPROM is not code-protected)

// CONFIG6L
#pragma config WRT0 = OFF       // Write Protection bit (Block 0 (000800-001FFFh) is not write-protected)
#pragma config WRT1 = OFF       // Write Protection bit (Block 1 (002000-003FFFh) is not write-protected)
#pragma config WRT2 = OFF       // Write Protection bit (Block 2 (004000-005FFFh) is not write-protected)
#pragma config WRT3 = OFF       // Write Protection bit (Block 3 (006000-007FFFh) is not write-protected)

// CONFIG6H
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) are not write-protected)
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot block (000000-0007FFh) is not write-protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM is not write-protected)

// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protection bit (Block 0 (000800-001FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF      // Table Read Protection bit (Block 1 (002000-003FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF      // Table Read Protection bit (Block 2 (004000-005FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR3 = OFF      // Table Read Protection bit (Block 3 (006000-007FFFh) is not protected from table reads executed in other blocks)

// CONFIG7H
#pragma config EBTRB = OFF      // Boot Block Table Read Protection bit (Boot block (000000-0007FFh) is not protected from table reads executed in other blocks)


#endif    /* __MCC18_18F4550___H */

Arquivo tempo.h
/* 
 * File:   tempo.h
 * Author: aguiv
 *
 * Created on 8 de Novembro de 2019, 15:54
 */
#include <delays.h>
#ifndef TEMPO_H
#define    TEMPO_H

 void _delay_us(int valor);
 void _delay_ms(int valor);
 #include "tempo_20MHz.c"

#endif    /* TEMPO_H */

Aquivo tempo_20MHz.c
/* 
 * File:   tempo.c
 * Author: aguivone
 *
 * Created on 8 de Novembro de 2019, 16:02
 */
// usado para criar funções de tempo

 void _delay_us(int valor)
 {
     while(valor>0)
     {
      Nop();Nop();Nop();Nop();Nop();//Nop();Nop();Nop();      
      //para 32-> 8 ciclos ,20MHZ -> 5 ciclos dão 1us , para 8mhz -> 2ciclo, para 4mhz ->>1ciclo 
      valor--;
     }
 }
 void _delay_ms(int valor)
 {
     while(valor>0)
     {
      Delay1KTCYx(5);
      //para 32MHZ -> coloque 8
      //para 20MHZ -> 5000 ciclos dão 1ms -> coloque 5
      // 8mhz -> 2000 -> coloque 2
      // 4mhz -> 1000 -> coloque 1
      valor--;
     }
 }
 //delay de segundos
 void _delay_s(int valor)
 {
     while(valor>0)
     {
      _delay_ms(1000); 
      valor--;
     }
 }



Aquivo da biblioteca do LCD - LCD_4bits.h

/* 
 * File:   LCD_4bits.h
 * Author: aguivone
 *
 * Created on 8 de Novembro de 2019, 16:07
 */
//biblioteca para acessar o display de LCD no modo 4 bits
//o pino r/w é conectado ao terra pois não é feita nenhuma leitura no display
//configuração:
//
// pino display  / pino da porta selecionada
//
// D4 = bit 0 da porta
// D5 = bit 1 da porta
// D6 = bit 2 da porta
// D7 = bit 3 da porta
//
// RS = bit 4 da porta
// EN = bit 5 da porta
//

#include <stdio.h>
#include <p18f4550.h>    //se for necessario troque este
#include <string.h>

#ifndef LCD_4BITS_H
#define    LCD_4BITS_H
//variaveis locais
extern unsigned char Buffer_lcd[16]; //lembre de criar esta variavel no codigo principal
/////////////////////////////////////pinos do microcontrolador usado no lcd ///////////////////////////////////////////
//define qual porta vai usar neste caso port D

///acepic////////////
/*
  #define BIT_0  PORTDbits.RD4
 #define BIT_1  PORTDbits.RD5
 #define BIT_2  PORTDbits.RD6
 #define BIT_3  PORTDbits.RD7

 #define RS     PORTEbits.RE0
 #define EN     PORTEbits.RE1
*/
//prototipo montado na protoboard/////////
 #define BIT_0  PORTDbits.RD4
 #define BIT_1  PORTDbits.RD5
 #define BIT_2  PORTDbits.RD6
 #define BIT_3  PORTDbits.RD7

 #define RS     PORTDbits.RD0
 #define EN     PORTDbits.RD1


union{
    unsigned char VALOR;
    struct{
        unsigned b0:1;
        unsigned b1:1; 
        unsigned b2:1;
        unsigned b3:1;
        unsigned b4:1;
        unsigned b5:1;
        unsigned b6:1;
        unsigned b7:1;
    };    
}LCD;
void porta_lcd(unsigned char ucDado); 
void escreve_LCD(unsigned char ucDado,unsigned char ucVlr); 
void inicializa_LCD(void);
void impri_lcd(int iPos_inicial ,unsigned char ucLinha);
void impri_caracter_lcd(unsigned char ucCaracter,int iPos_inicial ,unsigned char ucLinha);
 #include "LCD_4bits.c"
#endif    /* LCD_4BITS_H */



Até a próxima! obrigado!

Nenhum comentário :

Postar um comentário

olá,digite aqui seu comentário!