【嵌入式】MCU(HC32F460)+SPI接口LCD液晶屏ILI9341 移植emWin记录1----点亮LCD屏

目录

一 SPI屏的接线

二 SPI屏驱动初始化

三 SPI屏点亮

四 附录


一 SPI屏的接线

        SPI屏的特点在于接线简单,只需要四根SPI线以及几个GPIO口即可驱动工作,但是由于非并口的,所以当像素比比较大的时候,刷新速度可能会受到考验。我这边使用的是一块320*240的串口屏,屏幕驱动为ILI9341,控制芯片选用的是华大的HC32F460,主频为168Mhz,因为主频比较高,同时对屏幕刷新显示要求不大,所以考虑基于此进行开发。

        首先根据显示屏的接线图进行接线:

【嵌入式】MCU(HC32F460)+SPI接口LCD液晶屏ILI9341 移植emWin记录1----点亮LCD屏_第1张图片

        其中,真正需要关注的是SPI的四线(SDA即MOSI、SDO即MISO、SCL即SCK、CS片选),GPIO三根线RST复位线、D/C区别输出的是指令还是数据以及LEDA(BL)背光线。

         接线示意图如下:

【嵌入式】MCU(HC32F460)+SPI接口LCD液晶屏ILI9341 移植emWin记录1----点亮LCD屏_第2张图片

二 SPI屏驱动初始化

        接线完成之后,就需要在程序中对这几个接口进行初始化。

        【1】首先选定几个管脚,做一些定义:

/* SPI_SCK Port/Pin definition */
#define SPI1_SCK_PORT                    (PortA)
#define SPI1_SCK_PIN                     (Pin06)
#define SPI1_SCK_FUNC                    (Func_Spi1_Sck)

/* SPI_NSS Port/Pin definition */
#define SPI1_NSS_PORT                    (PortB)
#define SPI1_NSS_PIN                     (Pin01)
#define SPI1_NSS_HIGH()                  (PORT_SetBits(SPI1_NSS_PORT, SPI1_NSS_PIN))
#define SPI1_NSS_LOW()                   (PORT_ResetBits(SPI1_NSS_PORT, SPI1_NSS_PIN))

/* SPI_MOSI Port/Pin definition */
#define SPI1_MOSI_PORT                   (PortA)
#define SPI1_MOSI_PIN                    (Pin07)
#define SPI1_MOSI_FUNC                   (Func_Spi1_Mosi)

/* SPI_MISO Port/Pin definition */
#define SPI1_MISO_PORT                   (PortB)
#define SPI1_MISO_PIN                    (Pin00)
#define SPI1_MISO_FUNC                   (Func_Spi1_Miso)

/* SPI unit and clock definition */
#define SPI1_UNIT                        (M4_SPI1)
#define SPI1_UNIT_CLOCK                  (PWC_FCG1_PERIPH_SPI1)

//RES引脚
#define LCD_RES_PORT                    (PortE)
#define LCD_RES_PIN                     (Pin11)
#define LCD_RES_HIGH()                  (PORT_SetBits(LCD_RES_PORT, LCD_RES_PIN))
#define LCD_RES_LOW()                   (PORT_ResetBits(LCD_RES_PORT, LCD_RES_PIN))
//DC引脚
#define LCD_DC_PORT                     (PortE)
#define LCD_DC_PIN                      (Pin12)
#define LCD_DC_HIGH()                   (PORT_SetBits(LCD_DC_PORT, LCD_DC_PIN))
#define LCD_DC_LOW()                    (PORT_ResetBits(LCD_DC_PORT, LCD_DC_PIN))
//BLK引脚
#define LCD_BL_PORT                     (PortE)
#define LCD_BL_PIN                      (Pin13)
#define LCD_BL_HIGH()                   (PORT_SetBits(LCD_BL_PORT, LCD_BL_PIN))
#define LCD_BL_LOW()                    (PORT_ResetBits(LCD_BL_PORT, LCD_BL_PIN))

        【2】其次是GPIO口初始化(这边将SPI的CS脚当作GPIO进行初始化):

/**************************************************************************
* 函数名称: LCD_InitGPIO
* 功能描述: LCD初始化GPIO引脚
* 输入参数: 
* 输出参数: 
* 返 回 值: 
* 其它说明: 初始化LCD用到的GPIO口,包括RES、DC、BL以及SPI的NSS引脚
**************************************************************************/
void LCD_InitGPIO(void)
{
    stc_port_init_t stcPortInit;

    /* configure structure initialization */
    MEM_ZERO_STRUCT(stcPortInit);

    stcPortInit.enPinMode = Pin_Mode_Out;

    /* RES & DC & BL */
    PORT_Init(LCD_RES_PORT, LCD_RES_PIN, &stcPortInit);
    PORT_Init(LCD_DC_PORT,  LCD_DC_PIN, &stcPortInit);
    PORT_Init(LCD_BL_PORT,  LCD_BL_PIN, &stcPortInit);

    LCD_BL_HIGH();   /* 打开背光 */

    /* SPI NSS */
    PORT_Init(SPI1_NSS_PORT, SPI1_NSS_PIN, &stcPortInit);
    SPI1_NSS_HIGH();
}

        【3】SPI初始化:

/**************************************************************************
* 函数名称: LCD_InitSPI1
* 功能描述: LCD初始化SPI
* 输入参数: 
* 输出参数: 
* 返 回 值: 
* 其它说明: 初始化SPI用到的口,包括MOSI、MISO、SCK
**************************************************************************/
void LCD_InitSPI1(void)
{
    stc_spi_init_t stcSpiInit;

    /* configuration structure initialization */
    MEM_ZERO_STRUCT(stcSpiInit);

    /* Configuration peripheral clock */
    PWC_Fcg1PeriphClockCmd(SPI1_UNIT_CLOCK, Enable);

    /* Configuration SPI pin */
    PORT_SetFunc(SPI1_SCK_PORT, SPI1_SCK_PIN, SPI1_SCK_FUNC,  Disable);
    PORT_SetFunc(SPI1_MOSI_PORT, SPI1_MOSI_PIN, SPI1_MOSI_FUNC, Disable);
    PORT_SetFunc(SPI1_MISO_PORT, SPI1_MISO_PIN, SPI1_MISO_FUNC, Disable);

    /* Configuration SPI structure */
    stcSpiInit.enClkDiv                 = SpiClkDiv2;
    stcSpiInit.enFrameNumber            = SpiFrameNumber1;
    stcSpiInit.enDataLength             = SpiDataLengthBit8;
    stcSpiInit.enFirstBitPosition       = SpiFirstBitPositionMSB;
    stcSpiInit.enSckPolarity            = SpiSckIdleLevelLow;
    stcSpiInit.enSckPhase               = SpiSckOddSampleEvenChange;
    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(SPI1_UNIT, &stcSpiInit);
    SPI_Cmd(SPI1_UNIT, Enable);
}

        【4】结合SPI的读写功能,封装接口供LCD进行写命令(LCD_WriteCMD)和写数据(LCD_WriteDAT):

/**************************************************************************
* 函数名称: SPI_RW
* 功能描述: SPI读写功能
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
**************************************************************************/
uint8_t SPI_RW(M4_SPI_TypeDef *SPIx, uint8_t data)
{
    while (Reset == SPI_GetFlag(SPIx, SpiFlagSendBufferEmpty))
    {
    }
    SPI_SendData8(SPIx, data);
    while (Reset == SPI_GetFlag(SPIx, SpiFlagReceiveBufferFull))
    {
    }
    return SPI_ReceiveData8(SPIx);
}

/**************************************************************************
* 函数名称: LCD_WriteCMD
* 功能描述: LCD写命令
* 输入参数: 
* 输出参数: 
* 返 回 值: 
* 其它说明: 
**************************************************************************/
void LCD_WriteCMD(U8 Command)
{
    SPI1_NSS_LOW();
    LCD_DC_LOW();
    SPI_RW(SPI1_UNIT, Command);
    SPI1_NSS_HIGH();
}

/**************************************************************************
* 函数名称: LCD_WriteDAT
* 功能描述: LCD写数据
* 输入参数: 
* 输出参数: 
* 返 回 值: 
* 其它说明: 
**************************************************************************/
void LCD_WriteDAT(U8 Data)
{
    SPI1_NSS_LOW();
    LCD_DC_HIGH();
    SPI_RW(SPI1_UNIT, Data);
    SPI1_NSS_HIGH();
}

        【5】封装LCD的一些基本的接口,比如复位接口以及寄存器配置接口(其中寄存器的相关配置可以参考附录中提供的ILI9431数据手册):

/**************************************************************************
* 函数名称: LCD_HardwareReset
* 功能描述: LCD复位
* 输入参数: 
* 输出参数: 
* 返 回 值: 
* 其它说明: 
**************************************************************************/
void LCD_HardwareReset(void)
{
    LCD_RES_HIGH();  Ddl_Delay1ms(1);
    LCD_RES_LOW();   Ddl_Delay1ms(80);
    LCD_RES_HIGH();  Ddl_Delay1ms(10);
}


/**************************************************************************
* 函数名称: LCD_ConfigureREG
* 功能描述: LCD寄存器配置
* 输入参数: 
* 输出参数: 
* 返 回 值: 
* 其它说明: 
**************************************************************************/
void LCD_ConfigureREG(void)
{
    //功耗控制B
    LCD_WriteCMD(0xCF);
	LCD_WriteDAT(0x00);
	LCD_WriteDAT(0xC1);
	LCD_WriteDAT(0X30);
    //电源时序控制
	LCD_WriteCMD(0xED);
	LCD_WriteDAT(0x64);
	LCD_WriteDAT(0x03);
	LCD_WriteDAT(0X12);
	LCD_WriteDAT(0X81);
    //驱动时序控制A
	LCD_WriteCMD(0xE8); 
	LCD_WriteDAT(0x85);
	LCD_WriteDAT(0x10);
	LCD_WriteDAT(0x7A);
    //功耗控制A
	LCD_WriteCMD(0xCB);
	LCD_WriteDAT(0x39);
	LCD_WriteDAT(0x2C);
	LCD_WriteDAT(0x00);
	LCD_WriteDAT(0x34);
	LCD_WriteDAT(0x02);
    //泵比控制
	LCD_WriteCMD(0xF7);
	LCD_WriteDAT(0x20);
    //驱动时序控制B
	LCD_WriteCMD(0xEA);
	LCD_WriteDAT(0x00);
	LCD_WriteDAT(0x00);
    //功耗控制1
	LCD_WriteCMD(0xC0);  //Power control 
	LCD_WriteDAT(0x1B);  //VRH[5:0]
    //功耗控制2
	LCD_WriteCMD(0xC1);  //Power control 
	LCD_WriteDAT(0x01);  //SAP[2:0];BT[3:0]
    //VCOM控制1
	LCD_WriteCMD(0xC5);
	LCD_WriteDAT(0x30);
	LCD_WriteDAT(0x30);
    //VCOM控制2
	LCD_WriteCMD(0xC7);
	LCD_WriteDAT(0XB7);
    //存储器访问控制
	LCD_WriteCMD(0x36);
	LCD_WriteDAT(0x48);
    //像素格式设置
	LCD_WriteCMD(0x3A);
	LCD_WriteDAT(0x55);
    //帧速率控制(正常模式/全色模式)
	LCD_WriteCMD(0xB1);
	LCD_WriteDAT(0x00);
	LCD_WriteDAT(0x1A);
    //显示功能设置控制
	LCD_WriteCMD(0xB6);
	LCD_WriteDAT(0x0A);
	LCD_WriteDAT(0xA2);
    //使能3G
	LCD_WriteCMD(0xF2);  
	LCD_WriteDAT(0x00);  //3Gamma Function Disable 
    //伽马设置
	LCD_WriteCMD(0x26);  
	LCD_WriteDAT(0x01);  //Gamma curve selected 
    //正极伽马校正
	LCD_WriteCMD(0xE0);
	LCD_WriteDAT(0x0F);
	LCD_WriteDAT(0x2A);
	LCD_WriteDAT(0x28);
	LCD_WriteDAT(0x08);
	LCD_WriteDAT(0x0E);
	LCD_WriteDAT(0x08);
	LCD_WriteDAT(0x54);
	LCD_WriteDAT(0XA9);
	LCD_WriteDAT(0x43);
	LCD_WriteDAT(0x0A);
	LCD_WriteDAT(0x0F);
	LCD_WriteDAT(0x00);
	LCD_WriteDAT(0x00);
	LCD_WriteDAT(0x00);
	LCD_WriteDAT(0x00);
    //负极伽马校正
	LCD_WriteCMD(0XE1);
	LCD_WriteDAT(0x00);
	LCD_WriteDAT(0x15);
	LCD_WriteDAT(0x17);
	LCD_WriteDAT(0x07);
	LCD_WriteDAT(0x11);
	LCD_WriteDAT(0x06);
	LCD_WriteDAT(0x2B);
	LCD_WriteDAT(0x56);
	LCD_WriteDAT(0x3C);
	LCD_WriteDAT(0x05);
	LCD_WriteDAT(0x10);
	LCD_WriteDAT(0x0F);
	LCD_WriteDAT(0x3F);
	LCD_WriteDAT(0x3F);
	LCD_WriteDAT(0x0F);
    //行地址设置
	LCD_WriteCMD(0x2B);
	LCD_WriteDAT(0x00);
	LCD_WriteDAT(0x00);
	LCD_WriteDAT(0x01);
	LCD_WriteDAT(0x3f);
    //列地址设置
	LCD_WriteCMD(0x2A);
	LCD_WriteDAT(0x00);
	LCD_WriteDAT(0x00);
	LCD_WriteDAT(0x00);
	LCD_WriteDAT(0xef);
    //退出睡眠模式
	LCD_WriteCMD(0x11);
	Ddl_Delay1ms(120);
    //开显示(0x28为关显示)
	LCD_WriteCMD(0x29);
}

        【6】添加清屏接口LCD_Clear,支持以某种颜色刷屏:

/**************************************************************************
* 函数名称: LCD_SetCursor
* 功能描述: 设置光标位置
* 输入参数: Xpos为横坐标,Ypos为纵坐标
* 输出参数: 
* 返 回 值: 
* 其它说明: 
**************************************************************************/
void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos)
{	 
	LCD_WriteCMD(lcddev.setxcmd);  //0x2A列地址设置命令
	LCD_WriteDAT(Xpos>>8); 
	LCD_WriteDAT(Xpos&0xFF);	
  	
	LCD_WriteCMD(lcddev.setycmd);  //0x2B行地址设置命令
	LCD_WriteDAT(Ypos>>8); 
	LCD_WriteDAT(Ypos&0xFF);
}

/**************************************************************************
* 函数名称: LCD_WriteRAM_Prepare
* 功能描述: 开始写GRAM
* 输入参数: 
* 输出参数: 
* 返 回 值: 
* 其它说明: 
**************************************************************************/
void LCD_WriteRAM_Prepare(void)
{
 	LCD_WriteCMD(lcddev.wramcmd);  //0x2C存储器写命令
}

/**************************************************************************
* 函数名称: LCD_WriteRAM
* 功能描述: LCD写GRAM,写颜色值
* 输入参数: 
* 输出参数: 
* 返 回 值: 
* 其它说明: 
**************************************************************************/
void LCD_WriteRAM(uint16_t Data)
{
 	SPI1_NSS_LOW();
    LCD_DC_HIGH();
    SPI_RW(SPI1_UNIT, Data);
    SPI_RW(SPI1_UNIT, Data >> 8);
    SPI1_NSS_HIGH();
}

/**************************************************************************
* 函数名称: LCD_Clear
* 功能描述: 清屏函数
* 输入参数: color:要清屏的填充色
* 输出参数: 
* 返 回 值: 
* 其它说明: 
**************************************************************************/
void LCD_Clear(uint16_t color)
{
	uint32_t index = 0;      
	uint32_t totalpoint = lcddev.width;  //屏幕横向总像素值
    
	totalpoint *= lcddev.height; //横向总像素*纵向总像素=得到总像素值
    LCD_SetCursor(0x00,0x0000);  //设置光标位置
	LCD_WriteRAM_Prepare();      //开始写入GRAM	 	  
	for(index = 0;index < totalpoint;index ++)
	{
		LCD_WriteRAM(color);	   
	}
}

        【7】画点函数LCD_DrawPoint:

/**************************************************************************
* 函数名称: LCD_DrawPoint
* 功能描述: 画点
* 输入参数: x,y为坐标,POINT_COLOR为此点的颜色
* 输出参数: 
* 返 回 值: 
* 其它说明: 
**************************************************************************/
void LCD_DrawPoint(U16 x,U16 y)
{
	LCD_SetCursor(x, y);         //设置光标位置 
	LCD_WriteRAM_Prepare();	     //开始写入GRAM
	LCD_WriteRAM(POINT_COLOR);   //画笔颜色
}

三 SPI屏点亮

        有了上面的接口作为准备,就可以驱动SPI串口屏显示一些简单的界面了:

/**************************************************************************
* 函数名称: LCD_AllInit
* 功能描述: LCD初始化
* 输入参数: 
* 输出参数: 
* 返 回 值: 
* 其它说明: 
**************************************************************************/
void LCD_AllInit(void)
{
    LCD_InitGPIO();  //初始化几个GPIO口,包括BL、DC、RES以及SPI的CS

    LCD_InitSPI1();  //初始化SPI的几个口,包括SCK、MOSI以及MISO

    LCD_HardwareReset();  //LCD复位

    LCD_ConfigureREG();   //RGB配置初始化
    
    LCD_DisplayDir(1);  //默认为横屏

    LCD_Clear(WHITE);  //清屏白色
}

/**************************************************************************
* 函数名称: GUI_Task
* 功能描述: GUI子任务
* 输入参数: 
* 输出参数: 
* 返 回 值: 
* 其它说明: 
**************************************************************************/
void GUI_Task(void)
{
//直接使用SPI的驱动来绘图
    uint8_t i = 0;
    LCD_AllInit();
    
    while(1)
    {
        switch(i)
		{
			case 1: LCD_Clear(WHITE); break;
			case 2: LCD_Clear(BLACK); break;
			case 3: LCD_Clear(RED); break;
			case 4: LCD_Clear(GREEN); break;
			case 5: LCD_Clear(BLUE); break;
            default: break;
		}
        i ++;
		if(i == 6) i=0;
        
        os_dly_wait(1000);  //RTX操作系统延时
    }

                  

        至此,关于SPI的一些基本移植已经完成,后续需要增加更多丰富的界面元素,考虑移植emWin来设计GUI界面。(后续的移植操作参考SPI屏+emWin移植)

四 附录

【1】ILI9341资料汇总:

https://download.csdn.net/download/sinat_33408502/21516340

【2】HC32F460资料汇总:

https://download.csdn.net/download/sinat_33408502/21516444

【3】《【嵌入式】MCU(HC32F460)+SPI接口LCD液晶屏ILI9341 移植emWin记录2----移植emWin》:

https://blog.csdn.net/sinat_33408502/article/details/119915261

你可能感兴趣的:(嵌入式,stm32,嵌入式,spi,gui,c语言)