キャラクタLCD SC1602ドライバー
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