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!