MS51FB9AE – LCD 16×02 với module I2C

Tiếp tục bài viết về I2C hôm nay mình thực hiện ví dụ giao tiếp với LCD 1602 thông qua module I2C PCF8574.
Module I2C PCF8574 là module mở rộng chân IO, giúp cho việc giao tiếp với LCD1602 chỉ cần sử dụng 2 chân IO.
Datasheet của PCF8574:
https://drive.google.com/open?id=1bIFQ9zWs-Y60Jpt8SmvqlMB-CGydswMZ
Datasheet của IC dùng trong LCD1602: HD44780:
https://drive.google.com/open?id=14U6rp7oax6jRMp3Pj9qIAQ-tNK-HuxyP

Mình sẽ sử dụng lại hàm tạo delay ở bài viết này:
http://vidieukhien.org/ms51fb9ae-mot-so-ham-tao-delay.html
Giao tiếp I2C ở bài viết này:
http://vidieukhien.org/ms51fb9ae-i2c.html

Thư viện i2c_lcd

i2c_lcd.h

#ifndef I2C_LCD_H_
#define I2C_LCD_H_

#include "ms51.h"
#include "i2c.h"
#include "delay.h"
#include <stdint.h>

#define I2C_LCD_ADDR 0x4E

#define I2C_LCD_Delay_Ms(u16DelayMs) Delay_Ms(u16DelayMs)

#define LCD_EN 2
#define LCD_RW 1
#define LCD_RS 0
#define LCD_D4 4
#define LCD_D5 5
#define LCD_D6 6
#define LCD_D7 7
#define LCD_BL 3

void I2C_LCD_Init(void);
void I2C_LCD_Puts(char *szStr);
void I2C_LCD_Clear(void);
void I2C_LCD_NewLine(void);
void I2C_LCD_BackLight(uint8_t u8BackLight);

#endif

i2c_lcd.c

#include "ms51.h"
#include "i2c.h"
#include "i2c_lcd.h"

static uint8_t u8LCD_Buff[8];//bo nho dem luu lai toan bo
static uint8_t u8LcdTmp;

#define	MODE_4_BIT		0x28
#define	CLR_SCR			0x01
#define	DISP_ON			0x0C
#define	CURSOR_ON		0x0E
#define	CURSOR_HOME		0x80

static void I2C_LCD_Write_4bit(uint8_t u8Data);
static void I2C_LCD_FlushVal(void);
static void I2C_LCD_WriteCmd(uint8_t u8Cmd);

void I2C_LCD_FlushVal(void)
{
	uint8_t i;
	
	for (i = 0; i < 8; ++i) {
		u8LcdTmp >>= 1;
		if(u8LCD_Buff[i]) {
			u8LcdTmp |= 0x80;
		}
	}
	I2C_Write(I2C_LCD_ADDR, &u8LcdTmp, 1);
}

void I2C_LCD_Init(void)
{
	uint8_t i;
	
	I2C_LCD_Delay_Ms(50);
	
	I2C_Init();
	
	for (i = 0; i < 8; ++i) {
		u8LCD_Buff[i] = 0;
	}
	
	I2C_LCD_FlushVal();
	
	u8LCD_Buff[LCD_RS] = 0;
	I2C_LCD_FlushVal();
	
	u8LCD_Buff[LCD_RW] = 0;
	I2C_LCD_FlushVal();
	
	I2C_LCD_Write_4bit(0x03);
	I2C_LCD_Delay_Ms(5);
	
	I2C_LCD_Write_4bit(0x03);
	I2C_LCD_Delay_Ms(1);
	
	I2C_LCD_Write_4bit(0x03);
	I2C_LCD_Delay_Ms(1);
	
	I2C_LCD_Write_4bit(MODE_4_BIT >> 4);
	I2C_LCD_Delay_Ms(1);
	
	I2C_LCD_WriteCmd(MODE_4_BIT);
	I2C_LCD_WriteCmd(DISP_ON);
	I2C_LCD_WriteCmd(CURSOR_ON);
	I2C_LCD_WriteCmd(CLR_SCR);
}

void I2C_LCD_Write_4bit(uint8_t u8Data)
{
	//4 bit can ghi chinh la 4 5 6 7
	//dau tien gan LCD_E=1
	//ghi du lieu
	//sau do gan LCD_E=0

	if(u8Data & 0x08) {
		u8LCD_Buff[LCD_D7] = 1;
	} else {
		u8LCD_Buff[LCD_D7] = 0;
	}
	if(u8Data & 0x04) {
		u8LCD_Buff[LCD_D6] = 1;
	} else {
		u8LCD_Buff[LCD_D6] = 0;
	}
	if(u8Data & 0x02) {
		u8LCD_Buff[LCD_D5] = 1;
	} else {
		u8LCD_Buff[LCD_D5] = 0;
	}
	if(u8Data & 0x01) {
		u8LCD_Buff[LCD_D4] = 1;
	} else {
		u8LCD_Buff[LCD_D4] = 0;
	}
	
	u8LCD_Buff[LCD_EN] = 1;
	I2C_LCD_FlushVal();	
	
	u8LCD_Buff[LCD_EN] = 0;
	I2C_LCD_FlushVal();
	
}

void LCD_WaitBusy(void)
{
	char temp;
	
	//dau tien ghi tat ca 4 bit thap bang 1
	u8LCD_Buff[LCD_D4] = 1;
	u8LCD_Buff[LCD_D5] = 1;
	u8LCD_Buff[LCD_D6] = 1;
	u8LCD_Buff[LCD_D7] = 1;
	I2C_LCD_FlushVal();
	
	u8LCD_Buff[LCD_RS] = 0;
	I2C_LCD_FlushVal();
	
	u8LCD_Buff[LCD_RW] = 1;
	I2C_LCD_FlushVal();
	
	do {
		u8LCD_Buff[LCD_EN] = 1;
		I2C_LCD_FlushVal();
		I2C_Read(I2C_LCD_ADDR + 1, &temp, 1);
		
		u8LCD_Buff[LCD_EN] = 0;
		I2C_LCD_FlushVal();
		u8LCD_Buff[LCD_EN] = 1;
		I2C_LCD_FlushVal();
		u8LCD_Buff[LCD_EN] = 0;
		I2C_LCD_FlushVal();
	} while (temp & 0x08);
}

void I2C_LCD_WriteCmd(uint8_t u8Cmd)
{
	
	LCD_WaitBusy();

	u8LCD_Buff[LCD_RS] = 0;
	I2C_LCD_FlushVal();
	
	u8LCD_Buff[LCD_RW] = 0;
	I2C_LCD_FlushVal();
	
	I2C_LCD_Write_4bit(u8Cmd >> 4);
	I2C_LCD_Write_4bit(u8Cmd);
}

void LCD_Write_Chr(char chr)
{
	
	LCD_WaitBusy();
	u8LCD_Buff[LCD_RS] = 1;
	I2C_LCD_FlushVal();
	u8LCD_Buff[LCD_RW] = 0;
	I2C_LCD_FlushVal();
	I2C_LCD_Write_4bit(chr >> 4);
	I2C_LCD_Write_4bit(chr);
	
}

void I2C_LCD_Puts(char *sz)
{
	
	while (1) {
		if (*sz) {
			LCD_Write_Chr(*sz++);
		} else {
			break;
		}
	}
}

void I2C_LCD_Clear(void)
{
	
	I2C_LCD_WriteCmd(CLR_SCR);
}

void I2C_LCD_NewLine(void)
{
	
	I2C_LCD_WriteCmd(0xc0);
}

void I2C_LCD_BackLight(uint8_t u8BackLight)
{
	
	if(u8BackLight) {
		u8LCD_Buff[LCD_BL] = 1;
	} else {
		u8LCD_Buff[LCD_BL] = 0;
	}
	I2C_LCD_FlushVal();
}

Code ví dụ

main.c

/* main.c */
#include "ms51.h"
#include "i2c.h"
#include "i2c_lcd.h"
#include "delay.h"

void main(void)
{
	uint8_t test = 0;
	
	Delay_Init();
	P1M1 &= ~(1 << 5);
    P1M2 |= (1 << 5);
	P15 = 0;
	
	I2C_LCD_Init();
	I2C_LCD_Clear();
	I2C_LCD_BackLight(1);
	
	while (1) {
		if (test) {
			test = 0;
			I2C_LCD_Clear();
			I2C_LCD_Puts("MS51FB9AE");
			I2C_LCD_NewLine();
			I2C_LCD_Puts("LCD I2C Test");
			P15 = 0;
		} else {
			test = 1;
			I2C_LCD_Clear();
			I2C_LCD_Puts("Ngo Hung Cuong");
			I2C_LCD_NewLine();
			I2C_LCD_Puts("LCD I2C Library");
			P15 = 1;
		}
		Delay_Ms(2000);
	}
}

Project:
https://drive.google.com/open?id=1qut7aMbIom4WfAS5tJTaR49Lt9PA1E-V