前言
显示屏作为人机交互的一个重要窗口,在各类电子产品中被广泛地应用。在同类产品中,一个好的人机界面设计往往能更加吸引用户的目光。而显示器作为其载体,同样也是不可或缺的存在。作为一名嵌入式软件工程师,屏驱和人机界面的开发在我们的工作中是经常会遇到的,掌握此项技能也是必不可少的。本文主要基于HC32F460,简单介绍 spi屏驱的开发。
一、硬件介绍
这里我使用的屏是之前在某宝上淘来的带SPI接口通讯的TFT彩屏,下面是该屏的部分资料说明
接口定义
二、驱动代码实现
1.IO模拟SPI驱动
关于驱动部分,卖家也给了一些不同平台下的驱动例程,这些例程都是通过IO口模拟SPI的时序来驱动lcd屏的。移植到HC平台,很快就顺利点亮lcd屏。
代码如下:
/* Define port and pin for SDA and SCL */
#define SPI_SCK_PORT (PortD)
#define SPI_SCK_PIN (Pin00)
#define SPI_MOSI_PORT (PortD)
#define SPI_MOSI_PIN (Pin01)
/* RES Port/Pin definition */
#define RES_PORT (PortE)
#define RES_PIN (Pin09)
/* DC Port/Pin definition */
#define DC_PORT (PortE)
#define DC_PIN (Pin11)
/* BLK Port/Pin definition */
#define BLK_PORT (PortE)
#define BLK_PIN (Pin13)
//-----------------LCD端口定义----------------
#define LCD_SCLK_Clr() M4_PORT->PORRD |= SPI_SCK_PIN //SCL=SCLK
#define LCD_SCLK_Set() M4_PORT->POSRD |= SPI_SCK_PIN
#define LCD_MOSI_Clr() M4_PORT->PORRD |= SPI_MOSI_PIN //SDA=MOSI
#define LCD_MOSI_Set() M4_PORT->POSRD |= SPI_MOSI_PIN
#define LCD_RES_Clr() M4_PORT->PORRE |= RES_PIN //RES
#define LCD_RES_Set() M4_PORT->POSRE |= RES_PIN
#define LCD_DC_Clr() M4_PORT->PORRE |= DC_PIN //DC
#define LCD_DC_Set() M4_PORT->POSRE |= DC_PIN
#define LCD_BLK_Clr() PORT_ResetBits(BLK_PORT, BLK_PIN) //BLK
#define LCD_BLK_Set() PORT_SetBits(BLK_PORT, BLK_PIN)
void LCD_GPIO_Init(void)
{
stc_port_init_t stcPortInit;
/* configuration structure initialization */
MEM_ZERO_STRUCT(stcPortInit);
stcPortInit.enPinMode = Pin_Mode_Out;
/* SCL Port/Pin initialization */
LCD_SCLK_Clr();
PORT_Init(SPI_SCK_PORT, SPI_SCK_PIN, &stcPortInit);
/* SDA Port/Pin initialization */
LCD_MOSI_Clr();
PORT_Init(SPI_MOSI_PORT, SPI_MOSI_PIN, &stcPortInit);
/* RES Port/Pin initialization */
LCD_RES_Clr();
PORT_Init(RES_PORT, RES_PIN, &stcPortInit);
/* DC Port/Pin initialization */
LCD_DC_Clr();
PORT_Init(DC_PORT, DC_PIN, &stcPortInit);
/* BLK Port/Pin initialization */
LCD_BLK_Clr();
PORT_Init(BLK_PORT, BLK_PIN, &stcPortInit);
}
/******************************************************************************
函数说明:LCD串行数据写入函数
入口数据:dat 要写入的串行数据
返回值: 无
******************************************************************************/
void LCD_Writ_Bus(uint8_t dat)
{
uint8_t counter;
for(counter=0; counter<8; counter++)
{
LCD_SCLK_Clr();
if((dat&0x80)==0)
{
LCD_MOSI_Clr();
}
else
{
LCD_MOSI_Set();
}
dat=dat<<1;
LCD_SCLK_Set();
}
LCD_SCLK_Clr();
}
/******************************************************************************
函数说明:LCD写入数据
入口数据:dat 写入的数据
返回值: 无
******************************************************************************/
void LCD_WR_DATA8(uint8_t dat)
{
LCD_DC_Set();
LCD_Writ_Bus(dat);
}
/******************************************************************************
函数说明:LCD写入数据
入口数据:dat 写入的数据
返回值: 无
******************************************************************************/
void LCD_WR_DATA(uint16_t dat)
{
LCD_WR_DATA8(dat>>8);
LCD_WR_DATA8(dat);
}
/******************************************************************************
函数说明:LCD写入命令
入口数据:dat 写入的命令
返回值: 无
******************************************************************************/
void LCD_WR_REG(uint8_t dat)
{
LCD_DC_Clr();
LCD_Writ_Bus(dat);
}
/******************************************************************************
函数说明:设置起始和结束地址
入口数据:x1,x2 设置列的起始和结束地址
y1,y2 设置行的起始和结束地址
返回值: 无
******************************************************************************/
void LCD_Address_Set(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2)
{
LCD_WR_REG(0x2a); //Column address set
LCD_WR_DATA(x1); //start column
LCD_WR_DATA(x2); //end column
LCD_WR_REG(0x2b); //Row address set
LCD_WR_DATA(y1); //start row
LCD_WR_DATA(y2); //end row
LCD_WR_REG(0x2C); //Memory write
}
void LCD_Init(void)
{
LCD_GPIO_Init();//初始化GPIO
LCD_RES_Clr();
Ddl_Delay1ms(120);
LCD_RES_Set();
Ddl_Delay1ms(120);
LCD_SCLK_Set(); //特别注意!!
LCD_WR_REG(0x11); //Sleep Out
Ddl_Delay1ms(120); //DELAY120ms
//-----------------------ST7789V Frame rate setting-----------------//
//************************************************
LCD_WR_REG(0x3A); //65k mode
LCD_WR_DATA8(0x05);
LCD_WR_REG(0xC5); //VCOM
LCD_WR_DATA8(0x1A);
LCD_WR_REG(0x36); // 屏幕显示方向设置
LCD_WR_DATA8(0x00);
//-------------ST7789V Frame rate setting-----------//
LCD_WR_REG(0xb2); //Porch Setting
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x33);
LCD_WR_DATA8(0x33);
LCD_WR_REG(0xb7); //Gate Control
LCD_WR_DATA8(0x05); //12.2v -10.43v
//--------------ST7789V Power setting---------------//
LCD_WR_REG(0xBB);//VCOM
LCD_WR_DATA8(0x3F);
LCD_WR_REG(0xC0); //Power control
LCD_WR_DATA8(0x2c);
LCD_WR_REG(0xC2); //VDV and VRH Command Enable
LCD_WR_DATA8(0x01);
LCD_WR_REG(0xC3); //VRH Set
LCD_WR_DATA8(0x0F); //4.3+( vcom+vcom offset+vdv)
LCD_WR_REG(0xC4); //VDV Set
LCD_WR_DATA8(0x20); //0v
LCD_WR_REG(0xC6); //Frame Rate Control in Normal Mode
LCD_WR_DATA8(0X01); //111Hz
LCD_WR_REG(0xd0); //Power Control 1
LCD_WR_DATA8(0xa4);
LCD_WR_DATA8(0xa1);
LCD_WR_REG(0xE8); //Power Control 1
LCD_WR_DATA8(0x03);
LCD_WR_REG(0xE9); //Equalize time control
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x08);
//---------------ST7789V gamma setting-------------//
LCD_WR_REG(0xE0); //Set Gamma
LCD_WR_DATA8(0xD0);
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x08);
LCD_WR_DATA8(0x14);
LCD_WR_DATA8(0x28);
LCD_WR_DATA8(0x33);
LCD_WR_DATA8(0x3F);
LCD_WR_DATA8(0x07);
LCD_WR_DATA8(0x13);
LCD_WR_DATA8(0x14);
LCD_WR_DATA8(0x28);
LCD_WR_DATA8(0x30);
LCD_WR_REG(0XE1); //Set Gamma
LCD_WR_DATA8(0xD0);
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x08);
LCD_WR_DATA8(0x03);
LCD_WR_DATA8(0x24);
LCD_WR_DATA8(0x32);
LCD_WR_DATA8(0x32);
LCD_WR_DATA8(0x3B);
LCD_WR_DATA8(0x14);
LCD_WR_DATA8(0x13);
LCD_WR_DATA8(0x28);
LCD_WR_DATA8(0x2F);
LCD_WR_REG(0x21); //反显
LCD_WR_REG(0x29); //开启显示
}
/******************************************************************************
函数说明:在指定区域填充颜色
入口数据:xsta,ysta 起始坐标
xend,yend 终止坐标
color 要填充的颜色
返回值: 无
******************************************************************************/
void LCD_Fill(uint16_t xsta,uint16_t ysta,uint16_t xend,uint16_t yend,uint16_t color)
{
uint16_t i,j;
LCD_Address_Set(xsta,ysta,xend-1,yend-1);//设置显示范围
for(i=ysta;i<yend;i++)
{
for(j=xsta;j<xend;j++)
{
LCD_WR_DATA(color);
}
}
}
编写代码简单地刷下屏,效果如下:
虽说能成功点亮,速度也勉强能接受,但是还是很明显能看到刷屏时“拉窗帘”的现象(CSDN博客好像没办法插入小视频,只能截图了–_–|||)。
2.硬件SPI驱动
IO模拟SPI虽然能驱动LCD屏,但是刷屏速度就很明显会偏慢点,若是后续开发想利用屏幕播放一些动图(如GIF等),显示效果看起来就会很差。HC32F460本身带有4路的SPI外设,因此我们可以直接使用MCU本身的硬件SPI来驱动LCD屏,刷屏显示效果则会好很多。
代码如下:
/* RES Port/Pin definition */
#define RES_PORT (PortE)
#define RES_PIN (Pin09)
/* DC Port/Pin definition */
#define DC_PORT (PortE)
#define DC_PIN (Pin11)
/* BLK Port/Pin definition */
#define BLK_PORT (PortE)
#define BLK_PIN (Pin13)
#define LCD_RES_Clr() M4_PORT->PORRE |= RES_PIN //RES
#define LCD_RES_Set() M4_PORT->POSRE |= RES_PIN
#define LCD_DC_Clr() M4_PORT->PORRE |= DC_PIN //DC
#define LCD_DC_Set() M4_PORT->POSRE |= DC_PIN
#define LCD_BLK_Clr() PORT_ResetBits(BLK_PORT, BLK_PIN) //BLK
#define LCD_BLK_Set() PORT_SetBits(BLK_PORT, BLK_PIN)
/* SPI_SCK Port/Pin definition */
#define SPI_SCK_PORT (PortD)
#define SPI_SCK_PIN (Pin00)
#define SPI_SCK_FUNC (Func_Spi1_Sck)
/* SPI_MOSI Port/Pin definition */
#define SPI_MOSI_PORT (PortD)
#define SPI_MOSI_PIN (Pin01)
#define SPI_MOSI_FUNC (Func_Spi1_Mosi)
/* SPI unit and clock definition */
#define SPI_UNIT (M4_SPI1)
#define SPI_UNIT_CLOCK (PWC_FCG1_PERIPH_SPI1)
/* Choose SPI master or slave mode */
#define SPI_MASTER_MODE
void LCD_SPI_Write(uint8_t Data)
{
/* Send data */
SPI_SendData8(SPI_UNIT, Data);
/* Wait tx buffer empty */
while(Reset == SPI_GetFlag(SPI_UNIT, SpiFlagSendBufferEmpty));
}
void LCD_SPI_Init(void)
{
stc_spi_init_t stcSpiInit;
/* configuration structure initialization */
MEM_ZERO_STRUCT(stcSpiInit);
/* Configuration peripheral clock */
PWC_Fcg1PeriphClockCmd(SPI_UNIT_CLOCK, Enable);
/* Configuration SPI pin */
PORT_SetFunc(SPI_SCK_PORT, SPI_SCK_PIN, SPI_SCK_FUNC, Disable);
PORT_SetFunc(SPI_MOSI_PORT, SPI_MOSI_PIN, SPI_MOSI_FUNC, Disable);
/* Configuration SPI structure */
stcSpiInit.enClkDiv = SpiClkDiv2;
stcSpiInit.enFrameNumber = SpiFrameNumber1;
stcSpiInit.enDataLength = SpiDataLengthBit8;
stcSpiInit.enFirstBitPosition = SpiFirstBitPositionMSB;
stcSpiInit.enSckPolarity = SpiSckIdleLevelHigh;
stcSpiInit.enSckPhase = SpiSckOddChangeEvenSample;
stcSpiInit.enReadBufferObject = SpiReadReceiverBuffer;
stcSpiInit.enWorkMode = SpiWorkMode3Line;
stcSpiInit.enTransMode = SpiTransFullDuplex;
stcSpiInit.enCommAutoSuspendEn = Disable;
stcSpiInit.enModeFaultErrorDetectEn = Disable;
stcSpiInit.enParitySelfDetectEn = Disable;
stcSpiInit.enParityEn = Disable;
stcSpiInit.enParity = SpiParityEven;
/* SPI master mode */
stcSpiInit.enMasterSlaveMode = SpiModeMaster;
stcSpiInit.stcDelayConfig.enSsSetupDelayOption = SpiSsSetupDelayCustomValue;
stcSpiInit.stcDelayConfig.enSsSetupDelayTime = SpiSsSetupDelaySck1;
stcSpiInit.stcDelayConfig.enSsHoldDelayOption = SpiSsHoldDelayCustomValue;
stcSpiInit.stcDelayConfig.enSsHoldDelayTime = SpiSsHoldDelaySck1;
stcSpiInit.stcDelayConfig.enSsIntervalTimeOption = SpiSsIntervalCustomValue;
stcSpiInit.stcDelayConfig.enSsIntervalTime = SpiSsIntervalSck6PlusPck2;
stcSpiInit.stcSsConfig.enSsValidBit = SpiSsValidChannel0;
stcSpiInit.stcSsConfig.enSs0Polarity = SpiSsLowValid;
SPI_Init(SPI_UNIT, &stcSpiInit);
SPI_Cmd(SPI_UNIT, Enable);
}
void LCD_GPIO_Init(void)
{
stc_port_init_t stcPortInit;
/* configuration structure initialization */
MEM_ZERO_STRUCT(stcPortInit);
stcPortInit.enPinMode = Pin_Mode_Out;
/* RES Port/Pin initialization */
LCD_RES_Clr();
PORT_Init(RES_PORT, RES_PIN, &stcPortInit);
/* DC Port/Pin initialization */
LCD_DC_Clr();
PORT_Init(DC_PORT, DC_PIN, &stcPortInit);
/* BLK Port/Pin initialization */
LCD_BLK_Clr();
PORT_Init(BLK_PORT, BLK_PIN, &stcPortInit);
}
/******************************************************************************
函数说明:LCD串行数据写入函数
入口数据:dat 要写入的串行数据
返回值: 无
******************************************************************************/
void LCD_Writ_Bus(uint8_t dat)
{
LCD_SPI_Write(dat);
}
void LCD_Init(void)
{
LCD_GPIO_Init();//初始化GPIO
LCD_RES_Clr();
Ddl_Delay1ms(120);
LCD_RES_Set();
Ddl_Delay1ms(120);
LCD_SPI_Init();
LCD_WR_REG(0x11); //Sleep Out
Ddl_Delay1ms(120); //DELAY120ms
//-----------------------ST7789V Frame rate setting-----------------//
//************************************************
LCD_WR_REG(0x3A); //65k mode
LCD_WR_DATA8(0x05);
LCD_WR_REG(0xC5); //VCOM
LCD_WR_DATA8(0x1A);
LCD_WR_REG(0x36); // 屏幕显示方向设置
LCD_WR_DATA8(0x00);
//-------------ST7789V Frame rate setting-----------//
LCD_WR_REG(0xb2); //Porch Setting
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x33);
LCD_WR_DATA8(0x33);
LCD_WR_REG(0xb7); //Gate Control
LCD_WR_DATA8(0x05); //12.2v -10.43v
//--------------ST7789V Power setting---------------//
LCD_WR_REG(0xBB);//VCOM
LCD_WR_DATA8(0x3F);
LCD_WR_REG(0xC0); //Power control
LCD_WR_DATA8(0x2c);
LCD_WR_REG(0xC2); //VDV and VRH Command Enable
LCD_WR_DATA8(0x01);
LCD_WR_REG(0xC3); //VRH Set
LCD_WR_DATA8(0x0F); //4.3+( vcom+vcom offset+vdv)
LCD_WR_REG(0xC4); //VDV Set
LCD_WR_DATA8(0x20); //0v
LCD_WR_REG(0xC6); //Frame Rate Control in Normal Mode
LCD_WR_DATA8(0X01); //111Hz
LCD_WR_REG(0xd0); //Power Control 1
LCD_WR_DATA8(0xa4);
LCD_WR_DATA8(0xa1);
LCD_WR_REG(0xE8); //Power Control 1
LCD_WR_DATA8(0x03);
LCD_WR_REG(0xE9); //Equalize time control
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x08);
//---------------ST7789V gamma setting-------------//
LCD_WR_REG(0xE0); //Set Gamma
LCD_WR_DATA8(0xD0);
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x08);
LCD_WR_DATA8(0x14);
LCD_WR_DATA8(0x28);
LCD_WR_DATA8(0x33);
LCD_WR_DATA8(0x3F);
LCD_WR_DATA8(0x07);
LCD_WR_DATA8(0x13);
LCD_WR_DATA8(0x14);
LCD_WR_DATA8(0x28);
LCD_WR_DATA8(0x30);
LCD_WR_REG(0XE1); //Set Gamma
LCD_WR_DATA8(0xD0);
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x08);
LCD_WR_DATA8(0x03);
LCD_WR_DATA8(0x24);
LCD_WR_DATA8(0x32);
LCD_WR_DATA8(0x32);
LCD_WR_DATA8(0x3B);
LCD_WR_DATA8(0x14);
LCD_WR_DATA8(0x13);
LCD_WR_DATA8(0x28);
LCD_WR_DATA8(0x2F);
LCD_WR_REG(0x21); //反显
LCD_WR_REG(0x29); //开启显示
}
编译重上电,可以看到刷屏效果明显改善了很多。前后波形对比图如下,可以看到,发送一个字节所耗费的时间快了10余倍,基本符合我们的预期。(好像SPI+DMA刷屏时间会更快,后续有时间可以再优化下)
总结
关于SPI屏驱动这部分的内容暂时就介绍到这里,后续有时间再详细介绍下lvgl库的移植。最后附上源代码链接:hc32f460petb_template.zip
版权声明:本文为CSDN博主「Top0_0lll」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_39597546/article/details/122478110
前言
显示屏作为人机交互的一个重要窗口,在各类电子产品中被广泛地应用。在同类产品中,一个好的人机界面设计往往能更加吸引用户的目光。而显示器作为其载体,同样也是不可或缺的存在。作为一名嵌入式软件工程师,屏驱和人机界面的开发在我们的工作中是经常会遇到的,掌握此项技能也是必不可少的。本文主要基于HC32F460,简单介绍 spi屏驱的开发。
一、硬件介绍
这里我使用的屏是之前在某宝上淘来的带SPI接口通讯的TFT彩屏,下面是该屏的部分资料说明
接口定义
二、驱动代码实现
1.IO模拟SPI驱动
关于驱动部分,卖家也给了一些不同平台下的驱动例程,这些例程都是通过IO口模拟SPI的时序来驱动lcd屏的。移植到HC平台,很快就顺利点亮lcd屏。
代码如下:
/* Define port and pin for SDA and SCL */
#define SPI_SCK_PORT (PortD)
#define SPI_SCK_PIN (Pin00)
#define SPI_MOSI_PORT (PortD)
#define SPI_MOSI_PIN (Pin01)
/* RES Port/Pin definition */
#define RES_PORT (PortE)
#define RES_PIN (Pin09)
/* DC Port/Pin definition */
#define DC_PORT (PortE)
#define DC_PIN (Pin11)
/* BLK Port/Pin definition */
#define BLK_PORT (PortE)
#define BLK_PIN (Pin13)
//-----------------LCD端口定义----------------
#define LCD_SCLK_Clr() M4_PORT->PORRD |= SPI_SCK_PIN //SCL=SCLK
#define LCD_SCLK_Set() M4_PORT->POSRD |= SPI_SCK_PIN
#define LCD_MOSI_Clr() M4_PORT->PORRD |= SPI_MOSI_PIN //SDA=MOSI
#define LCD_MOSI_Set() M4_PORT->POSRD |= SPI_MOSI_PIN
#define LCD_RES_Clr() M4_PORT->PORRE |= RES_PIN //RES
#define LCD_RES_Set() M4_PORT->POSRE |= RES_PIN
#define LCD_DC_Clr() M4_PORT->PORRE |= DC_PIN //DC
#define LCD_DC_Set() M4_PORT->POSRE |= DC_PIN
#define LCD_BLK_Clr() PORT_ResetBits(BLK_PORT, BLK_PIN) //BLK
#define LCD_BLK_Set() PORT_SetBits(BLK_PORT, BLK_PIN)
void LCD_GPIO_Init(void)
{
stc_port_init_t stcPortInit;
/* configuration structure initialization */
MEM_ZERO_STRUCT(stcPortInit);
stcPortInit.enPinMode = Pin_Mode_Out;
/* SCL Port/Pin initialization */
LCD_SCLK_Clr();
PORT_Init(SPI_SCK_PORT, SPI_SCK_PIN, &stcPortInit);
/* SDA Port/Pin initialization */
LCD_MOSI_Clr();
PORT_Init(SPI_MOSI_PORT, SPI_MOSI_PIN, &stcPortInit);
/* RES Port/Pin initialization */
LCD_RES_Clr();
PORT_Init(RES_PORT, RES_PIN, &stcPortInit);
/* DC Port/Pin initialization */
LCD_DC_Clr();
PORT_Init(DC_PORT, DC_PIN, &stcPortInit);
/* BLK Port/Pin initialization */
LCD_BLK_Clr();
PORT_Init(BLK_PORT, BLK_PIN, &stcPortInit);
}
/******************************************************************************
函数说明:LCD串行数据写入函数
入口数据:dat 要写入的串行数据
返回值: 无
******************************************************************************/
void LCD_Writ_Bus(uint8_t dat)
{
uint8_t counter;
for(counter=0; counter<8; counter++)
{
LCD_SCLK_Clr();
if((dat&0x80)==0)
{
LCD_MOSI_Clr();
}
else
{
LCD_MOSI_Set();
}
dat=dat<<1;
LCD_SCLK_Set();
}
LCD_SCLK_Clr();
}
/******************************************************************************
函数说明:LCD写入数据
入口数据:dat 写入的数据
返回值: 无
******************************************************************************/
void LCD_WR_DATA8(uint8_t dat)
{
LCD_DC_Set();
LCD_Writ_Bus(dat);
}
/******************************************************************************
函数说明:LCD写入数据
入口数据:dat 写入的数据
返回值: 无
******************************************************************************/
void LCD_WR_DATA(uint16_t dat)
{
LCD_WR_DATA8(dat>>8);
LCD_WR_DATA8(dat);
}
/******************************************************************************
函数说明:LCD写入命令
入口数据:dat 写入的命令
返回值: 无
******************************************************************************/
void LCD_WR_REG(uint8_t dat)
{
LCD_DC_Clr();
LCD_Writ_Bus(dat);
}
/******************************************************************************
函数说明:设置起始和结束地址
入口数据:x1,x2 设置列的起始和结束地址
y1,y2 设置行的起始和结束地址
返回值: 无
******************************************************************************/
void LCD_Address_Set(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2)
{
LCD_WR_REG(0x2a); //Column address set
LCD_WR_DATA(x1); //start column
LCD_WR_DATA(x2); //end column
LCD_WR_REG(0x2b); //Row address set
LCD_WR_DATA(y1); //start row
LCD_WR_DATA(y2); //end row
LCD_WR_REG(0x2C); //Memory write
}
void LCD_Init(void)
{
LCD_GPIO_Init();//初始化GPIO
LCD_RES_Clr();
Ddl_Delay1ms(120);
LCD_RES_Set();
Ddl_Delay1ms(120);
LCD_SCLK_Set(); //特别注意!!
LCD_WR_REG(0x11); //Sleep Out
Ddl_Delay1ms(120); //DELAY120ms
//-----------------------ST7789V Frame rate setting-----------------//
//************************************************
LCD_WR_REG(0x3A); //65k mode
LCD_WR_DATA8(0x05);
LCD_WR_REG(0xC5); //VCOM
LCD_WR_DATA8(0x1A);
LCD_WR_REG(0x36); // 屏幕显示方向设置
LCD_WR_DATA8(0x00);
//-------------ST7789V Frame rate setting-----------//
LCD_WR_REG(0xb2); //Porch Setting
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x33);
LCD_WR_DATA8(0x33);
LCD_WR_REG(0xb7); //Gate Control
LCD_WR_DATA8(0x05); //12.2v -10.43v
//--------------ST7789V Power setting---------------//
LCD_WR_REG(0xBB);//VCOM
LCD_WR_DATA8(0x3F);
LCD_WR_REG(0xC0); //Power control
LCD_WR_DATA8(0x2c);
LCD_WR_REG(0xC2); //VDV and VRH Command Enable
LCD_WR_DATA8(0x01);
LCD_WR_REG(0xC3); //VRH Set
LCD_WR_DATA8(0x0F); //4.3+( vcom+vcom offset+vdv)
LCD_WR_REG(0xC4); //VDV Set
LCD_WR_DATA8(0x20); //0v
LCD_WR_REG(0xC6); //Frame Rate Control in Normal Mode
LCD_WR_DATA8(0X01); //111Hz
LCD_WR_REG(0xd0); //Power Control 1
LCD_WR_DATA8(0xa4);
LCD_WR_DATA8(0xa1);
LCD_WR_REG(0xE8); //Power Control 1
LCD_WR_DATA8(0x03);
LCD_WR_REG(0xE9); //Equalize time control
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x08);
//---------------ST7789V gamma setting-------------//
LCD_WR_REG(0xE0); //Set Gamma
LCD_WR_DATA8(0xD0);
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x08);
LCD_WR_DATA8(0x14);
LCD_WR_DATA8(0x28);
LCD_WR_DATA8(0x33);
LCD_WR_DATA8(0x3F);
LCD_WR_DATA8(0x07);
LCD_WR_DATA8(0x13);
LCD_WR_DATA8(0x14);
LCD_WR_DATA8(0x28);
LCD_WR_DATA8(0x30);
LCD_WR_REG(0XE1); //Set Gamma
LCD_WR_DATA8(0xD0);
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x08);
LCD_WR_DATA8(0x03);
LCD_WR_DATA8(0x24);
LCD_WR_DATA8(0x32);
LCD_WR_DATA8(0x32);
LCD_WR_DATA8(0x3B);
LCD_WR_DATA8(0x14);
LCD_WR_DATA8(0x13);
LCD_WR_DATA8(0x28);
LCD_WR_DATA8(0x2F);
LCD_WR_REG(0x21); //反显
LCD_WR_REG(0x29); //开启显示
}
/******************************************************************************
函数说明:在指定区域填充颜色
入口数据:xsta,ysta 起始坐标
xend,yend 终止坐标
color 要填充的颜色
返回值: 无
******************************************************************************/
void LCD_Fill(uint16_t xsta,uint16_t ysta,uint16_t xend,uint16_t yend,uint16_t color)
{
uint16_t i,j;
LCD_Address_Set(xsta,ysta,xend-1,yend-1);//设置显示范围
for(i=ysta;i<yend;i++)
{
for(j=xsta;j<xend;j++)
{
LCD_WR_DATA(color);
}
}
}
编写代码简单地刷下屏,效果如下:
虽说能成功点亮,速度也勉强能接受,但是还是很明显能看到刷屏时“拉窗帘”的现象(CSDN博客好像没办法插入小视频,只能截图了–_–|||)。
2.硬件SPI驱动
IO模拟SPI虽然能驱动LCD屏,但是刷屏速度就很明显会偏慢点,若是后续开发想利用屏幕播放一些动图(如GIF等),显示效果看起来就会很差。HC32F460本身带有4路的SPI外设,因此我们可以直接使用MCU本身的硬件SPI来驱动LCD屏,刷屏显示效果则会好很多。
代码如下:
/* RES Port/Pin definition */
#define RES_PORT (PortE)
#define RES_PIN (Pin09)
/* DC Port/Pin definition */
#define DC_PORT (PortE)
#define DC_PIN (Pin11)
/* BLK Port/Pin definition */
#define BLK_PORT (PortE)
#define BLK_PIN (Pin13)
#define LCD_RES_Clr() M4_PORT->PORRE |= RES_PIN //RES
#define LCD_RES_Set() M4_PORT->POSRE |= RES_PIN
#define LCD_DC_Clr() M4_PORT->PORRE |= DC_PIN //DC
#define LCD_DC_Set() M4_PORT->POSRE |= DC_PIN
#define LCD_BLK_Clr() PORT_ResetBits(BLK_PORT, BLK_PIN) //BLK
#define LCD_BLK_Set() PORT_SetBits(BLK_PORT, BLK_PIN)
/* SPI_SCK Port/Pin definition */
#define SPI_SCK_PORT (PortD)
#define SPI_SCK_PIN (Pin00)
#define SPI_SCK_FUNC (Func_Spi1_Sck)
/* SPI_MOSI Port/Pin definition */
#define SPI_MOSI_PORT (PortD)
#define SPI_MOSI_PIN (Pin01)
#define SPI_MOSI_FUNC (Func_Spi1_Mosi)
/* SPI unit and clock definition */
#define SPI_UNIT (M4_SPI1)
#define SPI_UNIT_CLOCK (PWC_FCG1_PERIPH_SPI1)
/* Choose SPI master or slave mode */
#define SPI_MASTER_MODE
void LCD_SPI_Write(uint8_t Data)
{
/* Send data */
SPI_SendData8(SPI_UNIT, Data);
/* Wait tx buffer empty */
while(Reset == SPI_GetFlag(SPI_UNIT, SpiFlagSendBufferEmpty));
}
void LCD_SPI_Init(void)
{
stc_spi_init_t stcSpiInit;
/* configuration structure initialization */
MEM_ZERO_STRUCT(stcSpiInit);
/* Configuration peripheral clock */
PWC_Fcg1PeriphClockCmd(SPI_UNIT_CLOCK, Enable);
/* Configuration SPI pin */
PORT_SetFunc(SPI_SCK_PORT, SPI_SCK_PIN, SPI_SCK_FUNC, Disable);
PORT_SetFunc(SPI_MOSI_PORT, SPI_MOSI_PIN, SPI_MOSI_FUNC, Disable);
/* Configuration SPI structure */
stcSpiInit.enClkDiv = SpiClkDiv2;
stcSpiInit.enFrameNumber = SpiFrameNumber1;
stcSpiInit.enDataLength = SpiDataLengthBit8;
stcSpiInit.enFirstBitPosition = SpiFirstBitPositionMSB;
stcSpiInit.enSckPolarity = SpiSckIdleLevelHigh;
stcSpiInit.enSckPhase = SpiSckOddChangeEvenSample;
stcSpiInit.enReadBufferObject = SpiReadReceiverBuffer;
stcSpiInit.enWorkMode = SpiWorkMode3Line;
stcSpiInit.enTransMode = SpiTransFullDuplex;
stcSpiInit.enCommAutoSuspendEn = Disable;
stcSpiInit.enModeFaultErrorDetectEn = Disable;
stcSpiInit.enParitySelfDetectEn = Disable;
stcSpiInit.enParityEn = Disable;
stcSpiInit.enParity = SpiParityEven;
/* SPI master mode */
stcSpiInit.enMasterSlaveMode = SpiModeMaster;
stcSpiInit.stcDelayConfig.enSsSetupDelayOption = SpiSsSetupDelayCustomValue;
stcSpiInit.stcDelayConfig.enSsSetupDelayTime = SpiSsSetupDelaySck1;
stcSpiInit.stcDelayConfig.enSsHoldDelayOption = SpiSsHoldDelayCustomValue;
stcSpiInit.stcDelayConfig.enSsHoldDelayTime = SpiSsHoldDelaySck1;
stcSpiInit.stcDelayConfig.enSsIntervalTimeOption = SpiSsIntervalCustomValue;
stcSpiInit.stcDelayConfig.enSsIntervalTime = SpiSsIntervalSck6PlusPck2;
stcSpiInit.stcSsConfig.enSsValidBit = SpiSsValidChannel0;
stcSpiInit.stcSsConfig.enSs0Polarity = SpiSsLowValid;
SPI_Init(SPI_UNIT, &stcSpiInit);
SPI_Cmd(SPI_UNIT, Enable);
}
void LCD_GPIO_Init(void)
{
stc_port_init_t stcPortInit;
/* configuration structure initialization */
MEM_ZERO_STRUCT(stcPortInit);
stcPortInit.enPinMode = Pin_Mode_Out;
/* RES Port/Pin initialization */
LCD_RES_Clr();
PORT_Init(RES_PORT, RES_PIN, &stcPortInit);
/* DC Port/Pin initialization */
LCD_DC_Clr();
PORT_Init(DC_PORT, DC_PIN, &stcPortInit);
/* BLK Port/Pin initialization */
LCD_BLK_Clr();
PORT_Init(BLK_PORT, BLK_PIN, &stcPortInit);
}
/******************************************************************************
函数说明:LCD串行数据写入函数
入口数据:dat 要写入的串行数据
返回值: 无
******************************************************************************/
void LCD_Writ_Bus(uint8_t dat)
{
LCD_SPI_Write(dat);
}
void LCD_Init(void)
{
LCD_GPIO_Init();//初始化GPIO
LCD_RES_Clr();
Ddl_Delay1ms(120);
LCD_RES_Set();
Ddl_Delay1ms(120);
LCD_SPI_Init();
LCD_WR_REG(0x11); //Sleep Out
Ddl_Delay1ms(120); //DELAY120ms
//-----------------------ST7789V Frame rate setting-----------------//
//************************************************
LCD_WR_REG(0x3A); //65k mode
LCD_WR_DATA8(0x05);
LCD_WR_REG(0xC5); //VCOM
LCD_WR_DATA8(0x1A);
LCD_WR_REG(0x36); // 屏幕显示方向设置
LCD_WR_DATA8(0x00);
//-------------ST7789V Frame rate setting-----------//
LCD_WR_REG(0xb2); //Porch Setting
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x33);
LCD_WR_DATA8(0x33);
LCD_WR_REG(0xb7); //Gate Control
LCD_WR_DATA8(0x05); //12.2v -10.43v
//--------------ST7789V Power setting---------------//
LCD_WR_REG(0xBB);//VCOM
LCD_WR_DATA8(0x3F);
LCD_WR_REG(0xC0); //Power control
LCD_WR_DATA8(0x2c);
LCD_WR_REG(0xC2); //VDV and VRH Command Enable
LCD_WR_DATA8(0x01);
LCD_WR_REG(0xC3); //VRH Set
LCD_WR_DATA8(0x0F); //4.3+( vcom+vcom offset+vdv)
LCD_WR_REG(0xC4); //VDV Set
LCD_WR_DATA8(0x20); //0v
LCD_WR_REG(0xC6); //Frame Rate Control in Normal Mode
LCD_WR_DATA8(0X01); //111Hz
LCD_WR_REG(0xd0); //Power Control 1
LCD_WR_DATA8(0xa4);
LCD_WR_DATA8(0xa1);
LCD_WR_REG(0xE8); //Power Control 1
LCD_WR_DATA8(0x03);
LCD_WR_REG(0xE9); //Equalize time control
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x08);
//---------------ST7789V gamma setting-------------//
LCD_WR_REG(0xE0); //Set Gamma
LCD_WR_DATA8(0xD0);
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x08);
LCD_WR_DATA8(0x14);
LCD_WR_DATA8(0x28);
LCD_WR_DATA8(0x33);
LCD_WR_DATA8(0x3F);
LCD_WR_DATA8(0x07);
LCD_WR_DATA8(0x13);
LCD_WR_DATA8(0x14);
LCD_WR_DATA8(0x28);
LCD_WR_DATA8(0x30);
LCD_WR_REG(0XE1); //Set Gamma
LCD_WR_DATA8(0xD0);
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x08);
LCD_WR_DATA8(0x03);
LCD_WR_DATA8(0x24);
LCD_WR_DATA8(0x32);
LCD_WR_DATA8(0x32);
LCD_WR_DATA8(0x3B);
LCD_WR_DATA8(0x14);
LCD_WR_DATA8(0x13);
LCD_WR_DATA8(0x28);
LCD_WR_DATA8(0x2F);
LCD_WR_REG(0x21); //反显
LCD_WR_REG(0x29); //开启显示
}
编译重上电,可以看到刷屏效果明显改善了很多。前后波形对比图如下,可以看到,发送一个字节所耗费的时间快了10余倍,基本符合我们的预期。(好像SPI+DMA刷屏时间会更快,后续有时间可以再优化下)
总结
关于SPI屏驱动这部分的内容暂时就介绍到这里,后续有时间再详细介绍下lvgl库的移植。最后附上源代码链接:hc32f460petb_template.zip
版权声明:本文为CSDN博主「Top0_0lll」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_39597546/article/details/122478110
暂无评论