Tuesday, April 19, 2016

Graphic 128x64 LCD interface with Atmega8 and Arduino

This tutorial describes how to interface between a 128x64 graphic LCD and an 8-bit
micro-controller. The techniques described here are useful for any other controller type and
interfacing technique. The micro-controller is connected via its I/O lines and all signals to the LCD are controlled directly by software. All control electronics, contrast control and bias circuits and temperature compensation circuits are built into the module. Each of these circuits is described separately below.

Display mapping: Individual pixels can be controlled by writing a byte to a specific address. Each address is mapped to a corresponding set of 8 pixels on the display. Please refer to Figure 1. Note that the order of the columns is reversed. The first byte of data entered after setting the address registers to 0 will appear in the upper right of the display.






This display has blue/yelow backlight and white/black writing, and with it (and the right library) you can really cool graphical effects such as screen rotation, change text fonts, text rotation and, of course, draw. I published a short video on YouTube showing some of these functions:

The display has 20 pins, numbered from right to left, as we can see in the picture below. It can be used to communicate with the Arduino both serial and parallel manner. In this article, where the LCD refresh rate is not a critical point, we will use the serial communication, occupying only 4 Arduino ports:
The circuit uses a potentiometer (used a 50K) for adjusting the display contrast, and power is made ​​by 5v power supply. 

Method 1: Uses 13 IO Lines
download Proteus simulation file

Graphic 128x64 LCD interface with AVR Arduino


Code for Method 1:

Save this as "GraphicLCD.h"

#include <avr/io.h>
#include <string.h>
//#include <avr/pgmspace.h> 
#include <avr/interrupt.h>

#define RS    PA1  
#define E     PA3  
#define CS1    PC3  
#define CS2    PC2
#define RST    PC1

#define DATA   PORTD


void Delay1();
void InitLCD();
void LCDout(char a);
void Epulse();
void PutPixel(unsigned char x,unsigned char y,char color);
void LCD_Clear();
void line(char x0, char y0, char x1, char y1,char color);
void rect(char x0, char y0, char x1, char y1,char color);
//void circle(int xCenter, int yCenter, int radius, char c);
void DisplayChar(unsigned char x,unsigned char y, char d);
void DisplayText(unsigned char x, unsigned char y, char d[21]);
void DisplayCharSmall(unsigned char x,unsigned char y, char d);
char Pix[128][8];
//char mystr[16], Height[4], Height1[4],bits;
//uint32_t WordOfData; 
//long Cunt;
//int Height;
/*--------------------------------------------------------------------------------------------------
                                     Character generator

             This table defines the standard ASCII characters in a 5x7 dot format.
--------------------------------------------------------------------------------------------------*/
PROGMEM static const char FontLookup [][5] =
{
 {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} // <- 
};

//Hex And Decimal Numbers in 3 X 5 Format 
PROGMEM static const char FontLookup1 [][3] =
{
    { 0xF8, 0x88, 0xF8 },   // 0
    { 0x48, 0xF8, 0x08 },   // 1
    { 0xB8, 0xA8, 0xE8 },   // 2
    { 0xA8, 0xA8, 0xF8 },   // 3
    { 0xE0, 0x20, 0xF8 },   // 4
    { 0xE8, 0xA8, 0xB8 },   // 5
    { 0xF8, 0xA8, 0xB8 },   // 6
    { 0x80, 0x80, 0xF8 },   // 7
    { 0xF8, 0xA8, 0xF8 },   // 8
    { 0xE8, 0xA8, 0xF8 },   // 9
 { 0xF8, 0xA0, 0xF8 },   // A
    { 0xF8, 0xA8, 0x50 },   // B
    { 0xF8, 0x88, 0x88 },   // C
    { 0x88, 0xF8, 0xF8 },   // D
    { 0xF8, 0xA8, 0xA8 },   // E
    { 0xF8, 0xA0, 0xA0 },   // F
 { 0x00, 0x00, 0x00 },   // Space
};

/*********************************************************************************/
/*         MAIN PROGRAM                                 */
/*********************************************************************************/
/*********************************************************************************/
/*         LCD out                                   */
/*********************************************************************************/
void LCDout(char a)
{
 PORTD = a;
 Epulse();
}

/*********************************************************************************/
/*         DELAY 100mSec                                */
/*********************************************************************************/
void Delay1()
{
 int t;
  for(t=0;t<125;t++);
}

/*********************************************************************************/
/*         Init LCD                                     */
/*********************************************************************************/

void InitLCD()
{
    DDRD = 0xFF;
 DDRA |=(1<<RS);
 DDRA |=(1<<E);
 DDRC |=(1<<CS1);
 DDRC |=(1<<CS2);
 DDRC |=(1<<RST);

 PORTC &= ~(1<<RST);   //Make sure rst state
 Delay1();
 PORTC |= (1<<RST);   //Make sure rst state
 Delay1();

 PORTA &=~(1<<RS);  //Command mode
    PORTC |= (1<<CS1);  //CS1 CS2 selected
    PORTC |= (1<<CS2);  //CS1 CS2 selected
 LCDout(0x3F);   //LCD on
 LCDout(0xC0);   //z-axis to zero 

 Delay1();
 Delay1();
 PORTC &=~ (1<<CS1);  
    PORTC &=~ (1<<CS2);  
}

/*********************************************************************************/
/*         Enable Pulse                                 */
/*********************************************************************************/
void Epulse()
{
 //E=PA3
 PORTA = PORTA | 0x08;
 PORTA = PORTA & 0xF7;
}

/*********************************************************************************/
/*         PUT PIXEL(X,Y,color)                         */
/*********************************************************************************/
void PutPixel(unsigned char x,unsigned char y, char color)
{

//Inverse Display
//x = 127-x;
//y = 63-y;

unsigned char c,y1;
c=0;
y1=y; //+3
   
   while(y1 >= 8)
   {
     y1=y1-8;
  c++;
   }

if (x < 64)
{
 PORTA &=~(1<<RS);  //Command mode
    PORTC |= (1<<CS1);  //CS1 selected
 PORTC &=~(1<<CS2);
 c = c & 0x07;
 LCDout(0xB8 | c);  //C (y-axis) is having 3-bit address
 x = x & 0x3F;
 LCDout(0x40 | x);  //C (x-axis) is having 3-bit address
}
else
{
 x = x - 64;
 PORTA &=~(1<<RS);  //Command mode
 PORTC &=~(1<<CS1);  
    PORTC |= (1<<CS2);  //CS2 selected
 c = c & 0x07;
 LCDout(0xB8 | c);  //C (y-axis) is having 3-bit address
 x = x & 0x3F;
 LCDout(0x40 | x);  //C (x-axis) is having 3-bit address
 x = x+64;
}
 
 PORTA |= (1<<RS); 
  if(color==1)
  {
  Pix [x][c]=(Pix [x][c]) | (1<<y1) ;  //y1 is having bit position to set
  LCDout(Pix [x][c]);
 }
 else
 {
  Pix [x][c] &=~ (1<<y1);  //y1 is having bit position to reset
  LCDout(Pix [x][c]);
 }
}

/*********************************************************************************/
/*         LCD CLEAR                                    */
/*********************************************************************************/

void LCD_Clear()
{
unsigned char x,y;
 
unsigned char c;
c=0;
   for(y=0;y<8;y++)
    {
 c=y;
   for(x=0;x<128;x++)
    {
     Pix[x][y]=0x00;
  //=======================
   if ( x < 64)
   {
    PORTA &=~(1<<RS);  //Command mode
       PORTC |= (1<<CS1);  //CS1 selected
    PORTC &=~(1<<CS2);
    c = c & 0x07;
    LCDout(0xB8 | c);  //C (y-axis) is having 3-bit address
    x = x & 0x3F;
    LCDout(0x40 | x);  //C (x-axis) is having 3-bit address
   }
   else
   {
    x = x - 64;
    PORTA &=~(1<<RS);  //Command mode
    PORTC &=~(1<<CS1);  
       PORTC |= (1<<CS2);  //CS2 selected
    c = c & 0x07;
    LCDout(0xB8 | c);  //C (y-axis) is having 3-bit address
    x = x & 0x3F;
    LCDout(0x40 | x);  //C (x-axis) is having 3-bit address
    x = x+64;
   }
   PORTA |=(1<<RS);
   LCDout(0x00);
  //=======================
   
    }
    }
}
/*********************************************************************************/
/*         LINE(X0,Y0,X1,Y1,color)                      */
/*********************************************************************************/

void line(char x0, char y0, char x1, char y1,char color) 
{
 int dy = y1 - y0;
 int dx = x1 - x0;
 int stepx, stepy;
 if (dy < 0) { dy = -dy; stepy = -1; 
 } else { stepy = 1; 
 }
  if (dx < 0) { dx = -dx; stepx = -1; 
 } else { stepx = 1; 
 }
 dy <<= 1;        // dy is now 2*dy
 dx <<= 1;        // dx is now 2*dx
 
 PutPixel(x0, y0,color);

 if (dx > dy) {
  int fraction = dy - (dx >> 1); // same as 2*dy - dx
  while (x0 != x1) {
   if (fraction >= 0) {
    y0 += stepy;
    fraction -= dx;   // same as fraction -= 2*dx
   }
     x0 += stepx;
     fraction += dy;     // same as fraction -= 2*dy
     PutPixel(x0, y0,color);
  }
 } else {
  int fraction = dx - (dy >> 1);
  while (y0 != y1) {
   if (fraction >= 0) {
    x0 += stepx;
    fraction -= dy;
   }
  y0 += stepy;
  fraction += dx;
  PutPixel(x0, y0,color);
  }
 }
} 
/*********************************************************************************/
/*         RECT(X0,Y0,X1,Y1,color)                      */
/*********************************************************************************/
void rect(char x0, char y0, char x1, char y1,char color)
{
 line(x0,y0,x1,y0,color);
 line(x0,y0,x0,y1,color);
 line(x0,y1,x1,y1,color);
 line(x1,y0,x1,y1,color); 
}

/*********************************************************************************/
/*         Circle(X0,Y0,radius,color)                   */
/*********************************************************************************/
void circle(int xCenter, int yCenter, int radius, char c)
    {
        int x, y, r2;

        r2 = radius * radius;
        PutPixel(xCenter, yCenter + radius,c);
        PutPixel(xCenter, yCenter - radius,c);
        PutPixel(xCenter + radius, yCenter,c);
        PutPixel(xCenter - radius, yCenter,c);
        x = 1;
        y = (int) (sqrt(r2 - 1) + 0.5);
        while (x < y) {
            PutPixel(xCenter + x, yCenter + y,c);
            PutPixel(xCenter + x, yCenter - y,c);
            PutPixel(xCenter - x, yCenter + y,c);
            PutPixel(xCenter - x, yCenter - y,c);
            PutPixel(xCenter + y, yCenter + x,c);
            PutPixel(xCenter + y, yCenter - x,c);
            PutPixel(xCenter - y, yCenter + x,c);
            PutPixel(xCenter - y, yCenter - x,c);
            x += 1;
            y = (int) (sqrt(r2 - x*x) + 0.5);
        }
        if (x == y) {
            PutPixel(xCenter + x, yCenter + y,c);
            PutPixel(xCenter + x, yCenter - y,c);
            PutPixel(xCenter - x, yCenter + y,c);
            PutPixel(xCenter - x, yCenter - y,c);
        }
    }
/*********************************************************************************/
/*         Display Text (5x7)                       */
/*********************************************************************************/
void DisplayChar(unsigned char x,unsigned char y, char d)
{
unsigned char r,c,c1;
d=d-32;
 for(r=0;r<5;r++)
 {
  c1=0;   //4
  for(c=0;c<8;c++)
  {
   PutPixel(x+r,y+c1,((0x01) & (pgm_read_byte(&FontLookup[d][r]) >> c )));//>>(c+3)
   c1=c1+1;
  }
 }
}
/*********************************************************************************/
/*         Display Text (3x5)                       */
/*********************************************************************************/
void DisplayCharSmall(unsigned char x,unsigned char y, char d)
{
unsigned char r,c,c1;
 for(r=0;r<3;r++)
 {
  c1=4;  
  for(c=0;c<5;c++)
  {
   PutPixel(x+r,y+c1,((0x01) & (pgm_read_byte(&FontLookup1[d][r]) >> (c+3))));
   c1=c1-1;
  }
 }
}

/*********************************************************************************/
/*         Display Text (5x7)                       */
/*********************************************************************************/
void DisplayText(unsigned char x, unsigned char y, char d[21])
{
int i;
int j;
j=strlen(d);
 for (i=0;i<j;i++)
 {
  DisplayChar((i*6)+x,y,d[i]);
 } 
}


Main Program File: save as main.c



/*********************************************************************************/
/*   blog.circuits4you.com */
/*  128x64 Graphic LCD Demo Code */
/*********************************************************************************/
#include <avr/io.h>
#include <string.h>
#include <avr/pgmspace.h> 
#include "GraphicLCD.h"


void Delay();
void Wait();
/*********************************************************************************/
/*         MAIN PROGRAM                                 */
/*********************************************************************************/
int main(void)
{
 Delay();
 InitLCD(); 
 LCD_Clear(); 

 DisplayText(1,3,"blog.circuits4you.com");
 DisplayText(1,15,"   GLCD 128x64 Demo ");
 circle(40,40,20,1);
 line(20,20,64,64,1);
 rect(15,15,100,60,1);
 //PutPixel(unsigned char x,unsigned char y, char color);
 //line(char x0, char y0, char x1, char y1,char color) 
 //DisplayCharSmall(unsigned char x,unsigned char y, char d)


  Wait();
  Wait();
  Wait();
  Wait();
  LCD_Clear();
  Delay100ms();
}

/*********************************************************************************/
/*      100 mSec Delay                    */
/*********************************************************************************/
void Delay100ms()
{
int k;
 for(k=-29000;k<29000;k++)
 {
  asm("nop");
 }
}
/*********************************************************************************/
/*         DELAY 100mSec                                */
/*********************************************************************************/
void Delay()
{
 int t;
  for(t=-22500;t<22500;t++);
}
/****************************************************************************************/
/*           WAIT                                              */
/****************************************************************************************/
void Wait()
{
  Delay100ms();
  Delay100ms();
  Delay100ms();
  Delay100ms();
  Delay100ms();
  Delay100ms();
  Delay100ms();
  Delay100ms();
  Delay100ms();
  Delay100ms();
  Delay100ms();
}

Method 2 uses only 8 IO Lines:
download Proteus simulation file
Graphic 128x64 LCD interfacing


main program remains same for both circuits





No comments:

Post a Comment