NT35510的LCD函数详解01(洋桃电子-触摸屏开发者笔记)
资料下载:
洋桃电子 YoungTalk 探索最好的 STM32 教学 (doyoung.net)
接口类型
NT35510 数据手册(英文).pdf
NT35510 应用手册(英文).pdf
根据 NT35510 数据手册,支持的屏幕接口类型包括:
- RGB 接口:支持 16 位、18 位和 24 位的 RGB 数据接口,用于接收红绿蓝(RGB)颜色数据。
- MIPI 接口:支持 MIPI Display Serial Interface(DSI),这是一种用于移动设备的显示标准,支持高速度的数据传输。
- MDDI 接口:支持 Mobile Display Digital Interface(MDDI),这是另一种用于移动设备的显示接口,也支持高速数据传输。
- SPI 接口:支持 16 位串行外围设备接口(SPI),用于微控制器和显示驱动器之间的通信。
- I2C 接口:支持 I2C 接口,用于低速设备通信,如 EEPROM 或某些类型的传感器。
- 80 系列 MPU 接口:支持 8 位、16 位和 24 位的并行微处理器(MPU)接口,用于与微处理器单元进行数据交换。
这些接口类型使得 NT35510 能够适用于多种不同的显示面板和系统设计,包括智能手机、平板电脑、便携式媒体播放器、数码相机等设备。
基础函数
读取指令/寄存器
LCD_COM 和 LCD_DAT 取决于 FSMC 的地址。
FSMC 地址计算方法:
所以 FSMC 的数据操作地址是算法是按上面的方法来算,洋桃电子视频里面讲的就是 A18:
#define LCD_COM (uint32_t *)0X60000000 //将A18地址端口置0后的地址(表示向LCD发送指令)
#define LCD_DAT (uint32_t *)0X60080000 //将A18地址端口置1后的地址(表示向LCD发送数据)
void LCD_Write_COM(uint16_t R){//向LCD写指令COM
__NOP();__NOP();
HAL_SRAM_Write_16b(&hsram1,LCD_COM,&R,1);//向LCD写16位数据(句柄,指令COM/数据DAT,存放寄存器,数量)
}
void LCD_Write_DAT(uint16_t D){//向LCD写数据DAT
__NOP();__NOP();
HAL_SRAM_Write_16b(&hsram1,LCD_DAT,&D,1);//向LCD写16位数据(句柄,指令COM/数据DAT,存放寄存器,数量)
}
uint16_t LCD_Read_DAT(void){//读LCD的RAM空间
uint16_t RAM;
HAL_SRAM_Read_16b(&hsram1,LCD_DAT,&RAM,1);//向LCD读16位数据(句柄,指令COM/数据DAT,存放寄存器,数量)
return RAM;
}
void LCD_Write_REG(uint16_t R,uint16_t D){//写LCD寄存器(参数:地址,数据)
HAL_SRAM_Write_16b(&hsram1,LCD_COM,&R,1);//向LCD写16位数据(句柄,指令COM/数据DAT,存放寄存器,数量)
HAL_SRAM_Write_16b(&hsram1,LCD_DAT,&D,1);//向LCD写16位数据(句柄,指令COM/数据DAT,存放寄存器,数量)
}
uint16_t LCD_Read_REG(uint16_t R){//读LCD寄存器(参数:LCD寄存器地址,返回:读出数据)
LCD_Write_COM(R);//写入要读的寄存器序号
delay_us(5);
return LCD_Read_DAT();//返回读到的值
}
这段代码是用于向 LCD(液晶显示器)写入指令和数据,以及从 LCD 读取数据的函数。它使用了 HAL 库(硬件抽象层库)来操作 SRAM(静态随机存取存储器),这是 LCD 控制器通常使用的存储器接口。下面是每个函数的详细解释:
-
LCD_Write_COM(uint16_t R)
:- 功能:向 LCD 写入指令(Command)。
- 实现原理:通过调用
HAL_SRAM_Write_16b
函数,将 16 位指令写入 LCD 的指令寄存器。 - 注意事项:在写入指令之前,使用
__NOP();__NOP();
进行两次空操作,可能是为了确保之前的操作完成。
-
LCD_Write_DAT(uint16_t D)
:- 功能:向 LCD 写入数据(Data)。
- 实现原理:通过调用
HAL_SRAM_Write_16b
函数,将 16 位数据写入 LCD 的数据寄存器。 - 注意事项:与
LCD_Write_COM
类似,在写入数据之前,使用__NOP();__NOP();
进行两次空操作。
-
uint16_t LCD_Read_DAT(void)
:- 功能:从 LCD 的 RAM 空间读取数据。
- 实现原理:通过调用
HAL_SRAM_Read_16b
函数,从 LCD 的数据寄存器读取 16 位数据。 - 注意事项:读取的数据存储在变量
RAM
中,并作为函数的返回值。
-
LCD_Write_REG(uint16_t R, uint16_t D)
:- 功能:向 LCD 写入寄存器(Register)。
- 实现原理:首先通过调用
HAL_SRAM_Write_16b
函数,将 16 位寄存器地址写入指令寄存器,然后再次调用HAL_SRAM_Write_16b
函数,将 16 位数据写入数据寄存器。 - 注意事项:这个函数实际上是先写地址,再写数据,符合许多 LCD 控制器的寄存器写入顺序。
-
uint16_t LCD_Read_REG(uint16_t R)
:- 功能:从 LCD 读取寄存器数据。
- 实现原理:首先调用
LCD_Write_COM
函数,将寄存器地址写入指令寄存器,然后延时 5 微秒,最后调用LCD_Read_DAT
函数读取数据寄存器中的数据。 - 注意事项:延时是为了确保寄存器地址写入后,LCD 有足够的时间处理。
用途: 这些函数主要用于与 LCD 控制器通信,包括发送指令、写入数据、读取数据以及读写寄存器。这些操作是显示和控制 LCD 的基础,例如设置显示模式、调整对比度、读取显示数据等。
设置光标位置
void LCD_Write_Cursor(uint16_t x,uint16_t y){//设置光标位置(参数:X坐标,Y坐标)
if(LCD_ID==LCD_ID_OTM8009){//判断LCD ID OTM8009A(不同型号的指令有差异)
LCD_Write_REG(SET_X,x>>8);
LCD_Write_REG(SET_X+1,x&0xFF);
LCD_Write_REG(SET_X+2,(SET_Width-1)>>8);
LCD_Write_REG(SET_X+3,(SET_Width-1)&0xFF);
LCD_Write_REG(SET_Y,y>>8);
LCD_Write_REG(SET_Y+1,y&0xFF);
LCD_Write_REG(SET_Y+2,(SET_Height-1)>>8);
LCD_Write_REG(SET_Y+3,(SET_Height-1)&0xFF);
}else{ //判断LCD ID NT35510/RM68120
LCD_Write_REG(SET_X,x>>8);
LCD_Write_REG(SET_X+1,x&0xFF);
LCD_Write_REG(SET_Y,y>>8);
LCD_Write_REG(SET_Y+1,y&0xFF);
}
}
这段代码的实现原理是将给定的坐标值拆分为高 8 位和低 8 位,然后分别写入到 LCD 的 X 坐标寄存器和 Y 坐标寄存器中,从而控制 LCD 的显示位置。
将一个 16 位的坐标值(x 和 y)拆分为两个 8 位的数据,并分别写入到 LCD 的寄存器中。具体原因如下:
- LCD 寄存器要求:许多 LCD 控制器要求坐标值(如 X 和 Y 坐标)以 8 位为单位进行设置。这意味着,即使坐标值是一个 16 位的整数,也需要将其拆分为两个 8 位的数据分别写入寄存器。
- 数据传输效率:将一个 16 位的坐标值拆分为两个 8 位的数据,可以减少数据传输的次数。因为大多数 LCD 控制器一次只能处理一个 8 位的数据,所以将 16 位的数据拆分为两个 8 位的数据可以更高效地传输数据。
- 避免数据溢出:将 16 位的坐标值拆分为两个 8 位的数据,可以避免数据溢出的问题。因为每个 8 位的数据范围是 0 到 255,所以将 16 位的坐标值拆分为两个 8 位的数据可以确保数据不会超出范围。
- 兼容性:这种拆分方式可以确保代码在不同型号的 LCD 控制器上具有较好的兼容性。因为大多数 LCD 控制器都要求坐标值以 8 位为单位进行设置,所以这种拆分方式可以确保代码在不同型号的 LCD 控制器上都能正常工作。
综上所述,这段代码之所以这样写,主要是为了满足 LCD 寄存器的要求,提高数据传输效率,避免数据溢出,并确保代码在不同型号的 LCD 控制器上具有较好的兼容性。
LCD 初始化
uint8_t LCD_Init(void){ //LCD彩屏初始化(其中参数参考LCD模块数据手册)(返回值1:初始化成功,0:初始化失败)
uint16_t a,i;
uint8_t buf[52]= //Gamma设置的参数
{0x00,0x33,0x00,0x34,0x00,0x3A,0x00,0x4A,0x00,0x5C,0x00,0x81,0x00,0xA6,0x00,0xE5,
0x01,0x13,0x01,0x54,0x01,0x82,0x01,0xCA,0x02,0x00,0x02,0x01,0x02,0x34,0x02,0x67,
0x02,0x84,0x02,0xA4,0x02,0xB7,0x02,0xCF,0x02,0xDE,0x02,0xF2,0x02,0xFE,0x03,0x10,
0x03,0x33,0x03,0x6D};
LCD_ID = LCD_Read_REG(0XDA00);//读取LCD ID指令(24位ID顺序D3,D2,D1)参考LCD数据手册
LCD_ID<<=8;//将数据左移8位
LCD_ID |= LCD_Read_REG(0XDB00);
LCD_ID<<=8;//将数据左移8位
LCD_ID |= LCD_Read_REG(0XDC00);
a=0;//初始化失败的值预先赋值
if(LCD_ID==LCD_ID_NT35510){ //判断LCD ID是否读取正确
LCD_Write_REG(0xF000,0x55);LCD_Write_REG(0xF001,0xAA);LCD_Write_REG(0xF002,0x52);
LCD_Write_REG(0xF003,0x08);LCD_Write_REG(0xF004,0x01);
//AVDD Set AVDD 5.2V
LCD_Write_REG(0xB000,0x0D);LCD_Write_REG(0xB001,0x0D);LCD_Write_REG(0xB002,0x0D);
//AVDD ratio
LCD_Write_REG(0xB600,0x34);LCD_Write_REG(0xB601,0x34);LCD_Write_REG(0xB602,0x34);
//AVEE -5.2V
LCD_Write_REG(0xB100,0x0D);LCD_Write_REG(0xB101,0x0D);LCD_Write_REG(0xB102,0x0D);
//AVEE ratio
LCD_Write_REG(0xB700,0x34);LCD_Write_REG(0xB701,0x34);LCD_Write_REG(0xB702,0x34);
//VCL -2.5V
LCD_Write_REG(0xB200,0x00);LCD_Write_REG(0xB201,0x00);LCD_Write_REG(0xB202,0x00);
//VCL ratio
LCD_Write_REG(0xB800,0x24);LCD_Write_REG(0xB801,0x24);LCD_Write_REG(0xB802,0x24);
//VGH 15V (Free pump)
LCD_Write_REG(0xBF00,0x01);LCD_Write_REG(0xB300,0x0F);LCD_Write_REG(0xB301,0x0F);
LCD_Write_REG(0xB302,0x0F);
//VGH ratio
LCD_Write_REG(0xB900,0x34);LCD_Write_REG(0xB901,0x34);LCD_Write_REG(0xB902,0x34);
//VGL_REG -10V
LCD_Write_REG(0xB500,0x08);LCD_Write_REG(0xB501,0x08);LCD_Write_REG(0xB502,0x08);
LCD_Write_REG(0xC200,0x03);
//VGLX ratio
LCD_Write_REG(0xBA00,0x24);LCD_Write_REG(0xBA01,0x24);LCD_Write_REG(0xBA02,0x24);
//VGMP/VGSP 4.5V/0V
LCD_Write_REG(0xBC00,0x00);LCD_Write_REG(0xBC01,0x78);LCD_Write_REG(0xBC02,0x00);
//VGMN/VGSN -4.5V/0V
LCD_Write_REG(0xBD00,0x00);LCD_Write_REG(0xBD01,0x78);LCD_Write_REG(0xBD02,0x00);
//VCOM
LCD_Write_REG(0xBE00,0x00);LCD_Write_REG(0xBE01,0x64);
//Gamma Setting
for(i=0xD1;i<=0xD6;i++){ //循环写入buf数组值
for(a=0;a<52;a++){
LCD_Write_REG(i*0x100+a,buf[a]);
}
}
//LV2 Page 0 enable
LCD_Write_REG(0xF000,0x55);LCD_Write_REG(0xF001,0xAA);LCD_Write_REG(0xF002,0x52);
LCD_Write_REG(0xF003,0x08);LCD_Write_REG(0xF004,0x00);
//Display control
LCD_Write_REG(0xB100, 0xCC);LCD_Write_REG(0xB101, 0x00);
//Source hold time
LCD_Write_REG(0xB600,0x05);
//Gate EQ control
LCD_Write_REG(0xB700,0x70);LCD_Write_REG(0xB701,0x70);
//Source EQ control (Mode 2)
LCD_Write_REG(0xB800,0x01);LCD_Write_REG(0xB801,0x03);LCD_Write_REG(0xB802,0x03);
LCD_Write_REG(0xB803,0x03);
//Inversion mode (2-dot)
LCD_Write_REG(0xBC00,0x02);LCD_Write_REG(0xBC01,0x00);LCD_Write_REG(0xBC02,0x00);
//Timing control 4H w/ 4-delay
LCD_Write_REG(0xC900,0xD0);LCD_Write_REG(0xC901,0x02);LCD_Write_REG(0xC902,0x50);
LCD_Write_REG(0xC903,0x50);LCD_Write_REG(0xC904,0x50);LCD_Write_REG(0x3500,0x00);
LCD_Write_REG(0x3A00,0x55); //16-bit/pixel
LCD_Write_COM(0x1100);
delay_us(120);//设置后必要的延时
LCD_OFF();//初始化设置之前关显示(防止显示出乱码)
LCD_Direction(UDRL);//设置显示方向
LCD_CLEAR(White);//清屏
LCD_ON();//初始化完成后打开显示和背光
a=1;//写入初始化成功的值1
}
return a;
}
这段参考应用手册:
NT35510应用手册(英文).pdf - p8 - 2.2.2 Software Setting
LCD 显示方向
void LCD_Direction(uint8_t dir){//设置LCD显示方向
SET_GRAM=0X2C00;//设置写入GRAM的指令
SET_X=0X2A00;//设置写X坐标指令
SET_Y=0X2B00; //设置写Y坐标指令
if(dir==LRUD || dir==LRDU || dir==RLUD || dir==RLDU){ //竖屏
SET_Width=LCD_Width;//设置宽度
SET_Height=LCD_Height;//设置高度
}else{ //横屏
SET_Width=LCD_Height;//设置宽度
SET_Height=LCD_Width;//设置高度
}
LCD_Write_REG(0X3600,dir);//写入显示方向
LCD_Write_COM(SET_X);LCD_Write_DAT(0);//x轴起始位置的高8位
LCD_Write_COM(SET_X+1);LCD_Write_DAT(0);//X轴起始位置的低8位
LCD_Write_COM(SET_X+2);LCD_Write_DAT((SET_Width-1)>>8);//X轴结束位置的高8位
LCD_Write_COM(SET_X+3);LCD_Write_DAT((SET_Width-1)&0XFF);//X轴结束位置的低8位
LCD_Write_COM(SET_Y);LCD_Write_DAT(0);//Y轴起始位置的高8位
LCD_Write_COM(SET_Y+1);LCD_Write_DAT(0);//Y轴起始位置的低8位
LCD_Write_COM(SET_Y+2);LCD_Write_DAT((SET_Height-1)>>8);//Y轴结束位置的高8位
LCD_Write_COM(SET_Y+3);LCD_Write_DAT((SET_Height-1)&0XFF);//Y轴结束位置的低8位
}
NT35510数据手册(英文).pdf - p284 - CASET: Column Address Set (2A00h~2A03h)
x 轴坐标寄存器:
- XS[15:0] :代表列地址的起始值,是一个 16 位的值。
- XE[15:0] :代表列地址的结束值,也是一个 16 位的值。
NT35510数据手册(英文).pdf - p295 - MADCTL: Memory Data Access Control (3600h)
这里对 0X3600 寄存器做一下详细解释:
-
MY Row Address Order:
- 这个寄存器用于控制行地址的顺序。在显示内存中写入或读取数据时,可以指定是按照从上到下的顺序(递增)还是从下到上的顺序(递减)来处理行地址。
-
MX Column Address Order:
- 这个寄存器用于控制列地址的顺序。类似于行地址,它可以指定在一行中数据是按照从左到右(递增)还是从右到左(递减)的顺序来处理。
-
MV Row/Column Exchange:
- 这个寄存器用于交换行和列的顺序。当启用时,可以改变数据写入或读取的优先级,使得先处理列地址,然后再处理行地址。这可以影响数据在显示内存中的布局。
-
ML Vertical Refresh Order:
- 这个寄存器用于控制 TFT LCD 的垂直刷新方向。它可以决定屏幕刷新是从上到下开始,还是从下到上开始。
这些寄存器共同控制着数据在显示内存中的组织方式和屏幕刷新的行为。改变这些设置可能会影响显示图案的布局和刷新顺序,从而影响显示效果。
所以宏定义方向:
#define LRUD 0x00 //从左到右,从上到下
#define LRDU 0x80 //从左到右,从下到上
#define RLUD 0x40 //从右到左,从上到下
#define RLDU 0xC0 //从右到左,从下到上
#define UDLR 0x20 //从上到下,从左到右
#define UDRL 0x60 //从上到下,从右到左
#define DULR 0xA0 //从下到上,从左到右
#define DURL 0xE0 //从下到上,从右到左
0x00:
- MY = 0x0:可能表示行地址顺序为正常(从上到下递增)。
- MX = 0x0:可能表示列地址顺序为正常(从左到右递增)。
- MV = 0x0:可能表示没有行/列交换,即正常顺序(先行后列)
MV 决定了屏幕是横屏还是竖屏,就要根据设置调整屏幕的宽度和高度:
图中第三位都是 1,代表横屏。
LCD 控制背光
void LCD_ON(void){//LCD开启显示和背光
LCD_Write_COM(0X2900); //开启显示
HAL_GPIO_WritePin(GPIOB,LCD_BL_Pin,GPIO_PIN_SET);
}
void LCD_OFF(void){//LCD关闭显示和背光
HAL_GPIO_WritePin(GPIOB,LCD_BL_Pin,GPIO_PIN_RESET);
LCD_Write_COM(0X2800); //关闭显示
}
开关引脚。
LCD 清屏
void LCD_CLEAR(uint16_t COLOR){//清屏函数(参数:背景的单色值)
uint32_t index=0;
uint32_t totalpoint=LCD_Width;
totalpoint*=LCD_Height;//得到总点数
LCD_Write_Cursor(0x00,0x0000);//设置光标位置
LCD_Write_COM(SET_GRAM);//开始写入GRAM
for(index=0;index<totalpoint;index++){
HAL_SRAM_Write_16b(&hsram1,LCD_DAT,&COLOR,1);//向LCD写16位数据(句柄,指令COM/数据DAT,存放寄存器,数量)
}
BackColor = COLOR; //将清屏后的颜色值作为字符显示的背景颜色
ForeColor = ~COLOR;//将清屏后的颜色值的“补色”作为字符颜色
}
#define LCD_Height 800 //洋桃LCD彩屏模块 固定分辨率800x480
#define LCD_Width 480 //(以竖屏为原始方位,长边是上下高度LCD_Height,短边是左右宽度LCD_Width)
SET_GRAM=0X2C00;//设置写入GRAM的指令
该函数是一个清屏函数,功能是将 LCD 屏幕上的所有点设置为指定的颜色值。参数 COLOR
表示背景的单色值。函数首先计算出 LCD 屏幕的总点数,然后设置光标位置,并开始写入 GRAM。接下来,使用 HAL_SRAM_Write_16b
函数向 LCD 写入 16 位数据,数据内容为 COLOR
,写入次数为总点数。最后,将 COLOR
值作为背景颜色,其补色作为字符颜色。