Proyecto 12 - Nokia Graphic LCD

Proyecto 12a - Nokia 3310 Display LCD Gráfico

En el proyecto anterior vimos como conectar y controlar un display LCD para texto.

En los ejemplos siguientes veremos como mostrar texto e imágenes en un display LCD gráfico.

Usaremos un display gráfico procedente del NOKIA 3310. Este display funciona 3,3V por lo que debemos adaptar el nivel de las salidas de Arduino de 5V a 3,3V, para ello empleamos el integrado 4050, un buffer no inversor que convierte las entradas de 5V en salidas de 3,3V.

Debido al bajo consumo del display (< 10mA) podemos alimentar el conjunto con la salida de 3,3V de Arduino. Recordar que esta salida de 3,3V suministra como máximo 50mA.

En este ejemplo mostraremos hasta 5 líneas de texto x 12 caracteres cada línea.

Esquema

Sketch

/*  

Este Código tiene características adicionales

incluyendo una función de posicionamiento XY en la pantalla

y una función Dibuja la linea de Nokia 3310 LCD

Se modificó a partir del original

http://playground.arduino.cc/Code/PCD8544

*/

// Espero que le funcione a usted//

// Mods by V. García. 15/05/2013.

// 

#define PIN_DC 2 // LCD Data/Commmand

#define PIN_SCE 3 // LCD ChipSelect

#define PIN_SDIN 4 // LCD SPIDat

#define PIN_RESET 5 // LCD RST

#define PIN_SCLK 6 // LCD SPIClk

#define LCD_C LOW

#define LCD_D HIGH

#define LCD_X 84

#define LCD_Y 48

#define LCD_CMD 0

int progress = 0;

int prev_prog = 0;

int pixels[85][6] = {{0}};

int a = 0;

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 $

,{0x23, 0x13, 0x08, 0x64, 0x62} // 25 %

,{0x36, 0x49, 0x55, 0x22, 0x50} // 26 &

,{0x00, 0x05, 0x03, 0x00, 0x00} // 27 '

,{0x00, 0x1c, 0x22, 0x41, 0x00} // 28 (

,{0x00, 0x41, 0x22, 0x1c, 0x00} // 29 )

,{0x14, 0x08, 0x3e, 0x08, 0x14} // 2a *

,{0x08, 0x08, 0x3e, 0x08, 0x08} // 2b +

,{0x00, 0x50, 0x30, 0x00, 0x00} // 2c ,

,{0x08, 0x08, 0x08, 0x08, 0x08} // 2d -

,{0x00, 0x60, 0x60, 0x00, 0x00} // 2e .

,{0x20, 0x10, 0x08, 0x04, 0x02} // 2f /

,{0x3e, 0x51, 0x49, 0x45, 0x3e} // 30 0

,{0x00, 0x42, 0x7f, 0x40, 0x00} // 31 1

,{0x42, 0x61, 0x51, 0x49, 0x46} // 32 2

,{0x21, 0x41, 0x45, 0x4b, 0x31} // 33 3

,{0x18, 0x14, 0x12, 0x7f, 0x10} // 34 4

,{0x27, 0x45, 0x45, 0x45, 0x39} // 35 5

,{0x3c, 0x4a, 0x49, 0x49, 0x30} // 36 6

,{0x01, 0x71, 0x09, 0x05, 0x03} // 37 7

,{0x36, 0x49, 0x49, 0x49, 0x36} // 38 8

,{0x06, 0x49, 0x49, 0x29, 0x1e} // 39 9

,{0x00, 0x36, 0x36, 0x00, 0x00} // 3a :

,{0x00, 0x56, 0x36, 0x00, 0x00} // 3b ;

,{0x08, 0x14, 0x22, 0x41, 0x00} // 3c <

,{0x14, 0x14, 0x14, 0x14, 0x14} // 3d =

,{0x00, 0x41, 0x22, 0x14, 0x08} // 3e >

,{0x02, 0x01, 0x51, 0x09, 0x06} // 3f ?

,{0x32, 0x49, 0x79, 0x41, 0x3e} // 40 @

,{0x7e, 0x11, 0x11, 0x11, 0x7e} // 41 A

,{0x7f, 0x49, 0x49, 0x49, 0x36} // 42 B

,{0x3e, 0x41, 0x41, 0x41, 0x22} // 43 C

,{0x7f, 0x41, 0x41, 0x22, 0x1c} // 44 D

,{0x7f, 0x49, 0x49, 0x49, 0x41} // 45 E

,{0x7f, 0x09, 0x09, 0x09, 0x01} // 46 F

,{0x3e, 0x41, 0x49, 0x49, 0x7a} // 47 G

,{0x7f, 0x08, 0x08, 0x08, 0x7f} // 48 H

,{0x00, 0x41, 0x7f, 0x41, 0x00} // 49 I

,{0x20, 0x40, 0x41, 0x3f, 0x01} // 4a J

,{0x7f, 0x08, 0x14, 0x22, 0x41} // 4b K

,{0x7f, 0x40, 0x40, 0x40, 0x40} // 4c L

,{0x7f, 0x02, 0x0c, 0x02, 0x7f} // 4d M

,{0x7f, 0x04, 0x08, 0x10, 0x7f} // 4e N

,{0x3e, 0x41, 0x41, 0x41, 0x3e} // 4f O

,{0x7f, 0x09, 0x09, 0x09, 0x06} // 50 P

,{0x3e, 0x41, 0x51, 0x21, 0x5e} // 51 Q

,{0x7f, 0x09, 0x19, 0x29, 0x46} // 52 R

,{0x46, 0x49, 0x49, 0x49, 0x31} // 53 S

,{0x01, 0x01, 0x7f, 0x01, 0x01} // 54 T

,{0x3f, 0x40, 0x40, 0x40, 0x3f} // 55 U

,{0x1f, 0x20, 0x40, 0x20, 0x1f} // 56 V

,{0x3f, 0x40, 0x38, 0x40, 0x3f} // 57 W

,{0x63, 0x14, 0x08, 0x14, 0x63} // 58 X

,{0x07, 0x08, 0x70, 0x08, 0x07} // 59 Y

,{0x61, 0x51, 0x49, 0x45, 0x43} // 5a Z

,{0x00, 0x7f, 0x41, 0x41, 0x00} // 5b [

,{0x02, 0x04, 0x08, 0x10, 0x20} // 5c ¥

,{0x00, 0x41, 0x41, 0x7f, 0x00} // 5d ]

,{0x04, 0x02, 0x01, 0x02, 0x04} // 5e ^

,{0x40, 0x40, 0x40, 0x40, 0x40} // 5f _

,{0x00, 0x01, 0x02, 0x04, 0x00} // 60 `

,{0x20, 0x54, 0x54, 0x54, 0x78} // 61 a

,{0x7f, 0x48, 0x44, 0x44, 0x38} // 62 b

,{0x38, 0x44, 0x44, 0x44, 0x20} // 63 c

,{0x38, 0x44, 0x44, 0x48, 0x7f} // 64 d

,{0x38, 0x54, 0x54, 0x54, 0x18} // 65 e

,{0x08, 0x7e, 0x09, 0x01, 0x02} // 66 f

,{0x0c, 0x52, 0x52, 0x52, 0x3e} // 67 g

,{0x7f, 0x08, 0x04, 0x04, 0x78} // 68 h

,{0x00, 0x44, 0x7d, 0x40, 0x00} // 69 i

,{0x20, 0x40, 0x44, 0x3d, 0x00} // 6a j

,{0x7f, 0x10, 0x28, 0x44, 0x00} // 6b k

,{0x00, 0x41, 0x7f, 0x40, 0x00} // 6c l

,{0x7c, 0x04, 0x18, 0x04, 0x78} // 6d m

,{0x7c, 0x08, 0x04, 0x04, 0x78} // 6e n

,{0x38, 0x44, 0x44, 0x44, 0x38} // 6f o

,{0x7c, 0x14, 0x14, 0x14, 0x08} // 70 p

,{0x08, 0x14, 0x14, 0x18, 0x7c} // 71 q

,{0x7c, 0x08, 0x04, 0x04, 0x08} // 72 r

,{0x48, 0x54, 0x54, 0x54, 0x20} // 73 s

,{0x04, 0x3f, 0x44, 0x40, 0x20} // 74 t

,{0x3c, 0x40, 0x40, 0x20, 0x7c} // 75 u

,{0x1c, 0x20, 0x40, 0x20, 0x1c} // 76 v

,{0x3c, 0x40, 0x30, 0x40, 0x3c} // 77 w

,{0x44, 0x28, 0x10, 0x28, 0x44} // 78 x

,{0x0c, 0x50, 0x50, 0x50, 0x3c} // 79 y

,{0x44, 0x64, 0x54, 0x4c, 0x44} // 7a z

,{0x00, 0x08, 0x36, 0x41, 0x00} // 7b {

,{0x00, 0x00, 0x7f, 0x00, 0x00} // 7c |

,{0x00, 0x41, 0x36, 0x08, 0x00} // 7d }

,{0x10, 0x08, 0x08, 0x10, 0x08} // 7e ←

,{0x00, 0x06, 0x09, 0x09, 0x06} // 7f →

,{0x00, 0x00, 0x7D, 0x00, 0x00} // 80 ¡

};

void LcdCharacter(char character) {

LcdWrite(LCD_D, 0x00);

for (int index = 0; index < 5; index++) {

LcdWrite(LCD_D, ASCII[character - 0x20][index]);

}

LcdWrite(LCD_D, 0x00);

}

void LcdClear(void) {

for (int index = 0; index < LCD_X * LCD_Y / 8; index++) {

LcdWrite(LCD_D, 0x00);

}

}

void LcdInitialise(void) {

pinMode(PIN_SCE, OUTPUT);

pinMode(PIN_RESET, OUTPUT);

pinMode(PIN_DC, OUTPUT);

pinMode(PIN_SDIN, OUTPUT);

pinMode(PIN_SCLK, OUTPUT);

digitalWrite(PIN_RESET, LOW);

delay(1);

digitalWrite(PIN_RESET, HIGH);

LcdWrite( LCD_CMD, 0x21 ); // LCD Extended Commands.

LcdWrite( LCD_CMD, 0xB9 ); // Set LCD Vop (Contrast). //B1

LcdWrite( LCD_CMD, 0x04 ); // Set Temp coefficent. //0x04

LcdWrite( LCD_CMD, 0x14 ); // LCD bias mode 1:48. //0x13

LcdWrite( LCD_CMD, 0x0C ); // LCD in 0x0C normal mode. 0x0d for inverse

LcdWrite(LCD_C, 0x20);

LcdWrite(LCD_C, 0x0C);

}

void LcdString(char *characters) {

while (*characters) {

LcdCharacter(*characters++);

}

}

void LcdWrite(byte dc, byte data) {

digitalWrite(PIN_DC, dc);

digitalWrite(PIN_SCE, LOW);

shiftOut(PIN_SDIN, PIN_SCLK, MSBFIRST, data);

digitalWrite(PIN_SCE, HIGH);

}

// gotoXY routine to position cursor

// x - range: 0 to 84

// y - range: 0 to 5

void gotoXY(int x, int y) {

LcdWrite( 0, 0x80 | x); // Column.

LcdWrite( 0, 0x40 | y); // Row.

}

// ***************

// Enable or disable a specific pixel

// x: 0 to 84, y: 0 to 48

void setPixel(int x, int y, int d) {

if (x > 84 || y > 48) { return; }

// The LCD has 6 rows, with 8 pixels per row.

// 'y_mod' is the row that the pixel is in.

// 'y_pix' is the pixel in that row we want to enable/disable

int y_mod = (int)(y >> 3);  // >>3 divides by 8

int y_pix = (y-(y_mod << 3));// << 3 multiplies by 8

int val = 1 << y_pix;

/// We have to keep track of which pixels are on/off in order to

// write the correct character out to the LCD.

if (d){

pixels[x][y_mod] |= val;

} else {

pixels[x][y_mod] &= ~val;

}

// Write the updated pixel out to the LCD

// TODO Check if the pixel is already in the state requested,

// if so, don't write to LCD.

gotoXY(x,y_mod);

LcdWrite (1,pixels[x][y_mod]);

}

void drawLine(int x1, int y1, int x2, int y2) {

}

// Draw a horizontal line of width w from x,y

void drawHorizontalLine(int x, int y, int w){

drawHorizontalLineXY(x,x+w,y);

}

// Draw a horizontal line between x1 and x2 at row y

void drawHorizontalLineXY(int x1, int x2, int y){

for (int i=x1;i<=x2;i++) {

setPixel(i,y,1);

}

}

// Draw a vertical line of height h from x,y

void drawVerticalLine(int x, int y, int h){

drawVerticalLineXY(y,y+h,x);

}

// Draw a vertical line from y1 to y2 on column x

void drawVerticalLineXY(int y1, int y2, int x){

for (int i=y1;i<=y2;i++) {

setPixel(x,i,1);

}

}

void clearPixels() {

for (int x=0;x<83;x++) {

for(int y=0;y<47;y++) {

pixels[x][y] = 0;

}

}

}

// Draw a rectangle of width w and height h from x,y

void drawRect(int x, int y, int w, int h) {

drawHorizontalLineXY(x,x+w,y);

drawHorizontalLineXY(x,x+w,y+h);

drawVerticalLineXY(y,y+h,x);

drawVerticalLineXY(y,y+h,x+w);

}

void initProgressBar() {

LcdClear();

clearPixels();

drawRect(10,21, 64, 5);

}

void setProgressBar(int value) {

int startValue = ((float)prev_prog/100.0)*64;

int newValue = ((float)value/100.0)*64;

if (newValue < startValue) { startValue = 0; }

int pb_x = 10;

int pb_y = 21;

for (int i=startValue;i<newValue;i++) {

drawVerticalLine(pb_x+i,pb_y,5);

}

prev_prog = value;

}

// ******** *****

void setup(void) {

LcdInitialise();

initProgressBar();

while (progress < 100) {

progress++;

setProgressBar(progress);

delay(25);

}

LcdClear();

clearPixels();

}

void loop(void) {

// Muestra algunas animaciones sencillas de caracteres

int a,b;

char Str[20]; //15

{

gotoXY(4,0); //gotoXY(4,1); // Poner el texto en el recuadro

LcdString ("Test");

gotoXY(0,1);

LcdString ("Nokia 3310");

gotoXY(0,2);

LcdString ("LCD Display");

gotoXY(0,3);

LcdString ("Hola ");

gotoXY(22,4);

LcdString (" Mundo ");

gotoXY(0,5);

LcdString ("0123456789AB");

}

}

Proyecto 12b - Nokia 5210 Display LCD Gráfico

En el siguiente proyecto veremos cómo mostrar imágenes en el display.

Abrimos el Paint, seleccionar en atributos 84x48 pixeles monocromo, que son las dimensiones de nuestro display. Cargamos la imagen que queramos, se puede buscar en google imágenes, seleccionar tamaño icono y en blanco y negro. Abrir con el paint y guardar el archivo en formato .bmp.

Con el LCD Assistant cargamos la imagen, configuramos la orientación y guardamos como archivo .txt

Descarga LCD Assistant aquí

El programa convierte la imagen de bits en un array hexadecimal, lo pegamos en el cógido y listo.

Esquema

Sketch

#include <NokiaLCD.h>

NokiaLCD NokiaLCD(6,4,2,5,3); // (SCK, MOSI, DC, RST, CS)

void setup()

{

Serial.begin(9600);

NokiaLCD.init(); // Init screen.

NokiaLCD.clear(); // Clear screen.

}

void loop()

{

byte array[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x8E, 0xDE, 0xFE, 0xFC, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8,

0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xFC, 0xFE, 0xDE, 0x8E, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x7C, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x79, 0x79, 0x7F, 0x7F, 0x7F,

0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x79, 0x79, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7C, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,

0xFE, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,

0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,

0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,

0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,

0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,

0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x07, 0x07, 0x07,

0x03, 0x00, 0x00, 0x1F, 0x1F, 0x1F, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F,

0x1F, 0x1F, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x1F, 0x1F, 0x1F, 0x00,

0x00, 0x03, 0x07, 0x07, 0x07, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x7F, 0x7F, 0x7F, 0x7F, 0x3F, 0x00,

0x00, 0x00, 0x00, 0x3F, 0x7F, 0x7F, 0x7F, 0x7F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00};

NokiaLCD.bitmap(array);

}

Y este es el resultado

Como aprovechar la pantalla de tu antiguo Nokia

Si tienes un Nokia de los antiguos y eres un poco mañoso con el destornillador quizás puedas aprovechar el display del móvil para tus proyectos con Arduino.

Aquí dejo unas imágenes de un Nokia 5210 que tenía por casa.

Links

Gracias a V. García por el sketch del primer ejemplo.