PIC16F1827 ブレッドボード配線４　＜I2C通信＞LCD液晶　SC1602

# キャラクター液晶SC1602ドライバー

<iframe width="560" height="315" src="https://www.youtube.com/embed/Q4TAlCLaEfY?si=KQ8k8o9sLjYyfFLO" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

前回、I2C通信が行えるように配線しました。キャラクター液晶が使えると、便利なので、配線したI2CラインにLCDを増設します。
![IMG_4947.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/da9a66ff-169d-f988-2e4a-274d9499db51.jpeg)

LCDの表　端子配列
![IMG_4949.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/ba7d3e77-406a-e95b-2f1b-2c1b54ad85a3.jpeg)


LCDの裏側。8ビットIOエキスパンダーPCF8574でLCDを制御しています。
![IMG_4948.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/80b8629f-7da3-a51a-3906-2eda76711ba1.jpeg)

LCDアダプターボード　回路図
![LCDアダプターボード回路図.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/f8b59477-37db-3014-481e-16cade8e69df.jpeg)


# SC1602液晶 with PCF8574　のコード
```C:LCDdriver.h

#ifndef LCDDRIVER_H
#define	LCDDRIVER_H

#ifdef	__cplusplus
extern "C" {
#endif

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

#define _XTAL_FREQ  16000000
    
#define I2C_b1Write I2C1_b1Write    
#define CM	0	//Command Mode
#define DM	1	//Data Mode
#define WM  0	//出力WriteMode
#define RM  1   //入力ReadMode
#define High 1
#define Low  0
#define LcdDeviceAdd 0x4E//FC-113(RCF8574 address)
#define LcdDeviceAdd_AT 0x7E//RCF8574AT address    

#define LcdDDRAMAdd_firstline 0x80
#define LcdDDRAMAdd_secondline 0xC0
#define LcdDDRAMAdd_thirdline 0x94
#define LcdDDRAMAdd_forthline 0xD4
#define LcdCmd_Clear_all 0x01
    
//LCD SC1602構造体宣言
//Optical Device _OD
typedef union {
	uint8_t byt;
	struct{
		uint8_t RS:1;//LSB
		uint8_t RW:1;
		uint8_t EN:1;
		uint8_t LED:1;
		uint8_t D4:1;
		uint8_t D5:1;
		uint8_t D6:1;
		uint8_t D7:1;//MSB
	};
}_LCDdata;


extern _LCDdata LCDdata;
extern void LCD_send( uint8_t _device_add,uint8_t _data, uint8_t _mode);
extern void LCD_WriteData(uint8_t _device_add,uint8_t data);
extern void LCD_Command(uint8_t _device_add,uint8_t cmd);
extern void LCD_Init(uint8_t _device_add);
extern void LCD_Printf(uint8_t _device_add, uint8_t *string, uint8_t _length, uint8_t _DDRAM_Add);
extern void LCD_LED_Pow(uint8_t _device_add,uint8_t _led);
 


#ifdef	__cplusplus
}
#endif

#endif	/* LCDDRIVER_H */

```
```C:LCDdriver.c

#include "LCDdriver.h"

_LCDdata LCDdata;
//-----------------------------------------//
//関数名：LCD_send
//機能：LCDコマンド、データ送信
//data: Upper or Lower 4bits data
//_mode: CM 0 :Command Mode
//		   DM 1 :Data Mode
//_device_add
//-----------------------------------------//
void LCD_send(uint8_t _device_add,uint8_t _data, uint8_t _mode)
{   
    LCDdata.byt=0x00;
    LCDdata.LED=High;//バックライト点灯
    LCDdata.byt = LCDdata.byt|(_data& 0xF0);
    I2C_b1Write(_device_add,LCDdata.byt);
    NOP();
    NOP();
    LCDdata.RS=_mode;
    I2C_b1Write(_device_add,LCDdata.byt);
    NOP();
    NOP();
    LCDdata.EN=High;
    I2C_b1Write(_device_add,LCDdata.byt);
    NOP();
    NOP();
    NOP();
    LCDdata.EN=Low;
    I2C_b1Write(_device_add,LCDdata.byt);
    __delay_us(500);    
}

//----------------------------------------------//
//関数名：LCD_WriteData
//機能：データ送信
//引数１：_device_add スレーブアドレス(8bits)
//引数２：_data 送信データ
//----------------------------------------------//
void LCD_WriteData(uint8_t _device_add,uint8_t _data)
{
    LCD_send(_device_add, _data,DM);    //下位4ビット
    LCD_send(_device_add, _data<<4,DM); //上位４ビット
    __delay_us(40);
}

//----------------------------------------------//
//関数名：LCD_Command
//機能：コマンド送信
//引数１：_device_add スレーブアドレス(8bits)
//引数２：_cmd コマンド(8bits)
//----------------------------------------------//
void LCD_Command(uint8_t _device_add,uint8_t cmd)
{
    LCD_send(_device_add,cmd,CM);
    LCD_send(_device_add,cmd<<4,CM);
    __delay_us(40);
}

//----------------------------------------------//
//関数名：LCD_Init
//機能：LCD初期化
//引数１：_device_add スレーブアドレス
//----------------------------------------------//
void LCD_Init(uint8_t _device_add)
{
    __delay_ms(15);
    LCD_send(_device_add,0x30,CM);//8bits mode
    __delay_ms(5);
    LCD_send(_device_add,0x30,CM);//8bits mode
	__delay_us(100);
	LCD_send(_device_add,0x30,CM);//8bits mode three times setting
	LCD_send(_device_add,0x20,CM);//4bits mode 
	LCD_Command(_device_add,0x28);//Function setting.
	LCD_Command(_device_add,0x08);//display off
	LCD_Command(_device_add,0x01);//display clear
	LCD_Command(_device_add,0x06);//entry
	LCD_Command(_device_add,0x02);//cursor home
	LCD_Command(_device_add,0x0C);//display on
}

//----------------------------------------------//
//関数名：LCD_Printf
//機能：文字列表示
//引数１：_device_add スレーブアドレス(8bits)
//引数２：*string 文字列先頭アドレス
//引数３：文字列長
//引数４：表示位置アドレス
//----------------------------------------------//
void LCD_Printf(uint8_t _device_add, uint8_t *string, uint8_t _length, uint8_t _DDRAM_Add)
{
    LCD_Command(_device_add,_DDRAM_Add);
    do{
        LCD_WriteData(_device_add, *string);
        string++;
    }while(--_length);
}

//------------------------------------------------//
//関数名：LCD_LED_Pow
//機能：LCDバックライト点灯
//引数１：_device_add スレーブアドレス(8bits)
//引数２：_led 0:消灯　１：点灯
//------------------------------------------------//
void LCD_LED_Pow(uint8_t _device_add,uint8_t _led)
{
    uint8_t _data=0x01;
    
    LCDdata.byt=0x00;
    LCDdata.LED=_led;
    LCDdata.byt = LCDdata.byt|(_data& 0xF0);
    I2C_b1Write(_device_add,LCDdata.byt);
    NOP();
    NOP();
    LCDdata.RS=DM;
    I2C_b1Write(_device_add,LCDdata.byt);
    NOP();
    NOP();
    LCDdata.EN=High;
    I2C_b1Write(_device_add,LCDdata.byt);
    NOP();
    NOP();
    NOP();
    LCDdata.EN=Low;
    I2C_b1Write(_device_add,LCDdata.byt);
    __delay_us(500);
    
}



```