一 并口屏接线
? ? ? ? 之前整了一块串口屏,实际使用中,感觉整屏(320*240)的刷新速度还是有点偏慢,肉眼能够看到明显的刷屏动作,故而考虑改用并口屏来实现显示功能。
????????首先根据显示屏的接线图进行接线:
?
? ? ? ? 其中,真正需要关注的是CS、RS、WR、RD、RESET以及DB0-15数据线。?
?
二 并口屏驱动初始化
????????接线完成之后,就需要在程序中对这几个接口进行初始化。
? ? ? ? 这边区别于SPI的串口屏,只要把所有的引脚作为GPIO口输入输出即可。
????????【1】首先选定几个管脚,做一些定义(注意!!!:这边的DATAOUT(x)宏是采用了位带操作,直接对PortE的PODRE寄存器进行操作,这样就相当于在PortE接满0-15管脚的情况下,输出对应的16位数据):
#define LCD_CS_HIGH() (PORT_SetBits(PortC, Pin00))
#define LCD_CS_LOW() (PORT_ResetBits(PortC, Pin00))
#define LCD_RS_HIGH() (PORT_SetBits(PortC, Pin01))
#define LCD_RS_LOW() (PORT_ResetBits(PortC, Pin01))
#define LCD_WR_HIGH() (PORT_SetBits(PortC, Pin02))
#define LCD_WR_LOW() (PORT_ResetBits(PortC, Pin02))
#define LCD_RD_HIGH() (PORT_SetBits(PortC, Pin03))
#define LCD_RD_LOW() (PORT_ResetBits(PortC, Pin03))
#define LCD_RES_HIGH() (PORT_SetBits(PortA, Pin07))
#define LCD_RES_LOW() (PORT_ResetBits(PortA, Pin07))
#define DATAOUT(x) M4_PORT->PODRE=(x)
? ? ? ? 【2】其次是GPIO口初始化:
/**************************************************************************
* 函数名称: LCD_InitGPIO
* 功能描述: LCD初始化GPIO引脚
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明: 初始化LCD用到的GPIO口,包括CS\RS\WR\RD\RES\DB0-15
**************************************************************************/
void LCD_InitGPIO(void)
{
stc_port_init_t stcPortInit;
/* configure structure initialization */
MEM_ZERO_STRUCT(stcPortInit);
stcPortInit.enPinMode = Pin_Mode_Out;
/* CS & RS & WR & RD & RES*/
PORT_Init(PortC, Pin00, &stcPortInit);
PORT_Init(PortC, Pin01, &stcPortInit);
PORT_Init(PortC, Pin02, &stcPortInit);
PORT_Init(PortC, Pin03, &stcPortInit);
PORT_Init(PortA, Pin07, &stcPortInit);
LCD_CS_HIGH();
LCD_RS_HIGH();
LCD_WR_HIGH();
LCD_RD_HIGH();
LCD_RES_HIGH();
/*DB0-15*/
PORT_Init(PortE, Pin00, &stcPortInit);
PORT_Init(PortE, Pin01, &stcPortInit);
PORT_Init(PortE, Pin02, &stcPortInit);
PORT_Init(PortE, Pin03, &stcPortInit);
PORT_Init(PortE, Pin04, &stcPortInit);
PORT_Init(PortE, Pin05, &stcPortInit);
PORT_Init(PortE, Pin06, &stcPortInit);
PORT_Init(PortE, Pin07, &stcPortInit);
PORT_Init(PortE, Pin08, &stcPortInit);
PORT_Init(PortE, Pin09, &stcPortInit);
PORT_Init(PortE, Pin10, &stcPortInit);
PORT_Init(PortE, Pin11, &stcPortInit);
PORT_Init(PortE, Pin12, &stcPortInit);
PORT_Init(PortE, Pin13, &stcPortInit);
PORT_Init(PortE, Pin14, &stcPortInit);
PORT_Init(PortE, Pin15, &stcPortInit);
}
? ? ? ? 【3】封装LCD写命令、写数据、写GRAM接口(注意!!!:这边的入参与串口屏有区别,串口屏入参为一个字节数据,而这边是U16即两字节数据,这会影响到颜色的表现):
/**************************************************************************
* 函数名称: LCD_WriteCMD
* 功能描述: LCD写命令
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
**************************************************************************/
void LCD_WriteCMD(U16 Command)
{
LCD_RS_LOW();
LCD_CS_LOW();
DATAOUT(Command);
LCD_WR_LOW();
LCD_WR_HIGH();
LCD_CS_HIGH();
}
/**************************************************************************
* 函数名称: LCD_WriteDAT
* 功能描述: LCD写数据
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
**************************************************************************/
void LCD_WriteDAT(U16 Data)
{
LCD_RS_HIGH();
LCD_CS_LOW();
DATAOUT(Data);
LCD_WR_LOW();
LCD_WR_HIGH();
LCD_CS_HIGH();
}
/**************************************************************************
* 函数名称: LCD_WriteRAM
* 功能描述: LCD写GRAM,写颜色值
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
**************************************************************************/
void LCD_WriteRAM(uint16_t Data)
{
LCD_RS_HIGH();
LCD_CS_LOW();
DATAOUT(Data);
LCD_WR_LOW();
LCD_WR_HIGH();
LCD_CS_HIGH();
}
????????【4】有了底层驱动之后,因为串口屏和并口屏都是用的ILI9341驱动,所以其他的功能接口,包括寄存器的配置,参考【嵌入式】MCU(HC32F460)+SPI接口LCD液晶屏ILI9341 移植emWin记录1----点亮LCD屏即可。
三 并口屏点亮
????????有了上面的接口作为准备,就可以驱动并口屏显示一些简单的界面了。这边的程序也与串口屏类似,这边不再赘述。
四 移植emwin
????????完成了点亮LCD屏之后,考虑到将要设计较为复杂的界面GUI,光用一些基本的绘图、显示字符接口不能满足要求,所以琢磨着再移植一套emWin,用来辅助设计GUI(由emWin的用户手册中可以看到,emWin是可以支持ILI9341的液晶屏驱动芯片的)。
? ? ? ? 移植准备与串口屏类似,参考【嵌入式】MCU(HC32F460)+SPI接口LCD液晶屏ILI9341 移植emWin记录2----移植emWin,这边也不再赘述。
? ? ? ? 需要重点提一下与串口屏emwin移植的区别,这也是本文的重点:
? ? ? ? 这边涉及到两种移植方法,一种是直接线性访问驱动、第二种是间接访问驱动。关于这两种移植方法的区别可以参考方法一:直接线性访问驱动、方法一:间接访问驱动。
? ? ? ? 【方法一】:直接线性访问驱动
void LCD_X_Config(void) {
//方法1:直接线性访问驱动
GUI_DEVICE_CreateAndLink(DISPLAY_DRIVER, COLOR_CONVERSION, 0, 0);
if (LCD_GetSwapXY()) {
LCD_SetSizeEx (0, YSIZE_PHYS, XSIZE_PHYS);
LCD_SetVSizeEx(0, YSIZE_PHYS, XSIZE_PHYS);
} else {
LCD_SetSizeEx (0, XSIZE_PHYS, YSIZE_PHYS);
LCD_SetVSizeEx(0, XSIZE_PHYS, YSIZE_PHYS);
}
}
????????修改GUIDRV_Template.c文件。这边需要修改画点函数_SetPixelIndex(),在其中嵌入
自己的打点函数LCD_DrawPoint(x, y):
static void _SetPixelIndex(GUI_DEVICE * pDevice, int x, int y, LCD_PIXELINDEX PixelIndex) {
#ifdef WIN32
LCDSIM_SetPixelIndex(x, y, PixelIndex, pDevice->LayerIndex);
#else
//
// Convert logical into physical coordinates (Dep. on LCDConf.h)
//
#if (LCD_MIRROR_X == 1) || (LCD_MIRROR_Y == 1) || (LCD_SWAP_XY == 1)
int xPhys, yPhys;
xPhys = LOG2PHYS_X(x, y);
yPhys = LOG2PHYS_Y(x, y);
#else
#define xPhys x
#define yPhys y
#endif
GUI_USE_PARA(pDevice);
GUI_USE_PARA(x);
GUI_USE_PARA(y);
GUI_USE_PARA(PixelIndex);
{
//
// Write into hardware ... Adapt to your system
//
// TBD by customer...
//
LCD_DrawPoint(x, y); //重要:自行添加的画点函数
}
#if (LCD_MIRROR_X == 0) && (LCD_MIRROR_Y == 0) && (LCD_SWAP_XY == 0)
#undef xPhys
#undef yPhys
#endif
#endif
}
? ? ? ? 与此同时,清屏程序_FillRect也需要改一下,有利于提高清屏速度(注意!!!:之前的串口屏程序没有这个操作也能用,但可能会影响到清屏速度):
/**************************************************************************
* 函数名称: LCD_Fill
* 功能描述: 填充色块函数
* 输入参数:
* 输出参数:
* 返 回 值:
* 其它说明:
**************************************************************************/
void LCD_Fill(U16 sx,U16 sy,U16 ex,U16 ey,U16 color)
{
U16 i,j;
U16 xlen=0;
xlen=ex-sx+1;
for(i=sy;i<=ey;i++)
{
LCD_SetCursor(sx,i); //设置光标位置
LCD_WriteRAM_Prepare(); //开始写入GRAM
for(j=0;j<xlen;j++)LCD_WriteRAM(color); //设置光标位置
}
}
/*********************************************************************
*
* _FillRect
*/
static void _FillRect(GUI_DEVICE * pDevice, int x0, int y0, int x1, int y1) {
LCD_PIXELINDEX PixelIndex;
int x;
PixelIndex = LCD__GetColorIndex();
if (GUI_pContext->DrawMode & LCD_DRAWMODE_XOR) {
for (; y0 <= y1; y0++) {
for (x = x0; x <= x1; x++) {
_XorPixel(pDevice, x, y0);
}
}
} else {
// for (; y0 <= y1; y0++) {
// for (x = x0; x <= x1; x++) {
// _SetPixelIndex(pDevice, x, y0, PixelIndex);
// }
// }
LCD_Fill(x0,y0,x1,y1,LCD_COLORINDEX);
}
}
? ? ? ? 其他部分的改动延用串口屏的移植即可。这样直接线性访问(LIN方式)移植成功。
????????【方法二】:间接访问驱动
void LCD_X_Config(void) {
//方法2:间接访问驱动
GUI_DEVICE * pDevice;
GUI_PORT_API PortAPI = {0};
pDevice = GUI_DEVICE_CreateAndLink(&GUIDRV_FlexColor_API, COLOR_CONVERSION, 0, 0);
if (LCD_GetSwapXY()) {
LCD_SetSizeEx (0, YSIZE_PHYS, XSIZE_PHYS);
LCD_SetVSizeEx(0, YSIZE_PHYS, XSIZE_PHYS);
} else {
LCD_SetSizeEx (0, XSIZE_PHYS, YSIZE_PHYS);
LCD_SetVSizeEx(0, XSIZE_PHYS, YSIZE_PHYS);
}
// PortAPI.pfWrite8_A0 = LcdWriteReg;
// PortAPI.pfWrite8_A1 = LcdWriteData;
// PortAPI.pfWriteM8_A1 = LcdWriteDataMultiple;
// PortAPI.pfReadM8_A1 = LcdReadDataMultiple;
PortAPI.pfWrite16_A0 = LcdWriteReg;
PortAPI.pfWrite16_A1 = LcdWriteData;
PortAPI.pfWriteM16_A1 = LcdWriteDataMultiple;
PortAPI.pfReadM16_A1 = LcdReadDataMultiple;
GUIDRV_FlexColor_SetFunc(pDevice, &PortAPI, GUIDRV_FLEXCOLOR_F66709, GUIDRV_FLEXCOLOR_M16C0B16);
}
? ? ? ? 这边的读写命令接口仍然使用8位访问的话,对于并口屏会有问题,所以修改接口为16位访问的方式:
static void LcdWriteReg(U16 Data) {
LCD_WriteCMD(Data);
}
static void LcdWriteData(U16 Data) {
LCD_WriteDAT(Data);
}
static void LcdWriteDataMultiple(U16 * pData, int NumItems) {
while(NumItems--){
LCD_WriteDAT(*pData);
}
}
static void LcdReadDataMultiple(U16 * pData, int NumItems) {
return ;
}
? ? ? ? 后面的GUIDRV_FlexColor_SetFunc接口内容,由于还是用的驱动芯片ILI9341,所以也无需改动这边的代码。(注意!!!:GUIDRV_FLEXCOLOR_F66709 和 GUIDRV_FLEXCOLOR_M16C0B16 ,前一个参数是选择控制器的,后一个参数是选择位宽等模式的。首先你要看一下你所用的LCD控制器是否在受支持的范围内,如果不支持那就GG了。我的显示器是ILI9341所以我选择了66709这种方式。具体可以参考emWin用户手册中的内容)
? ? ? ? ?至此,第二种方法也移植成功。
五 汇总几个遇到的坑
? ? ? ? (1)设置LCD自动扫描方向的接口LCD_ScanDir中,有一段这样的代码:
? ? ? ? 这边我一开始设置成regval |= 0x08,导致的结果就是颜色反向了,原因在于0x36命令是存储器访问控制,其中有一位寄存器表示RGB与BGR的顺序(若为1,则是BGR;若为0,则是RGB):
?????????(2)emWin中定义驱动器颜色COLOR_CONVERSION为GUICC_565或者GUICC_M565是有区别的,同样一个是RGB,一个是BGR。
? ? ? ? (3)一开始使用方法二间接访问驱动,不管怎么操作,预期是GUI_SetBkColor(GUI_WHITE),然而出来的屏幕背景都是红色。后来查明原因在于LCDConf.c中,还是使用的之前串口屏的8位读写访问,可能预期发送的是白色(0xFFFF)命令,而实际只发出去了一半,即红色(0xFF00)命令。后来将这边的8位访问修改为16位访问,问题得到解决。
六 附录
【1】【嵌入式】MCU(HC32F460)+SPI接口LCD液晶屏ILI9341 移植emWin记录1----点亮LCD屏
【2】【嵌入式】MCU(HC32F460)+SPI接口LCD液晶屏ILI9341 移植emWin记录2----移植emWin
【3】HC32F460相关文档资料汇总
【4】emWin_V5.42中文手册
【5】ILI9341驱动器相关文档资料汇总
|