Tutorial 7 : LiquidCrystal library - sudeshmoreyos/Morey_os-demo-1.0 GitHub Wiki

Home <<Prev 7 Next>>

In this tutorial, we will explore LiquidCrystal.h library. Let us first take a brief introduction of an Alphanumeric LCD.

1. Introduction to Alphanumeric LCD

Wikipedia defines a Liquid Crystal Display as "A liquid-crystal display (LCD) is a flat-panel display or other electronically modulated optical device that uses the light-modulating properties of liquid crystals combined with polarizers. Liquid crystals do not emit light directly, instead using a backlight or reflector to produce images in color or monochrome." An alphanumeric LCD can display only alphanumeric characters and no images. Also it is monochrome. A typical 16x2 LCD looks like as shown below :

16x2 here means we can display 32 alphaumeric characters on this LCD. Also it has 2 rows and 16 columns. There are many variants available like 8x1, 8x2, 16x1, 20x4, etc. As shown above it has 16 pins named below :

pin-1 : Gnd

pin-2 : Vcc

pin-3 : Contrast

pin-4 : RS

pin-5 : RW

pin-6 : EN

pin-7 : Data0

pin-8 : Data1

pin-9 : Data2

pin-10 : Data3

pin-11 : Data4

pin-12 : Data5

pin-13 : Data6

pin-14 : Data7

pin-15 : Backlight+

pin-16 : Backlight-

Vcc and Gnd pins are used to power up the LCD. Contrast pin is used to control intensity of displayed text on LCD. RS, RW, EN are control pins. Data0 to Data7 are data pins to communicate with LCD. Backlight+ and Backlight- are used to optionally glow backlight of the LCD.

2. Liquid Crystal Wiring connections

In order to display text on LCD, we need to first connect it with controller/Board. As discussed before LCD has three control pins and eight data pins. In standard wiring connections, we need to connect all control pins plus data pins. That uses total 11 pins of controller/board. Using these many pins waste lots of controllers pins. Hence a different option is used, in which only 6 pins are required, namely RS, EN, Data4, Data5, Data6, and Data7. However, it must be noted that RW pin must be grounded by default. LiquidCrystal library currently supports only 6 pin mode. So wiring connection with Arduino Uno may typically look like as follows :

As shown above pin13 to pin8 of Arduino Uno are connected to RS, EN, Data4, Data5, Data6 and Data7 respectively. RW pin of LCD is grounded while Vcc and Gnd are connected to power supply. Data0 to Data3 are left unconnected. Backlight pins may optionally be connected to 5V supply.

3. LiquidCrystal Library

To include LiquidCrystal header file in your code, you need to add following lines in your code :

#include "lib/LiquidCrystal.h"

You can also find sources for LiquidCrystal library here LiquidCrystal Lib

This Lib supports following initialization and functions :

3.1 Liquid Crystal Struct initialization

First step is to initialize the Liquid Crystal structure, which holds the essential data required by LiquidCrystal lib functions. Initialization is done as follows :

LiquidCrystal_t lcd={pin13,pin12,pin11,pin10,pin9,pin8};

In above declaration we are creating a struct of type LiquidCrystal_t. Also we are assigning digital pins to struct which should be connected to LCD in order RS, EN, Data4, Data5, Data6 and Data7 respectively. This structure should be defined above setup function.

3.2 LiquidCrystal_begin

Declaration:

void lcd_begin(LiquidCrystal_t * lcd_struct, mos_uint8_t cols, mos_uint8_t rows);

After LiquidCrystal_t struct initialization, first function that must be used is LiquidCrystal_begin. This function has three inputs. First input is LiquidCrystal_t struct pointer. Second is number of columns supported by LCD and third is number of rows supported by LCD. For example a 16x2 LCD has 16 columns and 2 rows. Function is usually declared in setup function as :

void setup

{

LiquidCrystal_begin(&lcd,16,2);

}

3.3 LiquidCrystal_clear

Declaration :

void lcd_clear(LiquidCrystal_t * lcd_struct);

This function is used to clear the LCD. It has only one input and that is pointer to LiquidCrsytal_t struct. After clearing the text, cursor position is automatically set to origin or (0,0) position.

3.4 LiquidCrystal_write

Declaration :

void lcd_write(LiquidCrystal_t * lcd_struct, char data);

This function is used to display a single character on the LCD. It has two inputs, first one is LiquidCrsytal_t struct pointer and other is character to be displayed. Character is printed at current cursor position and then cursor is automatically incremented to next position.

3.5 LiquidCrystal_print

Declaration :

void lcd_print(LiquidCrystal_t * lcd_struct, char * data_string);

This function is used to print a string on LCD. This function has two inputs. First one is LiquidCrystal_t struct pointer and second one is text string. If printed text overflows a line/row, it is automatically printed on the next line. If text overflows the last line/row it is automatically printed on the first line/row.

3.6 LiquidCrystal_setcursor

Declaration :

void lcd_setCursor(LiquidCrystal_t * lcd_struct, mos_uint8_t x, mos_uint8_t y);

This function is used to set the cursor to any position. This function is typically used before LiquidCrystal_write or LiquidCrystal_print function. It has three inputs. First one is LiquidCrsytal_t struct pointer, second is column/x position and third input is row/y position. Cursor position may vary from (0,0) position to (rows-1,cols-1) position, where rows and cols are number of rows and cols supported by LCD. For example for 16x2 LCD cols = 16 and rows = 2. Different possible cursor positions for a 16x2 LCD is shown below :

4. LiquidCrystal lib Example

Let us now check an example code named lcd-demo.c that can be found in example folder (examples/board-examples/arduino-uno/lcd-demo). The code is as follows :

#include "morey_os.h"

#include "lib/LiquidCrystal.h"

#include "Digital.h"

LiquidCrystal_t lcd={pin13,pin12,pin11,pin10,pin9,pin8};

void setup(void)

{

lcd_begin(&lcd,16,2);

Digital.pinmode(pina0,OUTPUT);

}

TASK_CREATE(lcd_test,"lcd_test");

TASK_CREATE(led,"led");

TASK_AUTOSTART(&lcd_test,&led);

TASK_RUN(lcd_test)

{

static int i = 0;

BEGIN();

while(1)

{

for(i=0;i<16;i++)

{

lcd_clear(&lcd);

lcd_setCursor(&lcd,i,0);

lcd_print(&lcd,"Morey_os");

DELAY_SEC_PRECISE(1);

}

for(i=0;i<16;i++)

{

lcd_clear(&lcd);

lcd_setCursor(&lcd,i,1);

lcd_print(&lcd,"Morey_os");

DELAY_SEC_PRECISE(1);

}

for(i=0;i<16;i++)

{

lcd_clear(&lcd);

lcd_setCursor(&lcd,i,0);

lcd_write(&lcd,'A');

DELAY_SEC_PRECISE(1);

}

for(i=0;i<16;i++)

{

lcd_clear(&lcd);

lcd_setCursor(&lcd,i,1);

lcd_write(&lcd,'A');

DELAY_SEC_PRECISE(1);

}

}

END();

}

TASK_RUN(led)

{

BEGIN();

while(1)

{

Digital.write(pinA0,HIGH);

DELAY_SEC(0.1);

Digital.write(pinA0,LOW);

DELAY_SEC(0.1);

}

END();

}

Code Explanation :

  1. morey_os.h header file is compulsory to include in all codes. Since we are using LiquidCrystal lib functionality, we have added lib/LiquidCrystal.h header too.

#include "morey_os.h"

#include "lib/SevenSegment.h"

One struct of type LiquidCrystal_t is initialized by name lcd and respective digital pins of board are assigned to it.

LiquidCrystal_t lcd={pin13,pin12,pin11,pin10,pin9,pin8};

  1. lcd is initialized with 16 cols and 2 rows in setup function.

void setup(void)

{

lcd_begin(&lcd,16,2);

Digital.pinmode(pina0,OUTPUT);

}

  1. We have created two tasks named lcd_test and led. Please note TASK_CREATE Macro has two inputs. First input is name of the task to be created, other input is string name of the task which is used during code debugging process. We will discuss more about code debugging in subsequent tutorials.

TASK_CREATE(lcd_test,"lcd_test");

TASK_CREATE(led,"led");

  1. Next we auto-start both the tasks at startup or powerup of the board. We can optionally start these tasks manually inside some other tasks. Starting or ending tasks inside a task will be discussed in subsequent tutorials. For now we will auto-start all tasks at controller/board boot time.

TASK_AUTOSTART(&lcd_test,&led);

  1. Next we declare TASK_RUN for both the tasks. lcd_test task implements all five functions namely LiquidCrystal_begin, LiquidCrystal_clear, LiquidCrystal_write, LiquidCrystal_print and LiquidCrystal_setcursor for lcd.

In TASK_RUN(lcd_test) a static integer variable 'i' is declared. Please note all variables in Morey_os must be declared as static. Reason for this is declared in subsequent tutorials.

After BEGIN(); Macro code implements a while(1) loop. Inside this loop, we have four different for loops. Each for loop implements moving message display. First for loop implements moving message starting from position (0,0) to position (15,0). You will notice that overflown text is going to next line. In each loop run, first LiquidCrsytal_clear function clears the LCD, then cursor position is selected using LiquidCrystal_setCursor, text is printed using LiquidCrystal_print function and finally we give delay of 1 second using DELAY_SEC_PRECISE(1) macro.

Similarly in second for loop moving message is displayed in second row, in third for loop moving message of single character 'A' is displayed in first row and finally in last for loop moving message of single character 'A' is displayed in second row.

To give delay in morey_os we can use DELAY_SEC() or DELAY_SEC_PRECISE() macros. Detailed discussion of these two macros is to be done in subsequent tutorials. Also it is very important to note that both tasks uses while(1) which is an infinite loop. Morey_os is based on cooperative threads, thats why this infinite loop must have at least one DELAY_SEC() or DELAY_SEC_PRECISE() macro. And we have used DELAY_SEC_PRECISE(1) inside for loops, hence this condition is satisfied.

TASK_RUN(lcd_test)

{ static int i = 0;

BEGIN();

while(1)

{

for(i=0;i<16;i++)

{

lcd_clear(&lcd);

lcd_setCursor(&lcd,i,0);

lcd_print(&lcd,"Morey_os");

DELAY_SEC_PRECISE(1);

}

for(i=0;i<16;i++)

{

lcd_clear(&lcd);

lcd_setCursor(&lcd,i,1);

lcd_print(&lcd,"Morey_os");

DELAY_SEC_PRECISE(1);

}

for(i=0;i<16;i++)

{

lcd_clear(&lcd);

lcd_setCursor(&lcd,i,0);

lcd_write(&lcd,'A');

DELAY_SEC_PRECISE(1);

}

for(i=0;i<16;i++)

{

lcd_clear(&lcd);

lcd_setCursor(&lcd,i,1);

lcd_write(&lcd,'A');

DELAY_SEC_PRECISE(1);

}

}

// process ends here

END();

}

  1. led Task simply switches pinA0 on and off after every 0.1 second.

TASK_RUN(led)

{

BEGIN();

while(1)

{

Digital.write(pinA0,HIGH);

DELAY_SEC(0.1);

Digital.write(pinA0,LOW);

DELAY_SEC(0.1);

}

END();

}

  1. Content of Makefile is as follows :

PROJECT = lcd-demo

MOREY_OS_PATH = ../../../..

BOARD = ARDUINO_UNO

include $(MOREY_OS_PATH)/Makefile.include

PROJECT Macro will hold name of the project file name. MOREY_OS_PATH holds the location of Morey_os root directory. BOARD Macro should hold ARDUINO_UNO since we are programming for Arduino_uno board. And last line should remain the same as mentioned above.

  1. This code is simple and requires no special configurations. Hence config.h file content will remain same as below :

#ifndef CONFIG_H

#define CONFIG_H

#define COMPILER AVR_GCC

#endif

Home <<Prev 7 Next>>