PIC18F27Q43 I2Cキャラクタ液晶 ドライバー

# キャラクタLCD SC1602ドライバー

![IMG_4734.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/4ceb5c6b-dd81-03a5-c377-9436d7a1f872.jpeg)

# Code
:::note warn
I2Cクロック速度100kHzで初期化、そのあとで、400KHzにスピードアップ。
:::
```C:I2C_LCD.h

#ifndef LCDDRIVER_H
#define	LCDDRIVER_H

#ifdef	__cplusplus
extern "C" {
#endif

#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include "Q_peripheral27Q43.h"

    
#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 LED_ON 1
#define LED_OFF 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
    
extern uint8_t LCD_BackLight_EN[2];
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
	};
}OD;

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);
  
extern uint8_t LcdTextBuf[30];
#ifdef	__cplusplus
}
#endif

#endif	/* LCDDRIVER_H */

```

```C:I2C_LCD.c
#include "Q_I2C1.h"
#include "I2C_LCD.h"

uint8_t LCD_BackLight_EN[2];
uint8_t LcdTextBuf[30];
/**
* @fn LCD_send(uint8_t _device_add, uint8_t _data, uint8_t _mode)
* @brief データ、コマンド送信、バックライト
* @param[in] _device_add:I2Cクライアントアドレス
* @param[in] _data:送信データ
* @param[in] _mode:CommandMode:0 DataMode:1
* @return なし
* @details 4bitとに分けて、２回送信
*/
#define LCD_WAIT_US 300
#define LCD_WAIT_US1 300
void LCD_send(uint8_t _device_add,uint8_t _data, uint8_t _mode)
{   
    OD.byt=0x00;
    
    if(_device_add==LcdDeviceAdd_AT)
          OD.LED=LCD_BackLight_EN[0];
    else
          OD.LED=LCD_BackLight_EN[1];
    OD.byt = OD.byt|(_data& 0xF0);
    I2C1_b1Write(_device_add,OD.byt);
    __delay_us(LCD_WAIT_US);
    OD.RS=_mode;
    I2C1_b1Write(_device_add,OD.byt);
    __delay_us(LCD_WAIT_US);
    OD.EN=High;
    I2C1_b1Write(_device_add,OD.byt);
   __delay_us(LCD_WAIT_US);
    OD.EN=Low;
    I2C1_b1Write(_device_add,OD.byt);
    __delay_us(LCD_WAIT_US1);
    
}

/**
* @fn LCD_WriteData(uint8_t _device_add, uint8_t _data)
* @brief LCDにデータを送信
* @param[in] _device_add:I2Cクライアントアドレス
* @param[in] _data:送信データ
* @return なし
* @details 4bitとに分けて、２回送信
*/
void LCD_WriteData(uint8_t _device_add,uint8_t _data)
{
    LCD_send(_device_add, _data,DM);
    LCD_send(_device_add, _data<<4,DM);
    __delay_us(40);
}

/**
* @fn LCD_Command(uint8_t _device_add, uint8_t cmd)
* @brief LCDにCommandを送信
* @param[in] _device_add:I2Cクライアントアドレス
* @param[out] cmd:コマンド
* @return なし
* @details 4bitとに分けて、２回送信
*/
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);
}

/**
* @fn LCD_Init(uint8_t _device_add)
* @brief LCDにデータを送信
* @param[in] _device_add:I2Cクライアントアドレス
* @return なし
* @details 4bitとに分けて、２回送信
*/
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_BackLight_EN[0]=LED_ON;
    LCD_BackLight_EN[1]=LED_ON;
    
}

/**
* @fn LCD_Printf(uint8_t _device_add, uint8_t *string, uint8_t _length, uint8_t _DDRAM_Add)
* @brief LCDに文字列を送信
* @param　_device_add:I2Cクライアントアドレス
 * @param *string:文字配列先頭アドレス
 * @param _length:文字数
 * @param _DDRAM_Add:DDRAMアドレス
* @return なし
* @details sprintfと併用する。
*/
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);
}

/**
* @fn LCD_LED_Pow(uint8_t _device_add)
* @brief LCDバックライト
* @param　_device_add:I2Cクライアントアドレス
* @return なし
* @details 
*/
void LCD_LED_Pow(uint8_t _device_add)
{
    uint8_t cmd=0x80;
    cmd|=0x08;
    LCD_send(_device_add,cmd,CM);
    LCD_send(_device_add,cmd<<4,CM);
    __delay_us(40);
}

```

```C:Q_I2C1.h
#ifndef Q_I2C1_H
#define	Q_I2C1_H
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include "Q_peripheral27Q43.h"

extern void I2C1_Init(void);
extern bool I2C1_b1Write(uint8_t _deviceAdd, uint8_t _data1);
extern uint8_t I2C1_b2Write(uint8_t _deviceAdd, uint8_t _data1, uint8_t _data2);
extern uint8_t I2C1_b1Read(uint8_t _deviceAdd,uint8_t _address);
#ifdef	__cplusplus
extern "C" {
#endif

#ifdef	__cplusplus
}
#endif

#endif	/* Q_I2C1_H */

```

```C:Q_I2C1.c
#include <pic18f27q43.h>

#include "Q_I2C1.h"

uint8_t i2c1Cnt;
//*************************************************//
//** I2C1初期化
//*************************************************//
void I2C1_Init(void)
{
     //Set Clear Buffer Flag
    I2C1STAT1bits.CLRBF = 1;//I2Cバッファ、RXBF、TXBEビットクリア
    I2C1CON0bits.MODE=0b100;//Host mode, 7bits address
    I2C1CON1bits.ACKCNT=1;  //最終ACK確認で返す値0:ACK 1:NACK
    I2C1CON2bits.ABD=0;     //I2C1ADB0をアドレスバッファとして使用
    I2C1CON2bits.BFRET=0b00;//8clocksスタートになる準備ﾊﾟﾙｽ数
    I2C1CON2bits.FME=1;     //
    I2C1CLK=0b0011;         //MFINTOSC500kHz//I2C用クロックソース
    //I2C1CLK = 0b00100;    //Clock Reference Output//I2C用クロックソース400KHz
    I2C1PIR=0x00;           //I2C1専用割り込みフラグのクリア
    I2C1CON0bits.EN=1;      //I2C1モジュール有効
}



//*************************************************//
//** I2C1 1バイト送信
//*************************************************//
bool I2C1_b1Write(uint8_t _deviceAdd, uint8_t _data1)
{
    I2C1ADB1 = _deviceAdd;       //ｱﾄﾞﾚｽﾊﾞｯﾌｧにClientアドレスをセット
    I2C1CNT=1;                   //送信データ数をセット
    I2C1TXB=_data1;              //送信データを1バイトだけ、前もってセット
    I2C1CON0bits.S=1;            //Startコンディション
    while(!I2C1STAT0bits.BFRE);  //I2Cバスが解放されているか？
    while(!I2C1STAT1bits.TXBE);  //送信バッファが空か？（セットしたデータの送信完了）
    while(I2C1PIRbits.PC1IF==0); //Stopコンディションになったか？
    I2C1PIRbits.PC1IF=0;         //Stopフラグクリア
    while(I2C1STAT0bits.MMA);    //Host mode active を見て終了確認 0:not active 1:active
    //Set Clear Buffer Flag
    I2C1STAT1bits.CLRBF = 1;     //I2Cバッファ、RXBF,TXBEのクリア
    return true;
}

//*************************************************//
//** I2C1 2バイト送信
//*************************************************//
uint8_t I2C1_b2Write(uint8_t _deviceAdd, uint8_t _data1, uint8_t _data2)
{
    I2C1ADB1 = _deviceAdd;  //Clientデバイスアドレスセット
    I2C1CNT=2;              //送信データ数
    I2C1TXB=_data1;         //送信バッファに最初のデータをセット
    I2C1CON0bits.S=1;       //スタートコンディションセット
    
    while(!I2C1STAT0bits.BFRE)      //I2Cバスが解放されているか？
    {};
    while(I2C1STAT1bits.TXBE!=1)
    {};                             //最初のデータ送信完了？
    //while(!I2C1CON1bits.ACKSTAT);
    I2C1TXB=_data2;                 //次の送信データをセット
    while(I2C1STAT1bits.TXBE!=1);   //送信完了？
    while(I2C1PIRbits.PC1IF==0);    //ストップコンディション確定？
    I2C1PIRbits.PC1IF=0;            //ストップフラグクリア
    while(I2C1STAT0bits.MMA);       //Host mode Active確認 0:not Active 1:active
    //Set Clear Buffer Flag         
    I2C1STAT1bits.CLRBF = 1;        //I2C1バッファ、TXBE,RXBFクリア
    return true;
}

//*************************************************//
//** I2C1 1バイト受信
//*************************************************//
#if 0
uint8_t I2C1_b1Read(uint8_t _deviceAdd,uint8_t _address)
{
    uint8_t ret;
    I2C1ADB1 = _deviceAdd;          //Clientアドレスセット
    I2C1CNT=1;                      //送信バイト数(この場合は、引数の_address)
    I2C1TXB=_address;               //送信バイトセット
    I2C1CON0bits.S=1;               //Startコンディションセット
    while(!I2C1STAT0bits.BFRE);     //I2Cバス解放？確認
    while(I2C1STAT1bits.TXBE!=1);   //送信バッファ 0:full 1:empty 送信完了確認
    //リスタート
    I2C1CON0bits.RSEN=1;            //リスタート開始
    while(!I2C1CON0bits.MDR);       //RSENセットで１になる。
    I2C1CON0bits.S=1;               //Startコンディションセット
    I2C1ADB1 = _deviceAdd|0x01;     //Clientｱﾄﾞﾚｽ＋R/Wビット
    I2C1CON1bits.ACKCNT=1;          //I2C1CNT==0でNack返信
    I2C1CNT=1;                      //読み出し数
    while(!I2C1STAT1bits.RXBF);     //読み込み完了待ち
    ret=I2C1RXB;                    //バッファから読み出し
    I2C1CON0bits.RSEN=0;            //リスタート解除
    I2C1PIR=0x00;                   //PIRクリア
    while(I2C1STAT0bits.MMA);       //HostmodeActime 0:not Active 1:active
    //Set Clear Buffer Flag
    I2C1STAT1bits.CLRBF = 1;        //I2C1バッファクリア
    return ret;
}
#else
uint8_t I2C1_b1Read(uint8_t _deviceAdd,uint8_t _address)
{
    uint8_t ret;
    I2C1ADB1 = _deviceAdd;          //Clientアドレスセット
    I2C1CNT=1;                      //送信バイト数(この場合は、引数の_address)
    I2C1TXB=_address;               //送信バイトセット
    I2C1CON0bits.S=1;               //Startコンディションセット
    while(!I2C1STAT0bits.BFRE);     //I2Cバス解放？確認
    while(I2C1STAT1bits.TXBE!=1);   //送信バッファ 0:full 1:empty 送信完了確認
    //リスタート
    I2C1CON0bits.RSEN=1;            //リスタート開始(I2C1CNT==0の時)
    while(!I2C1CON0bits.MDR);       //RSENセットで１になる。SCL:Hold
    I2C1ADB1 = _deviceAdd|0x01;     //Clientｱﾄﾞﾚｽ＋R/Wビット
    I2C1CON1bits.ACKCNT=1;          //I2C1CNT==0でNack返信
    I2C1CNT=1;                      //読み出し数  
    I2C1CON0bits.S=1;               //Startコンディションセット
    while(I2C1CON0bits.MDR);
    while(!I2C1STAT1bits.RXBF);     //読み込み完了待ち
    ret=I2C1RXB;                    //バッファから読み出し
    I2C1CON0bits.RSEN=0;            //リスタート解除
    I2C1PIR=0x00;                   //PIRクリア
    while(I2C1STAT0bits.MMA);       //HostmodeActime 0:not Active 1:active
    //Set Clear Buffer Flag
    I2C1STAT1bits.CLRBF = 1;        //I2C1バッファクリア
    return ret;
}

#endif
```