轉自:http://bbs.armfly.com/read.php?tid=1545
重要說明:
(0)由於這個移植教程是去年過年的時候做的,用的是5.16,這就不再做個5.20的移植了,方法是一樣的。
(1)emWin手冊里面有這樣一句話:“驅動接口的改變始於emWin V5。不再支持針對emWin V4 或更早版本開發的老顯示驅動”。
(2)如果不使用V5以后版本的新特性,基本和以前的版本使用是一樣的,也就是說,大家用V5以前版本實現的功能,直接升級
到現有的版本,基本可以正常運行。
(3)盡管emWin提供了大部分屏的驅動,但是不能包含所有,這篇移植文檔就因此而生。不管是emWin已經支持的,還是沒有
提供支持的,均可采用這種方法。
(4)提供了一個非常好的觸摸濾波方法,此方法可以有效的濾除飛點。
STM42F4+emWin5.16+3.0寸視頻演示
STM42F4+emWin5.16+4.3寸視頻演示
STM42F4+emWin5.16+7寸視頻演示
(1)MDK4.54版本里面的有emWin5.16的庫,大家注意一下這個文件夾里面的emWin庫。

可以看到支持M4的GUI庫,所有就用這個庫,大家都知道M4相對於M3,主要是增加了浮點運算,
但是emWin手冊里面有這樣一個說明。

手冊里面明確的說明了emWin的庫,絕對無浮點使用。所有如果使用M3的emWin庫也是沒有問題的。
(2)MDK要添加下面的LICENSE, 如果不添加是不能用emWin的庫。

添加方法也很簡單,用大家注冊MDK時的-注-冊-機就可以的,不貼全圖了。

(3)要添加MDK對M4的浮點支持,添加方法也很簡單,提供的例程里面就有,看一下就會了,這里不
再做說明了。
二.現在就可以開始移植工作了。
主要添加下圖所示的幾個文件

下面就對這些文件進行詳細的說明
(1) bsp_touch.c這個文件主要提供觸摸的驅動函數,以便emWin中
GUI_TOUCH_X_MeasureX GUI_TOUCH_X_MeasureY
兩個函數的調用。
特別注意,這里改變觸摸的濾波方法,以前用去點前幾個點和后幾個點,然后中間數值取平均的方法,效果並不理想,
不用有效的濾除飛點,這里使用一個新的方法。
1.1、在emWin里面使用使用觸摸的中斷方式,效果並不好,所以這里使用查詢,查詢此引腳的電平,這樣可以避免不必要的調用
GUI_TOUCH_X_MeasureX
GUI_TOUCH_X_MeasureY
兩個函數。
1.2、觸摸濾波,主要是濾的是飛點,就應為這些飛點的存在,才使得觸摸很不穩定。
下面的這個函數,大家應該很熟悉,就是濾除前幾個點和后面幾個點,然后中間幾個點取平均
/* 讀取次數 根據實際情況修改 */
#define XPT2046_READ_TIMES 5
/* 丟棄值 */
#define XPT2046_LOST_VAL 1
uint16_t TOUCH_DataFilter(uint8_t _ucCh)
{
uint16_t i, j;
uint16_t buf[XPT2046_READ_TIMES];
uint16_t usSum;
uint16_t usTemp;/* 讀取READ_TIMES次數據 */
for(i=0; i < XPT2046_READ_TIMES; i++)
{
if (g_ChipID == IC_8875)
{
if(_ucCh == ADC_CH_X)
{
buf = RA8875_TouchReadX();
}
else
{
buf = RA8875_TouchReadY();
}
}
else
{
buf = TSC2046_ReadAdc(_ucCh);
}
}
/* 升序排列 */
for(i = 0; i < XPT2046_READ_TIMES - 1; i++)
{
for(j = i + 1; j < XPT2046_READ_TIMES; j++)
{
if(buf > buf[j])
{
usTemp = buf;
buf = buf[j];
buf[j] = usTemp;
}
}
}
usSum = 0;
/*求和 */
for(i = XPT2046_LOST_VAL; i < XPT2046_READ_TIMES - XPT2046_LOST_VAL; i++)
{
usSum += buf;
}
/*求平均 */
usTemp = usSum / (XPT2046_READ_TIMES - 2 * XPT2046_LOST_VAL);
return usTemp;
}
下面的這個函數就很重要了,要濾除飛點,就全靠它了。
/* 誤差范圍 根據實際情況調節誤差范圍 */
uint8_t ADC_ERR_RANGE = 5;
uint8_t TOUCH_ReadAdcXY(int16_t *_usX, int16_t *_usY)
{
uint16_t iX1, iY1;
uint16_t iX2, iY2;
uint16_t iX, iY;
iX1 = TOUCH_DataFilter(ADC_CH_X);
iY1 = TOUCH_DataFilter(ADC_CH_Y);
iX2 = TOUCH_DataFilter(ADC_CH_X);
iY2 = TOUCH_DataFilter(ADC_CH_Y);
iX = TOUCH_Abs(iX1 - iX2);
iY = TOUCH_Abs(iY1 - iY2);
/* 前后兩次采樣在+-ERR_RANGE內 */
if ((iX <= ADC_ERR_RANGE) && (iY <= ADC_ERR_RANGE))
{
if(g_ucGPIX == 1)
{
*_usY = (iX1 + iX2) / 2;
*_usX = (iY1 + iY2) / 2;
}
else
{
*_usX = (iX1 + iX2) / 2;
*_usY = (iY1 + iY2) / 2;
}
return 1;
}
else
{
return 0;
}
}
觸摸的驅動就這些東西,詳細的使用看例程級可以,然后在文件GUI_X_Touch_Analog.c里面調用就可以了。
int GUI_TOUCH_X_MeasureX(void)
{
TOUCH_SCAN();
return(g_tTP.usAdcNowX);
}
int GUI_TOUCH_X_MeasureY(void)
{
return(g_tTP.usAdcNowY);
}
(2) 下面的說明就很重要了,這個是實現emWin移植成功的關鍵。
在文件夾DisplayDriver有這三個文件,這里我們使用第一個。
打開這個文件,會發現里面的函數很面熟,是的,基本和UCGUI3.98里面的差不多,但是這個里面的功能更加全面。
2.1、如果不使用優化,直接提供一個打點和讀點的函數就可以了,如果想優化一下,就繼續往下看。
優化需要修改的函數有下面幾個。
/*
********************************************************************
*
* _DrawHLine
*
*******************************************************************
*/
static void _DrawHLine (GUI_DEVICE * pDevice, int x0, int y, int x1) {
if (GUI_Context.DrawMode & LCD_DRAWMODE_XOR) {
for (; x0 <= x1; x0++) {
_XorPixel(pDevice, x0, y);
}
} else {
#if emWin_Optimize //這里使用了一個宏定義,是否使用優化
//LCD8875_DrawHLine(x0, y, x1, LCD_COLORINDEX);
s_ucRA8875BusyNow = 1;
LCD_DrawLineH(x0, y, x1, LCD_COLORINDEX);
s_ucRA8875BusyNow = 0;
#else
LCD_PIXELINDEX ColorIndex;
ColorIndex = LCD__GetColorIndex();
for (; x0 <= x1; x0++) {
_SetPixelIndex(pDevice, x0, y, ColorIndex);
}
#endif
}
}
/*
*************************************************************************
*
* _DrawVLine, not optimized
*
*************************************************************************
*/
static void _DrawVLine (GUI_DEVICE * pDevice, int x, int y0, int y1) {
if (GUI_Context.DrawMode & LCD_DRAWMODE_XOR) {
for (; y0 <= y1; y0++) {
_XorPixel(pDevice, x, y0);
}
} else {
#if emWin_Optimize
// LCD8875_DrawVLine(x, y0, y1, LCD_COLORINDEX);
s_ucRA8875BusyNow = 1;
LCD_DrawLineV(x, y0, y1, LCD_COLORINDEX);
s_ucRA8875BusyNow = 0;
#else
LCD_PIXELINDEX ColorIndex;
ColorIndex = LCD__GetColorIndex();
for (; y0 <= y1; y0++) {
_SetPixelIndex(pDevice, x, y0, ColorIndex);
}
#endif
}
}
/*
**************************************************************************
*
* _FillRect
*
**************************************************************************
*/
static void _FillRect(GUI_DEVICE * pDevice, int x0, int y0, int x1, int y1)
{
#if emWin_Optimize
if (g_ChipID == IC_8875)
{
s_ucRA8875BusyNow = 1;
BTE_SetTarBlock(x0, y0, y1-y0+1, x1-x0+1, 0); /* 設置BTE位置和寬度高度 */
BTE_SetOperateCode(0x0C); /* 設定BTE 操作碼和光柵運算碼 REG[51h] Bit[3:0] = 0Ch */
RA8875_SetFrontColor(LCD_COLORINDEX); /* 設置BTE前景色 */
BTE_Start(); /* 開啟BTE 功能 */
BTE_Wait(); /* 等待操作結束 */
s_ucRA8875BusyNow = 0;
}
else
{
for (; y0 <= y1; y0++)
{
_DrawHLine(pDevice, x0, y0, x1);
}
}
#else
for (; y0 <= y1; y0++)
{
_DrawHLine(pDevice, x0, y0, x1);
}
#endif
}
下面的這個函數優化很重要,要想窗口打開的快點,下面的必須優化!!!!!!!
/*
**************************************************************************
*
* Draw Bitmap 16 BPP, not optimized
*
**************************************************************************
*/
static void _DrawBitLine16BPP(GUI_DEVICE * pDevice, int x, int y, U16 const GUI_UNI_PTR * p, int xsize)
{
#if emWin_Optimize
// RA8875_SetCursor(x,y);
// RA8875_REG = 0x02;
// for (;xsize > 0; xsize--,p++)
// {
// RA8875_RAM = *p;
// }
s_ucRA8875BusyNow = 1;
LCD_DrawHColorLine(x, y, xsize, (uint16_t *)p);
s_ucRA8875BusyNow = 0;
#else
for (;xsize > 0; xsize--, x++, p++)
{
_SetPixelIndex(pDevice, x, y, *p);
}
#endif
}
(3)驅動函數寫好以后,就是配置函數了,配置函數寫好了,emWin就可以跑起來了。
寫貼一個官方的配置流程。
下面就按照這個流程進行配置,如果沒有說到的,看例程就可以。
/* Define the available number of bytes available for the GUI */
#define GUI_NUMBYTES 130000
/* Define the average block size */
#define GUI_BLOCKSIZE 0x80
為emWin分配動態內存
/*********************************************************************
*
* GUI_X_Config
*
* Purpose:
* Called during the initialization process in order to set up the
* available memory for the GUI.
**********************************************************************
*/
void GUI_X_Config(void)
{
/* 32 bit aligned memory area */
static U32 aMemory[GUI_NUMBYTES / 4];
/* Assign memory to emWin */
GUI_ALLOC_AssignMemory(aMemory, GUI_NUMBYTES);
GUI_ALLOC_SetAvBlockSize(GUI_BLOCKSIZE);
}
然后就是最關鍵的LCD_X_Config,這里對7寸4.3寸 3.0寸都做了支持。
/*
****************************************************************************
*
* LCD_X_Config
*
* Purpose:
* Called during the initialization process in order to set up the
* display driver configuration.
*
****************************************************************************
*/
void LCD_X_Config(void)
{
/* Set display driver and color conversion for 1st layer */
GUI_DEVICE_CreateAndLink(DISPLAY_DRIVER, COLOR_CONVERSION, 0, 0);
if (g_ChipID == IC_8875)
{
if (g_ucGPIX == 1) /* GPIX = 1 4.3 480x272 */
{
/* Display driver configuration */
LCD_SetSizeEx (0, 480, 272);
LCD_SetVSizeEx (0, 480, 272);
/* Touch calibration */
GUI_TOUCH_Calibrate(GUI_COORD_X, 0, 479, 985, 50);
GUI_TOUCH_Calibrate(GUI_COORD_Y, 0, 271, 920, 100);
}
else /* GPIX = 0 7 800*480 */
{
/* Display driver configuration */
LCD_SetSizeEx (0, XSIZE_PHYS, YSIZE_PHYS);
LCD_SetVSizeEx (0, VXSIZE_PHYS, VYSIZE_PHYS);
// LCD_SetVRAMAddrEx(0, (void *)VRAM_ADDR);
/* Touch calibration */
// GUI_TOUCH_SetOrientation(0);
GUI_TOUCH_Calibrate(GUI_COORD_X, 0, XSIZE_PHYS - 1, GUI_TOUCH_AD_LEFT, GUI_TOUCH_AD_RIGHT);
GUI_TOUCH_Calibrate(GUI_COORD_Y, 0, YSIZE_PHYS - 1, GUI_TOUCH_AD_TOP, GUI_TOUCH_AD_BOTTOM);
}
}
else
{
LCD_SetSizeEx (0, 400, 240);
LCD_SetVSizeEx (0, 400, 240);
/* Touch calibration */
GUI_TOUCH_Calibrate(GUI_COORD_X, 0, 399, 300, 3600);
GUI_TOUCH_Calibrate(GUI_COORD_Y, 0, 239, 273, 3671);
}
}
大家根據自己的屏,配置屏的大小和觸摸校准就可以了。到這里移植就算結束了。