ARM嵌入式开发第九章:通过GPIO驱动正点原子TFTLCD屏
我在看的是正点原子精英板+3.5寸显示屏的配置,不过,其他开发板TFT-LCD屏幕这块的电路图也应该大差不差这个屏幕包含了显示屏和触摸两部分,当前只关注显示部分,也就是上图红色框图框起来的部分,包含了FSMC前缀的引脚+BL背光引脚,RESET引脚是和复位电路直接相连的,按动复位按钮也会复位屏幕模块。其余都是供电和触摸相关引脚,暂时不用探究。引脚模块原理图和引脚详细信息可以在正点原子资料里的开发指
前言
看正点原子的例程看到了TFTLCD(MCU屏)实验,发现这个屏幕是通过FSMC外设来控制的。这样虽然配置和使用变得方便简单,但是真的学习起来会有点一头雾水的感觉,知其然不知其所以然。万一实际工程遇到不带FSMC外设的芯片,又要怎么办。
因此,我这次摈弃FSMC外设,只通过普通的GPIO口外设的读写控制来实现开发板上TFTLCD的屏幕控制。完整梳理一下屏幕驱动就完整过程。
一、TFTLCD屏幕驱动引脚介绍
我在看的是正点原子精英板+3.5寸显示屏的配置,不过,其他开发板TFT-LCD屏幕这块的电路图也应该大差不差

这个屏幕包含了显示屏和触摸两部分,当前只关注显示部分,也就是上图红色框图框起来的部分,包含了FSMC前缀的引脚+BL背光引脚,RESET引脚是和复位电路直接相连的,按动复位按钮也会复位屏幕模块。其余都是供电和触摸相关引脚,暂时不用探究。

引脚模块原理图和引脚详细信息可以在正点原子资料里的开发指南上找到,不做过多赘述,
总之,这个屏幕采用I8080的驱动方式来驱动显示屏。
具体的控制逻辑就是几根控制线进行片选控制,读写控制,数据或命令选择控制,再加上16根并行数据线进行数据传输。
串行数据传输类似UART通信,一根线一次只能传输1bit,并行数据传输存在多根线,比如上图8080的DB[15:0],一次能传输16bit数据。
因为屏幕驱动每个像素点就需要一组RGB数据,屏幕越大,像素点越多,所以一般为了保证每秒屏幕刷新高帧率,都会选择用并行数据线进行数据传输,当然,也有比较小的屏幕用串行SPI进行数据传输的。
然后嘞,我手里这块3.5寸显示屏内部液晶显示控制器是NT35310型号的,这个型号是烧录正点原子的TFT屏幕例程通过ID判断出来的

其他不同尺寸的屏幕好像控制器型号各不相同,不过例程里已经写好了所有控制器的初始化指令和屏幕刷新指令,屏幕不一样到时候自己修改一下就行,具体的电平控制时序各个控制器应该都是一致的,这方面问题不大。

具体的屏幕刷新原理:
MCU发送像素颜色数据到液晶显示控制器更新缓冲区像素点数据,液晶显示控制器对液晶屏幕进行描点。
二、I8080通信协议时序分析


信号传输存在发送命令,发送数据,读取数据三种情况。当然,为了使用方便,我不做数据读取的功能也是一样可以让屏幕亮起来的。
时序分析
观察上图所示时序图
发送数据:
1. 拉低CS片选信号,表示该设备被选中
2. 拉低RS命令数据选择标志,表示这次输出的是命令数据
3. 拉低WR写数据引脚,见上图序号3可分析出来,MCU输出16位数据信号后液晶显示控制器在WR引脚的上升沿进行数据读取。
4. 控制D[15:0]引脚输出16bit数据
5. 拉高WR写数据引脚,形成上升沿,通知液晶显示控制器进行数据读取
步骤2按照要发送的是数据还是命令自行选择是将RS拉高还是拉低
结束,8080时序整体就这么简单。
指令分析
一切从简,只说明三个目前点亮屏幕会用到的指令格式,命令后面需要参数,参数怎么设置也不要管,正点原子的例程怎么用我就怎么用就行
0X2A

设置列地址命令(x坐标),后面有四字节参数,因此要发送此命令需要格式如下:
第一次数据传输 CMD:0x002A
第二次数据传输 DATA:刷新列起始地址
第三次数据传输 DATA:刷新列结束地址
0X2B

设置页地址命令(y坐标),后面有四字节参数
0x2C

向液晶显示控制器内存传输像素点颜色数据的命令。
正常使用就是先通过0X2A,0X2B命令设置XY的起始坐标和结束坐标,则液晶显示控制器内存数据更新指针只会在这个XY区间内按从上到下从左到右的顺序(默认顺序,也可以通过命令修改顺序)累加更新。
三、通过Cubemx进行相关GPIO的初始化配置
参考原理图文档找齐第一节中的所有与GPIO相关的引脚进行初始化,因为并没有读命令,所有将所有引脚全部配置成输出模式即可,又因为没有在外部电路看到上拉电阻,并且TFTLCD显示屏为了保证GPIO输出速率则引脚配置模式如下:



如图所示为所有与LCD屏幕驱动有关的引脚的GPIO的引脚配置,配置为推挽输出,引脚最大输出速度为高速。
四、编写屏幕驱动代码
先完成关于各个功能引脚的GPIO控制代码
void set_LCD_BL_Pin(uint8_t val)
{
if(val) HAL_GPIO_WritePin(LCD_BL_GPIO_Port,LCD_BL_Pin,GPIO_PIN_SET);
else HAL_GPIO_WritePin(LCD_BL_GPIO_Port,LCD_BL_Pin,GPIO_PIN_RESET);
}
void set_LCD_RS_Pin(uint8_t val)
{
if(val) HAL_GPIO_WritePin(LCD_RS_GPIO_Port,LCD_RS_Pin,GPIO_PIN_SET);
else HAL_GPIO_WritePin(LCD_RS_GPIO_Port,LCD_RS_Pin,GPIO_PIN_RESET);
}
void set_LCD_RD_Pin(uint8_t val)
{
if(val) HAL_GPIO_WritePin(LCD_RD_GPIO_Port,LCD_RD_Pin,GPIO_PIN_SET);
else HAL_GPIO_WritePin(LCD_RD_GPIO_Port,LCD_RD_Pin,GPIO_PIN_RESET);
}
void set_LCD_WR_Pin(uint8_t val)
{
if(val) HAL_GPIO_WritePin(LCD_WR_GPIO_Port,LCD_WR_Pin,GPIO_PIN_SET);
else HAL_GPIO_WritePin(LCD_WR_GPIO_Port,LCD_WR_Pin,GPIO_PIN_RESET);
}
void set_LCD_CS_Pin(uint8_t val)
{
if(val) HAL_GPIO_WritePin(LCD_CS_GPIO_Port,LCD_CS_Pin,GPIO_PIN_SET);
else HAL_GPIO_WritePin(LCD_CS_GPIO_Port,LCD_CS_Pin,GPIO_PIN_RESET);
}
void set_data_val(uint16_t val)
{
uint16_t gpiod_set = 0;
uint16_t gpiod_reset = 0;
uint16_t gpioe_set = 0;
uint16_t gpioe_reset = 0;
if(val&(1<<0))//GPIOD 14
gpiod_set|=LCD_D0_Pin;
else
gpiod_reset|=LCD_D0_Pin;
if(val&(1<<1))//GPIOD 15
gpiod_set|=LCD_D1_Pin;
else
gpiod_reset|=LCD_D1_Pin;
if(val&(1<<2))//GPIOD 0
gpiod_set|=LCD_D2_Pin;
else
gpiod_reset|=LCD_D2_Pin;
if(val&(1<<3))//GPIOD 1
gpiod_set|=LCD_D3_Pin;
else
gpiod_reset|=LCD_D3_Pin;
if(val&(1<<13))////GPIOD 8
gpiod_set|=LCD_D13_Pin;
else
gpiod_reset|=LCD_D13_Pin;
if(val&(1<<14))//GPIOD 9
gpiod_set|=LCD_D14_Pin;
else
gpiod_reset|=LCD_D14_Pin;
if(val&(1<<15))////GPIOD 10
gpiod_set|=LCD_D15_Pin;
else
gpiod_reset|=LCD_D15_Pin;
GPIOD->BSRR = gpiod_set;
GPIOD->BSRR = (uint32_t)gpiod_reset << 16u;
if(val&(1<<4))//GPIOE 7
gpioe_set|=LCD_D4_Pin;
else
gpioe_reset|=LCD_D4_Pin;
if(val&(1<<5))//GPIOE 8
gpioe_set|=LCD_D5_Pin;
else
gpioe_reset|=LCD_D5_Pin;
if(val&(1<<6))//GPIOE 9
gpioe_set|=LCD_D6_Pin;
else
gpioe_reset|=LCD_D6_Pin;
if(val&(1<<7))//GPIOE 10
gpioe_set|=LCD_D7_Pin;
else
gpioe_reset|=LCD_D7_Pin;
if(val&(1<<8))//GPIOE 11
gpioe_set|=LCD_D8_Pin;
else
gpioe_reset|=LCD_D8_Pin;
if(val&(1<<9))//GPIOE 12
gpioe_set|=LCD_D9_Pin;
else
gpioe_reset|=LCD_D9_Pin;
if(val&(1<<10))//GPIOE 13
gpioe_set|=LCD_D10_Pin;
else
gpioe_reset|=LCD_D10_Pin;
if(val&(1<<11))//GPIOE 14
gpioe_set|=LCD_D11_Pin;
else
gpioe_reset|=LCD_D11_Pin;
if(val&(1<<12))//GPIOE 15
gpioe_set|=LCD_D12_Pin;
else
gpioe_reset|=LCD_D12_Pin;
GPIOE->BSRR = gpioe_set;
GPIOE->BSRR = (uint32_t)gpioe_reset << 16u;
}
CS,RS等功能引脚就直接通过HAL库函数操作寄存器就行
set_data_val函数按照传入的16bit数据,操作16个数据GPIO引脚的高低电平,前面测试过,倘若每个引脚都调用一次HAL_GPIO_WritePin函数,则屏幕刷新速度将会慢到一个很离谱的地步,所有后面改了一下直接操作寄存器得了,好歹提了一点速度。
这里也补上旧版本set_data_val可做对比测试
void set_data_val(uint16_t val)
{
if(val&(1<<0))//GPIOD 14
HAL_GPIO_WritePin(LCD_D0_GPIO_Port,LCD_D0_Pin,GPIO_PIN_SET);
else
HAL_GPIO_WritePin(LCD_D0_GPIO_Port,LCD_D0_Pin,GPIO_PIN_RESET);
if(val&(1<<1))//GPIOD 15
HAL_GPIO_WritePin(LCD_D1_GPIO_Port,LCD_D1_Pin,GPIO_PIN_SET);
else
HAL_GPIO_WritePin(LCD_D1_GPIO_Port,LCD_D1_Pin,GPIO_PIN_RESET);
if(val&(1<<2))//GPIOD 0
HAL_GPIO_WritePin(LCD_D2_GPIO_Port,LCD_D2_Pin,GPIO_PIN_SET);
else
HAL_GPIO_WritePin(LCD_D2_GPIO_Port,LCD_D2_Pin,GPIO_PIN_RESET);
if(val&(1<<3))//GPIOD 1
HAL_GPIO_WritePin(LCD_D3_GPIO_Port,LCD_D3_Pin,GPIO_PIN_SET);
else
HAL_GPIO_WritePin(LCD_D3_GPIO_Port,LCD_D3_Pin,GPIO_PIN_RESET);
if(val&(1<<13))////GPIOD 8
HAL_GPIO_WritePin(LCD_D13_GPIO_Port,LCD_D13_Pin,GPIO_PIN_SET);
else
HAL_GPIO_WritePin(LCD_D13_GPIO_Port,LCD_D13_Pin,GPIO_PIN_RESET);
if(val&(1<<14))//GPIOD 9
HAL_GPIO_WritePin(LCD_D14_GPIO_Port,LCD_D14_Pin,GPIO_PIN_SET);
else
HAL_GPIO_WritePin(LCD_D14_GPIO_Port,LCD_D14_Pin,GPIO_PIN_RESET);
if(val&(1<<15))////GPIOD 10
HAL_GPIO_WritePin(LCD_D15_GPIO_Port,LCD_D15_Pin,GPIO_PIN_SET);
else
HAL_GPIO_WritePin(LCD_D15_GPIO_Port,LCD_D15_Pin,GPIO_PIN_RESET);
if(val&(1<<4))//GPIOE 7
HAL_GPIO_WritePin(LCD_D4_GPIO_Port,LCD_D4_Pin,GPIO_PIN_SET);
else
HAL_GPIO_WritePin(LCD_D4_GPIO_Port,LCD_D4_Pin,GPIO_PIN_RESET);
if(val&(1<<5))//GPIOE 8
HAL_GPIO_WritePin(LCD_D5_GPIO_Port,LCD_D5_Pin,GPIO_PIN_SET);
else
HAL_GPIO_WritePin(LCD_D5_GPIO_Port,LCD_D5_Pin,GPIO_PIN_RESET);
if(val&(1<<6))//GPIOE 9
HAL_GPIO_WritePin(LCD_D6_GPIO_Port,LCD_D6_Pin,GPIO_PIN_SET);
else
HAL_GPIO_WritePin(LCD_D6_GPIO_Port,LCD_D6_Pin,GPIO_PIN_RESET);
if(val&(1<<7))//GPIOE 10
HAL_GPIO_WritePin(LCD_D7_GPIO_Port,LCD_D7_Pin,GPIO_PIN_SET);
else
HAL_GPIO_WritePin(LCD_D7_GPIO_Port,LCD_D7_Pin,GPIO_PIN_RESET);
if(val&(1<<8))//GPIOE 11
HAL_GPIO_WritePin(LCD_D8_GPIO_Port,LCD_D8_Pin,GPIO_PIN_SET);
else
HAL_GPIO_WritePin(LCD_D8_GPIO_Port,LCD_D8_Pin,GPIO_PIN_RESET);
if(val&(1<<9))//GPIOE 12
HAL_GPIO_WritePin(LCD_D9_GPIO_Port,LCD_D9_Pin,GPIO_PIN_SET);
else
HAL_GPIO_WritePin(LCD_D9_GPIO_Port,LCD_D9_Pin,GPIO_PIN_RESET);
if(val&(1<<10))//GPIOE 13
HAL_GPIO_WritePin(LCD_D10_GPIO_Port,LCD_D10_Pin,GPIO_PIN_SET);
else
HAL_GPIO_WritePin(LCD_D10_GPIO_Port,LCD_D10_Pin,GPIO_PIN_RESET);
if(val&(1<<11))//GPIOE 14
HAL_GPIO_WritePin(LCD_D11_GPIO_Port,LCD_D11_Pin,GPIO_PIN_SET);
else
HAL_GPIO_WritePin(LCD_D11_GPIO_Port,LCD_D11_Pin,GPIO_PIN_RESET);
if(val&(1<<12))//GPIOE 15
HAL_GPIO_WritePin(LCD_D12_GPIO_Port,LCD_D12_Pin,GPIO_PIN_SET);
else
HAL_GPIO_WritePin(LCD_D12_GPIO_Port,LCD_D12_Pin,GPIO_PIN_RESET);
}
然后参考序号二时序分析的内容来实现GPIO发送命令和发送数据函数的编写
//写命令
void lcd_wr_regno(volatile uint16_t regno)
{
//CS片选拉低
set_LCD_CS_Pin(0);
//RS拉低
set_LCD_RS_Pin(0);
//WR拉低
set_LCD_WR_Pin(0);
//数据设置
set_data_val(regno);
//WR拉高
set_LCD_WR_Pin(1);
set_LCD_CS_Pin(1);
}
//写数据
void lcd_wr_data(volatile uint16_t data)
{
//CS片选拉低
set_LCD_CS_Pin(0);
//RS拉高
set_LCD_RS_Pin(1);
//WR拉低
set_LCD_WR_Pin(0);
//数据设置
set_data_val(data);
//WR拉高
set_LCD_WR_Pin(1);
set_LCD_CS_Pin(1);
}
至此要字节纯粹手搓的部分都写完了,剩下的就是移植正点原子的屏幕代码框架
五、正点原子TFT屏幕驱动移植
这里我们只关注NT35310部分的代码即可
移植LCD的初始化函数
这一部分一般由屏厂提供,我们只需要移植即可,其中都对屏幕启动的一些基本功能的设置。
将例程里的
/**
* @brief NT35310寄存器初始化代码
* @param 无
* @retval 无
*/
void lcd_ex_nt35310_reginit(void)
函数移植到自己写好部分屏幕驱动的工程之中,将其命名为LCD_init。
void LCD_init()
{
lcd_wr_regno(0xED);
lcd_wr_data(0x01);
lcd_wr_data(0xFE);
lcd_wr_regno(0xEE);
lcd_wr_data(0xDE);
lcd_wr_data(0x21);
lcd_wr_regno(0xF1);
lcd_wr_data(0x01);
lcd_wr_regno(0xDF);
lcd_wr_data(0x10);
/* VCOMvoltage */
lcd_wr_regno(0xC4);
lcd_wr_data(0x8F); /* 5f */
lcd_wr_regno(0xC6);
lcd_wr_data(0x00);
lcd_wr_data(0xE2);
lcd_wr_data(0xE2);
lcd_wr_data(0xE2);
lcd_wr_regno(0xBF);
lcd_wr_data(0xAA);
lcd_wr_regno(0xB0);
lcd_wr_data(0x0D);
lcd_wr_data(0x00);
lcd_wr_data(0x0D);
lcd_wr_data(0x00);
lcd_wr_data(0x11);
lcd_wr_data(0x00);
lcd_wr_data(0x19);
lcd_wr_data(0x00);
lcd_wr_data(0x21);
lcd_wr_data(0x00);
lcd_wr_data(0x2D);
lcd_wr_data(0x00);
lcd_wr_data(0x3D);
lcd_wr_data(0x00);
lcd_wr_data(0x5D);
lcd_wr_data(0x00);
lcd_wr_data(0x5D);
lcd_wr_data(0x00);
lcd_wr_regno(0xB1);
lcd_wr_data(0x80);
lcd_wr_data(0x00);
lcd_wr_data(0x8B);
lcd_wr_data(0x00);
lcd_wr_data(0x96);
lcd_wr_data(0x00);
lcd_wr_regno(0xB2);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x02);
lcd_wr_data(0x00);
lcd_wr_data(0x03);
lcd_wr_data(0x00);
lcd_wr_regno(0xB3);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_regno(0xB4);
lcd_wr_data(0x8B);
lcd_wr_data(0x00);
lcd_wr_data(0x96);
lcd_wr_data(0x00);
lcd_wr_data(0xA1);
lcd_wr_data(0x00);
lcd_wr_regno(0xB5);
lcd_wr_data(0x02);
lcd_wr_data(0x00);
lcd_wr_data(0x03);
lcd_wr_data(0x00);
lcd_wr_data(0x04);
lcd_wr_data(0x00);
lcd_wr_regno(0xB6);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_regno(0xB7);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x3F);
lcd_wr_data(0x00);
lcd_wr_data(0x5E);
lcd_wr_data(0x00);
lcd_wr_data(0x64);
lcd_wr_data(0x00);
lcd_wr_data(0x8C);
lcd_wr_data(0x00);
lcd_wr_data(0xAC);
lcd_wr_data(0x00);
lcd_wr_data(0xDC);
lcd_wr_data(0x00);
lcd_wr_data(0x70);
lcd_wr_data(0x00);
lcd_wr_data(0x90);
lcd_wr_data(0x00);
lcd_wr_data(0xEB);
lcd_wr_data(0x00);
lcd_wr_data(0xDC);
lcd_wr_data(0x00);
lcd_wr_regno(0xB8);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_regno(0xBA);
lcd_wr_data(0x24);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_regno(0xC1);
lcd_wr_data(0x20);
lcd_wr_data(0x00);
lcd_wr_data(0x54);
lcd_wr_data(0x00);
lcd_wr_data(0xFF);
lcd_wr_data(0x00);
lcd_wr_regno(0xC2);
lcd_wr_data(0x0A);
lcd_wr_data(0x00);
lcd_wr_data(0x04);
lcd_wr_data(0x00);
lcd_wr_regno(0xC3);
lcd_wr_data(0x3C);
lcd_wr_data(0x00);
lcd_wr_data(0x3A);
lcd_wr_data(0x00);
lcd_wr_data(0x39);
lcd_wr_data(0x00);
lcd_wr_data(0x37);
lcd_wr_data(0x00);
lcd_wr_data(0x3C);
lcd_wr_data(0x00);
lcd_wr_data(0x36);
lcd_wr_data(0x00);
lcd_wr_data(0x32);
lcd_wr_data(0x00);
lcd_wr_data(0x2F);
lcd_wr_data(0x00);
lcd_wr_data(0x2C);
lcd_wr_data(0x00);
lcd_wr_data(0x29);
lcd_wr_data(0x00);
lcd_wr_data(0x26);
lcd_wr_data(0x00);
lcd_wr_data(0x24);
lcd_wr_data(0x00);
lcd_wr_data(0x24);
lcd_wr_data(0x00);
lcd_wr_data(0x23);
lcd_wr_data(0x00);
lcd_wr_data(0x3C);
lcd_wr_data(0x00);
lcd_wr_data(0x36);
lcd_wr_data(0x00);
lcd_wr_data(0x32);
lcd_wr_data(0x00);
lcd_wr_data(0x2F);
lcd_wr_data(0x00);
lcd_wr_data(0x2C);
lcd_wr_data(0x00);
lcd_wr_data(0x29);
lcd_wr_data(0x00);
lcd_wr_data(0x26);
lcd_wr_data(0x00);
lcd_wr_data(0x24);
lcd_wr_data(0x00);
lcd_wr_data(0x24);
lcd_wr_data(0x00);
lcd_wr_data(0x23);
lcd_wr_data(0x00);
lcd_wr_regno(0xC4);
lcd_wr_data(0x62);
lcd_wr_data(0x00);
lcd_wr_data(0x05);
lcd_wr_data(0x00);
lcd_wr_data(0x84);
lcd_wr_data(0x00);
lcd_wr_data(0xF0);
lcd_wr_data(0x00);
lcd_wr_data(0x18);
lcd_wr_data(0x00);
lcd_wr_data(0xA4);
lcd_wr_data(0x00);
lcd_wr_data(0x18);
lcd_wr_data(0x00);
lcd_wr_data(0x50);
lcd_wr_data(0x00);
lcd_wr_data(0x0C);
lcd_wr_data(0x00);
lcd_wr_data(0x17);
lcd_wr_data(0x00);
lcd_wr_data(0x95);
lcd_wr_data(0x00);
lcd_wr_data(0xF3);
lcd_wr_data(0x00);
lcd_wr_data(0xE6);
lcd_wr_data(0x00);
lcd_wr_regno(0xC5);
lcd_wr_data(0x32);
lcd_wr_data(0x00);
lcd_wr_data(0x44);
lcd_wr_data(0x00);
lcd_wr_data(0x65);
lcd_wr_data(0x00);
lcd_wr_data(0x76);
lcd_wr_data(0x00);
lcd_wr_data(0x88);
lcd_wr_data(0x00);
lcd_wr_regno(0xC6);
lcd_wr_data(0x20);
lcd_wr_data(0x00);
lcd_wr_data(0x17);
lcd_wr_data(0x00);
lcd_wr_data(0x01);
lcd_wr_data(0x00);
lcd_wr_regno(0xC7);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_regno(0xC8);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_regno(0xC9);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_regno(0xE0);
lcd_wr_data(0x16);
lcd_wr_data(0x00);
lcd_wr_data(0x1C);
lcd_wr_data(0x00);
lcd_wr_data(0x21);
lcd_wr_data(0x00);
lcd_wr_data(0x36);
lcd_wr_data(0x00);
lcd_wr_data(0x46);
lcd_wr_data(0x00);
lcd_wr_data(0x52);
lcd_wr_data(0x00);
lcd_wr_data(0x64);
lcd_wr_data(0x00);
lcd_wr_data(0x7A);
lcd_wr_data(0x00);
lcd_wr_data(0x8B);
lcd_wr_data(0x00);
lcd_wr_data(0x99);
lcd_wr_data(0x00);
lcd_wr_data(0xA8);
lcd_wr_data(0x00);
lcd_wr_data(0xB9);
lcd_wr_data(0x00);
lcd_wr_data(0xC4);
lcd_wr_data(0x00);
lcd_wr_data(0xCA);
lcd_wr_data(0x00);
lcd_wr_data(0xD2);
lcd_wr_data(0x00);
lcd_wr_data(0xD9);
lcd_wr_data(0x00);
lcd_wr_data(0xE0);
lcd_wr_data(0x00);
lcd_wr_data(0xF3);
lcd_wr_data(0x00);
lcd_wr_regno(0xE1);
lcd_wr_data(0x16);
lcd_wr_data(0x00);
lcd_wr_data(0x1C);
lcd_wr_data(0x00);
lcd_wr_data(0x22);
lcd_wr_data(0x00);
lcd_wr_data(0x36);
lcd_wr_data(0x00);
lcd_wr_data(0x45);
lcd_wr_data(0x00);
lcd_wr_data(0x52);
lcd_wr_data(0x00);
lcd_wr_data(0x64);
lcd_wr_data(0x00);
lcd_wr_data(0x7A);
lcd_wr_data(0x00);
lcd_wr_data(0x8B);
lcd_wr_data(0x00);
lcd_wr_data(0x99);
lcd_wr_data(0x00);
lcd_wr_data(0xA8);
lcd_wr_data(0x00);
lcd_wr_data(0xB9);
lcd_wr_data(0x00);
lcd_wr_data(0xC4);
lcd_wr_data(0x00);
lcd_wr_data(0xCA);
lcd_wr_data(0x00);
lcd_wr_data(0xD2);
lcd_wr_data(0x00);
lcd_wr_data(0xD8);
lcd_wr_data(0x00);
lcd_wr_data(0xE0);
lcd_wr_data(0x00);
lcd_wr_data(0xF3);
lcd_wr_data(0x00);
lcd_wr_regno(0xE2);
lcd_wr_data(0x05);
lcd_wr_data(0x00);
lcd_wr_data(0x0B);
lcd_wr_data(0x00);
lcd_wr_data(0x1B);
lcd_wr_data(0x00);
lcd_wr_data(0x34);
lcd_wr_data(0x00);
lcd_wr_data(0x44);
lcd_wr_data(0x00);
lcd_wr_data(0x4F);
lcd_wr_data(0x00);
lcd_wr_data(0x61);
lcd_wr_data(0x00);
lcd_wr_data(0x79);
lcd_wr_data(0x00);
lcd_wr_data(0x88);
lcd_wr_data(0x00);
lcd_wr_data(0x97);
lcd_wr_data(0x00);
lcd_wr_data(0xA6);
lcd_wr_data(0x00);
lcd_wr_data(0xB7);
lcd_wr_data(0x00);
lcd_wr_data(0xC2);
lcd_wr_data(0x00);
lcd_wr_data(0xC7);
lcd_wr_data(0x00);
lcd_wr_data(0xD1);
lcd_wr_data(0x00);
lcd_wr_data(0xD6);
lcd_wr_data(0x00);
lcd_wr_data(0xDD);
lcd_wr_data(0x00);
lcd_wr_data(0xF3);
lcd_wr_data(0x00);
lcd_wr_regno(0xE3);
lcd_wr_data(0x05);
lcd_wr_data(0x00);
lcd_wr_data(0xA);
lcd_wr_data(0x00);
lcd_wr_data(0x1C);
lcd_wr_data(0x00);
lcd_wr_data(0x33);
lcd_wr_data(0x00);
lcd_wr_data(0x44);
lcd_wr_data(0x00);
lcd_wr_data(0x50);
lcd_wr_data(0x00);
lcd_wr_data(0x62);
lcd_wr_data(0x00);
lcd_wr_data(0x78);
lcd_wr_data(0x00);
lcd_wr_data(0x88);
lcd_wr_data(0x00);
lcd_wr_data(0x97);
lcd_wr_data(0x00);
lcd_wr_data(0xA6);
lcd_wr_data(0x00);
lcd_wr_data(0xB7);
lcd_wr_data(0x00);
lcd_wr_data(0xC2);
lcd_wr_data(0x00);
lcd_wr_data(0xC7);
lcd_wr_data(0x00);
lcd_wr_data(0xD1);
lcd_wr_data(0x00);
lcd_wr_data(0xD5);
lcd_wr_data(0x00);
lcd_wr_data(0xDD);
lcd_wr_data(0x00);
lcd_wr_data(0xF3);
lcd_wr_data(0x00);
lcd_wr_regno(0xE4);
lcd_wr_data(0x01);
lcd_wr_data(0x00);
lcd_wr_data(0x01);
lcd_wr_data(0x00);
lcd_wr_data(0x02);
lcd_wr_data(0x00);
lcd_wr_data(0x2A);
lcd_wr_data(0x00);
lcd_wr_data(0x3C);
lcd_wr_data(0x00);
lcd_wr_data(0x4B);
lcd_wr_data(0x00);
lcd_wr_data(0x5D);
lcd_wr_data(0x00);
lcd_wr_data(0x74);
lcd_wr_data(0x00);
lcd_wr_data(0x84);
lcd_wr_data(0x00);
lcd_wr_data(0x93);
lcd_wr_data(0x00);
lcd_wr_data(0xA2);
lcd_wr_data(0x00);
lcd_wr_data(0xB3);
lcd_wr_data(0x00);
lcd_wr_data(0xBE);
lcd_wr_data(0x00);
lcd_wr_data(0xC4);
lcd_wr_data(0x00);
lcd_wr_data(0xCD);
lcd_wr_data(0x00);
lcd_wr_data(0xD3);
lcd_wr_data(0x00);
lcd_wr_data(0xDD);
lcd_wr_data(0x00);
lcd_wr_data(0xF3);
lcd_wr_data(0x00);
lcd_wr_regno(0xE5);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x02);
lcd_wr_data(0x00);
lcd_wr_data(0x29);
lcd_wr_data(0x00);
lcd_wr_data(0x3C);
lcd_wr_data(0x00);
lcd_wr_data(0x4B);
lcd_wr_data(0x00);
lcd_wr_data(0x5D);
lcd_wr_data(0x00);
lcd_wr_data(0x74);
lcd_wr_data(0x00);
lcd_wr_data(0x84);
lcd_wr_data(0x00);
lcd_wr_data(0x93);
lcd_wr_data(0x00);
lcd_wr_data(0xA2);
lcd_wr_data(0x00);
lcd_wr_data(0xB3);
lcd_wr_data(0x00);
lcd_wr_data(0xBE);
lcd_wr_data(0x00);
lcd_wr_data(0xC4);
lcd_wr_data(0x00);
lcd_wr_data(0xCD);
lcd_wr_data(0x00);
lcd_wr_data(0xD3);
lcd_wr_data(0x00);
lcd_wr_data(0xDC);
lcd_wr_data(0x00);
lcd_wr_data(0xF3);
lcd_wr_data(0x00);
lcd_wr_regno(0xE6);
lcd_wr_data(0x11);
lcd_wr_data(0x00);
lcd_wr_data(0x34);
lcd_wr_data(0x00);
lcd_wr_data(0x56);
lcd_wr_data(0x00);
lcd_wr_data(0x76);
lcd_wr_data(0x00);
lcd_wr_data(0x77);
lcd_wr_data(0x00);
lcd_wr_data(0x66);
lcd_wr_data(0x00);
lcd_wr_data(0x88);
lcd_wr_data(0x00);
lcd_wr_data(0x99);
lcd_wr_data(0x00);
lcd_wr_data(0xBB);
lcd_wr_data(0x00);
lcd_wr_data(0x99);
lcd_wr_data(0x00);
lcd_wr_data(0x66);
lcd_wr_data(0x00);
lcd_wr_data(0x55);
lcd_wr_data(0x00);
lcd_wr_data(0x55);
lcd_wr_data(0x00);
lcd_wr_data(0x45);
lcd_wr_data(0x00);
lcd_wr_data(0x43);
lcd_wr_data(0x00);
lcd_wr_data(0x44);
lcd_wr_data(0x00);
lcd_wr_regno(0xE7);
lcd_wr_data(0x32);
lcd_wr_data(0x00);
lcd_wr_data(0x55);
lcd_wr_data(0x00);
lcd_wr_data(0x76);
lcd_wr_data(0x00);
lcd_wr_data(0x66);
lcd_wr_data(0x00);
lcd_wr_data(0x67);
lcd_wr_data(0x00);
lcd_wr_data(0x67);
lcd_wr_data(0x00);
lcd_wr_data(0x87);
lcd_wr_data(0x00);
lcd_wr_data(0x99);
lcd_wr_data(0x00);
lcd_wr_data(0xBB);
lcd_wr_data(0x00);
lcd_wr_data(0x99);
lcd_wr_data(0x00);
lcd_wr_data(0x77);
lcd_wr_data(0x00);
lcd_wr_data(0x44);
lcd_wr_data(0x00);
lcd_wr_data(0x56);
lcd_wr_data(0x00);
lcd_wr_data(0x23);
lcd_wr_data(0x00);
lcd_wr_data(0x33);
lcd_wr_data(0x00);
lcd_wr_data(0x45);
lcd_wr_data(0x00);
lcd_wr_regno(0xE8);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x99);
lcd_wr_data(0x00);
lcd_wr_data(0x87);
lcd_wr_data(0x00);
lcd_wr_data(0x88);
lcd_wr_data(0x00);
lcd_wr_data(0x77);
lcd_wr_data(0x00);
lcd_wr_data(0x66);
lcd_wr_data(0x00);
lcd_wr_data(0x88);
lcd_wr_data(0x00);
lcd_wr_data(0xAA);
lcd_wr_data(0x00);
lcd_wr_data(0xBB);
lcd_wr_data(0x00);
lcd_wr_data(0x99);
lcd_wr_data(0x00);
lcd_wr_data(0x66);
lcd_wr_data(0x00);
lcd_wr_data(0x55);
lcd_wr_data(0x00);
lcd_wr_data(0x55);
lcd_wr_data(0x00);
lcd_wr_data(0x44);
lcd_wr_data(0x00);
lcd_wr_data(0x44);
lcd_wr_data(0x00);
lcd_wr_data(0x55);
lcd_wr_data(0x00);
lcd_wr_regno(0xE9);
lcd_wr_data(0xAA);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_regno(0x00);
lcd_wr_data(0xAA);
lcd_wr_regno(0xCF);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_regno(0xF0);
lcd_wr_data(0x00);
lcd_wr_data(0x50);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_data(0x00);
lcd_wr_regno(0xF3);
lcd_wr_data(0x00);
lcd_wr_regno(0xF9);
lcd_wr_data(0x06);
lcd_wr_data(0x10);
lcd_wr_data(0x29);
lcd_wr_data(0x00);
lcd_wr_regno(0x3A);
lcd_wr_data(0x55); /* 66 */
lcd_wr_regno(0x11);
HAL_Delay(100);
lcd_wr_regno(0x29);
lcd_wr_regno(0x35);
lcd_wr_data(0x00);
lcd_wr_regno(0x51);
lcd_wr_data(0xFF);
lcd_wr_regno(0x53);
lcd_wr_data(0x2C);
lcd_wr_regno(0x55);
lcd_wr_data(0x82);
lcd_wr_regno(0x2c);
}
上面的初始化程序主要调用lcd_wr_regno(0xF1); lcd_wr_data(0x01);两个函数,而这两个函数已经在四中实现。
移植页刷新函数
正点原子例程代码烧录进去后屏幕会不停刷新背景颜色,其相关函数为lcd_clear(BLUE)
这个函数按照传入的颜色宏定义将屏幕上所有像素点刷新成对应的颜色。
进去后逐层解析分析可得程序逻辑为:
1. 计算得出屏幕像素点个数
2. 0x2A设置X坐标
3. 0x2B设置Y坐标
4. 0x2C发送像素数据
正点原子例程通过不同的液晶显示控制器通过读ID,设置了每个控制器所对应的XY坐标设置命令和数据发送命令,NT35310的控制指令是2A2B2C,其他型号控制器需要自己判断修改一下。
代码移植到自己的工程中:
void LCD_Show_OngPage(uint16_t color)
{
//lcddev.width = 320;
//lcddev.height = 480;
//lcddev.wramcmd = 0X2C;
//lcddev.setxcmd = 0X2A;
//lcddev.setycmd = 0X2B;
uint32_t index = 0;
uint32_t totalpoint = 320;//lcddev.width;
totalpoint *= 480; /* 得到总点数 */
lcd_wr_regno(0X2A);
lcd_wr_data(0 >> 8);
lcd_wr_data(0 & 0XFF);
lcd_wr_regno(0X2B);
lcd_wr_data(0 >> 8);
lcd_wr_data(0 & 0XFF);
lcd_wr_regno(0X2C);
for (index = 0; index < totalpoint; index++)
{
lcd_wr_data(color);
}
}
至此移植大功告成,然后就是驱动调用了
六、屏幕展示
main函数中执行LCD初始化,背光点亮,RD引脚配置,然后进行屏幕刷新即可
/* 常用画笔颜色 */
#define WHITE 0xFFFF /* 白色 */
#define BLACK 0x0000 /* 黑色 */
#define RED 0xF800 /* 红色 */
#define GREEN 0x07E0 /* 绿色 */
#define BLUE 0x001F /* 蓝色 */
#define MAGENTA 0XF81F /* 品红色/紫红色 = BLUE + RED */
#define YELLOW 0XFFE0 /* 黄色 = GREEN + RED */
#define CYAN 0X07FF /* 青色 = GREEN + BLUE */
/* 非常用颜色 */
#define BROWN 0XBC40 /* 棕色 */
#define BRRED 0XFC07 /* 棕红色 */
#define GRAY 0X8430 /* 灰色 */
#define DARKBLUE 0X01CF /* 深蓝色 */
#define LIGHTBLUE 0X7D7C /* 浅蓝色 */
#define GRAYBLUE 0X5458 /* 灰蓝色 */
#define LIGHTGREEN 0X841F /* 浅绿色 */
#define LGRAY 0XC618 /* 浅灰色(PANNEL),窗体背景色 */
#define LGRAYBLUE 0XA651 /* 浅灰蓝色(中间层颜色) */
#define LBBLUE 0X2B12 /* 浅棕蓝色(选择条目的反色) */
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
HAL_Delay(100);
set_LCD_RD_Pin(1);
LCD_init();
set_LCD_BL_Pin(1);
uint8_t x = 0;
while (1)
{
switch (x)
{
case 0:
LCD_Show_OngPage(WHITE);
break;
case 1:
LCD_Show_OngPage(BLACK);
break;
case 2:
LCD_Show_OngPage(BLUE);
break;
case 3:
LCD_Show_OngPage(RED);
break;
case 4:
LCD_Show_OngPage(MAGENTA);
break;
case 5:
LCD_Show_OngPage(GREEN);
break;
case 6:
LCD_Show_OngPage(CYAN);
break;
case 7:
LCD_Show_OngPage(YELLOW);
break;
case 8:
LCD_Show_OngPage(BRRED);
break;
case 9:
LCD_Show_OngPage(GRAY);
break;
case 10:
LCD_Show_OngPage(LGRAY);
break;
case 11:
LCD_Show_OngPage(BROWN);
break;
}
x++;
if (x == 12)
x = 0;
}
}
这里讲一下
首先需要进行一个100ms延时,应该是刚刚上电,时钟或者什么东西不稳定,如果没有这个延时有可能造成LCD_INIT函数执行GPIO引脚控制时序不稳定造成初始化失败,这个问题也是困扰我好久才发现的,我一直以为是我引脚控制时序不对排查了两天,就很离谱。
然后是RD引脚拉高,因为我们用不到读命令,所有这个RD引脚一直拉高即可
初始化完成后打开背光引脚屏幕。
然后就调用LCD_Show_OngPage函数执行页面刷新
效果如图所示

更多推荐



所有评论(0)