domingo, 8 de dezembro de 2019

Usando lcd no modo 4 bits, Wattímetro,voltímetro e amperímetro.


     Olá pessoal que acompanha o blog!
   Neste exemplo os conceitos abordados, no uso do compilador C18, serão o uso do conversor analógico digital e a implementação da comunicação em 4 bits utilizando LCD(funciona para 16X2 ou 4X20). A intenção é criar wattímetro que por consequência deve ler tensão e corrente, lembre-se que este circuito serve apenas para corrente continua. 

O código fonte :


/* 
 * File:   main_lcd.c
 * Author: aguivone
 * descrição: como usar display lcd no modo 4 bits no compilador C18
 * freq.de clock: 20MHZ
 * data:08/12/2019 
 */
#include <stdio.h>
#include <p18f4550.h>    
#include <string.h>
#include <delays.h>

//variaveis locais
unsigned char Buffer_lcd[16];
/////////////////////////////////////pinos do microcontrolador usado no lcd ///////////////////////////////////////////
//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
//
//define qual porta vai usar neste caso port D
 #define BIT_0  PORTDbits.RD0
 #define BIT_1  PORTDbits.RD1
 #define BIT_2  PORTDbits.RD2
 #define BIT_3  PORTDbits.RD3

 #define RS     PORTDbits.RD4
 #define EN     PORTDbits.RD5
//////////////usado para escrever em cada bit da porta com o lcd.
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;
////prototipos de funções //////////////////////////////////////////////////////////////////
void Inic_Regs (void);
void _delay_us(int valor);
void _delay_ms(int valor);
unsigned char valor_bit(char cDa,char cBit);
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);
void Read_ADC (void);

////////função principal /////////////////////////////////////////////////////////////////////

void main() 
{
  Inic_Regs();
  inicializa_LCD();
  sprintf(Buffer_lcd,"Volts Corr. Pot.");
  impri_lcd(0,'1');
  sprintf(Buffer_lcd,"  0     0    0  ");
  impri_lcd(0,'2'); 
  while(1)
   { 
         Read_ADC();
         _delay_ms(300);//lê a cada 2s
   }//fim do laçõ while
 
  }//fim do laço main
/////////////inicializa as portas ////////////////////////////////////// 
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 = 0x00;            //PORTC saida
    TRISD = 0x00;            //PORTD saida
    TRISE = 0x00;            //PORTE saida
    ADCON0 = 0X01;          //liga modulo analogico digital e configura entrada de sinal para o pino RA0(AN0)
    ADCON1=0b00001110;          // Vref- seta ao Vss e  Vref+ ao Vdd , somente Ra0 e Ra1 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)
    PORTA = 0x00;            //limpa PORTA
    PORTB = 0x00;            //limpa PORTB
    PORTC = 0x00;            //limpa PORTC
    PORTD = 0x00;            //limpa PORTD:
    PORTE = 0x00;            //limpa PORTE
//********************************************************************
}
//////////////funções de tempo /////////////////////////////////////////////////////////////// 
//===================================================================================
//Função:     _delay_us())
//Parâmetros: inteiro
//Retorno:   não tem retorno.
//Descrição: perde tempo em microsegundoas.
//===================================================================================
 void _delay_us(int valor)
 {
     while(valor>0)
     {
      Nop();Nop();Nop();Nop();Nop();//para 20MHZ -> 5 ciclos dão 1us//  para 8mhz -> 0,5 -> 2 ciclos
      valor--;
     }
 }
 //===================================================================================
//Função:     _delay_ms())
//Parâmetros: inteiro
//Retorno:   não tem retorno.
//Descrição: perde tempo em milisegundos.
//===================================================================================
 void _delay_ms(int valor)
 {
     while(valor>0)
     {
      Delay1KTCYx(5);//para 20MHZ -> 5000 ciclos dão 1ms -> [5]// 8mhz -> 2000 -> [2].
      valor--;
     }
 }

//===================================================================================
//Função:     _porta_lcd
//Parâmetros: char cDado
//Retorno:   não tem retorno.
//Descrição: envia um comando de configuração veja que os tempos devem ser maiores .
//===================================================================================
void porta_lcd(unsigned char ucDado)//byte a ser enviado
{
       LCD.VALOR = ucDado;
       //envia os bytes mais altos
       RS = 0; //habilita comandos
       BIT_0 = LCD.b4;
       BIT_1 = LCD.b5;
       BIT_2 = LCD.b6;
       BIT_3 = LCD.b7;
       EN = 1;
       _delay_ms(15);
       EN = 0;
       _delay_ms(15);
       //envia os bytes mais baixos
       BIT_0 = LCD.b0;
       BIT_1 = LCD.b1;
       BIT_2 = LCD.b2;
       BIT_3 = LCD.b3;
       EN = 1;
       _delay_ms(15);
       EN = 0;
       _delay_ms(15);
}
//===================================================================================
//Função:     _escreve_LCD
//Parâmetros: char cDado,
//            int iVlr
//Retorno:   não tem retorno.
//Descrição: escreve um caracter no display ou envia um comando.
//===================================================================================
void escreve_LCD(unsigned char ucDado,unsigned char ucVlr)//byte a ser enviado ,escreve caracter(0) ou comando(1)
{
    if(ucVlr == '0')
       {
         RS = 0; //habilita comandos
       }
       else
       {
        RS = 1; //habilita dados
       }
       LCD.VALOR = ucDado;
        _delay_us(5);//tempo para display atualizar
       //envia os bytes mais altos
       BIT_0 = LCD.b4;
       BIT_1 = LCD.b5;
       BIT_2 = LCD.b6;
       BIT_3 = LCD.b7;
       EN = 1;
       _delay_us(50);//tempo estabilizar o pino
       EN = 0;
       _delay_us(50);//tempo estabilizar o pino
       //envia os bytes mais baixos
       BIT_0 = LCD.b0;
       BIT_1 = LCD.b1;
       BIT_2 = LCD.b2;
       BIT_3 = LCD.b3;
       EN = 1;
       _delay_us(50);//tempo estabilizar o pino
       EN = 0;
       _delay_us(200);
}
//===================================================================================
//Função:     _inicializa_LCD
//Parâmetros: não tem
//Retorno:   não tem retorno.
//Descrição: faz a configuração inicial do display, verifique os datasheet dos fabricantes.
//===================================================================================
void inicializa_LCD(void)
{
       EN = 0;
       _delay_ms(15);//tempo para estabilizar a tensão e preparar o display
       porta_lcd(0X02);//cursor home - posiciona no inicio
       porta_lcd(0X28);//configura para usar modo 4bits,manda usar 2 linhas e matriza de caracter de 5X7.
       porta_lcd(0X01);//limpa display
       porta_lcd(0X06);//deslocamento do cursor para direita ,sem deslocamento de caracter automaticamente. 
       porta_lcd(0X0C);//liga display :0XC0 -> cursor desligado, 0X0F ->intermitente,0E -> fixo ,08 -> desligado.
       RS = 1; //habilita dados        

}
//===================================================================================
//Função:    _impri_caracter_lcd
//Parâmetros: char cCaracter, -> caracter a ser escrito
//            int iPos_inicial, indica em qual posição deve  colocar o caracter
//            int iLinha, indica qual o a linha do display vai usar
//Retorno:   não tem retorno.
//Descrição: usada para escrever um caracter em um display de lcd.
//===================================================================================
void impri_caracter_lcd(unsigned char ucCaracter,int iPos_inicial ,unsigned char ucLinha)
{
      switch(ucLinha)
           {
            case '1' :{escreve_LCD(0X80 + iPos_inicial,'0');}break;//linha1
            case '2' :{escreve_LCD(0XC0 + iPos_inicial,'0');}break;//linha2
            case '3' :{escreve_LCD(0X94 + iPos_inicial,'0');}break;//linha3
            case '4' :{escreve_LCD(0XD4 + iPos_inicial,'0');}//linha4
            }
       escreve_LCD(ucCaracter,'1');
}
 

//===================================================================================
//Função:    _impri_lcd
//Parâmetros: const char *ccFrase, mensagem que deve ser escrita usando "(aspas) para delimitar o tamanho
//            int iPos_inicial, indica em qual posição deve começar a colocar a mensagem
//            int iLinha, indica qual o a linha do display vai usar
//Retorno:   não tem retorno.
//Descrição: usada para escrever uma string(vetor de caracteres) em um display de lcd com parametro string.
//===================================================================================
//void impri_lcd(unsigned char frase[],int iPos_inicial ,unsigned char ucLinha)//  cuidado para não exceder a quantidade de caracter
void impri_lcd(int iPos_inicial ,unsigned char ucLinha)
{
      unsigned int indice=0;
      unsigned int tamanho = strlen(Buffer_lcd);
      switch(ucLinha)
           {
            case '1' :{escreve_LCD(0X80 + iPos_inicial,'0');}break;//linha1
            case '2' :{escreve_LCD(0XC0 + iPos_inicial,'0');}break;//linha2
            case '3' :{escreve_LCD(0X94 + iPos_inicial,'0');}break;//linha3
            case '4' :{escreve_LCD(0XD4 + iPos_inicial,'0');}//linha4
            }
      while(indice<tamanho)
       {
          if(Buffer_lcd[indice]!='\0')
          {           
            if((Buffer_lcd[indice]!='"') && (indice<21))//dados
                        {
                          escreve_LCD(Buffer_lcd[indice],'1');
                        }
          }
          else
          {
              indice = tamanho;//finaliza impressão
          }
       indice++;
       }
}

void Read_ADC (void)
{
       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
       //////////Lê tensão////////////////////
        ADCON0 = 0X05; 
        _delay_us(40);//espera tensão estabilizar
        ADCON0bits.GO = 1; //RA1
        while (ADCON0bits.DONE == 1); //espera finalizar leitura
       // lido_adc = ((((int)ADRESH <<8)|(ADRESL))&0x03FF); //Lê os valores em hexa
        lido_adc =  (((int)ADRESH)<<8)|(ADRESL);
        temp = (float)((lido_adc*5.0)/1023);       
    //*******************************************************************
        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(0,'2');
        
        //////////Lê corrente ////////////////////
       ADCON0 = 0X01; ///liga RA0        
        _delay_us(40);//espera tensão estabilizar
        ADCON0bits.GO = 1; //RA1
        while (ADCON0bits.DONE == 1); //espera finalizar leitura
       // lido_adc = ((((int)ADRESH <<8)|(ADRESL))&0x03FF); //Lê os valores em hexa
        lido_adc =  (((int)ADRESH)<<8)|(ADRESL);
        temp = (float)((lido_adc*5.0)/1023);       
    //*******************************************************************
        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(6,'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(12,'2');
}


A simulação do proteus:


     Muito obrigado,e até a próxima!

Nenhum comentário :

Postar um comentário

olá,digite aqui seu comentário!