Thursday 1 August 2013

Interfacing Nokia 3310 LCD with Arduino

After using a basic 16 X 2 LCD modules with Arduino most of hobbyist think about how to display an image with an LCD screen. The most easy way is to get  an LCD of old Nokia phone 3310. It has an SPI interface so it can be easily setup with an Arduino.  Here I describe my experience with that LCD module.

Get an old Nokia 3310 and remove the display module from it. There will be an LCD controlled inside all LCD modules. Here the controller of this LCD module is Philips PCD8544 controller. This LCD is a 84x48 Module, it means there is 84 columns and 48 rows of pixel. This is a monochrome display module just as the 16 X 2 LCD module. The controller of module has a set of commands to control its function and it is clearly defined in the PCD8544 datasheet. Fortunately there are so many drivers are available that are compatible with the Arduino. you can find it here. Just download the drivers and save in Arduino library directory. The pinout of the LCD is as follows:


Carefully solder wires to the pins as shown above. The LCD is working at 2.7V-3.3V so cares must be taken to level convert the 5V from Arduino to 3.3V or else it will fry your LCD controller. Wire the LCD to Arduino with a level converter circuit, I used a simple voltage divide for this.
Instead of the diodes(1N4148) you can use a 3.3V regulator also. After download the driver files go through the 'Hello World'example programs and you can find how to display characters with this LCD module. You can make the special custom characters and symbols using  lcd.createChar() function, with the help of this Glyph Editor you can easily make your own shapes. To display an image with this LCD we need to go through some steps.
1. Load the image to be displayed into a picture editor software like Microsoft Office Picture Manager and change the image to a monochrome image that is Black and White.
2. Increase the contrast of the image so that the image will be displayed more clearly
3. Convert the resolution of the image it 84x48 because our LCD is 84x48 pixels.
4. Save it as .bmp file
Now you need a software to convert the .bmp image to a bit mapped hex code. Download the software FastLCD. Open the software click on grid size and change image size to 84x48. Load the saved .bmp image to the software. Click on 'Generate BSA table' ->select LCD 3310 and save as image-> click OK, now give the file name and save to a location. Open the .bas file you saved, this is the hex code that the Arduino can understand how to draw the image on the LCD. You can also modify the image with the drawing tools available in the FastLCD. Now open the Arduino IDE and paste the code :

#include <PCD8544.h>
static PCD8544 lcd;
void setup()
{
  lcd.begin(84, 48);
static const byte image[] ={
// Here you copy the entire hex code(like &hFF) from the .bas file and replace the '&h' with '0x'
};
lcd.drawBitmap(image,84,48);
}
void loop()
{
}
and upload to the board. I have made the image of South Indian superstar Mohanlal's image to display on the LCD.
The .bas file for this image is :
static const byte image[] ={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFE,0xFE,0xFC,0xF8,0xF0,0xE0,0xC0,0x80,0x80,0x00,0x00,0x40,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xC0,0x80,0x80,
0x80,0x80,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,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0x1F,0x0F,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,
0x07,0x07,0x07,0x07,0x06,0x0E,0x0E,0x0E,0x0F,0x0F,0x1F,0x1F,0x3F,0x3F,0x7F,0x3F,
0x3F,0x3F,0x3F,0x7F,0x7F,0xFF,0xFF,0xFF,0xFF,0xFE,0xFC,0xFC,0xF0,0xE0,0xC0,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,0x1F,0x1F,0x0F,0x07,0x01,0xF8,0xFF,0xFF,
0xFF,0x1F,0x07,0x03,0x03,0x03,0x87,0xE3,0x63,0x53,0xFF,0xFF,0xFE,0xFC,0xF8,0x00,
0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xB4,0xBC,0x00,0xC0,0xFF,0x3E,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xF0,0xF0,0xF0,
0xF3,0xFF,0xFF,0xFF,0xE3,0xC0,0x80,0x80,0x80,0x00,0x1F,0xB1,0xE0,0xFF,0xFF,0xFF,
0xFF,0x3F,0x81,0x80,0x00,0x00,0x01,0x00,0x00,0x03,0x02,0x06,0x01,0x00,0x00,0x01,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xF8,0xFC,0xFE,0xFE,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F,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,0x7F,0x7F,0x3F,0x3F,0x1F,0x0F,0x0F,0x06,0x05,0x00,0x09,0x11,0x23,
0x23,0x03,0x03,0x03,0x01,0x01,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x32,0x3E,0x03,
0xC0,0x7C,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x1F,0x7F,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0x1F,0x07,0x01,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x01,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,0x01,0x01,
0x01,0x03,0x03,0x03,0x07,0x0E,0x1E,0x1E,0x3E,0x7C,0x7C,0x7C,0xFC,0xFC,0xFC,0xFC,
0xFF,0xFF,0xFF,0x7F,0x7F,0x7F,0x3F,0x1F,0x1F,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};
Test the following sketch also with the library itself:
Thermometer with graphical display:

#include <PCD8544.h>


static const byte sensorPin = 0;
static const byte ledPin = 13;

// The dimensions of the LCD (in pixels)...
static const byte LCD_WIDTH = 84;
static const byte LCD_HEIGHT = 48;

// The number of lines for the temperature chart...
static const byte CHART_HEIGHT = 5;

// A custom "degrees" symbol...
static const byte DEGREES_CHAR = 1;
static const byte degrees_glyph[] = { 0x00, 0x07, 0x05, 0x07, 0x00 };

// A bitmap graphic (10x2) of a thermometer...
static const byte THERMO_WIDTH = 10;
static const byte THERMO_HEIGHT = 2;
static const byte thermometer[] = { 0x00, 0x00, 0x48, 0xfe, 0x01, 0xfe, 0x00, 0x02, 0x05, 0x02,
                                    0x00, 0x00, 0x62, 0xff, 0xfe, 0xff, 0x60, 0x00, 0x00, 0x00};

static PCD8544 lcd;


void setup() {
  lcd.begin(LCD_WIDTH, LCD_HEIGHT);

  // Register the custom symbol...
  lcd.createChar(DEGREES_CHAR, degrees_glyph);

  pinMode(ledPin, OUTPUT);

  // The internal 1.1V reference provides for better
  // resolution from the LM35, and is also more stable
  // when powered from either a battery or USB...
  analogReference(INTERNAL);
}


void loop() {
  // Start beyond the edge of the screen...
  static byte xChart = LCD_WIDTH;

  digitalWrite(ledPin, HIGH);

  // Read the temperature (in celsius)...
  float temp = (1.1 * analogRead(sensorPin) * 100.0) / 1024.0;

  // Print the temperature (using the custom "degrees" symbol)...
  lcd.setCursor(0, 0);
  lcd.print("Temp: ");
  lcd.print(temp, 1);
  lcd.print(" \001C ");

  // Draw the thermometer bitmap at the bottom left corner...
  lcd.setCursor(0, LCD_HEIGHT/8 - THERMO_HEIGHT);
  lcd.drawBitmap(thermometer, THERMO_WIDTH, THERMO_HEIGHT);

  // Wrap the chart's current position...
  if (xChart >= LCD_WIDTH) {
    xChart = THERMO_WIDTH + 2;
  }

  // Update the temperature chart...
  lcd.setCursor(xChart, 1);
  lcd.drawColumn(CHART_HEIGHT, map(temp, 0, 45, 0, CHART_HEIGHT*8));  // ...clipped to the 0-45C range.
  lcd.drawColumn(CHART_HEIGHT, 0);         // ...with a clear marker to see the current chart position.

  xChart++;

  digitalWrite(ledPin, LOW);
  delay(500);
}


2 comments:

  1. This article is still great at the hardware level!

    /Mikael

    ReplyDelete