/* LCD.c LCD 中文顯示器 */
#include <reg51.h> 			// 載入暫存器之標頭檔 
#define	 crystal 12				// 定義石英晶體的頻率  
#include "display.h"			// 載入所要顯示之字串及圖形 
#include "LCM.h"	 			// 載入LCD模組函數 
#include "Sound.h"	 			// 載入發聲函數 
// 掃瞄輸出埠(高位元)及鍵盤輸入埠(低位元)
void scanner(void);			// 掃瞄函數開始 
unsigned char kcode;			// 宣告變數(kcode:按鍵碼)
#define	 KEYP		P2	
#define  End		0			// 0 鍵   
#define  Yes		10			// A 鍵   
#define  No  		11			// B 鍵   
#define  Stop 		12			// C 鍵   
#define  Pause 		13			// D 鍵   
#define  Reverse 	14			// E 鍵   
#define  Forward 	15			// F 鍵   
// 步進馬達相關宣告  
#define  motor		P1			// 步進馬達連接 P1^0~P1^3
#define  T_step	50000		//步進時間 50ms*4=0.2s
char step_H,step_L,counts=0,s=0;// s:旋轉指標  
char steps[4]={1,2,4,8};		// 步進馬達驅動信號  
bit  DIR;					// 步進馬達旋選方向旗標   
// 按鍵與密碼相關宣告  
char ID[8]={1,2,3,4,5,6,7,8};// 原始密碼  
// ====== 主程式 =========================================
void main(void)
{	int i;						// 宣告變數 
	char TMP[8]={0,0,0,0,0,0,0,0};// 密碼操作暫存器  
	bit pass,change,PFlag,FFlag,RFlag;
	init_LCM();				// LCM 初始化 
	IE=0x8a;					// 開啟Timer 0/1中斷
	TMOD=0x11;				
	// 設定Timer 0/1為MODE 1(16 bit Timer)
	IP=0x08;					// Timer 1 優先  
	TH1=step_H=(65536-T_step)/256; //設定步進中斷時間  
	TL1=step_L=(65536-T_step)%256; //設定步進中斷時間   
	motor=0; 					// 步進馬達斷磁  
	while(1)					// 無盡迴圈 
	{	// 載入起始圖, 演奏望春風       
again0:	clearROW(0);			// 清空LCD之第0列    
		clearROW(1);			// 清空LCD之第1列    
		write_bmp(Startpic);	// 載入圖形 
		play(song0,beat0);		// 播放望春風  
		flash(1,3,200);		// 圖形,閃爍3次,延遲200ms
		rotate_left(16,200);	// 向左旋轉,延遲200ms
		delay1ms(3000);		// 延遲3s
		beep(2);				// 嗶兩聲  
		// 展示標題文字   
		reverse(0);			// LCD之第0列反白 
		// mes[0]=一例就go－專題製作  
		write_str(0,mes[0],100);// LCD之第0列,寫入字串,延遲200ms
		reverse(0);			// LCD之第0列還原 
		reverse(1);			// LCD之第1列反白 
		// mes[1]=中文-LCD顯示器應用   
		write_str(1,mes[1],100);// LCD之第1列,寫入字串,延遲200ms
		reverse(1);			// LCD之第1列還原 
		flash(0,3,200);		// 文字,閃爍3次,延遲200ms
		delay1ms(1000);		// 延遲1s
		rotate_left(16,400);	// 向左旋轉,16字,延遲400ms
		LDEL_str(0,50);		// LCD之第0列,左側逐字消去 	  
		LDEL_str(1,50);		// LCD之第1列,左側逐字消去 
		// 輸入密碼  
		// mes[2]=請輸入密碼(8碼):  
		write_str(0,mes[2],200);// LCD之第2列,寫入字串,延遲200ms
again1:	clearROW(1);			// 清空LCD第1列   
		write_inst(0x90);		// 移至第1列開始  
		beep(1);				// 嗶一聲  
		kcode=20;				// 預設kcode值   
		while(kcode!=Yes)		// 若非鍵入 A 鍵 
		{	kcode=20;			// 預設kcode值 
			scanner();			// 掃瞄按鍵  
			if(kcode>=0 && kcode<=9)// 若是 0-9 數字鍵 
			{	beep(1);		// 嗶一聲 
				// 在LCD上顯示所鍵入之數字 
				write_char(kcode+0x30);	 

				for(i=0;i<8;i++)
					TMP[i]=TMP[i+1];// 密碼暫存器移位  
				TMP[7]=kcode;	// 鍵值填入密碼暫存器 
			}
			else if (kcode!=20)// 輸入錯誤   
				beep(2);		// 非 0-9, 嗶兩聲  
			delay1ms(200);	  	// 延遲200*1ms
		}
		// 檢查密碼  
		pass=1;					// 預設 pass 旗標為1 
		for(i=0;i<8;i++)
			if(ID[i]!=TMP[i]) pass=0;
			//若密碼不符, 則取消pass旗標(pass=0)
		if (!pass)  			// 若密碼不符  
		{	clearROW(1);		// 清空LCD第1列  
			// mes[3]=密碼錯誤! 請重新輸入(3次)   
			write_str(0,mes[3],200);
			if(++counts==3) 
			{	counts=0;
				goto again0;	// 從頭開始  
			}
			else goto again1;  // 重新輸入密碼   
		}
		counts=0;
//====== 詢問是否更改密碼? ==============
		clearROW(0);			// 清空LCD第0列  
		clearROW(1);			// 清空LCD第1列  
		// mes[4]=需要更改密碼嗎？  
		write_str(0,mes[4],200);	
		// mes[5]=需要請按A,不要按B     
		write_str(1,mes[5],200);	
		kcode=0;pass=0;change=0;// 鍵值與旗標歸零   
		while(!pass)			// 若 pass=0
		{	scanner();			// 掃瞄按鍵  
			if(kcode==Yes) 		// 若按 A 鍵   
			{	change=1;		// 設定 change 旗標  
				pass=1;			// 設定 pass 旗標  
				beep(1);		// 嗶一聲 
			}
			else if(kcode==No)	// 若按 B 鍵   
			{	change=0;		// 解除 change 旗標  
				pass=1;			// 設定 pass 旗標  
				beep(1);		// 嗶一聲 
			}
		}
//====== 更改密碼 ==========================================
		if (change)	   			// 若 change=1  
		{	clearROW(0);		// 清空LCD第1列  
			clearROW(1);		// 清空LCD第2列  
			// mes[6]=更改密碼(8碼):   
			write_str(0,mes[6],200);
			write_inst(0x90);	// 移至LCD第1列開頭   
			for(i=0;i<8;i++) TMP[i]=0;// 清空密碼暫存器  
			kcode=20;			// 預設 kcode=20
			while(kcode!=Yes)	// 若非 A 鍵  
			{	kcode=20;		// 預設 kcode=20
				scanner();		// 掃瞄按鍵  
				if(kcode>=0 && kcode<=9)// 若是 0-9 數字鍵 
				{	beep(1);	// 嗶一聲 
					// 在LCD上顯示所鍵入之數字 
					write_char(kcode+0x30);	
					for(i=0;i<8;i++)
						TMP[i]=TMP[i+1];// 密碼暫存器移位  
					TMP[7]=kcode;// 鍵值填入密碼暫存器 
				}
				else if (kcode!=20)
					beep(2);	// 非 0-9 , 嗶兩聲  
		 		delay1ms(200);	// 延遲200*1ms
			}
			for(i=0;i<8;i++) ID[i]=TMP[i];// 設定新密碼  
			change=0;			// change 旗標歸零   
		}
//====== 生日快樂 =========================================
		clearROW(0);			// 清空LCD第0列  
		clearROW(1);			// 清空LCD第1列  
		write_bmp(Happy);		// 載入圖形 
		play(song1,beat1);		// 播放生日快樂歌  
		delay1ms(500);	  		// 延遲500*1ms
		clear_bmp();			// 清除圖形 
//====== 步進馬達 =========================================
		// mes[7]=F:正轉  E:反轉  D:停止  C:重新    
		write_str(0,mes[7],200);// 寫入LCD第0列  
		write_inst(0x90);	 	// 移至LCD第1列開頭   
		beep(2);				// 嗶兩聲 
		kcode=20;				// 預設 kcode=20
		i=0;PFlag=FFlag=RFlag=TR1=0;// 變數, 旗標歸零   
		while(kcode!=End)		// 若非停止命令    
		{	scanner();			// 掃瞄按鍵  
			if(kcode==Forward)	// 若正轉命令    
			{	if (!RFlag)	// 若沒有反轉旗標  
				{	beep(1);	// 嗶一聲 
					clearROW(1);// 清空LCD第1列  
					// 正轉中.... 
					write_str(1,mes[8],200);
					FFlag=1;	// 設定正轉旗標  
					DIR=1;		// DIR旗標設定為1(正轉)  
					TR1=1;		// 啟動計時器, 開始運轉   
				}	
				else  beep(3);	// 無法正轉, 嗶三聲        
			}
			else if(kcode==Reverse)// 若反轉命令    
			{	if (!FFlag) 	// 若沒有正轉旗標  
				{	beep(1);	// 嗶一聲 
					clearROW(1);// 清空LCD第1列  
					// 反轉中.... 
					write_str(1,mes[9],200);
					RFlag=1;	// 設定反轉旗標  
					DIR=0;		// DIR旗標設定為0(反轉)  
					TR1=1;		// 啟動計時器, 開始運轉   
				}
				else  beep(3);	// 無法反轉, 嗶三聲     
			}
			else if (kcode==Pause)// 若暫停命令    
			{	if(FFlag||RFlag)// 若有正轉旗標或反轉旗標  
				{	beep(1);	// 嗶一聲 
					if (!PFlag)// 若非暫停旗標   
					{	clearROW(1);// 清空LCD第1列  
						// 暫停   
						write_str(1,mes[10],200);
						TR1=0;	// 停止計時器, 停止運轉   
						PFlag=1;// 設定暫停旗標 
					}				
					else		// 若有暫停旗標   
					{	clearROW(1);// 清空LCD第1列  
						if(FFlag)// 若有正轉旗標  
							// 正轉中.... 
							write_str(1,mes[8],200);
						else if(RFlag)// 若有反轉旗標  
							// 反轉中.... 
							write_str(1,mes[9],200);
						TR1=1;	// 啟動計時器, 開始運轉 
						PFlag=0;// 取消暫停旗標 
					}	
				}
				else  beep(3);	// 停機中,無法暫停,嗶三聲   
			}
			else if(kcode==Stop)
			{	TR1=0;			// 停用計時器   
				FFlag=RFlag=PFlag=0;// 清除旗標    
				clearROW(1);	// 清空LCD第1列 
				motor=0;		// 斷磁 
				beep(1);		// 嗶一聲 
			}
			delay1ms(100);	  	// 延遲100*1ms
		}
		motor=0; 				// 斷磁
	}							// while結束 
}								// main()	結束 					
// ======= 掃瞄4*4鍵盤函數 ================
void scanner(void)				// 掃瞄函數開始 
{	unsigned char col,row;	// 宣告變數(col:行,row:列)
	unsigned char rowkey;		// 宣告變數(rowkey:列鍵值)
	// 鍵盤之掃瞄碼 
	unsigned char scan[4]={ 0xef, 0xdf ,0xbf ,0x7f }; 
	kcode=20; 					// kcode預設值     
	for(col=0;col<4;col++)  // for迴圈,掃瞄第col行 
	{	// 高4位輸入掃瞄信號,低4位元輸出按鍵狀態(列值)
		KEYP  = scan[3-col];
		rowkey= ~KEYP & 0x0f;
		// 讀取KEYP低4位，反相再清除高4位求出列鍵值	 
		if(rowkey != 0)						// 若有按鍵 
		{	if(rowkey == 0x01)     	row=3;	// 若第0列被按下 
			else if(rowkey == 0x02)	row=2;	// 若第1列被按下 
			else if(rowkey == 0x04)	row=1;	// 若第2列被按下 
			else if(rowkey == 0x08)	row=0;	// 若第3列被按下 
			kcode = 4 * col + row;			// 算出按鍵之號碼 
			while(rowkey != 0)				// 當按鈕未放開 	
				rowkey=~KEYP & 0x0f;		// 再讀入列鍵值 
		}							//	if敘述(有按鍵時)結束	
		delay1ms(4);				//	延遲4ms
	}								//	for迴圈結束(掃瞄col行)
}									//	掃瞄函數scanner()結束	
//==== Timer 1 中斷副程式－步進馬達驅動程式 ==================
void stepper(void) interrupt 3	
{	TH1=step_H;				// 填入時間之高八位元 
	TL1=step_L;				// 填入時間之低八位元 
	if(++counts==4)			// 中斷次數是否達到4次? 
	{	counts=0;			// 中斷次數歸零    
		motor=steps[s];		// 驅動步進馬達      
		if(++s==4) s=0;		// 若是最後一個驅動信號,則從頭開始     
	}
}
//  ===================== 程式結束=============================
