20. Chapter LCD1602

In this chapter, we will learn about the LCD1602 Display Screen

20.1. Project I2C LCD1602

There are LCD1602 display screen and the I2C LCD. We will introduce both of them in this chapter. But what we use in this project is an I2C LCD1602 display screen. The LCD1602 Display Screen can display 2 lines of characters in 16 columns. It is capable of displaying numbers, letters, symbols, ASCII code and so on. As shown below is a monochrome LCD1602 Display Screen along with its circuit pin diagram

../../../_images/LCD1602_1.png

I2C LCD1602 Display Screen integrates a I2C interface, which connects the serial-input & parallel-output module to the LCD1602 Display Screen. This allows us to only use 4 lines to operate the LCD1602.

../../../_images/LCD1602_2.png

The serial-to-parallel IC chip used in this module is PCF8574T (PCF8574AT), and its default I2C address is 0x27(0x3F). You can also view the RPI bus on your I2C device address through command “i2cdetect -y 1” (refer to the “configuration I2C” section below).

Below is the PCF8574 chip pin diagram and its module pin diagram:

../../../_images/PCF8574.png

PCF8574 module pins and LCD1602 pins correspond to each other and connected to each other:

../../../_images/PCF8574_1.png

Because of this, as stated earlier, we only need 4 pins to control the16 pins of the LCD1602 Display Screen through the I2C interface.

In this project, we will use the I2C LCD1602 to display some static characters and dynamic variables.

20.1.1. Component List

  1. Raspberry Pi (with 40 GPIO) x1

  2. GPIO Extension Board & Ribbon Cable x1

  3. Breadboard x1

Jumper Wires x4

jumper-wire

I2C LCD1602 Module x1

LCD1602

20.1.2. Circuit

Note that the power supply for I2C LCD1602 in this circuit is 5V.

Schematic diagram

LCD1602_Sc

Hardware connection. If you need any support,please feel free to contact us via:

support@freenove.com

LCD1602_Fr

Note

It is necessary to configure 12C and install Smbus first (see Chapter 7 ADC for details)

20.1.3. Code

This code will have your RPi’s CPU temperature and System Time Displayed on the LCD1602.

20.1.3.1. C Code I2CLCD1602

If you did not configure I2C and install Smbus, please refer to Chapter 7. If you did, please continue.

First, observe the project result, and then learn about the code in detail.

Hint

If you have any concerns, please contact us via: support@freenove.com

  1. Use cd command to enter 20.1.1_ I2CLCD1602 directory of C code.

$ cd ~/Freenove_Kit/Code/C_Code/20.1.1_I2CLCD1602
  1. Use following command to compile “I2CLCD1602.c” and generate executable file I2CLCD1602.

$ gcc I2CLCD1602.c -o I2CLCD1602 -lwiringPi -lwiringPiDev
  1. Then run the generated file “I2CLCD1602”.

$ sudo ./I2CLCD1602

After the program is executed, the LCD1602 Screen will display your RPi’s CPU Temperature and System Time.

So far, at this writing, we have two types of LCD1602 on sale. One needs to adjust the backlight, and the other does not.

The LCD1602 that does not need to adjust the backlight is shown in the figure below.

../../../_images/LCD1602_back.png

The following is the program code:

  1/**********************************************************************
  2* Filename    : I2CLCD1602.c
  3* Description : Use the LCD display data
  4* Author      : www.freenove.com
  5* modification: 2020/07/23
  6**********************************************************************/
  7#include <stdlib.h>
  8#include <stdio.h>
  9#include <wiringPi.h>
 10#include <wiringPiI2C.h>
 11#include <pcf8574.h>
 12#include <lcd.h>
 13#include <time.h>
 14
 15int pcf8574_address = 0x27;        // PCF8574T:0x27, PCF8574AT:0x3F
 16#define BASE 64         // BASE any number above 64
 17//Define the output pins of the PCF8574, which are directly connected to the LCD1602 pin.
 18#define RS      BASE+0
 19#define RW      BASE+1
 20#define EN      BASE+2
 21#define LED     BASE+3
 22#define D4      BASE+4
 23#define D5      BASE+5
 24#define D6      BASE+6
 25#define D7      BASE+7
 26
 27int lcdhd;// used to handle LCD
 28void printCPUTemperature(){// sub function used to print CPU temperature
 29    FILE *fp;
 30    char str_temp[15];
 31    float CPU_temp;
 32    // CPU temperature data is stored in this directory.
 33    fp=fopen("/sys/class/thermal/thermal_zone0/temp","r");
 34    fgets(str_temp,15,fp);      // read file temp
 35    CPU_temp = atof(str_temp)/1000.0;   // convert to Celsius degrees
 36    printf("CPU's temperature : %.2f \n",CPU_temp);
 37    lcdPosition(lcdhd,0,0);     // set the LCD cursor position to (0,0) 
 38    lcdPrintf(lcdhd,"CPU:%.2fC",CPU_temp);// Display CPU temperature on LCD
 39    fclose(fp);
 40}
 41void printDataTime(){//used to print system time 
 42    time_t rawtime;
 43    struct tm *timeinfo;
 44    time(&rawtime);// get system time
 45    timeinfo = localtime(&rawtime);//convert to local time
 46    printf("%s \n",asctime(timeinfo));
 47    lcdPosition(lcdhd,0,1);// set the LCD cursor position to (0,1) 
 48    lcdPrintf(lcdhd,"Time:%02d:%02d:%02d",timeinfo->tm_hour,timeinfo->tm_min,timeinfo->tm_sec); //Display system time on LCD
 49}
 50int detectI2C(int addr){
 51    int _fd = wiringPiI2CSetup (addr);   
 52    if (_fd < 0){		
 53        printf("Error address : 0x%x \n",addr);
 54        return 0 ;
 55    } 
 56    else{	
 57        if(wiringPiI2CWrite(_fd,0) < 0){
 58            printf("Not found device in address 0x%x \n",addr);
 59            return 0;
 60        }
 61        else{
 62            printf("Found device in address 0x%x \n",addr);
 63            return 1 ;
 64        }
 65    }
 66}
 67int main(void){
 68    int i;
 69
 70    printf("Program is starting ...\n");
 71
 72    wiringPiSetup();  
 73    if(detectI2C(0x27)){
 74        pcf8574_address = 0x27;
 75    }else if(detectI2C(0x3F)){
 76        pcf8574_address = 0x3F;
 77    }else{
 78        printf("No correct I2C address found, \n"
 79        "Please use command 'i2cdetect -y 1' to check the I2C address! \n"
 80        "Program Exit. \n");
 81        return -1;
 82    }
 83    pcf8574Setup(BASE,pcf8574_address);//initialize PCF8574
 84    for(i=0;i<8;i++){
 85        pinMode(BASE+i,OUTPUT);     //set PCF8574 port to output mode
 86    } 
 87    digitalWrite(LED,HIGH);     //turn on LCD backlight
 88    digitalWrite(RW,LOW);       //allow writing to LCD
 89	lcdhd = lcdInit(2,16,4,RS,EN,D4,D5,D6,D7,0,0,0,0);// initialize LCD and return “handle” used to handle LCD
 90    if(lcdhd == -1){
 91        printf("lcdInit failed !");
 92        return 1;
 93    }
 94    while(1){
 95        printCPUTemperature();//print CPU temperature
 96        printDataTime();        // print system time
 97        delay(1000);
 98    }
 99    return 0;
100}

From the code, we can see that the PCF8591 and the PCF8574 have many similarities in using the I2C interface to expand the GPIO RPI.

First, define the I2C address of the PCF8574 and the Extension of the GPIO pin, which is connected to the GPIO pin of the LCD1602. LCD1602 has two different i2c addresses. Set 0x27 as default.

 1int pcf8574_address = 0x27;        // PCF8574T:0x27, PCF8574AT:0x3F
 2#define BASE 64         // BASE any number above 64
 3//Define the output pins of the PCF8574, which are directly connected to the LCD1602 pin.
 4#define RS      BASE+0
 5#define RW      BASE+1
 6#define EN      BASE+2
 7#define LED     BASE+3
 8#define D4      BASE+4
 9#define D5      BASE+5
10#define D6      BASE+6
11#define D7      BASE+7

Then, in main function, initialize the PCF8574, set all the pins to output mode, and turn ON the LCD1602 backlight (without the backlight the Display is difficult to read).

1pcf8574Setup(BASE,pcf8574_address);//initialize PCF8574
2for(i=0;i<8;i++){
3    pinMode(BASE+i,OUTPUT);     //set PCF8574 port to output mode
4} 
5digitalWrite(LED,HIGH);     //turn on LCD backlight

Then use lcdInit() to initialize LCD1602 and set the RW pin of LCD1602 to 0 (can be written) according to requirements of this function. The return value of the function called “Handle” is used to handle LCD1602”.

1lcdhd = lcdInit(2,16,4,RS,EN,D4,D5,D6,D7,0,0,0,0);// initialize LCD and return "handle" used to handle LCD

Details about lcdInit():

int lcdInit(int rows, int cols, int bits, int rs, int strb, int d0, int d1, int d2, int d3, int d4, int d5, int d6, int d7);

This is the main initialization function and must be executd first before you use any other LCD functions. Rows and cols are the rows and columns of the Display (e.g. 2, 16 or 4, 20). Bits is the number of how wide the number of bits is on the interface (4 or 8). The rs and strb represent the pin numbers of the Display’s RS pin and Strobe (E) pin. The parameters d0 through d7 are the pin numbers of the 8 data pins connected from the RPi to the display. Only the first 4 are used if you are running the display in 4-bit mode.

The return value is the ‘handle’ to be used for all subsequent calls to the lcd library when dealing with that LCD, or -1 to indicate a fault (usually incorrect parameter)

For more details about LCD Library, please refer to: https://projects.drogon.net/raspberry-pi/wiringpi/lcd-library/

In the next “while”, two subfunctions are called to display the RPi’s CPU Temperature and the SystemTime. First look at subfunction printCPUTemperature(). The CPU temperature data is stored in the “/sys/class/thermal/thermal_zone0/temp” file. We need to read the contents of this file, which converts it to temperature value stored in variable CPU_temp and uses lcdPrintf() to display it on LCD.

 1void printCPUTemperature(){// sub function used to print CPU temperature
 2    FILE *fp;
 3    char str_temp[15];
 4    float CPU_temp;
 5    // CPU temperature data is stored in this directory.
 6    fp=fopen("/sys/class/thermal/thermal_zone0/temp","r");
 7    fgets(str_temp,15,fp);      // read file temp
 8    CPU_temp = atof(str_temp)/1000.0;   // convert to Celsius degrees
 9    printf("CPU's temperature : %.2f \n",CPU_temp);
10    lcdPosition(lcdhd,0,0);     // set the LCD cursor position to (0,0) 
11    lcdPrintf(lcdhd,"CPU:%.2fC",CPU_temp);// Display CPU temperature on LCD
12    fclose(fp);
13}

Details about lcdPosition() and lcdPrintf():

lcdPosition (int handle, int x, int y);

Set the position of the cursor for subsequent text entry.

lcdPutchar(int handle, uint8_t data) & lcdPuts (int handle, char *string) & lcdPrintf (int handle, char *message, )

These output a single ASCII character, a string or a formatted string using the usual print formatting commands to display individual characters (it is how you are able to see characters on your computer monitor).

Next is subfunction printDataTime() used to display System Time. First, it gets the Standard Time and stores it into variable Rawtime, and then converts it to the Local Time and stores it into timeinfo, and finally displays the Time information on the LCD1602 Display.

1void printDataTime(){//used to print system time 
2    time_t rawtime;
3    struct tm *timeinfo;
4    time(&rawtime);// get system time
5    timeinfo = localtime(&rawtime);//convert to local time
6    printf("%s \n",asctime(timeinfo));
7    lcdPosition(lcdhd,0,1);// set the LCD cursor position to (0,1) 
8    lcdPrintf(lcdhd,"Time:%02d:%02d:%02d",timeinfo->tm_hour,timeinfo->tm_min,timeinfo->tm_sec); //Display system time on LCD
9}