/***********************************************************

	pic18clcd.c

	Version 1.00: 2009/10/10

	Copyright (C) 2008-2009, MicroFan Div., PeopleMedia, Inc.
	All rights reserved.

***********************************************************/

#include "picsys18.h"

#if defined(USE_CLCD)

static BYTE rsPin, ePin ;
static BYTE dbPin[4] ;


/*----------------------------------------------------------
	__CLCD_outN():上位ニブルをLCDモジュールに出力
----------------------------------------------------------*/

static void
__CLCD_outN(BYTE c)
{
#if defined(OPTIMIZE)
	OPT_SEG1 = (c >> 4) & 1 ;
	OPT_SEG2 = (c >> 5) & 1 ;
	OPT_SEG3 = (c >> 6) & 1 ;
	OPT_SEG3 = (c >> 7) & 1 ;

#if defined(OPT_CLCD_CLK)
	OPT_CLCD_CLK = 1 ;
	delayMicroseconds(1) ;
	OPT_CLCD_CLK = 0 ;
#else
	OPT_SR_CLK = 1 ;
	delayMicroseconds(1) ;
	OPT_SR_CLK = 0 ;
#endif
#else
	char i ;
	
	for (i = 0; i < 4; i++)
		bitOut(dbPin[i], c & BIT(i + 4)) ;

	bitOut(ePin, HIGH) ;
	bitOut(ePin, LOW) ;
#endif
}


/*----------------------------------------------------------
	__CLCD_outB():バイトデータをLCDモジュールに出力
----------------------------------------------------------*/

static void
__CLCD_outB(BYTE c)
{
#if defined(OPTIMIZE)
	OPT_SEG1 = (c >> 4) & 1 ;
	OPT_SEG2 = (c >> 5) & 1 ;
	OPT_SEG3 = (c >> 6) & 1 ;
	OPT_SEG4 = (c >> 7) & 1 ;

#if defined(OPT_CLCD_CLK)
	OPT_CLCD_CLK = 1 ;
	delayMicroseconds(1) ;
	OPT_CLCD_CLK = 0 ;
#else
	OPT_SR_CLK = 1 ;
	delayMicroseconds(1) ;
	OPT_SR_CLK = 0 ;
#endif

	OPT_SEG1 = (c >> 0) & 1 ;
	OPT_SEG2 = (c >> 1) & 1 ;
	OPT_SEG3 = (c >> 2) & 1 ;
	OPT_SEG4 = (c >> 3) & 1 ;

#if defined(OPT_CLCD_CLK)
	OPT_CLCD_CLK = 1 ;
	delayMicroseconds(1) ;
	OPT_CLCD_CLK = 0 ;
#else
	OPT_SR_CLK = 1 ;
	delayMicroseconds(1) ;
	OPT_SR_CLK = 0 ;
#endif
	
#else
	char i ;

	for (i = 0; i < 4; i++)
		bitOut(dbPin[i], c & BIT(i + 4)) ;
	bitOut(ePin, HIGH) ;
	bitOut(ePin, LOW) ;

	for (i = 0; i < 4; i++)
		bitOut(dbPin[i], c & BIT(i)) ;
	bitOut(ePin, HIGH) ;
	bitOut(ePin, LOW) ;
#endif
}


/***********************************************************
	文字液晶の初期化関数
***********************************************************/

void
CLCD_init(BYTE rs, BYTE e, BYTE seg1, BYTE seg2, BYTE seg3, BYTE seg4)
{
	char i ;

#if defined(PICSYS18_SP)
	/* 現状では利用しないR/Wをグランドに落とす */
	pinMode(CLCD_RW, OUTPUT) ;
	digitalWrite(CLCD_RW, LOW) ;
	
	/* 7SEGなどのLEDを無効に */
	pinMode(SR_DAT, OUTPUT) ;
	pinMode(SR_CLK, OUTPUT) ;
	shiftOut(SR_DAT, SR_CLK, LSBFIRST, 0xff) ;
#endif

	rsPin = rs ;
	ePin = e ;
	dbPin[0] = seg1 ;
	dbPin[1] = seg2 ;
	dbPin[2] = seg3 ;
	dbPin[3] = seg4 ;

	pinMode(rsPin, OUTPUT) ;
	pinMode(ePin, OUTPUT) ;

	digitalWrite(ePin, LOW) ;

// データの出力ピンを出力モードに変更
	for (i = 0; i < 4; i++)
		pinMode(dbPin[i], OUTPUT) ;

	delayMilliseconds(20) ;	// LCDのパワーオンリセットの待ち時間: 15ms以上
        
// 4ビットインターフェースに設定するための初期化プロトコル
	digitalWrite(rsPin, LOW) ;	// コマンドレジスタの選択

	__CLCD_outN(CLCD_INTERFACE_8BIT) ;
	delayMilliseconds(5) ; // 4.1ms以上
	__CLCD_outN(CLCD_INTERFACE_8BIT) ;
	delayMilliseconds(1) ;
	__CLCD_outN(CLCD_INTERFACE_8BIT) ;
	delayMilliseconds(1) ;

// インターフェースを4ビットに
	__CLCD_outN(CLCD_INTERFACE_4BIT) ;
	delayMilliseconds(1) ;

// 行数とフォントの設定
	CLCD_cmd(CLCD_2LINE) ;

// ディスプレイの表示初期化
	CLCD_cmd(CLCD_DISPLAY_OFF) ;
	CLCD_cmd(CLCD_DISPLAY_ON & CLCD_CURSOR_ON & CLCD_BLINK_ON) ;

// エントリーモードの設定
	CLCD_cmd(CLCD_CURSOR_INC) ;
// 以上で初期化プロトコル終了

	CLCD_cmd(CLCD_CLEAR) ;
}

#if defined(CLCD_RS) || defined(SR_DAT)

void
CLCD_initDefault()
{
#if defined(PICSYS18_SP)
	CLCD_init(CLCD_RS, CLCD_E, SEG1, SEG2, SEG3, SEG4) ;
#else
	CLCD_init(SR_DAT, SR_CLK, SEG1, SEG2, SEG3, SEG4) ;
#endif
}

#endif


/***********************************************************
	文字液晶へのコマンド書き込み
***********************************************************/

void
CLCD_cmd(BYTE cmd)
{
	bitOut(rsPin, LOW) ;	// コマンドレジスタの選択

	__CLCD_outB(cmd) ;

	if (cmd < 0x04)	
		delayMilliseconds(2) ;	// 特定のコマンドは処理時間が長い
	else
		delayMicroseconds(50) ;
}


/***********************************************************
	データの指定文字液晶への文字出力
***********************************************************/

void
CLCD_data(BYTE data)
{
	bitOut(rsPin, HIGH) ;	// データレジスタの選択

	__CLCD_outB(data) ;

	delayMicroseconds(50) ;
}


/***********************************************************
	文字液晶のカーソル操作
***********************************************************/

void
CLCD_setCursor(unsigned char row, unsigned char line)
{
	line *= 0x40 ;
	row += line ;
		
	CLCD_cmd(CLCD_DDRAM_ADDR | row) ;
}


/***********************************************************
	文字液晶への(RAM上の)文字列出力
***********************************************************/

void
CLCD_puts(char *s)
{
	while(*s)
		CLCD_putc(*s++) ;
}


/***********************************************************
	文字液晶への(ROM上の)文字列出力
***********************************************************/

void
CLCD_putrs(const rom char *s)
{
	while(*s)
		CLCD_putc(*s++) ;
}

/***********************************************************
	文字液晶への整数値出力
***********************************************************/

void
CLCD_puti(long n)
{
	ltos(_fmtbuf, n, 10) ;
	
	CLCD_puts(_fmtbuf) ;
}

/***********************************************************
	文字液晶への実数値出力
***********************************************************/

void
CLCD_putf(float v, char n)
{
	ftos(_fmtbuf, v, n) ;
	
	CLCD_puts(_fmtbuf) ;
}

/***********************************************************
	文字液晶へのバイナリ値出力
***********************************************************/

void
CLCD_putb(long n, BYTE base)
{
	ltos(_fmtbuf, n, base) ;
	
	CLCD_puts(_fmtbuf) ;
}

#endif
