LoginSignup
0
0

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

Last updated at Posted at 2024-05-27

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

IMG_4734.JPG

Code

I2Cクロック速度100kHzで初期化、そのあとで、400KHzにスピードアップ。

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 */

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とに分けて、2回送信
*/
#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とに分けて、2回送信
*/
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とに分けて、2回送信
*/
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とに分けて、2回送信
*/
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);
}

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 */

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セットで1になる。
    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セットで1になる。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
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0