Description

NOTE :- The following code is written with STM32CUBEIDE. If you are using keil, or any other IDE, code will still work for you. But you have to create a project and than import those files, as shown in the video.

Today I am going to interface LCD to STM32 using an I2C device (PCF8574). PCF8574 can be used as a port extender, to which LCD will be connected. If you haven’t read my previous post about I2C go check that out HERE.

pcf8574
pcf8574

As you can see above PCF8574 has 4 input pins GND, VCC, SDA, SCLand 16 output pins. We will connect our LCD to these 16 pins.

ADDRESSING of PCF8574

The higher nibble of PCF8574 address is 0100 and this is fixed. But lower nibble can be modified according to our convenience.  The question you must be thinking is  why we need to modify lower nibble? Well you generally don’t but as I mentioned in my previous article that we can connect upto 128 devices on the same line of I2C and let’s say we want to connect two different LCDs on the same I2C line, than we can’t use two PCF8574 with same addresses and we need to modify one of them.

So how do we modify the address?

The address of the PCF8574 is 0 1 0 0 A2 A1 A0 R/W. To change the address we are provided with A0, A1 and A2 pins.
By default these three pins are high so the address by default is 01001110 which is 0x4E.  
To change the address of this device, you have to connect any/all of these three pins to ground, which is provided just above them.
So let’s say you connected A0 to ground, new address will be 01001100 which is 0x4C.
In this manner, we can connect upto 8 LCDs to the same line.
I want to point to one more thing here, the last bit of the address is kept 0 intentionally, because this bit is responsible for read(1)/ write(0) operation.

Connecting LCD to PCF8574

As shown in the figure above, first pin of the device is Vss which is pin 1 of LCD. So all you have to do is connect first pins of the LCD to Vss above and rest will connect accordingly.   Starting with Vss as first pin, connection is as follows:-

pcf connection to lcd
pcf connection to lcd

 Connections

1     —>   Vss
2     —>   Vcc
3     —>   Vee
4     —>   RS      —> p0
5     —>   R/W   —> p1
6     —>   En      —> p2
7     —>   DB0
8     —>   DB1
9     —>   DB2
10   —>   DB3
11   —>   DB4    —> p4
12   —>   DB5    —> p5
13   —>   DB6    —> p6
14   —>   DB7    —> p7
15   —>   LED+
16   —>   LED-

connection LCD
connection LCD

Some Insight into the Code:-

#define SLAVE_ADDRESS_LCD 0x4E // change this according to ur setup

The default slave address defined in the i2c-lcd.c is 0x4E. This is default for the PCF8574.


void lcd_send_cmd (char cmd)
{
  char data_u, data_l;
	uint8_t data_t[4];
	data_u = (cmd&0xf0);
	data_l = ((cmd<<4)&0xf0);
	data_t[0] = data_u|0x0C;  //en=1, rs=0
	data_t[1] = data_u|0x08;  //en=0, rs=0
	data_t[2] = data_l|0x0C;  //en=1, rs=0
	data_t[3] = data_l|0x08;  //en=0, rs=0
	HAL_I2C_Master_Transmit (&hi2c1, SLAVE_ADDRESS_LCD,(uint8_t *) data_t, 4, 100);
}

The above function will send the command to the device to which our LCD is connected. As we are using 4 bit LCD mode, we have to send command in two parts. First we send the upper nibble, and than the lower one. Both parts are sent along enable pin 1 and than with enable pin 0.

When the data_t is OR(|) with 0x0C, which implies that P2 (En) pin is high and P0 (RS), P1(R/W) are low for the command and write operation. In the second case data is sent along with 0x08 only. This is to ensure that the back light is on and En, RS, R/W are all low.


void lcd_send_data (char data)
{
	char data_u, data_l;
	uint8_t data_t[4];
	data_u = (data&0xf0);
	data_l = ((data<<4)&0xf0);
	data_t[0] = data_u|0x0D;  //en=1, rs=1
	data_t[1] = data_u|0x09;  //en=0, rs=1
	data_t[2] = data_l|0x0D;  //en=1, rs=1
	data_t[3] = data_l|0x09;  //en=0, rs=1
	HAL_I2C_Master_Transmit (&hi2c1, SLAVE_ADDRESS_LCD,(uint8_t *) data_t, 4, 100);
}

The above functions ends the data to the device to which our LCD is connected. Similarly like command, We have to send data in two parts, first upper and than lower half. Both parts are sent along enable pin 1 and than with enable pin 0. Data is OR(|) with 0x0D which implies that P2 (En) and P0 (RS) pin are high , P1(R/W) is low and back light is on, for the data and write operation. In second case data is OR(|) with 0x09 to make only RS pin high and for the back light, and all others low.  


As according to the datasheet of the LCD 16×2, in order to initialize the LCD, we have to use some sequence of commands. The code is commented properly, so that you can understand it better

void lcd_init (void)
{
	// 4 bit initialisation
	HAL_Delay(50);  // wait for >40ms
	lcd_send_cmd (0x30);
	HAL_Delay(5);  // wait for >4.1ms
	lcd_send_cmd (0x30);
	HAL_Delay(1);  // wait for >100us
	lcd_send_cmd (0x30);
	HAL_Delay(10);
	lcd_send_cmd (0x20);  // 4bit mode
	HAL_Delay(10);

  // dislay initialisation
	lcd_send_cmd (0x28); // Function set --> DL=0 (4 bit mode), N = 1 (2 line display) F = 0 (5x8 characters)
	HAL_Delay(1);
	lcd_send_cmd (0x08); //Display on/off control --> D=0,C=0, B=0  ---> display off
	HAL_Delay(1);
	lcd_send_cmd (0x01);  // clear display
	HAL_Delay(1);
	HAL_Delay(1);
	lcd_send_cmd (0x06); //Entry mode set --> I/D = 1 (increment cursor) & S = 0 (no shift)
	HAL_Delay(1);
	lcd_send_cmd (0x0C); //Display on/off control --> D = 1, C and B = 0. (Cursor and blink, last two bits)
}

To send string directly, there is another function as shown below

void lcd_send_string (char *str)
{
	while (*str) lcd_send_data (*str++);
}


YOU CAN DOWNLOAD FULL CODE AT THE END OF THIS POST

Result

Result_lcd
Result_lcd
Check out the VIDEO Below

100%
100%

DOWNLOAD

You can buy me a coffee sensor 🙂

download the CODE below

4.5 2 votes
Article Rating
Subscribe
Notify of
guest
82 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
Menu
82
0
Would love your thoughts, please comment.x
()
x