CONTROLANDO UM LCD
16X2 SEM BIBLIOTECAS “MÁGICAS” COM PIC16F628A
APRENDA A USAR O TIMER0
Nessa experiência
será demonstrado o uso de um LCD tipo caracter com 16
colunas e 2 linhas (16x2), com sua configuração e uso.
A placa de estudos
PE-PIC16F628A não possui um LCD “nativo”, nem mesmo
pontos de conexão prontos para o mesmo. Porém é bem
fácil realizar estas conexões e você vai precisar apenas
de:
1 – LCD 16x2 sem nenhum tipo de
placa adicional (LCD “puro”);
8 – cabinhos tipo jumper fêmea para fêmea com 20 cm
para realizar as conexões entre o LCD e a placa;
Conecte os pinos 10
a 14 (D4 a D7) do LCD aos pontos 1 a 4 do conector
PORTB_2 da placa, e os pontos 4 e 6 (R/S e EN,
respectivamente) do LCD aos pontos 1 e 2 (RA0 e RA1) do
conector PORTA da placa. A figura abaixo mostra estas
conexões.
Obs. O VCC e
GND do LCD devem ser conectados aos pontos +5V e GND
da placa. Cuidado para não inverter estas ligações!
Confira todas as
conexões antes de alimentar a placa! Não tenha pressa
aqui!
O programa faz uso
do TIMER0 para realizar a alteração da mensagem
no LCD. Note que, o timer0 foi configurado para
gerar uma interrupção a cada 8ms aproximadamente. Os
registradores necessários para uso do timer0 estão
basicamente dentro de INTCON e OPTION (já
descrito em "Registradores).
Em OPTION
deve-se zerar o bit TOCS para que o clock
do timer0 seja retirado do sistema (PIC). Em
seguida o bit PSA deve ser também zerado para
que o prescaler seja desviado para o timer0.
Os bits PS2, PS1 e PS0 devem ser
configurados para que se consiga um divisor por 64.
Após isso o valor
inicial da contagem é inserido no registrador TMR0.
Dessa forma o timer contará de um valor até seu estouro
(overflow) em 255H (o timer0 tem apenas 8
bits).
E finalmente em INTCON
deve ser setado o bit T0IE que ativará a
interrupção do timer0 por overflow (gera
a int sempre que o timer0 chegar ao final da
contagem).
Sempre que uma
interrupção é gerada, a mesma é analizada dentro da
função pic_isr() e se for uma interrupção
do timer0 a função trata_int_timer0()
será chamada. Na mesma a variável count_timer é
incrementada até chegar a aproximadamente 2000ms (8ms x
250 = 2s). Sempre que essa variável chegar a 250 a mesma
será zerada, e a variável nr_msg sofrerá uma
alteração através da lógica XOR, alternando sempre entre
0 e 1 e em seguida a variável change_msg recebe
o valor “1”. Dessa forma, dentro da função main,
no laço while, é possível observar a alteração
das variáveis e realizar o envio da mensagem correta
para o LCD.
Note que dentro da
função o valor inicial de TMR0 deve ser
restabelecido. Sem isso não haverá uma próxima
contagem!!!
A programação do LCD
segue exatamente conforme descrito nos manuais da
maioria dos fabricantes.
Esta
experiência, assim como a anterior, tem alguns módulos
(arquivos). Crie mesmos conforme as listagens abaixo
e os adicione em seu projeto. Grave o PIC e observe os
resultados.
Listagem main.c
//****************************************************************************** // Projeto LCD para placa PE-PIC16F628A - teste de LCD 16x2 // Demonstra como enviar mensagens para um LCD 16 colunas 2 linhas // Troca mensagens via timer0 // // Desenvolvido por: Eng. Márcio José Soares // // V1.0 - 12/09/2022 // // Compilador: XC8 v2.45 // IDE : MPLABX 6.0 Linux // Plataforma: placa PE-PIC16F628A com PIC16F648A // Gravador : PICKIT3 // // Pinos utilizados: // RA0 : EN // RA1 : RS // RB4 : D4 - LCD // RB5 : D5 - LCD // RB6 : D6 - LCD // RB7 : D7 - LCD // // Obs.: Os jumpers JP2 e JP3 devem ser removidos! //******************************************************************************
//****************************************************************************** // O Copyright deste programa está reservado para Márcio José Soares e seu // conteúdo está protegido pela Lei de Direitos Autorais LEI Nº 9.610, de // 19 de Fevereiro de 1998. É estritamente proibida a reprodução total ou // parcial dos conteúdos aqui apresentados sem prévia autorização, por escrito, // do autor. //******************************************************************************
//****************************************************************************** // Bits de configuração #pragma config FOSC = HS // Seleção do oscilador (Oscilador externo: cristal) #pragma config WDTE = OFF // WDT desabilitado #pragma config PWRTE = ON // Power-up Timer habilitado #pragma config MCLRE = ON // reset externo via resistor em MCLR #pragma config BOREN = OFF // Brown-out Detect BOD desabilitado #pragma config LVP = OFF // Low-Voltage Programming desabilitado - I/O RB4 #pragma config CPD = OFF // EEPROM desabilitada #pragma config CP = OFF // Flash desabilitada
//****************************************************************************** // Se nenhuma freqüência foi definida, assume 4MHz // Esta definição é exigida para calibrar as funções __delay_us() e __delay_ms() #define _XTAL_FREQ 4000000
//****************************************************************************** // Inclui arquivos #include <xc.h> #include <string.h> #include "my_defines.h" #include "pic_lcd.h"
//****************************************************************************** // Variáveis do módulo volatile byte count_timer0 = 0; volatile byte change_msg = 1; volatile byte nr_msg = 0;
//****************************************************************************** // Funções externas do módulo extern void clear_LCD(byte modo); extern void mudalinha(char linha); extern void config_LCD(void); extern void stringR_LCD(char *msg); extern void init_timer0(void); //extern void I2C_Slave_Init(uint8_t address);
//****************************************************************************** // Funções do módulo
//****************************************************************************** // Função config pic - configura pinos de I/O e outros // // Entradas - nenhuma // Saídas - nenhuma //****************************************************************************** void config_pic(void){ PORTA = 0; // zera ports PORTB = 0; INTCON = 0x00; // Todas as ints desligadas CMCON = 0x07; // desliga comparadores TRISA = 0xFC; // Configura PORT A - entrada, exceto RA0 e RA1 TRISB = 0x00; // Configura PORT B - saída //************************************************************************** // Prepara LCD res_lcden; res_lcdrs; PLCDDATA = 0x00; //I2C_Slave_init(I2C_ADD); //inicia I2C no modo slave config_LCD(); //configura LCD clear_LCD(0); //apaga display - 2x para estabilizar }
//****************************************************************************** // Função principal // // Entradas - nenhuma // Saídas - nenhuma //****************************************************************************** void main(void) { char msg[NRCOLS+2]; config_pic(); // configura pic __delay_ms(250); // aguarda estabilizar clear_LCD(0); // limpa LCD //************************************************************************** // Flags de controle das interrupções INTCONbits.PEIE = 1; // PEIE=1 - habilita int dos periféricos // timers, comparadores, usart, etc) INTCONbits.GIE = 1; // GIE=1 - habilita interrupções globais. while(TRUE){ clear_LCD(0); // limpa LCD strcpy(msg," PLACA "); stringR_LCD(&msg[0]); // envia para LCD strcpy(msg," PE-PIC16F628A"); mudalinha(2); // muda para linha 2 stringR_LCD(&msg[0]); // envia para LCD __delay_ms(2000); clear_LCD(0); // limpa LCD strcpy(msg," by Arne "); stringR_LCD(&msg[0]); // envia para LCD strcpy(msg," 2022 "); mudalinha(2); // muda para linha 2 stringR_LCD(&msg[0]); // envia para LCD __delay_ms(2000); } return; }
|
Listagem pic_timer0.c
//***************************************************************************** // Arquivo pic_timer0.c - módulo de configuração e uso do timer0 // Desenvolvido por Márcio José Soares //*****************************************************************************
//***************************************************************************** // O Copyright deste programa está reservado para Márcio José Soares e seu // conteúdo está protegido pela Lei de Direitos Autorais LEI Nº 9.610, de // 19 de Fevereiro de 1998. É estritamente proibida a reprodução total ou // parcial dos conteúdos aqui apresentados sem prévia autorização, por escrito, // do autor. //*****************************************************************************
//***************************************************************************** // Arquivos incluídos no módulo //***************************************************************************** #include <xc.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "my_defines.h"
//***************************************************************************** // Tipos definidos pelo usuário //***************************************************************************** #ifndef _MYDEFS_ #define _MYDEFS_ typedef unsigned char byte; typedef unsigned char Uint8; typedef unsigned short Uint16; #endif
//***************************************************************************** // Se nenhuma freqüência foi definida, assume 4MHz // Esta definição é exigida para calibrar as funções __delay_us() e __delay_ms() #ifndef _XTAL_FREQ #define _XTAL_FREQ 4000000 #endif
//***************************************************************************** // Variáveis externas do módulo //***************************************************************************** extern volatile byte count_timer0; extern volatile byte change_msg; extern volatile byte nr_msg;
//****************************************************************************** // Funções externas do módulo //*****************************************************************************
//***************************************************************************** // Funções do módulo //***************************************************************************** void init_timer0(void); void trata_int_timer0(void);
//***************************************************************************** // Função init_timer0 -inicia timer 0 // // Entradas - nenhuma // Saidas - nenhuma //***************************************************************************** void init_timer0(void){
//************************************************************************** // Timer 0 habilitado em // 4MHz/4 = 1MHz => 1MHz/64= 15.625Khz => T=1/15.625 = T=64us // 64us x 125 = 8 ms - tempo de cada int do timer0 // para obter o valor de inicializaçãoo do timer deve-se fazer (256-125)=131 T0CS = 0; //clock retirado do sistema PSA = 0; //prescaler desviado para timer0 PS0 = 1; //prescaler setado em 1:64 PS1 = 0; PS2 = 1; TMR0 = 0x83; //131 decimal INTCON |= 0x20; //habilita int do timer 0 }
//***************************************************************************** // Função trata_int_timer0 -trata chamada da int do timer 0 // // Conta 8 horas para tempo ligado e 16 horas para tempo desligado // // Entradas - nenhuma // Saidas - nenhuma //***************************************************************************** void trata_int_timer0(void){ count_timer0++; //verifica se já ocorreram 250 interrupções //8 ms x 250 = 2 segundos if (count_timer0 >= 250) { count_timer0 = 0; // zera contador nr_msg ^= 0x01; // muda mensagem change_msg = 1; // autoriza troca } TMR0 = 0x83; // reestabelece valor inicial do contador }
|
Listagem pic_ints.c
//***************************************************************************** // Arquivo my_ints.c - tratamento das interrupções no PIC by Arne // Desenvolvido por Eng. Márcio José Soares //*****************************************************************************
//****************************************************************************** // O Copyright deste programa está reservado para Márcio José Soares e seu // conteúdo está protegido pela Lei de Direitos Autorais LEI Nº 9.610, de // 19 de Fevereiro de 1998. É estritamente proibida a reprodução total ou // parcial dos conteúdos aqui apresentados sem prévia autorização, por escrito, // do autor. //******************************************************************************
//****************************************************************************** // Arquivos incluídos no módulo //****************************************************************************** #include <xc.h> //#include <pic16f648a.h>
//****************************************************************************** // Definições importantes no módulo //****************************************************************************** #ifndef byte #define byte uint8_t #endif
//***************************************************************************** // Funções externas do módulo //***************************************************************************** extern void trata_int_comm(void); extern void putch(unsigned char mbyte); extern void trata_int_timer0(void);
//***************************************************************************** // Funções do módulo //*****************************************************************************
//***************************************************************************** // Função para tratar o vetor de interrupções no PIC // // Este é o tratamento de interrupçõe no PIC. Como este microcontrolador possui // apenas um único vetor de interrupção (0x0004), toda e qualquer interrupção será // tratada aqui. Se uma única interrupção for utilizada, o tratamento pode ser direto, // sem a necessidade de se testar qual int ocorreu. Porém se mais de uma estiver // em uso, a função deverá testar os flags das ints para saber qual ocorreu, extamente // como é feito em assembly. // O uso da diretriz "interrupt 0" é importante, pois é assim que o SDCC reconhece que // esta função é na verdade um serviço para tratamento das interrupções. Para PICs usar // apenas nível 0. // // Entradas - nenhuma // Saídas - nenhuma //***************************************************************************** void __interrupt() pic_isr(void){
INTCON &= ~0x80; //desabilita ints
//analisa se é int do timer0 if((T0IF == 1) && (T0IE == 1)){ // é int do timer1 trata_int_timer0(); // trata int T0IF = 0x00; // zera flag } //analisa se é int externa //if((INTF == 1) && (INTE == 1)){ //é int externa // trata_int_ext(); //trata int //}
//analisa se é int da usart //if((RCIF == 1) && (RCIE == 1)){ // é int de recepção da USART // trata_int_comm(); // trata int //} INTCON |= 0x80; // habilita novamente as ints
}
|
Listagem pic_lcd.h
/* * File: pic_lcd.h * Author: arne * * Created on 12 de Setembro de 2022, 14:56 */
#ifndef PIC_LCD_H #define PIC_LCD_H
//****************************************************************************** //Definições do módulo //******************************************************************************
//****************************************************************************** // Se nenhuma freqüência foi definida, assume 4MHz // Esta definição é exigida para calibrar as funções __delay_us() e __delay_ms() #ifndef _XTAL_FREQ #define _XTAL_FREQ 4000000 #endif
//****************************************************************************** //Modo de uso do LCD - selecionar apenas um //****************************************************************************** //#define __LCD_4__ //modo de operação com 4 bits //#define __LCD_8__ //modo de operação com 8 bits #ifndef __LCDDEFS__ #define __LCDDEFS__ #define __LCD_4__
//****************************************************************************** // As definições a seguir são utilizadas para acesso aos pinos do display // caso o pino RW não seja utilizado, comente a definição lcd_rw // // Algumas definições foram modificadas para compatibilizar com a PIC16F877 // definições modificadas (pinos de trabalho para o LCD) //******************************************************************************
//****************************************************************************** // Endereços para linhas dos display's possíveis de se utilizar com este // módulo: // // Display 1ª linha 2ª linha 3ª linha 4ª linha // 16 x 2 80H C0H XX XX // 16 x 4 80H C0H 94H D4H // 20 x 4 80H C0H 90H D0H // 40 x 2 80H C0H XX XX //******************************************************************************
//***************************************************************************** //Definição das portas e pinos de I/O para LCD //***************************************************************************** #define PLCDDATA PORTB #define PLCDCTRL PORTA #define pLCD_RS PORTAbits.RA1 #define pLCD_EN PORTAbits.RA0
//***************************************************************************** // Macros para controle dos pinos de I/O //***************************************************************************** #define set_lcdrs pLCD_RS = 1 //liga pino RS #define res_lcdrs pLCD_RS = 0 //desliga pino RS #define set_lcden pLCD_EN = 1 //liga pino EN #define res_lcden pLCD_EN = 0 //desliga pino EN
#define lcd_type 2 // 0=5x7, 1=5x10, 2=2 linhas #endif
//*********************************************************************** // Funções do módulo //*********************************************************************** void strobe(void); void sendC(const char val); void dataC(char val); void commandC(char val); void clear_LCD(byte modo); void pos_LCD(byte pos); void mudalinha(char linha); void config_LCD(void); void stringR_LCD(char *msg);
#endif /* PIC_LCD_H */
|
Listagem pic_lcd.c
//******************************************************************************
// Funções para uso de LCDs tipo caracter - modo transferência 4/8 bits
// Desenvolvido por Márcio José Soares
//
// Microcontrolador: AVR
// Compilador: avr-gcc (GCC) 4.1.0 - Linux
//
// Última alteração: 09/08/2007
//
//******************************************************************************
//******************************************************************************
// O Copyright deste programa está reservado para Márcio José Soares e seu
// conteúdo está protegido pela Lei de Direitos Autorais LEI Nº 9.610, de
// 19 de Fevereiro de 1998. É estritamente proibida a reprodução total ou
// parcial dos conteúdos aqui apresentados sem prévia autorização, por escrito,
// do autor.
//******************************************************************************
//******************************************************************************
// Inclui arquivos
#include "my_defines.h"
#include "pic_lcd.h"
//******************************************************************************
// Funções do módulo
//******************************************************************************
//Pulsa pino E (habilitação) no display
//Entradas - nenhuma
//Saidas - nenhuma
//******************************************************************************
void strobe(void){
set_lcden; //pulsa pino de controle - habilita
res_lcden;
}
//******************************************************************************
//Envia um byte para o display - dados ou comando
//Entradas - byte a enviar
//Saidas - nenhuma
//******************************************************************************
void sendC(const char val){
__delay_us(250);
PLCDDATA = val;
strobe(); // strobe pino E
#if defined(__LCD_4__) // se modo 4 bits, envia segundo nible
PLCDDATA = val<<4; // envia nibble menos significativo
strobe(); // mais um strobe
#endif
}
//******************************************************************************
//Envia dados para o display
//Entradas - dado a enviar
//Saidas - nenhuma
//******************************************************************************
void dataC(char val){
set_lcdrs; //RS em 1
sendC(val); //escreve dado
}
//******************************************************************************
//Envia comandos para o display
//Entradas - byte de comando
//Saidas - nenhuma
//******************************************************************************
void commandC(char val){
res_lcdrs; //RS em 0
sendC(val); //escreve comando
}
//******************************************************************************
//Apaga LCD
//Entradas - byte: 0 - apaga todo LCD; 1
// 1 - apaga linha 1;
// 2 - apaga linha 2.
//Saidas - nenhuma
//******************************************************************************
void clear_LCD(byte modo){
byte i;
switch(modo){
case 0:
commandC(0x01); //apaga todo LCD
break;
case 1:
commandC(0x80); //muda para linha 1
for (i=0; i<16; i++) //envia 15 caracteres 'espaço'
dataC(' ');
commandC(0x80); //muda para linha 1 novamente
break;
case 2:
commandC(0xC0); //muda para linha 2
for (i=0; i<16; i++) //envia 15 caracteres 'espaço'
dataC(' ');
commandC(0xC0); //muda para linha 2 novamente
break; default: //se valor passado não confere
commandC(0x01); //apaga todo LCD
}
for (i=0; i<15; i++)
__delay_us(250); // espera 15 ms
}
//******************************************************************************
//Posiciona cursor no LCD
//Entradas - posição do cursor no LCD (1 - 32)
//Saidas - nenhuma
//******************************************************************************
void pos_LCD(byte pos){
if ((pos > 0) && (pos < 17)) //verifica se linha 1
commandC(0x80 + (pos)); //posiciona na linha 1
else{
pos -= 16; //tira uma linha
commandC(0xC0 + (pos)); //posiciona na linha 2
}
}
//******************************************************************************
//Muda linha no LCD
//Entradas - linha (1 ou 2)
//Saidas - nenhuma
//******************************************************************************
void mudalinha(char linha){
if (linha==1)
commandC(0x80); //muda para linha 1
if (linha==2)
commandC(0xC0); //muda para linha 2
}
//******************************************************************************
//Inicializa LCD
//
//Entradas - nenhuma
//Saidas - nenhuma
//******************************************************************************
void config_LCD(void){
byte i;
for (i=0; i< 100; i++)
__delay_ms(4); // power on em espera de 400ms
#if defined(__LCD_4__)
commandC(0x28); // modo 4-bits, 2-linha, caracter 5x7
commandC(0x28); // repete comando
#endif
#if defined(__LCD_8__)
commandC(0x38); // modo 8-bits, 2-linha, caracter 5x7
commandC(0x38); // repete comando
#endif
commandC(0x06); // incrementa caracter a direita, desliga display shift
commandC(0x0F); // display ligado, cursor ligado, cursor blink
clear_LCD(0); // apague display
}
//***********************************************************************
//Envia uma string para o LCD
//
//Entradas - ponteiro da string na memória RAM
//Saidas - nenhuma
//***********************************************************************
void stringR_LCD(char *msg){
while(*msg != 0x00) //envia enquanto msg for verdadeira
dataC(*msg++); //envia caracter por caracter
}
|
|