ULTIMATE GUIDE TO SEVEN SEGMENT DISPLAYS

by mshibili01 in Circuits > Microcontrollers

121 Views, 0 Favorites, 0 Comments

ULTIMATE GUIDE TO SEVEN SEGMENT DISPLAYS

2483356-40_600x.png

What is LCD Liquid Crystal Display?

To understand how liquid crystal display works, we have to go through some basics of liquid crystal material.

Liquid crystals are substances those exhibit properties of disparate liquid and crystalline solid states. Liquids can flow and crystalline solids can show unique symmetry properties. In a nutshell, liquid crystals share with liquids the ability to flow but also display symmetries inherited from crystalline solids and both properties can be controlled by applied eclectic fields. Thus they are the best-suited substance to be used as electronic displays.


So how they are used in a display, Hang in tight it, I assure you won't get bored.

As in the picture, Liquid Crystal is sandwiched between two transparent electrode sheets. Let's consider two scenarios in this setup,

  1. Without the applied voltage

Liquid crystals, are aligned parallel to the glass surface and light from beneath gets blocked on the way to the surface. And we are creating a blind.

2. When we apply an electric field between electrodes,

The Liquid crystal gets aligned perpendicular to the glass surface and light can pass through it easily.


So we can manipulate this electric field to get the required characters displayed on the screen, then why there are two 90 degrees shifted polarizers placed on both sides? 

They allow only certain orientation of light gets passed. Light becomes polarized as it passes through the first filter. After passing through the first filter, the light enters the liquid crystals. Next, the second polarized filter blocks out any “extra” light, while simultaneously only allowing the illuminated liquid crystals to display through.


So far so good,

Let's make a display out of this info, We will make our transparent electrode as pixels so that we can display something useful,

In this setup, we can control 8 raws and 5 columns of liquid crystal pixels using our 8x5 (40) grid electrode sheet. By controlling the electric field across these pixels I created these beautiful characters.


HC44780U LCD Driver IC


In order to make a commercial 16x2 LCD display we will need 32 of these pixel grids.

Ie,

Each pixel grid has 8x5 = 40 individual pixels


For 16x2 (32) characters, 32x40 = 1280 Individual pixels arranged in two lines.

Okay!! How to control all these pixel electric fields? Which MCU has 1280 Digital pins? Even using 40 pins and individually controlling each character is a misuse of MCU resources.


Here comes the HC44780 LCD Driver IC. It will manage the pixels and all we need to provide the necessary commands and data to the driver.




There are 40 segment control pins and 8 data pins. 

Okay!! We can feed data to these 8 pins to get output in our 1280 pixels. But HD4480 allows us to use 4-bit mode also, where we can control all these pixels with only 4 line data bus!!

What are the Other pins in this driver IC?


  1. (DB0 - DB3 ) Lower-order bidirectional data bus pins that are not used in 4-bit mode.
  2. (DB4 - DB7 ) Higher-order bidirectional data bus pins are used for 4-bit mode and 8-bit mode.
  3. RS - Selects registers.

0: Instruction register (for write) 

1: Data register (for write and read)

4. R/W - Selects read or write.

 0: Write 

1: Read

5. E - Starts data read/write.


RS - Register Select.


The HD44780U has two 8-bit registers, an instruction register (IR) and a data register (DR).

IR stores instruction codes such as display clear, cursor shift, and address information for display data RAM (DDRAM) and character generator RAM (CGRAM). The IR can only be written from the MPU.

The DR temporarily stores data to be written into DDRAM or CGRAM and temporarily stores data to be read from DDRAM or CGRAM. Data written into the DR from the MPU is automatically written into DDRAM or CGRAM by an internal operation. The DR is also used for data storage when reading data from DDRAM or CGRAM.


That's a lot of Info, We can conclude IR stores commands (what to do with data), and DR is used to store the data.


R/W - Selects read or write.


Whenever we have to display some characters we have to write DR register with data and IR register with the command to display. Understandable. But what are we going to read from the driver? Most of the time we will be just writing to the IC since reading will make it more complex and such scenarios are very rare. Information like the position of the cursor, status completion interrupts, etc. can be read if only required.



Busy Flag (BF)


 When the busy flag is 1, the HD44780U is busy with internal operation, and the next instruction will not be accepted. The busy flag is output to DB7 in the 8-bit mode. The next instruction must be written after ensuring that the busy flag is 0.


So before feeding the data into the bus, you have to make sure the driver is not busy with your previous command. Check whether DB7 is set or not before write operation.

Usually, we do not use the busy flag in 4-bit mode as we have to write code for reading two nibbles from the LCD. Instead, we simply put a certain amount of delay usually 300 to 600uS. This delay might vary depending on the LCD you are using, as you might have a different crystal frequency on which the LCD controller is running. So if you feel any problem running the LCD, simply try to increase the delay. This usually works. For me about 400uS works perfectly.

Supplies

MCU - Any microcontroller with more than 10 Digital pins.

LCD - Hitachi HD44780U

Crystal, Filter caps, and Power supply for Stalone MCU.

Jumper Wires.

croped .png

Electrical Interfacing


Basic LCD interface includes

Rs - Register select connected to Digital pin of MCU

RW - Read/Write connected to the Digital pin of MCU

EN - Enable pin also hooked to Digital pin of MC

D4 - MCU Digital pin

...(For 4BitMode)

D7

D0

....

D3

VCC - 5v PSU

GND - MCU GND


LCD Initialisation


4 bit Mode

  • Wait for about 20mS
  • Send the first init value (0x03)
  • Wait for about 10mS
  • Send second init value (0x03)
  • Wait for about 1mS
  • Send third init value (0x03)
  • Wait for 1mS
  • Select bus width ( 0x02 for 4-bit)
  • Wait for 1mS

8bit Mode

  • Wait for about 20mS
  • Send the first init value (0x30)
  • Wait for about 10mS
  • Send second init value (0x30)
  • Wait for about 1mS
  • Send third init value (0x30)
  • Wait for 1mS
  • Select bus width (0x38 - for 8-bit )
  • Wait for 1mS

C code 


void lcd_init_4bit(void)
{

__delay_ms(20); // Delay for 20ms


lcd_setBit(0x03);
__delay_ms(10); // Delay for 20ms

lcd_setBit(0x03);
__delay_ms(1); // Delay for 1ms

lcd_setBit(0x03);
__delay_ms(1); // Delay for 1ms

lcd_setBit(0x02); // Select 4bit 
__delay_ms(100); // Delay for 100ms

lcd_setBit(0x28); // Select 4bit 
__delay_ms(100); // Delay for 1ms

lcd_setBit(0x01); //Clear display screen
}

Void lcd_init_8bit(void)
{
__delay_ms(20); // Delay for 20ms
lcd_setBit(0x30);
__delay_ms(5); // Delay for 5ms
lcd_setBit(0x03);
__delay_ms(10); // Delay for 10ms
lcd_setBit(0x03);
__delay_ms(10); // Delay for 10ms
lcd_setBit(0x38); // Select 8bit 
lcd_setBit(08); // Display off Cursor off
lcd_setBit(0x01); //Clear display screen
}

How to Write to HD44780

Writing into the driver can be classified into commands and data, 


Write IR (Instruction Register)

Write DR (Data Register)

8bit mode write uses the byte method and 4bit mode write uses the nibble by nibble method.

So a portable write function should consider all these parameters.


Write procedure


Set the Register select bit, 0 for the command to Instruction register and 1 for the data register.

Determine the mode of write (8bit / 4bit) and feed the data to port.

Toggle Enable to LOW

Set D7 as Input to get the busy flag. D7 = 1(input) RW = 1(Read Mode) and RS=0 (Instruction Register)

Toggle Enable Low till the Busy flag is reset

Set RW = 0 (Write mode) again.


C code


void lcd_write( unsigned char byte, unsigned char RegSelect, unsigned char bitMode)
{
RS_PIN = RegSelect;
if(bitMode == 1) // Bit Mode
{
LCD_PORT = ((byte>>4) & 0x0F);
EN = 1;
EN = 0;
__delay_ms(100);
LCD_PORT = (byte & 0x0F);5
EN = 1;
EN = 0;
__delay_ms(100);
}
else{
LCD_PORT = byte;
EN = 1;
EN = 0;
D7 = 1; // set D7 as input to fetch busy flag
RW = 1 // shift to read register
do{
EN = 1;
EN = 0;
}while(D7);
D7 = 0; // Reset D7 to output
RW = 0; // Shift to write
}
}

Write a String to the LCD

  1. Get the DDRAM position address and string
  2. Send command to IR (set position to position address)
  3. Send each character of the string to the DR till null

C Code


#define INSTR_REG	0
#define DATA_REG 1
#define FOURbitMODE 1
#define EIGHTbitMODE 0
#define LINE1(n) (0x80+(n))
#define LINE2(n) (0x0C+(n))
unsigned char addr = LINE1(3);
unsigned char data[] = “String to print”; 
void lcd_print(const unsigned char *data, unsigned char addr )
{
lcd_write(addr, INSTR_REG, EIGHTbitMODE);
while(*data!=’\0’)
lcd_write(*data++, DATA_REG, EIGHTbitMODE);
}

Complete Portable LCD Software

LCD PRIMARY FUNCTIONS


//----------lcd.c-------------------------

#include <xc.h>
#include "clcd.h"

void clcd_write(unsigned char byte, unsigned char control_bit)
{
    CLCD_RS = control_bit;
    CLCD_PORT = byte;

    /* Should be atleast 200ns */
    CLCD_EN = HI;
    CLCD_EN = LO;

    PORT_DIR = INPUT;
    CLCD_RS = INSTRUCTION_COMMAND;

    do
    {
        CLCD_EN = HI;
        CLCD_EN = LO;
    } while (CLCD_BUSY);

    CLCD_RW = LO;
    PORT_DIR = OUTPUT;
}

void init_clcd()
{
    /* Set PortD as output port for CLCD data */
    TRISD = 0x00;
    /* Set PortC as output port for CLCD control */
    TRISC = TRISC & 0xF8;

    CLCD_RW = LO;

    CURSOR_HOME;
    TWO_LINE_5x8_MATRIX_8_BIT;
    DISP_ON_AND_CURSOR_OFF;
    CLEAR_DISP_SCREEN;
}

void clcd_print(const unsigned char *data, unsigned char addr)
{
    clcd_write(addr, INSTRUCTION_COMMAND);
    while (*data != '\0')
    {
        clcd_write(*data++, DATA_COMMAND);
    }
}

void clcd_putch(const unsigned char data, unsigned char addr)
{
    clcd_write(addr, INSTRUCTION_COMMAND);
    clcd_write(data, DATA_COMMAND);
}


//----------------lcd.h---------------

#ifndef LCD_H
#define LCD_H

#define CLCD_PORT           PORTD
#define CLCD_EN             RC2
#define CLCD_RS             RC1
#define CLCD_RW             RC0
#define CLCD_BUSY           RD7
#define PORT_DIR            TRISD7


#define HI                                              1
#define LO                                              0

#define INPUT                                           0xFF
#define OUTPUT                                          0x00

#define DATA_COMMAND                                    1
#define INSTRUCTION_COMMAND                             0

#define LINE1(x)                                    (0x80 + (x))
#define LINE2(x)                                    (0xC0 + (x))

#define TWO_LINE_5x8_MATRIX_8_BIT                   clcd_write(0x38, INSTRUCTION_COMMAND)
#define CLEAR_DISP_SCREEN                           clcd_write(0x01, INSTRUCTION_COMMAND)
#define CURSOR_HOME                                 clcd_write(0x02, INSTRUCTION_COMMAND)
#define DISP_ON_AND_CURSOR_OFF                      clcd_write(0x0C, INSTRUCTION_COMMAND)

void init_clcd(void);
void clcd_print(const unsigned char *data, unsigned char addr);
void clcd_putch(const unsigned char data, unsigned char addr);
void clcd_write(unsigned char bit_values, unsigned char control_bit);

#endif