Mais preocupante é a questão de armazenar na Flash a matriz de caracteres e outras imagens. A matriz que usamos no Arduino tem 96x5 bytes o que é uma quantidade respeitável para os PICs mais simples. Além disso, os modelos mais tradicionais assumem que a Flash conterá apenas código, não tendo instruções específicas para acessar dados armazenados nela. Vamos usar aqui um PIC mais moderno, o 16F882, e deixar por conta do compilador CSC C o trabalho sujo de armazenar e extrair os dados da Flash.
Hardware
O hardware é bastante simples, principalmente se alimentarmos o PIC com 3V:
![]() |
Montagem com alimentação de 3V |
![]() |
Circuito para alimentação de 3V |
![]() |
Montagem com alimentação de 5V |
![]() |
Circuito para alimentação de 5V |
Software
O software a seguir é uma adaptação direta do primeiro exemplo que vimos com o Arduino. As principais mudanças se devem às diferenças entre os compiladores e as bibliotecas. Como não temos a função shiftOut, os sinais de dados e clock são pulsados manualmente.
- #include <16f882.h>
- #device adc=8
- #use delay(clock=8000000)
- #fuses NOWDT, NOCPD, NOPROTECT
- #fuses MCLR, INTRC_IO
- #use fast_io(A)
- // Conexões do display ao PIC
- #define PIN_SCE PIN_A0
- #define PIN_RESET PIN_A1
- #define PIN_DC PIN_A2
- #define PIN_SDIN PIN_A3
- #define PIN_SCLK PIN_A4
- // Um LED para debug
- #define PIN_LED PIN_A5
- // Seleção de dado ou comando
- #define LCD_CMD 0
- #define LCD_DAT 1
- // Tamanho da tela
- #define LCD_DX 84
- #define LCD_DY 48
- static const byte ASCII[][5] =
- {
- {0x00, 0x00, 0x00, 0x00, 0x00} // 20
- ,{0x00, 0x00, 0x5f, 0x00, 0x00} // 21 !
- ,{0x00, 0x07, 0x00, 0x07, 0x00} // 22 "
- ,{0x14, 0x7f, 0x14, 0x7f, 0x14} // 23 #
- ,{0x24, 0x2a, 0x7f, 0x2a, 0x12} // 24 $
- // etc
- ,{0x10, 0x08, 0x08, 0x10, 0x08} // 7e ?
- ,{0x78, 0x46, 0x41, 0x46, 0x78} // 7f ?
- };
- // Rotinas locais
- void InitHw (void);
- void LcdWrite (byte dc, byte data);
- void LcdInitialise (void);
- void LcdClear (void);
- void LcdPos (byte lin, byte col);
- void LcdWriteChar (char character);
- void LcdWriteString(char *characters, byte lin, byte col);
- // Ponto de entrada e loop principal
- void main (void)
- {
- InitHw ();
- LcdInitialise ();
- LcdClear ();
- LcdPos (2, 3);
- LcdWriteChar ('D');
- LcdWriteChar ('Q');
- LcdWriteChar ('S');
- LcdWriteChar ('o');
- LcdWriteChar ('f');
- LcdWriteChar ('t');
- output_high (PIN_LED);
- for (;;)
- ;
- }
- // Iniciação do hardware
- void InitHw (void)
- {
- // Bota para correr
- setup_oscillator (OSC_8MHZ);
- // Dispositivos não usados
- setup_comparator(NC_NC);
- setup_vref(FALSE);
- setup_adc(ADC_OFF);
- // E/S
- set_tris_a (0xC0); // RA0-RA5 output
- }
- // Envia um byte para o controlador do display
- // dc: LCD_CMD ou LCD_DAT
- // data: byte a enviar
- void LcdWrite(byte dc, byte data)
- {
- byte i;
- if (dc == LCD_CMD)
- output_low (PIN_DC);
- else
- output_high (PIN_DC);
- output_low (PIN_SCE);
- delay_us(10);
- for (i = 0; i < 8; i++)
- {
- if (data & 0x80)
- output_high (PIN_SDIN);
- else
- output_low (PIN_SDIN);
- output_high (PIN_SCLK);
- delay_us(10);
- output_low (PIN_SCLK);
- delay_us(10);
- data = data << 1;
- }
- delay_us(10);
- output_high (PIN_SCE);
- }
- // Iniciação do display
- void LcdInitialise(void)
- {
- output_low (PIN_SCLK);
- output_high (PIN_SCE);
- // executa um reset do controlador
- output_low (PIN_RESET);
- delay_us (10);
- output_high (PIN_RESET);
- // envia os comandos de iniciação
- LcdWrite( LCD_CMD, 0x21 ); // LCD Extended Commands.
- LcdWrite( LCD_CMD, 0xaf ); // Set LCD Vop (Contraste)
- LcdWrite( LCD_CMD, 0x04 ); // Set Temp coefficent
- LcdWrite( LCD_CMD, 0x14 ); // LCD bias mode 1:48
- LcdWrite( LCD_CMD, 0x20 ); // LCD Basic Commands.
- LcdWrite( LCD_CMD, 0x0c ); // LCD no modo normal
- }
- // Limpa a tela
- void LcdClear(void)
- {
- int16 i;
- // posiciona ponteiro no inicio da memória
- LcdWrite( LCD_CMD, 0x40);
- LcdWrite( LCD_CMD, 0x80);
- // preenche a memória com zeros
- for (i = 0; i < ((LCD_DX * LCD_DY) / 8); i++)
- {
- LcdWrite(LCD_DAT, 0x00);
- }
- }
- // Posiciona em uma determina linha e coluna alfanuméricas
- void LcdPos(byte lin, byte col)
- {
- LcdWrite( LCD_CMD, 0x40 + lin);
- LcdWrite( LCD_CMD, 0x80 + col*7);
- }
- // Escreve um caracter na posição atual
- void LcdWriteChar(char character)
- {
- byte i;
- LcdWrite(LCD_DAT, 0x00);
- for (i = 0; i < 5; i++)
- {
- LcdWrite(LCD_DAT, ASCII[character - 0x20][i]);
- }
- LcdWrite(LCD_DAT, 0x00);
- }
- // Escreve um string a partir de uma certa
- // linha e coluna
- void LcdWriteString(char *characters, byte lin, byte col)
- {
- LcdPos (lin, col);
- while (*characters)
- LcdWriteChar(*characters++);
- }
Como de costume, o projeto completo está nos arquivos do blog, no arquivo Nokia5110_PIC.zip.
4 comentários:
Esses mesmos arquivos e bibliotecas funcionam com o 18F4550?
Nivaldo,
Não tenho experiência com o PIC18, mas acho que serão precisos ajustes, principalmente no InitHw(). Além disso, costuma ter uma diferença grande entre os compiladores C para PIC.
boa noite, no pic 16f877a é a mesma configuração?
Renato,
Em uma olhada rápida no datasheet do 16F877 reparei que ele não tem oscilador interno, portanto será necessário acrescentar componentes para gera o clock (por exemplo um cristal de 8MHz). Acho que o resto (inclusive o acesso ao gerador de caracteres na Flash) devem funcionar.
Postar um comentário