目录
一 SPI屏的接线
SPI屏的特点在于接线简单,只需要四根SPI线以及几个GPIO口即可驱动工作,但是由于非并口的,所以当像素比比较大的时候,刷新速度可能会受到考验。我这边使用的是一块320*240的串口屏,屏幕驱动为ILI9341,控制芯片选用的是华大的HC32F460,主频为168Mhz,因为主频比较高,同时对屏幕刷新显示要求不大,所以考虑基于此进行开发。
首先根据显示屏的接线图进行接线:
其中,真正需要关注的是SPI的四线(SDA即MOSI、SDO即MISO、SCL即SCK、CS片选),GPIO三根线RST复位线、D/C区别输出的是指令还是数据以及LEDA(BL)背光线。
接线示意图如下:
二 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