在这里首先感谢wzt的文章《ucgui液晶显示深度优化篇》写的很详细,运行很高效。
http://www.docin.com/p-453546222.html
在这里我提出另一种方法,在完全不破坏原有的uCGUI接口功能上进行强力提速。当然速度方面要弱于wzt的速度,当然优点就在于不破坏所有接口功能,保留下了uCGUI的所有功能。例如两个图片交叉异或显示。
好了,下面开始改进。
这里先提一下我用的LCD是3.2寸SSD1289屏,神舟三号开发板。 这里不管用什么屏,只要屏写像素点后如图所示移动就可以了。 从这里大家应该也看出来了, 我主要用到的方法就是在写连续像素时省去每次设置坐标点的问题。这就是我下面文章思想的基础了。
我用的是LCDTemplate.c接口文件。直接在其上进行改进。
在文件最上方添加以下几个基本函数:
typedef struct
{
vu16 LCD_REG;
vu16 LCD_RAM;
} LCD_TypeDef;
#define LCD_BASE ((u32)(0x60000000 | 0x0C000000))
static volatile LCD_TypeDef *LCD = ((volatile LCD_TypeDef *) LCD_BASE);
/*********************************************************************
*
* 设定坐标
*/
__forceinline void LCD_SetCursor(U16 x, U16 y)
{
int xPhys;
int yPhys;
/* Convert logical into physical coordinates (Dep. on LCDConf.h) */
#if LCD_SWAP_XY | LCD_MIRROR_X| LCD_MIRROR_Y
xPhys = LOG2PHYS_X(x, y);
yPhys = LOG2PHYS_Y(x, y);
#else
xPhys = x;
yPhys = y;
#endif
LCD->LCD_REG = 0x004F;
LCD->LCD_RAM = 319 - xPhys;
LCD->LCD_REG = 0x004E;
LCD->LCD_RAM = yPhys;
}
/*********************************************************************
*
* 当前坐标读一个像素
*/
__forceinline U16 LCD_GetPoint()
{
LCD->LCD_REG = 0x22;
LCD->LCD_RAM > 0; //等待数据稳定
return LCD->LCD_RAM;
}
/*********************************************************************
*
* 当前坐标写一个像素
*/
__forceinline void LCD_SetPoint(U16 point)
{
LCD->LCD_REG = 0x22;
LCD->LCD_RAM = point;
}
/*********************************************************************
*
* 当前坐标开始画一条水平线
* xEnd:结束坐标
*/
__forceinline void LCD_DrawHLineExt(int x, int xEnd, U16 point)
{
LCD->LCD_REG = 0x22;
while (x++ <= xEnd)
LCD->LCD_RAM = point;
}
这些基本函数 要根据各自的lcd屏驱动所定的。
在原先的移植上 做如下修改:
原函数
void LCD_L0_SetPixelIndex(int x, int y, int PixelIndex) {
int xPhys = 0;
int yPhys = 0;
GUI_USE_PARA(x);
GUI_USE_PARA(y);
GUI_USE_PARA(PixelIndex);
/* Convert logical into physical coordinates (Dep. on LCDConf.h) */
#if LCD_SWAP_XY | LCD_MIRROR_X| LCD_MIRROR_Y
xPhys = LOG2PHYS_X(x, y);
yPhys = LOG2PHYS_Y(x, y);
#else
xPhys = x;
yPhys = y;
#endif
/* Write into hardware ... Adapt to your system */
{
ili9320_SetPoint(xPhys, yPhys, PixelIndex);/* ... */
}
}
unsigned int LCD_L0_GetPixelIndex(int x, int y) {
int xPhys = 0;
int yPhys = 0;
LCD_PIXELINDEX PixelIndex;
GUI_USE_PARA(x);
GUI_USE_PARA(y);
/* Convert logical into physical coordinates (Dep. on LCDConf.h) */
#if LCD_SWAP_XY | LCD_MIRROR_X| LCD_MIRROR_Y
xPhys = LOG2PHYS_X(x, y);
yPhys = LOG2PHYS_Y(x, y);
#else
xPhys = x;
yPhys = y;
#endif
/* Read from hardware ... Adapt to your system */
{
PixelIndex = ili9320_GetPoint(xPhys, yPhys);/* ... */
}
return PixelIndex;
}
修改后
void LCD_L0_SetPixelIndex(int x, int y, int PixelIndex) {
GUI_USE_PARA(x);
GUI_USE_PARA(y);
GUI_USE_PARA(PixelIndex);
LCD_SetCursor(x, y);
LCD_SetPoint(PixelIndex);
}
unsigned int LCD_L0_GetPixelIndex(int x, int y) {
GUI_USE_PARA(x);
GUI_USE_PARA(y);
LCD_SetCursor(x, y);
return LCD_GetPoint();
}
原文件
void LCD_L0_DrawHLine (int x0, int y, int x1) {
if (GUI_Context.DrawMode & LCD_DRAWMODE_XOR) {
for (; x0 <= x1; x0++) {
LCD_L0_XorPixel(x0, y);
}
} else {
for (; x0 <= x1; x0++) {
LCD_L0_SetPixelIndex(x0, y, LCD_COLORINDEX);
}
}
}
修改后
void LCD_L0_DrawHLine (int x0, int y, int x1) {
if (GUI_Context.DrawMode & LCD_DRAWMODE_XOR) {
while(x0++ <= x1)
LCD_L0_XorPixel(x0, y);
} else {
LCD_SetCursor(x0, y);
LCD_DrawHLineExt(x0, x1, LCD_COLORINDEX);
}
}
细节观察,这个函数只是把写坐标分离出来了。
关键的修改,大部分刷屏程序都用到LCD_L0_DrawHLine函数,所以优化他对你的程序提速起了决定性的改变。
原理很简单,只要画水平线时,每写一个像素,坐标会自动后移一位。所以没必要每次都指定坐标,把设置坐标的时间给节约出来。
最后就是画图函数了,我的LCD是16位的,所以我只修改了DrawBitLine16BPP一个函数,如果你的是低于16位的,同理进行修改。
参考如下
原函数
static void DrawBitLine16BPP(int x, int y, U16 const GUI_UNI_PTR * p, int xsize, const LCD_PIXELINDEX * pTrans) {
LCD_PIXELINDEX pixel;
if ((GUI_Context.DrawMode & LCD_DRAWMODE_TRANS) == 0) {
if (pTrans) {
for (; xsize > 0; xsize--, x++, p++) {
pixel = *p;
LCD_L0_SetPixelIndex(x, y, *(pTrans + pixel));
}
} else {
for (;xsize > 0; xsize--, x++, p++) {
LCD_L0_SetPixelIndex(x, y, *p);
}
}
} else {
if (pTrans) {
for (; xsize > 0; xsize--, x++, p++) {
pixel = *p;
if (pixel) {
LCD_L0_SetPixelIndex(x, y, *(pTrans + pixel));
}
}
} else {
for (; xsize > 0; xsize--, x++, p++) {
pixel = *p;
if (pixel) {
LCD_L0_SetPixelIndex(x, y, pixel);
}
}
}
}
}
修改后如下
static void DrawBitLine16BPP(int x, int y, U16 const GUI_UNI_PTR * p, int xsize, const LCD_PIXELINDEX * pTrans) {
LCD_PIXELINDEX pixel;
LCD_SetCursor(x, y);
if ((GUI_Context.DrawMode & LCD_DRAWMODE_TRANS) == 0) {
if (pTrans) {
for (; xsize > 0; xsize--, x++, p++) {
pixel = *p;
LCD_SetPoint(*(pTrans + pixel));
}
} else {
for (;xsize > 0; xsize--, x++, p++) {
LCD_SetPoint(*p);
}
}
} else {
if (pTrans) {
for (; xsize > 0; xsize--, x++, p++) {
pixel = *p;
if (pixel) {
LCD_SetPoint(*(pTrans + pixel));
}
}
} else {
for (; xsize > 0; xsize--, x++, p++) {
pixel = *p;
if (pixel) {
LCD_SetPoint(pixel);
}
}
}
}
}
好了,修改完了,可以进行测试了。
这里附上我的测试工程:
http://pan.baidu.com/share/link?shareid=63325&uk=118334538
视频预览。
http://www.tudou.com/programs/view/sQexoNIhNR0/#