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.
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!