HC32F460开发:spi lcd屏驱动
前言
显示屏作为人机交互的一个重要窗口,在各类电子产品中被广泛地应用。在同类产品中,一个好的人机界面设计往往能更加吸引用户的目光。而显示器作为其载体,同样也是不可或缺的存在。作为一名嵌入式软件工程师,屏驱和人机界面的开发在我们的工作中是经常会遇到的,掌握此项技能也是必不可少的。本文主要基于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);
}
}
}
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
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhfkikhh
系列文章
更多
同类精品
更多
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
photoshop蒙版画笔没反应怎么办
PHP中文网 06-24