/*---------------------------------------------------------------------*/
/* --- STC MCU Limited ------------------------------------------------*/
/* --- STC 1T Series MCU Demo Programme -------------------------------*/
/* --- Mobile: (86)13922805190 ----------------------------------------*/
/* --- Fax: 86-0513-55012956,55012947,55012969 -----------------------*/
/* --- Tel: 86-0513-55012928,55012929,55012966 ------------------------*/
/* --- Web: www.STCMCU.com --------------------------------------------*/
/* --- Web: www.STCMCUDATA.com  ---------------------------------------*/
/* --- QQ:  800003751 -------------------------------------------------*/
/* 如果要在程序中使用此代码,请在程序中注明使用了STC的资料及程序        */
/*---------------------------------------------------------------------*/


/*************  功能说明    **************

LCM接口+BMM驱动液晶屏程序

16bit I8080模式, P0口接D0~D7, P2口接D8~D15

sbit LCD_RS = P4^1;      //数据/命令切换
sbit LCD_WR = P3^6;      //写控制
sbit LCD_RD = P3^7;      //读控制
sbit LCD_CS = P3^4;      //片选
sbit LCD_RESET = P3^5;   //复位

LCM指令通过NOP延时方式等待发送完成

BMM设置长度256字节，通过中断方式判断传输完成

下载时, 选择时钟 24MHz (用户可自行修改频率).

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


#include    "reg51.h"
#include    "intrins.h"

#define     MAIN_Fosc       24000000L   //定义主时钟

typedef     unsigned char   u8;
typedef     unsigned int    u16;
typedef     unsigned long   u32;

sfr IRCBAND  = 0x9D;
sfr IRTRIM = 0x9f;
sfr VRTRIM = 0xa6;

sfr TH2  = 0xD6;
sfr TL2  = 0xD7;
sfr IE2   = 0xAF;
sfr INT_CLKO = 0x8F;
sfr AUXR = 0x8E;
sfr AUXR1 = 0xA2;
sfr P_SW1 = 0xA2;
sfr P_SW2 = 0xBA;
sfr S2CON = 0x9A;
sfr S2BUF = 0x9B;

sfr P4   = 0xC0;
sfr P5   = 0xC8;
sfr P6   = 0xE8;
sfr P7   = 0xF8;
sfr P1M1 = 0x91;    //PxM1.n,PxM0.n     =00--->Standard,    01--->push-pull
sfr P1M0 = 0x92;    //                  =10--->pure input,  11--->open drain
sfr P0M1 = 0x93;
sfr P0M0 = 0x94;
sfr P2M1 = 0x95;
sfr P2M0 = 0x96;
sfr P3M1 = 0xB1;
sfr P3M0 = 0xB2;
sfr P4M1 = 0xB3;
sfr P4M0 = 0xB4;
sfr P5M1 = 0xC9;
sfr P5M0 = 0xCA;
sfr P6M1 = 0xCB;
sfr P6M0 = 0xCC;
sfr P7M1 = 0xE1;
sfr P7M0 = 0xE2;

sbit P00 = P0^0;
sbit P01 = P0^1;
sbit P02 = P0^2;
sbit P03 = P0^3;
sbit P04 = P0^4;
sbit P05 = P0^5;
sbit P06 = P0^6;
sbit P07 = P0^7;
sbit P10 = P1^0;
sbit P11 = P1^1;
sbit P12 = P1^2;
sbit P13 = P1^3;
sbit P14 = P1^4;
sbit P15 = P1^5;
sbit P16 = P1^6;
sbit P17 = P1^7;
sbit P20 = P2^0;
sbit P21 = P2^1;
sbit P22 = P2^2;
sbit P23 = P2^3;
sbit P24 = P2^4;
sbit P25 = P2^5;
sbit P26 = P2^6;
sbit P27 = P2^7;
sbit P30 = P3^0;
sbit P31 = P3^1;
sbit P32 = P3^2;
sbit P33 = P3^3;
sbit P34 = P3^4;
sbit P35 = P3^5;
sbit P36 = P3^6;
sbit P37 = P3^7;
sbit P40 = P4^0;
sbit P41 = P4^1;
sbit P42 = P4^2;
sbit P43 = P4^3;
sbit P44 = P4^4;
sbit P45 = P4^5;
sbit P46 = P4^6;
sbit P47 = P4^7;
sbit P50 = P5^0;
sbit P51 = P5^1;
sbit P52 = P5^2;
sbit P53 = P5^3;
sbit P54 = P5^4;
sbit P55 = P5^5;
sbit P56 = P5^6;
sbit P57 = P5^7;

//LCM
#define LCMIFCFG          (*(unsigned char volatile xdata *)0xfe50)
#define LCMCFG2           (*(unsigned char volatile xdata *)0xfe51)
#define LCMIFSTA          (*(unsigned char volatile xdata *)0xfe53)
#define LCMIFCR           (*(unsigned char volatile xdata *)0xfe52)
#define LCMIFDATL         (*(unsigned char volatile xdata *)0xfe54)
#define LCMIFDATH         (*(unsigned char volatile xdata *)0xfe55)

//BMM
#define LCMIF_BMM_CFG     (*(unsigned char volatile xdata *)0xfa70)
#define LCMIF_BMM_CR      (*(unsigned char volatile xdata *)0xfa71)
#define LCMIF_BMM_STA     (*(unsigned char volatile xdata *)0xfa72)
#define LCMIF_BMM_AMT     (*(unsigned char volatile xdata *)0xfa73)
#define LCMIF_BMM_DONE_N  (*(unsigned char volatile xdata *)0xfa74)
#define LCMIF_BMM_TXA     (*(unsigned int volatile xdata *)0xfa75)
#define LCMIF_BMM_TXAH    (*(unsigned char volatile xdata *)0xfa75)
#define LCMIF_BMM_TXAL    (*(unsigned char volatile xdata *)0xfa76)
#define LCMIF_BMM_RXA     (*(unsigned int volatile xdata *)0xfa77)
#define LCMIF_BMM_RXAH    (*(unsigned char volatile xdata *)0xfa77)
#define LCMIF_BMM_RXAL    (*(unsigned char volatile xdata *)0xfa78)

#define CKSEL (*(unsigned char volatile xdata *)0xfe00)
#define CLKDIV (*(unsigned char volatile xdata *)0xfe01)
#define MCLKOCR (*(unsigned char volatile xdata *)0xfe05)

#define T35M_ROMADDR (*(unsigned char code *)0xFDEF) //35MHz
#define VRT35M_ROMADDR (*(unsigned char code *)0xFDE9) //VRTRIM_35M

sbit LCD_RS = P4^1;      //数据/命令切换
sbit LCD_WR = P3^6;      //写控制
sbit LCD_RD = P3^7;      //读控制
sbit LCD_CS = P3^4;      //片选
sbit LCD_RESET = P3^5;   //复位

//IO连接
#define  LCD_DataPortH P2     //高8位数据口
#define  LCD_DataPortL P0     //低8位数据口

#define  USR_LCM_IF     1			//1: use LCM Interface; 0: use IO mode

//画笔颜色
#define WHITE         	 0xFFFF
#define BLACK         	 0x0000	  
#define BLUE             0x001F  
#define BRED             0XF81F
#define GRED             0XFFE0
#define GBLUE            0X07FF
#define RED           	 0xF800
#define MAGENTA       	 0xF81F
#define GREEN         	 0x07E0
#define CYAN          	 0x7FFF
#define YELLOW        	 0xFFE0
#define BROWN            0XBC40 //棕色
#define BRRED            0XFC07 //棕红色
#define GRAY             0X8430 //灰色

u16 index;
u16 xdata Color[256];

void delay_ms(u16 ms);
void GPIO_Init(void);
void LCM_Config(void);
void BMM_Config(void);
void LCD_Init(void);
void Test_Color(void);
void LCD_WR_DATA_16Bit(u16 Data);
void LCD_SetWindows(u16 xStar, u16 yStar,u16 xEnd,u16 yEnd);

void main(void)
{
	P0M1 = 0;   P0M0 = 0;   //设置为准双向口
	P1M1 = 0;   P1M0 = 0;   //设置为准双向口
	P2M1 = 0;   P2M0 = 0;   //设置为准双向口
	P3M1 = 0;   P3M0 = 0;   //设置为准双向口
	P4M1 = 0;   P4M0 = 0;   //设置为准双向口
	P5M1 = 0;   P5M0 = 0;   //设置为准双向口
	P6M1 = 0;   P6M0 = 0;   //设置为准双向口
	P7M1 = 0;   P7M0 = 0;   //设置为准双向口

	GPIO_Init();
#if USR_LCM_IF == 1	
	LCM_Config();
	BMM_Config();
	EA = 1;
#endif
	
	LCD_Init(); //LCM初始化

	while(1)
	{
		Test_Color();
	}
}

void LCD_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 color)
{  	
	u16 i,j;			
	u16 width=ex-sx+1; 		//得到填充的宽度
	u16 height=ey-sy+1;		//高度
	LCD_SetWindows(sx,sy,ex,ey);//设置显示窗口

#if USR_LCM_IF == 1
	
	for(j=0,i=0;i<256;i++)
	{
		Color[i] = color;
	}
	index = 300;
	LCD_CS=0;
	LCMIF_BMM_CR = 0xa0;	//Write dat
//	P40 = 0;
	
#else
	
//	P40 = 0;
	for(i=0;i<height;i++)
	{
		for(j=0;j<width;j++)
		LCD_WR_DATA_16Bit(color);	//写入数据 	 
	}
//	P40 = 1;
	
#endif
}

void Test_Color(void)
{
//	P40 = 0;
	LCD_Fill(0,0,320,240,WHITE);
//	P40 = 1;
	delay_ms(800);
//	P40 = 0;
	LCD_Fill(0,0,320,240,RED);
//	P40 = 1;
	delay_ms(800);
//	P40 = 0;
	LCD_Fill(0,0,320,240,GREEN);
//	P40 = 1;
	delay_ms(800);
//	P40 = 0;
	LCD_Fill(0,0,320,240,BLUE);
//	P40 = 1;
	delay_ms(800);
}

//========================================================================
// 函数: void delay_ms(u16 ms)
// 描述: 延时函数。
// 参数: ms,要延时的ms数, 自动适应主时钟.
// 返回: none.
// 版本: VER1.0
// 日期: 2013-4-1
// 备注: 
//========================================================================
void delay_ms(u16 ms)
{
	 u16 i;
	 do{
			i = MAIN_Fosc / 10000;
			while(--i)    ;   //10T per loop
	 }while(--ms);
}

void Write_Cmd(unsigned char DH,unsigned char DL)
{
#if USR_LCM_IF == 1
	
	LCMIFDATH = DH;
	LCMIFDATL = DL;
	LCD_CS=0;
	LCMIFCR = 0x84;		//Enable interface, write command out
	_nop_();
	LCD_CS=1;
	
#else
	
	LCD_CS=0;
	LCD_RS=0;
	LCD_WR=0;
	LCD_DataPortH=DH;
	LCD_DataPortL=DL;
	LCD_WR=1;
	LCD_CS=1;
	
#endif
}

void Write_Data(unsigned char DH,unsigned char DL)
{
#if USR_LCM_IF == 1
	
	LCMIFDATH = DH;
	LCMIFDATL = DL;
	LCD_CS=0;
	LCMIFCR = 0x85;		//Enable interface, write data out
	_nop_();
	LCD_CS=1;
	
#else
	
	LCD_CS=0;
	LCD_RS=1;
	LCD_WR=0;
	LCD_DataPortH=DH;
	LCD_DataPortL=DL;	
	LCD_WR=1;
	LCD_CS=1;
	
#endif
}

void LCD_WR_REG(u8 Reg)	 
{	
#if USR_LCM_IF == 1
	
	LCMIFDATH = 0;
	LCMIFDATL = Reg;
	LCD_CS=0;
	LCMIFCR = 0x84;		//Enable interface, write command out
	_nop_();
	LCD_CS=1;
	
#else
	
	LCD_RS=0;
	LCD_CS=0;
	LCD_WR=0;
	LCD_DataPortL = Reg;
	LCD_WR=1;
	LCD_CS=1;
	
#endif
}

void LCD_WR_REG16(u8 Reg, u16 dat)	 
{	
	Write_Cmd(0x00,Reg);
	Write_Data((dat>>8)&0xFF,dat&0xFF);
} 

void LCD_WR_DATA_16Bit(u16 Data)
{
	Write_Data((Data>>8)&0xFF,Data&0xFF);
}

/*****************************************************************************
 * @name       :void GPIO_Init(void)
 * @date       :2018-11-13 
 * @function   :Set the gpio to push-pull mode
 * @parameters :None
 * @retvalue   :None
******************************************************************************/	
void GPIO_Init(void)
{
  //P0口设置成推挽输出
	P0M0=0xff;
	P0M1=0x00;

	//P1口设置成准双向口
	P1M0=0x00;
	P1M1=0x00;

  //P2口设置成推挽输出
	P2M0=0xff;
	P2M1=0x00;

	//P3.4~P3.7口设置成推挽输出
	P3M0=0xf0;
	P3M1=0x00;

	//P4.1口设置成推挽输出
	P4M0=0x02;
	P4M1=0x00;
}

/*****************************************************************************
 * @name       :void LCM_Config(void)
 * @date       :2018-11-13 
 * @function   :Config LCM
 * @parameters :None
 * @retvalue   :None
******************************************************************************/	
void LCM_Config(void)
{
	P_SW2 = 0x80;
	LCMIFCFG = 0x02;	//bit7 1:Enable Interrupt, bit1 1:16bit mode; bit0 0:8080,1:6800
	LCMCFG2 = 0x29;		//RS:P41,RD:P37,WR:P36; Setup Time=2,HOLD Time=1
	LCMIFSTA = 0x00;
}

/*****************************************************************************
 * @name       :void BMM_Config(void)
 * @date       :2020-12-09 
 * @function   :Config BMM
 * @parameters :None
 * @retvalue   :None
******************************************************************************/	
void BMM_Config(void)
{
	P_SW2 = 0x80;
	LCMIF_BMM_AMT = 0xff;		//Exe 256(n+1) bytes
	LCMIF_BMM_TXA = &Color;
//	LCMIF_BMM_RXA = &Buffer;
	LCMIF_BMM_STA = 0x00;
	LCMIF_BMM_CFG = 0x82;
	LCMIF_BMM_CR = 0x80;
}

/*****************************************************************************
 * @name       :void LCDReset(void)
 * @date       :2018-08-09 
 * @function   :Reset LCD screen
 * @parameters :None
 * @retvalue   :None
******************************************************************************/	
void LCDReset(void)
{
	LCD_CS=1;
	delay_ms(50);	
	LCD_RESET=0;
	delay_ms(150);
	LCD_RESET=1;
	delay_ms(50);
}

/*****************************************************************************
 * @name       :void LCD_Init(void)
 * @date       :2018-08-09 
 * @function   :Initialization LCD screen
 * @parameters :None
 * @retvalue   :None
******************************************************************************/	 	 
void LCD_Init(void)
{
	LCDReset(); //初始化之前复位
	delay_ms(150);                     //根据不同晶振速度可以调整延时，保障稳定显示
//*************2.4inch ILI9325初始化**********//	
	LCD_WR_REG16(0x00E5,0x78F0); 
	LCD_WR_REG16(0x0001,0x0100); 
	LCD_WR_REG16(0x0002,0x0700); 
	LCD_WR_REG16(0x0003,0x1030); 
	LCD_WR_REG16(0x0004,0x0000); 
	LCD_WR_REG16(0x0008,0x0202);  
	LCD_WR_REG16(0x0009,0x0000);
	LCD_WR_REG16(0x000A,0x0000); 
	LCD_WR_REG16(0x000C,0x0000); 
	LCD_WR_REG16(0x000D,0x0000);
	LCD_WR_REG16(0x000F,0x0000);
	//power on sequence VGHVGL
	LCD_WR_REG16(0x0010,0x0000);   
	LCD_WR_REG16(0x0011,0x0007);  
	LCD_WR_REG16(0x0012,0x0000);  
	LCD_WR_REG16(0x0013,0x0000); 
	LCD_WR_REG16(0x0007,0x0000); 
	//vgh 
	LCD_WR_REG16(0x0010,0x1690);   
	LCD_WR_REG16(0x0011,0x0227);
	delay_ms(10);
	//vregiout 
	LCD_WR_REG16(0x0012,0x009D); //0x001b
	delay_ms(10); 
	//vom amplitude
	LCD_WR_REG16(0x0013,0x1900);
	delay_ms(10); 
	//vom H
	LCD_WR_REG16(0x0029,0x0025); 
	LCD_WR_REG16(0x002B,0x000D); 
	//gamma
	LCD_WR_REG16(0x0030,0x0007);
	LCD_WR_REG16(0x0031,0x0303);
	LCD_WR_REG16(0x0032,0x0003); //0006
	LCD_WR_REG16(0x0035,0x0206);
	LCD_WR_REG16(0x0036,0x0008);
	LCD_WR_REG16(0x0037,0x0406); 
	LCD_WR_REG16(0x0038,0x0304); //0200
	LCD_WR_REG16(0x0039,0x0007); 
	LCD_WR_REG16(0x003C,0x0602); //0504
	LCD_WR_REG16(0x003D,0x0008); 
	//ram
	LCD_WR_REG16(0x0050,0x0000); 
	LCD_WR_REG16(0x0051,0x00EF);
	LCD_WR_REG16(0x0052,0x0000); 
	LCD_WR_REG16(0x0053,0x013F);  
	LCD_WR_REG16(0x0060,0xA700); 
	LCD_WR_REG16(0x0061,0x0001); 
	LCD_WR_REG16(0x006A,0x0000); 
	//
	LCD_WR_REG16(0x0080,0x0000); 
	LCD_WR_REG16(0x0081,0x0000); 
	LCD_WR_REG16(0x0082,0x0000); 
	LCD_WR_REG16(0x0083,0x0000); 
	LCD_WR_REG16(0x0084,0x0000); 
	LCD_WR_REG16(0x0085,0x0000); 
	//
	LCD_WR_REG16(0x0090,0x0010); 
	LCD_WR_REG16(0x0092,0x0600); 
	
	LCD_WR_REG16(0x0007,0x0133);
	LCD_WR_REG16(0x0000,0x0022);

	//设置LCD属性参数
	LCD_WR_REG16(0x0003, 0x1030); // set GRAM write direction and BGR=1.
	LCD_WR_REG16(0x0001, 0x0100); // set SS and SM bit
}

#define WINDOW_XADDR_START	0x0050 // Horizontal Start Address Set
#define WINDOW_XADDR_END		0x0051 // Horizontal End Address Set
#define WINDOW_YADDR_START	0x0052 // Vertical Start Address Set
#define WINDOW_YADDR_END	0x0053 // Vertical End Address Set
#define GRAM_XADDR		    0x0020 // GRAM Horizontal Address Set
#define GRAM_YADDR		    0x0021 // GRAM Vertical Address Set
#define GRAMWR 			    0x0022 // memory write

void LCD_SetWindows(u16 yStar, u16 xStar,u16 yEnd,u16 xEnd)
{	
  LCD_WR_REG16(WINDOW_XADDR_START,xStar);
  LCD_WR_REG16(WINDOW_XADDR_END,xEnd);
  LCD_WR_REG16(WINDOW_YADDR_START,yStar);
  LCD_WR_REG16(WINDOW_YADDR_END,yEnd);
  LCD_WR_REG16(GRAM_XADDR,xStar);
  LCD_WR_REG16(GRAM_YADDR,yStar);
	LCD_WR_REG(GRAMWR);
}   

/*****************************************************************************
 * @name       :void LCM_Interrupt(void)
 * @date       :2018-11-13 
 * @function   :None
 * @parameters :None
 * @retvalue   :
******************************************************************************/ 
void LCMIF_BMM_Interrupt(void) interrupt 13
{
//	LCMIFSTA = 0x00;
//	LCD_CS=1;

	LCMIF_BMM_STA = 0;
	index--;
	if(index == 0)
	{
		LCMIF_BMM_CR = 0;
		LCD_CS=1;
//		P40 = 1;
	}
	else
	{
		LCMIF_BMM_CR = 0xa0;	//Write dat
	}
}
