/**************************************************
Copyright (A), 2023, DALIAN QIYUN DISPLAY Co., Ltd.
Description:Test GDM0103
Others:    Interface(SPI) 	 
           VDD;3.3V   	
Driver Card IC：HT1621B
*************************************************/ 
#include<reg52.h>
#include <intrins.h>
/*AT89C52接口定义*************************************************/
sbit sda = P1^0;
sbit sck = P1^1;
sbit cs = P1^5;

/***************************************************************/
void Lcd_init(void);
void LcdDisplay_All(unsigned char ucAddrValue,ucDataValue,ucSegNum);
void LcdDisplay_Single(unsigned char ucAddrValue,ucDataValue);
void Lcd_Display(unsigned char Num_1,Num_2,Num_3,Num_4,Num_8,Num_7,Num_6,Num_5);
void SendNBitToRAM(unsigned char ucDataValue,ucBitNum);
void SendAddrToRAM(unsigned char ucAddrValue);
void delay(unsigned int ulCnt);     

	unsigned char temp;

#define LCD_MODE_CMD 0x80    						//命令ID码：100*****
#define LCD_MODE_WRITE 0xa0   					//数据ID码：101*****
#define SYS_EN 0x01    									//0000-0001-X(Turn on system oscillator) 
#define BIAS 0x29    										//0010-1001-X(BIAS 1/3，4COM)
#define LCD_DISPLAY_ON 0x03   					//0000-0011-X(Turn on LCD display)
#define LCD_SEG_NUM 9   								//屏幕SEG的数量/2

/*********************************************************************************************************************
  PIN |  21   22   1    2    |  3    4    5    6    7    8    9    10   12   13   14   15   16   17   18   19   20  |
----------------------------------------------------------------------------------------------------------------------
  SEG |  D0   D1   D2   D3   |  S0   S1   S2   S3   S4   S6   S6   S7   S8   S9   S10  S11  S12  S13  S14  S15  S16 |
--------------------------------------------------------------------------------------------------------------------|
 COM0 | COM0   						   |  1F   1A   2F   2A   3F   3A   4F   4A   8A   8F		7A   7F   6A   6F   5A   5F   CP6 |  
 COM1 |      COM1  					 |  1G   1B   2G   2B   3G   3B   4G   4B   8B   8G   7B   7G   6B   6G   5B   5G   CP5 |  
 COM2 |           COM2       |  1E   1C   2E   2C   3E   3C   4E   4C   8C   8E   7C   7E   6C   6E   5C   5E   --  |  
 COM3 |                COM3  |  1D   CP1  2D   CP2  3D   CP3  4D   CP4  --   8D   CP9  7D   CP8  6D   CP7  5D   --  |  
----------------------------------------------------------------------------------------------------------------------
  ARR |  												00        02        04        06        08        0a        0c        0e        10  | 
**********************************************************************************************************************/

/**********************显示数据*********************************/

#define Digit_0 0xbe    					//数字0
#define Digit_1 0x06    					//数字1
#define Digit_2 0x7c    					//数字2
#define Digit_3 0x5e    					//数字3
#define Digit_4 0xc6    					//数字4
#define Digit_5 0xda    					//数字5
#define Digit_6 0xfa    					//数字6
#define Digit_7 0x0e    					//数字7
#define Digit_8 0xfe    					//数字8
#define Digit_9 0xde    					//数字9

#define Dot 0x01    					  	//小数点显示

#define CP5 0x40    							//CP5
#define CP6 0x80    							//CP6


#define LcdAll_On 0xff 						//全显示
#define Off 0x00    							//关显示

/**********************地址数据*********************************/

#define Addr_Num1 0x00    			//第一位数字地址
#define Addr_Num2 0x02    			//第二位数字地址
#define Addr_Num3 0x04    			//第三位数字地址
#define Addr_Num4 0x06    			//第四位数字地址
#define Addr_Num5 0x0e    			//第四位数字地址
#define Addr_Num6 0x0c    			//第一位数字地址
#define Addr_Num7 0x0a    			//第二位数字地址
#define Addr_Num8 0x08    			//第三位数字地址

#define Addr_COL 0x10    				//冒号地址


/***************************************************************/
void main()
{
	while(1)
	{
		Lcd_init();  																					//初始化
		LcdDisplay_All(0x00,LcdAll_On,LCD_SEG_NUM);     			//全屏显示
		delay(800);	   		
		LcdDisplay_All(0x00,Off,LCD_SEG_NUM);  								//清屏
		delay(300);	
		LcdDisplay_All(0x00,LcdAll_On,LCD_SEG_NUM);     			//全屏显示
		delay(800);	   		
		LcdDisplay_All(0x00,Off,LCD_SEG_NUM);  								//清屏
		delay(300);

		temp = 0x00;
		LcdDisplay_Single(Addr_Num1,Digit_0);  								//0
		delay(300);	
		LcdDisplay_Single(Addr_Num1,Dot);  										//0.
		delay(300);						
		temp = 0x00;
		LcdDisplay_Single(Addr_Num2,Digit_1);  								//0.1
		delay(300);	
		LcdDisplay_Single(Addr_Num2,Dot);  										//0.1.
		delay(300);						
		temp = 0x00;				
		LcdDisplay_Single(Addr_Num3,Digit_0);  								//0.1.0
		delay(300);		
		LcdDisplay_Single(Addr_Num3,Dot);  										//0.1.0.
		delay(300);				
		temp = 0x00;				
		LcdDisplay_Single(Addr_Num4,Digit_3);  								//0.1.0.3
		delay(300);		
		LcdDisplay_Single(Addr_Num4,Dot);  										//0.1.0.3.
		delay(300);		
		temp = 0x00;			
		LcdDisplay_Single(Addr_COL,CP5);  										//CP5
		delay(300);
		LcdDisplay_Single(Addr_COL,CP6);  										//CP6
		delay(300);	
		temp = 0x00;
		LcdDisplay_Single(Addr_Num5,Digit_4);  								//0.1.0.3.:4
		delay(300);	
		LcdDisplay_Single(Addr_Num5,Dot);  										//0.1.0.3.:4.
		delay(300);						
		temp = 0x00;
		LcdDisplay_Single(Addr_Num6,Digit_1);  								//0.1.0.3.:4.1
		delay(300);	
		LcdDisplay_Single(Addr_Num6,Dot);  										//0.1.0.3.:4.1.
		delay(300);						
		temp = 0x00;				
		LcdDisplay_Single(Addr_Num7,Digit_2);  								//0.1.0.3.:4.1.2
		delay(300);		
		LcdDisplay_Single(Addr_Num7,Dot);  										//0.1.0.3.:4.1.2.
		delay(300);				
		temp = 0x00;				
		LcdDisplay_Single(Addr_Num8,Digit_8);  								//0.1.0.3.:4.1.2.8
		delay(1000);		

		LcdDisplay_All(0x00,Off,LCD_SEG_NUM);  		//清屏
		delay(300);

		Lcd_Display(Digit_3,Digit_7,Digit_2,Digit_6,Digit_9,Digit_1,Digit_5,Digit_0);		// 3.7.2.6.:0.5.1.9
		delay(1500);			
		
	}	
}


/**************************************************************
初始化:（参阅HT1621数据手册）
**************************************************************/
void Lcd_init(void)
{
	cs=0;																//片选，选中HT1621
	SendNBitToRAM(LCD_MODE_CMD,3);			//发送命令ID码
	SendNBitToRAM(SYS_EN,9);					  //打开系统时钟
	SendNBitToRAM(BIAS,9);						  //方式设定：4COM，1/3偏压（对应LCD屏的参数是1/4 duty，1/3 bias）
	SendNBitToRAM(LCD_DISPLAY_ON,9);		//打开LCD偏置发生器	
	cs=1;												        //释放HT1621
} 

/***************************************************************
数据传送，其中：
ucDataValue：显示数据、命令ID码和数据ID码、初始化设置命令代码；
ucBitNum：位的长度（命令ID码和数据ID码是3位，显示数据是8位和4位，初始化设置命令代码9位）；
****************************************************************/
void SendNBitToRAM(unsigned char ucDataValue,ucBitNum)
{
	unsigned char i;
	for(i=0;i<ucBitNum;i++)
	{
		if(ucDataValue&0x80)
				sda=1;
		else
				sda=0;
			sck=0;
			_nop_();
			_nop_();
			sck=1;
			_nop_();
			_nop_();
		  ucDataValue=ucDataValue<<1;				
	} 
}

/***************************************************************
地址传送
****************************************************************/
void SendAddrToRAM(unsigned char ucAddrValue)
{
	unsigned char i;
		  ucAddrValue=ucAddrValue<<2;						//地址数据只有低6位，所以要先移掉高两位
	for(i=0;i<6;i++)
	{
		if(ucAddrValue&0x80)
			sda=1;
		else
		  sda=0;
		sck=0;
		_nop_();
		_nop_();
		sck=1;
		_nop_();
		_nop_();
	  ucAddrValue=ucAddrValue<<1;	
	}
}
/***************************************************************/
void delay(unsigned int ulCnt)
{
	unsigned int i;
	while(ulCnt--)
	{
	for(i=100;i>0;i--);
	}
}
/***************************************************************/
/**************************************************************
全屏显示，其中：
ucAddrValue：地址
ucDataValue：显示数据
ucSegNum：SEG数量，屏有多少个SEG，就传送多少次显示数据
**************************************************************/
void LcdDisplay_All(unsigned char ucAddrValue,ucDataValue,ucSegNum)
{
	unsigned char i;

	cs=0;																//片选，选中HT1621
	SendNBitToRAM(LCD_MODE_WRITE,3);		//发送数据码ID
	SendAddrToRAM(ucAddrValue);					//发送地址
	for(i=0;i<ucSegNum;i++)						  //连续传送显示数据的时候，地址自动加一
	{			
		SendNBitToRAM(ucDataValue,8);			//传送显示数据
	}
	cs=1;												        //释放HT1621
}



/********************************************************************************
																						 SEG（N）  |  SEG（N+1）
		 dataID          add          dat（COM1COM2COM3COM4|COM1COM2COM3COM4）
      101        A5A4A3A2A1A0                D0D1D2D3  |  D4D5D6D7

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

/*************************单个内容显示**************************************/
/***因为数字5-8和数字1-4的高低位是反的，所以对数字5-8高低位互换***/
void LcdDisplay_Single(unsigned char ucAddrValue,ucDataValue)
{
	unsigned char flags,flag_temp;	
	
	if(ucAddrValue == Addr_Num5 ||
		 ucAddrValue == Addr_Num6 ||
	   ucAddrValue == Addr_Num7 ||
	   ucAddrValue == Addr_Num8)
		{
/****高低4位互换互换****/
			flags = ucDataValue;
			ucDataValue &= 0xf0;								//取出高4位
			flag_temp = ucDataValue;
			flag_temp = flag_temp >> 4;					//高4位移到低4位

			ucDataValue = flags;
			ucDataValue &= 0x0f;								//取出低4位
			ucDataValue = ucDataValue << 4;			//低4位移到高4位
			ucDataValue |= flag_temp;						//合并高低4位
		}
		
	cs=0;																		//片选，选中HT1621

	ucDataValue |= temp;
	
	SendNBitToRAM(LCD_MODE_WRITE,3);				//发送数据码ID
	SendAddrToRAM(ucAddrValue);							//发送地址
	SendNBitToRAM(ucDataValue,8);						//显示内容

	temp = ucDataValue;
	
	cs=1;												 					 //释放HT1621
}


/*************************全屏内容显示**************************************/
void Lcd_Display(unsigned char Num_1,Num_2,Num_3,Num_4,Num_8,Num_7,Num_6,Num_5)
{
	int COL;
	unsigned char flags,flag_temp;

	Num_1 |= Dot;
	Num_2 |= Dot;
	Num_3 |= Dot;
	Num_4 |= Dot;
	Num_5 |= Dot;
	Num_6 |= Dot;
	Num_7 |= Dot;
	COL = CP5 | CP6;

/***数字8高低4位互换***/	
	flags = Num_8;
	Num_8 &= 0xf0;											//取出高4位
	flag_temp = Num_8;
	flag_temp = flag_temp >> 4;					//高4位移到低4位

	Num_8 = flags;
	Num_8 &= 0x0f;											//取出低4位
	Num_8 = Num_8 << 4;									//低4位移到高4位
	Num_8 |= flag_temp;									//合并高低4位	
	
/***数字7高低4位互换***/	
	flags = Num_7;
	Num_7 &= 0xf0;											//取出高4位
	flag_temp = Num_7;
	flag_temp = flag_temp >> 4;					//高4位移到低4位

	Num_7 = flags;
	Num_7 &= 0x0f;											//取出低4位
	Num_7 = Num_7 << 4;									//低4位移到高4位
	Num_7 |= flag_temp;									//合并高低4位		
	
/***数字6高低4位互换***/	
	flags = Num_6;
	Num_6 &= 0xf0;											//取出高4位
	flag_temp = Num_6;
	flag_temp = flag_temp >> 4;					//高4位移到低4位

	Num_6 = flags;
	Num_6 &= 0x0f;											//取出低4位
	Num_6 = Num_6 << 4;									//低4位移到高4位
	Num_6 |= flag_temp;									//合并高低4位		
	
/***数字5高低4位互换***/	
	flags = Num_5;
	Num_5 &= 0xf0;											//取出高4位
	flag_temp = Num_5;
	flag_temp = flag_temp >> 4;					//高4位移到低4位

	Num_5 = flags;
	Num_5 &= 0x0f;											//取出低4位
	Num_5 = Num_5 << 4;									//低4位移到高4位
	Num_5 |= flag_temp;									//合并高低4位		
	
	cs=0;																	//片选，选中HT1621
	
	SendNBitToRAM(LCD_MODE_WRITE,3);			//发送数据码ID
	SendAddrToRAM(0x00);									//发送地址

	SendNBitToRAM(Num_1,8);								//第一位数字
	SendNBitToRAM(Num_2,8);								//第二位数字
	SendNBitToRAM(Num_3,8);								//第三位数字
	SendNBitToRAM(Num_4,8);								//第四位数字
	SendNBitToRAM(Num_8,8);								//第五位数字	
	SendNBitToRAM(Num_7,8);								//第一位数字
	SendNBitToRAM(Num_6,8);								//第二位数字
	SendNBitToRAM(Num_5,8);								//第三位数字	
	SendNBitToRAM(COL,8);								//冒号
	
	cs=1;												  				//释放HT1621
}
