Hotová rutina pro LCD displej s řadičem PCF8814 (Nokia 1100)

Jednou jsem si řekl, že by nebylo marné si osvojit dovednost v programové obsluze LCD displeje.
Chvíli jsem uvažoval o zakoupení běžného displeje z SOS či GME, avšak cena mne odradila.
Vzpomněl jsem si však, že při svém websurfingu jsem narazil na bastl se zprovozněným displejem z mobilu.
A jelikož jsem měl k dispozici pouze vysloužilý mobil NOKIE 1100, tak nebylo co řešit.
Skoulel jsem to do kupy a tady to máte.

module.ro/circuite/lcdn8310.jpg

Toto schématko je určeno sice pro LCD z nokie8310, ale je použitelné i na nokii1100.

Displej obsahuje LCD driver PCF8814. mylcd.sourceforge.net/files/pcf8814.pdf
To pro případ, že si s tím budete chtít pohrát víc jak já…

Na adrese sunbizhosting.com/~spiral/ jsem nalezl knihovnu pro tento displej, ale byla dělaná pro procesor Microchipu.
Tak jsem se v něm pošťoural a zde máte výsledek.

[code]/*


| \ | | / _ \ | |/ / |_ | / \ / | / | / _ \ / _ \ | | / | | _
| | | | | | | | ’ / | | / _ \ | | | | | | | | | | | | | | | | | | | |
| |\ | | |
| | | . \ | | / ___ \ | | | | | |
| | | |
| | | |
__ | |___ | || |
|
| _| _/ ||_\ || // _\ || || _/ _/ |__| _| |___/

Tato knihovna převzata odsud: http://sunbizhosting.com/~spiral/

Následně upravena pro AVR od ATMELU Divousem.

File: lcd1100.h

*/
#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>

// set output pins for lcd here
#define sclk PE1
#define sda PE3
#define cs PE2
#define rst PE0

#define SETPE(pin,value) {if (value == 0) PORTE &= ~(1<<pin); else PORTE |= (1<<pin);}

#define CMD 0
#define DATA 1

void init(void);
void Lcd_Init(void);
void Lcd_Write(char cd,unsigned char c);
void Lcd_Clear(void);
void SetX(char x);
void SetY(char y);
void Gotoxy(char x,char y);
void VLine(char x,char y,char on);
void Line(unsigned char x,unsigned char y,unsigned char y2,unsigned char on);
void print_message(const char* message);
void print_char(char c);
void print_string(char * message);[/code]

[code]/*


| \ | | / _ \ | |/ / |_ | / \ / | / | / _ \ / _ \ | | / | | _
| | | | | | | | ’ / | | / _ \ | | | | | | | | | | | | | | | | | | | |
| |\ | | |
| | | . \ | | / ___ \ | | | | | |
| | | |
| | | |
__ | |___ | || |
|
| _| _/ ||_\ || // _\ || || _/ _/ |__| _| |___/

Tato knihovna převzata odsud: http://sunbizhosting.com/~spiral/

Následně upravena pro AVR od ATMELU Divousem.

File: lcd1100.c

*/

#include “lcd1100.h”
#include <avr/pgmspace.h>
char bitaddr;

// lookup table, here you can modify the font
static const unsigned char FontLookup[96][5] PROGMEM = {
{0x00, 0x00, 0x00, 0x00, 0x00},// (space)
{0x00, 0x00, 0x5F, 0x00, 0x00},// !
{0x00, 0x07, 0x00, 0x07, 0x00},// "
{0x14, 0x7F, 0x14, 0x7F, 0x14},// #
{0x24, 0x2A, 0x7F, 0x2A, 0x12},// $
{0x23, 0x13, 0x08, 0x64, 0x62},// %
{0x36, 0x49, 0x55, 0x22, 0x50},// &
{0x00, 0x05, 0x03, 0x00, 0x00},// ’
{0x00, 0x1C, 0x22, 0x41, 0x00},// (
{0x00, 0x41, 0x22, 0x1C, 0x00},// )
{0x08, 0x2A, 0x1C, 0x2A, 0x08},// *
{0x08, 0x08, 0x3E, 0x08, 0x08},// +
{0x00, 0x50, 0x30, 0x00, 0x00},// ,
{0x08, 0x08, 0x08, 0x08, 0x08},// -
{0x00, 0x30, 0x30, 0x00, 0x00},// .
{0x20, 0x10, 0x08, 0x04, 0x02},// /
{0x3E, 0x51, 0x49, 0x45, 0x3E},// 0
{0x00, 0x42, 0x7F, 0x40, 0x00},// 1
{0x42, 0x61, 0x51, 0x49, 0x46},// 2
{0x21, 0x41, 0x45, 0x4B, 0x31},// 3
{0x18, 0x14, 0x12, 0x7F, 0x10},// 4
{0x27, 0x45, 0x45, 0x45, 0x39},// 5
{0x3C, 0x4A, 0x49, 0x49, 0x30},// 6
{0x01, 0x71, 0x09, 0x05, 0x03},// 7
{0x36, 0x49, 0x49, 0x49, 0x36},// 8
{0x06, 0x49, 0x49, 0x29, 0x1E},// 9
{0x00, 0x36, 0x36, 0x00, 0x00},// :
{0x00, 0x56, 0x36, 0x00, 0x00},// ;
{0x00, 0x08, 0x14, 0x22, 0x41},// <
{0x14, 0x14, 0x14, 0x14, 0x14},// =
{0x41, 0x22, 0x14, 0x08, 0x00},// >
{0x02, 0x01, 0x51, 0x09, 0x06},// ?
{0x32, 0x49, 0x79, 0x41, 0x3E},// @
{0x7E, 0x11, 0x11, 0x11, 0x7E},// A
{0x7F, 0x49, 0x49, 0x49, 0x36},// B
{0x3E, 0x41, 0x41, 0x41, 0x22},// C
{0x7F, 0x41, 0x41, 0x22, 0x1C},// D
{0x7F, 0x49, 0x49, 0x49, 0x41},// E
{0x7F, 0x09, 0x09, 0x01, 0x01},// F
{0x3E, 0x41, 0x41, 0x51, 0x32},// G
{0x7F, 0x08, 0x08, 0x08, 0x7F},// H
{0x00, 0x41, 0x7F, 0x41, 0x00},// I
{0x20, 0x40, 0x41, 0x3F, 0x01},// J
{0x7F, 0x08, 0x14, 0x22, 0x41},// K
{0x7F, 0x40, 0x40, 0x40, 0x40},// L
{0x7F, 0x02, 0x04, 0x02, 0x7F},// M
{0x7F, 0x04, 0x08, 0x10, 0x7F},// N
{0x3E, 0x41, 0x41, 0x41, 0x3E},// O
{0x7F, 0x09, 0x09, 0x09, 0x06},// P
{0x3E, 0x41, 0x51, 0x21, 0x5E},// Q
{0x7F, 0x09, 0x19, 0x29, 0x46},// R
{0x46, 0x49, 0x49, 0x49, 0x31},// S
{0x01, 0x01, 0x7F, 0x01, 0x01},// T
{0x3F, 0x40, 0x40, 0x40, 0x3F},// U
{0x1F, 0x20, 0x40, 0x20, 0x1F},// V
{0x7F, 0x20, 0x18, 0x20, 0x7F},// W
{0x63, 0x14, 0x08, 0x14, 0x63},// X
{0x03, 0x04, 0x78, 0x04, 0x03},// Y
{0x61, 0x51, 0x49, 0x45, 0x43},// Z
{0x00, 0x00, 0x7F, 0x41, 0x41},//
{0x02, 0x04, 0x08, 0x10, 0x20},// ""
{0x41, 0x41, 0x7F, 0x00, 0x00},// ]
{0x04, 0x02, 0x01, 0x02, 0x04},// ^
{0x40, 0x40, 0x40, 0x40, 0x40},// _
{0x00, 0x01, 0x02, 0x04, 0x00},// `
{0x20, 0x54, 0x54, 0x54, 0x78},// a
{0x7F, 0x48, 0x44, 0x44, 0x38},// b
{0x38, 0x44, 0x44, 0x44, 0x20},// c
{0x38, 0x44, 0x44, 0x48, 0x7F},// d
{0x38, 0x54, 0x54, 0x54, 0x18},// e
{0x08, 0x7E, 0x09, 0x01, 0x02},// f
{0x08, 0x14, 0x54, 0x54, 0x3C},// g
{0x7F, 0x08, 0x04, 0x04, 0x78},// h
{0x00, 0x44, 0x7D, 0x40, 0x00},// i
{0x20, 0x40, 0x44, 0x3D, 0x00},// j
{0x00, 0x7F, 0x10, 0x28, 0x44},// k
{0x00, 0x41, 0x7F, 0x40, 0x00},// l
{0x7C, 0x04, 0x18, 0x04, 0x78},// m
{0x7C, 0x08, 0x04, 0x04, 0x78},// n
{0x38, 0x44, 0x44, 0x44, 0x38},// o
{0x7C, 0x14, 0x14, 0x14, 0x08},// p
{0x08, 0x14, 0x14, 0x18, 0x7C},// q
{0x7C, 0x08, 0x04, 0x04, 0x08},// r
{0x48, 0x54, 0x54, 0x54, 0x20},// s
{0x04, 0x3F, 0x44, 0x40, 0x20},// t
{0x3C, 0x40, 0x40, 0x20, 0x7C},// u
{0x1C, 0x20, 0x40, 0x20, 0x1C},// v
{0x3C, 0x40, 0x30, 0x40, 0x3C},// w
{0x44, 0x28, 0x10, 0x28, 0x44},// x
{0x0C, 0x50, 0x50, 0x50, 0x3C},// y
{0x44, 0x64, 0x54, 0x4C, 0x44},// z
{0x00, 0x08, 0x36, 0x41, 0x00},// {
{0x00, 0x00, 0x7F, 0x00, 0x00},// |
{0x00, 0x41, 0x36, 0x08, 0x00},// }
{0x08, 0x08, 0x2A, 0x1C, 0x08},// →
{0x08, 0x1C, 0x2A, 0x08, 0x08} // ←
};

// clear LCD
void Lcd_Clear(void){
unsigned int i;
Lcd_Write(CMD,0x40); // Y = 0
Lcd_Write(CMD,0xb0);
Lcd_Write(CMD,0x10); // X = 0
Lcd_Write(CMD,0x0);
Lcd_Write(CMD,0xae); // disable display;
for(i=0;i<864;i++)
Lcd_Write(DATA,0x00);
Lcd_Write(CMD,0xaf); // enable display;
}

// init LCD
void Lcd_Init(void){
SETPE(cs,0);
SETPE(rst,0);
_delay_ms(5); // 5mS so says the stop watch(less than 5ms will not work)
SETPE(rst,1);

Lcd_Write(CMD,0x20); // write VOP register
Lcd_Write(CMD,0x9f);
/*** Zde jsem nastavil vysoké napětí pro displej, jelikož ten můj displej
*** měl již bídný kontrast.
*** Pokud nemáte ten samý problém, tak by měla stačit hodnota 0x90 ***/

Lcd_Write(CMD,0xA4); // all on/normal display
Lcd_Write(CMD,0x2F); // Power control set(charge pump on/off)
Lcd_Write(CMD,0x40); // set start row address = 0
Lcd_Write(CMD,0xb0); // set Y-address = 0
Lcd_Write(CMD,0x10); // set X-address, upper 3 bits
Lcd_Write(CMD,0x0); // set X-address, lower 4 bits
Lcd_Write(CMD,0xC8); // mirror Y axis (about X axis)
Lcd_Write(CMD,0xa1); // Invert screen in horizontal axis
Lcd_Write(CMD,0xac); // set initial row (R0) of the display
Lcd_Write(CMD,0x07);

Lcd_Write(CMD,0xaf); // display ON/OFF

Lcd_Clear(); // clear LCD
Lcd_Write(CMD,0xa7); // invert display

_delay_ms(500); // 1/2 Sec delay
Lcd_Write(CMD,0xa6); // normal display (non inverted)
_delay_ms(500); // 1 Sec delay
}

void Lcd_Write(char cd,unsigned char c){
char i;

SETPE(cs,0);
SETPE(sclk,0);
SETPE(sda,cd);
SETPE(sclk,1);

for(i=0;i<8;i++){
SETPE(sclk,0);
if(c & 0x80)
SETPE(sda,1)
else
SETPE(sda,0)
SETPE(sclk,1);
c <<= 1;
_delay_us(100);
}
SETPE(cs,1);
}

void SetX(char x){
Lcd_Write(CMD,0x10 | ((x>>4)&0x7));
Lcd_Write(CMD,x & 0x0f);
}

void SetY(char y){
char aux = 0;
while(y>7){
y -=8;
aux ++;
}

bitaddr = y-1;
Lcd_Write(CMD,0xB0 | (aux & 0x0f));

}

void Gotoxy(char x,char y){
Lcd_Write(CMD,(0xB0|(y&0x0F))); // Y axis initialisation: 0100 yyyy
Lcd_Write(CMD,(0x00|(x&0x0F))); // X axis initialisation: 0000 xxxx ( x3 x2 x1 x0)
Lcd_Write(CMD,(0x10|((x>>4)&0x07))); // X axis initialisation: 0010 0xxx ( x6 x5 x4)
}

//x dir > y dir from last line to ^
void VLine(char x,char y,char on){
char aux[8];
int i;

for(i=0;i<8;i++)
    aux* = 0;
    
i = 7;
while(y > 9){
    aux* = 0xff;
    y -= 8;
    i--;
}

while(y > 0){
    aux* >>= 1;
    aux* |= 0x80;
    y --;
}    



for(y=0;y<8;y++){
    Lcd_Write(CMD,0xB0 | y);
    SetX(x);        
    Lcd_Write(DATA,aux(unsigned int)y]);
}    

}

// xdir is > y is always < than y2 can be used for graphs
void Line(unsigned char x,unsigned char y,unsigned char y2,unsigned char on){
char aux[8];
char o=0;
char c=1;
unsigned int index;
unsigned int i;

for(i=0;i<8;i++)
    aux* = 0;
    

index = 0;
for(i=0;i<64;i++){
    
    if(i >= y && i <= y2){
        aux[index] |= c << o;
    }
    
    o ++;
    if(o == 8){
        o = 0;
        index ++;
    }
}
        

for(i=0;i<8;i++){
    Lcd_Write(CMD,0xB0 | i);
    SetX(x);        
    Lcd_Write(DATA,aux*);
}

}

void print_char(char c)
{
int i;
for ( i = 0; i < 5; i++ )
{
Lcd_Write(DATA, pgm_read_byte(&FontLookup[c - 32]*) << 1);
}
Lcd_Write(DATA,0x00);
}

void print_message(const char * message)// Write message to LCD (C string type)
{
Lcd_Write(CMD,0xae); // disable display;
while (*message){ // Look for end of string
print_char(*message++);
}
Lcd_Write(CMD,0xaf); // enable display;
}

void print_string(char * message){ // Write message to LCD (C string type)
Lcd_Write(CMD,0xae); // disable display;
while (*message){ // Look for end of string
print_char(*message++);
}
Lcd_Write(CMD,0xaf); // enable display;
}
[/code]

[code]/*


| \ | | / _ \ | |/ / |_ | / \ / | / | / _ \ / _ \ | | / | | _
| | | | | | | | ’ / | | / _ \ | | | | | | | | | | | | | | | | | | | |
| |\ | | |
| | | . \ | | / ___ \ | | | | | |
| | | |
| | | |
__ | |___ | || |
|
| _| _/ ||_\ || // _\ || || _/ _/ |__| _| |___/

Pro Atmel AVR zprovoznil Divous

File: main.c

*/

#define F_CPU 12000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <string.h>

#include “lcd1100.h”

//
/
Přednadstavení portů /
/
/
void port_init(void)
{
PORTA = 0x00;
DDRA = 0xFF;

DDRB = 0xFF;
PORTB = 0x00;

PORTC = 0x00;
DDRC = 0xFF;

PORTD = 0x00;
DDRD = 0xFF;

PORTE = 0xFF;
DDRE = 0xFF;

PORTF = 0x00;
DDRF = 0xFF;

PORTG = 0x00;
DDRG = 0xFF;
}

int main(void)
{
port_init();
Lcd_Init();
Gotoxy(0,0);
print_message(“It works!!”);
Gotoxy(5,1);
print_message(“It works!!”);
Gotoxy(10,2);
print_message(“It works!!”);
Gotoxy(15,3);
print_message(“It works!!”);
Gotoxy(20,4);
print_message(“It works!!”);
Gotoxy(25,5);
print_message(“It works!!”);
Gotoxy(30,6);
print_message(“It works!!”);
Gotoxy(35,7);
print_message(“It works!!”);
while(1) {}
}
[/code]

Doufám, že vám tato menší inspirace pomůže k dalším úspěchům.

Edit:
Ještě dodávám menší foto, že mi to skutečně fungovalo…

:arrow_right: administrator: přejmenováno z “Displej z Nokie 1100”******

:arrow_right: administrator: příspěvek byl upraven

:arrow_right: administrator: přiloženy externí soubory*
nokia-lcd-1100-by-divous.zip (4.15 KB)
schema-lcd-nokia-1100-8310.jpg
pcf8814.pdf (390 KB)

Příspěvek jsem mírně upravil a Divousův program jsem přiložil k přímému stažení. Děkujeme Divousi!