/* LCM.h -- 定義LCD 模組要用到的函數 */
/*
V3.3/V4.2
4=P3.2=RS
5=P3.1=R/W
6=P3.0=EN
V3.3A/V4.2A
4=P3.6=RS
5=P3.5=R/W
6=P3.4=EN
#define LCDP P0	 // 定義LCM 資料匯流排接至P0

sbit RS = P3^7;	 // 暫存器選擇位元(0:指令,1:資料)
sbit RW = P3^6;	 // 設定讀寫位元 (0:寫入,1:讀取)
sbit E =  P3^5;	 // 致能位元 (0:禁能,1:致能)
#define LCDP P2	 // 定義LCM 資料匯流排接至P2
*/
//#define LCDP P2	 // 定義LCM 資料匯流排接至P2
#define LCDP P0	 // 定義LCM 資料匯流排接至P2
sbit RS = P3^2;	 // 暫存器選擇位元(0:指令,1:資料)
sbit RW = P3^1;	 // 設定讀寫位元 (0:寫入,1:讀取)
sbit E =  P3^0;	 // 致能位元 (0:禁能,1:致能)
//sbit BF = P2^7;	 // 忙碌檢查位元(0:不忙,1:忙碌)
sbit BF = P0^7;	 // 忙碌檢查位元(0:不忙,1:忙碌)
//==== 延遲函數 ================================
void delay1ms(int x)
{	int i,j;					// 宣告變數 
	for (i=1;i<x;i++)			// 執行x次,延遲X*1ms
		for (j=1;j<120;j++);	// 執行120次,延遲1ms
}								// delay1ms()函數結束 
//==== 檢查忙碌函數 ================================
void check_BF(void)
{	E=0;						// 禁止讀寫動作 
	do							// do-while迴圈開始 
	{ 	BF=1;					// 設定BF為輸入 
	  	RS = 0; RW = 1;E = 1; 	// 讀取BF及AC
	}while(BF == 1);			// 忙碌繼續等 
}								// check_BF()函數結束 
//==== 寫入指令函數 ================================
void write_inst(char inst)
{	check_BF();		      		// 檢查是否忙碌 
	LCDP = inst;				// LCM讀入MPU指令 
	RS = 0; RW = 0; E = 1;		// 寫入指令至LCM
	check_BF();		      		// 檢查是否忙碌 
}				       			// write_inst()函數結束 
//==== 寫入字元資料函數 ============================
void write_char(char chardata)
{	check_BF();					// 檢查是否忙碌 
	LCDP = chardata;			// LCM讀入字元  
	RS = 1; RW = 0 ;E = 1;		// 寫入資料至LCM
	check_BF();					// 檢查是否忙碌 
}								// write_char()函數結束 	 
//==== 寫入字串函數 ================================
void write_str(bit row,char *str,int time)
{	unsigned char i,j,addr;	  	// 宣告變數 
	addr = (row==0)? 0x80:0x90;	// 計算出字串列位址 
	write_inst(addr);		  	// 指定字串列位址 
	for(i=0;i<32;i++)		  	// 清除一整列  
		write_char(0x20);   	// 填入空白 
	write_inst(addr);		  	// 指定字串列位址 
	for(i=0;str[i] != '\0';i++) // i迴圈,寫入字串至結束 
	{	if(i>=18 && i%2==0)		// 超出顯示範圍 
			write_inst(0x18);	// 向左移1個中文字 
		write_char(str[i]);   	// 寫入字串內容	
	 	delay1ms(time);	  		// 延遲time*1ms
	}				 			// i迴圈結束	
	for(j=0;j<(i-18);j+=2)		// i迴圈,晝面移回 
	{	delay1ms(time);	  		// 延遲time*1ms
		write_inst(0x1C);		// 向右移1個中文字 
	}							// j迴圈結束	
	write_inst(0x02);			// 游標歸位  
}					  			// write_str()函數結束 
//==== 寫入圖形函數 ================================
void write_bmp()
{	int i,j;					// 宣告變數 
	write_inst(0x36);			// 設定為擴充指令 
	for(i=0;i<Height;i++)		// i迴圈,Height為圖高列數 
	{	write_inst(0x80+(31-i));// 設定GDRAM之Y軸 
		write_inst(0x80);		// 設定GDRAM之X軸 
		for(j=0;j<32;j++)		// j迴圈,圖最大32B=256b
		  if(j<Width)			// 小於圖寬之 Byte數 
		    write_char(~BMPpic[Width*i+j]); // 寫入圖形內容 			
		  else					// 超出圖寬 
		    write_char(0x00);	// 寫入空白 	
	}							// i迴圈結束 	
}								// write_bmp()函數結束 
//== 由左側刪除字串函數 =============================== 
void LDEL_str(bit row,int time)
{	unsigned char i,addr;		// 宣告變數 
	addr = (row==0)? 0x80:0x90;	// 計算出字串列位址 
	write_inst(addr);			// 指定字串寫入列起始位址 
	for(i=0;i<16;i++)			// 清除一整列(16個中文)
	{	write_char(0x20);		// 填入空白 
		write_char(0x20);		// 填入空白 
		if(i<9)					// 在顯示範圍 
		  delay1ms(time);		// 延遲時間 
	}							// for 結束 
}								// LDEL_str()函數結束 
// == 閃爍函數 == TG(0:文字,1:圖形)=======================================
void flash(bit TG,char count,int time)
{	char i;						// 宣告變數 
	for(i=0;i<count;i++)		// 閃爍3次 
	{	if(TG == 0)				// 文字介面 
			write_inst(0x08);	// 關閉顯示幕 
		else					// 圖形介面 
			write_inst(0x34);	// 關閉顯示幕 
		delay1ms(time);			// 延遲time*1ms
		if(TG == 0)				// 文字介面 
			write_inst(0x0C); 	// 開啟顯示幕 
		else					// 圖形介面 
			write_inst(0x36); 	// 開啟顯示幕 
		delay1ms(time);			// 延遲time*1ms
	}							// for迴圈結束		
}								// flash()函數結束 
// === 字串旋轉函數 ========================================
void rotate_left(int count,int time)
{	unsigned i;					// 宣告變數 
	write_inst(0x30);			// 設回為基本指令 
	for(i=0;i<count;i++)		// 向左旋轉16次 	
	{	write_inst(0x18);		// 向左旋轉1個中文字 
		delay1ms(time);			// 延遲time*1ms
	}							// i迴圈結束 
}								// rotate()函數結束 
// === 反白或還原函數==========================================
void reverse(bit row)
{ 	write_inst(0x34);			// 設定為擴充指令 
	if (row==0)					// 為第0列 
		write_inst(0x04);		// 反白或還原,第0列 
	else						// 為第1列  
		write_inst(0x05); 		// 反白或還原,第1列 
	write_inst(0x30);			// 設回為基本指令 
}								// reverse()函數結束 
//====初始設定函數(8位元傳輸模式)===================
void init_LCM(void)
{	write_inst(0x30); 			// 設定功能-8位元-基本指令 
	write_inst(0x30); 			// 設定功能-8位元-基本指令 
	write_inst(0x08); 			// 顯示功能-關顯示幕-無游標-游標不閃 
	write_inst(0x01); 			// 清除顯示幕(填0x20,I/D=1)
	write_inst(0x06); 			// 輸入模式-位址遞增-關顯示幕 
	write_inst(0x0C); 			// 顯示功能-開顯示幕-無游標-游標不閃 
}			  					// init_LCM()函數結束 
// ======= LCM.h 結束 ===============================