当前位置: 首页 > ds >正文

Ai8051 2.4寸320*240 ILI9341 I8080接口驱动

/*---------------------------------------------------------------------*/
/* --- Web: www.STCAI.com ---------------------------------------------*/
/* 液晶屏驱动程序参考wiki技术网站提供的开源源码,仅供学习使用          */
/*---------------------------------------------------------------------*/

/************************************************************************************************

本例程基于AI8051U为主控芯片的实验箱进行编写测试.

使用Keil C251编译器,Memory Model推荐设置XSmall模式,默认定义变量在edata,单时钟存取访问速度快。

edata建议保留1K给堆栈使用,空间不够时可将大数组、不常用变量加xdata关键字定义到xdata空间。

本实验测试使用的是2.4寸320*240 ILI9341 I8080接口驱动的并口彩屏。

主循环修改判断条件参数可修改测试模式:0:触摸测试, 1:显示测试

下载时, 选择时钟 40MHz (用户可自行修改频率).

************************************************************************************************/

//=========================================电源接线================================================//
//VDD接DC 3.3V电源
//GND接地
//=======================================液晶屏数据线接线==========================================//
//本模块数据总线类型为8位并口
// LCD_D0~D7     接       P20~P27        //液晶屏8位数据线
//=======================================液晶屏控制线接线==========================================//
// LCD_RS        接        P45           //数据/命令选择控制信号
// LCD_RD        接        P37           //读控制信号
// LCD_RST       接        P47           //复位信号
// LCD_WR        接        P36           //写控制信号
// LCD_CS        接        P05/P53       //片选控制信号
//================================================================================================//
//不使用触摸或者模块本身不带触摸,则可不连接
//触摸屏使用的数据总线类型为SPI
//  T_CS         接        P15          //触摸屏片选控制信号
//  T_CLK        接        P32          //触摸屏SPI时钟信号
//  T_DO         接        P33          //触摸屏SPI读信号
//  T_DIN        接        P34          //触摸屏SPI写信号
//  T_IRQ        接        P14          //触摸屏响应检查信号
//================================================================================================//
// 本实验使用的2.4寸320*240的并口彩屏,由冲哥淘宝店提供:http://e.tb.cn/h.gIlbVqAOj8YXlwo?tk=vFIr3RGTy2n
//**************************************************************************************************/

#include "sys.h"
#include "lcd.h"
#include "gui.h"
#include "test.h"
#include "touch.h"

//主函数
void main(void)

WTST = 0;  //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
EAXFR = 1; //扩展寄存器(XFR)访问使能
CKCON = 0; //提高访问XRAM速度

    //液晶屏初始化
LCD_Init();

    //循环进行各项测试    
while(1)
{
#if 1           //0:触摸测试, 1:显示测试
main_test();        //测试主界面
Test_Read();        //读ID和颜色值测试
Test_Color();       //简单刷屏填充测试
Test_FillRec();     //GUI矩形绘图测试
Test_Circle();      //GUI画圆测试
Test_Triangle();    //GUI三角形填充测试
English_Font_test();//英文字体示例测试
Chinese_Font_test();//中文字体示例测试
Pic_test();         //图片显示示例测试
Rotate_Test();      //屏幕旋转测试
#else
//需要触摸校准时,使用下面触摸校准测试项
Touch_Adjust();     //触摸校准
//不使用触摸或者模块本身不带触摸,请屏蔽下面触摸屏测试
Touch_Test();       //触摸屏手写测试
#endif
}
}

///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////

//////////////////////GUI_Draw.C/////////////////////////////////////

/*---------------------------------------------------------------------*/
/* --- Web: www.STCAI.com ---------------------------------------------*/
/* 液晶屏驱动程序参考wiki技术网站提供的开源源码,仅供学习使用          */
/*---------------------------------------------------------------------*/

//=========================================电源接线================================================//
//VDD接DC 3.3V电源
//GND接地
//=======================================液晶屏数据线接线==========================================//
//本模块数据总线类型为8位并口
// LCD_D0~D7     接       P20~P27        //液晶屏8位数据线
//=======================================液晶屏控制线接线==========================================//
// LCD_RS        接        P45           //数据/命令选择控制信号
// LCD_RD        接        P37           //读控制信号
// LCD_RST       接        P47           //复位信号
// LCD_WR        接        P36           //写控制信号
// LCD_CS        接        P05/P53       //片选控制信号
//================================================================================================//
//不使用触摸或者模块本身不带触摸,则可不连接
//触摸屏使用的数据总线类型为SPI
//  T_CS         接        P15          //触摸屏片选控制信号
//  T_CLK        接        P32          //触摸屏SPI时钟信号
//  T_DO         接        P33          //触摸屏SPI读信号
//  T_DIN        接        P34          //触摸屏SPI写信号
//  T_IRQ        接        P14          //触摸屏响应检查信号
//================================================================================================//
// 本实验使用的2.4寸320*240的并口彩屏,由冲哥淘宝店提供:http://e.tb.cn/h.gIlbVqAOj8YXlwo?tk=vFIr3RGTy2n
//**************************************************************************************************/

#include "lcd.h"
#include "font.h" 
#include "sys.h"
#include "gui.h"
#include "string.h"

/*******************************************************************
* @name       :void GUI_DrawPoint(u16 x,u16 y,u16 color)
* @date       :2018-08-09 
* @function   :draw a point in LCD screen
* @parameters :x:the x coordinate of the point
y:the y coordinate of the point
color:the color value of the point
* @retvalue   :None
********************************************************************/

void GUI_DrawPoint(u16 x,u16 y,u16 color)
{
LCD_SetCursor(x,y);//设置光标位置 
LCD_WR_DATA_16Bit(color); 
}

/*******************************************************************
* @name       :void LCD_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 color)
* @date       :2018-08-09 
* @function   :fill the specified area
* @parameters :sx:the beginning x coordinate of the specified area
sy:the beginning y coordinate of the specified area
ex:the ending x coordinate of the specified area
ey:the ending y coordinate of the specified area
color:the filled color value
* @retvalue   :None
********************************************************************/
void LCD_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 color)
{      
u16 i,j;            
u16 width=ex-sx+1;         //得到填充的宽度
u16 height=ey-sy+1;        //高度
LCD_SetWindows(sx,sy,ex,ey);//设置显示窗口
for(i=0;i<height;i++)
{
for(j=0;j<width;j++)
LCD_WR_DATA_16Bit(color);    //写入数据      
}
LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);//恢复窗口设置为全屏
}

/*******************************************************************
* @name       :void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2)
* @date       :2018-08-09 
* @function   :Draw a line between two points
* @parameters :x1:the beginning x coordinate of the line
y1:the beginning y coordinate of the line
x2:the ending x coordinate of the line
y2:the ending y coordinate of the line
* @retvalue   :None
********************************************************************/
void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2)
{
u16 t; 
int xerr=0,yerr=0,delta_x,delta_y,distance; 
int incx,incy,uRow,uCol; 

    delta_x=x2-x1; //计算坐标增量 
delta_y=y2-y1; 
uRow=x1; 
uCol=y1; 
if(delta_x>0)incx=1; //设置单步方向 
else if(delta_x==0)incx=0;//垂直线 
else {incx=-1;delta_x=-delta_x;} 
if(delta_y>0)incy=1; 
else if(delta_y==0)incy=0;//水平线 
else{incy=-1;delta_y=-delta_y;} 
if( delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴 
else distance=delta_y; 
for(t=0;t<=distance+1;t++ )//画线输出 
{  
LCD_DrawPoint(uRow,uCol);//画点 
xerr+=delta_x ; 
yerr+=delta_y ; 
if(xerr>distance) 

xerr-=distance; 
uRow+=incx; 

if(yerr>distance) 

yerr-=distance; 
uCol+=incy; 

}  

/*****************************************************************************
* @name       :void LCD_DrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2)
* @date       :2018-08-09 
* @function   :Draw a rectangle
* @parameters :x1:the beginning x coordinate of the rectangle
y1:the beginning y coordinate of the rectangle
x2:the ending x coordinate of the rectangle
y2:the ending y coordinate of the rectangle
* @retvalue   :None
******************************************************************************/
void LCD_DrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2)
{
LCD_DrawLine(x1,y1,x2,y1);
LCD_DrawLine(x1,y1,x1,y2);
LCD_DrawLine(x1,y2,x2,y2);
LCD_DrawLine(x2,y1,x2,y2);
}  

/*****************************************************************************
* @name       :void LCD_DrawFillRectangle(u16 x1, u16 y1, u16 x2, u16 y2)
* @date       :2018-08-09 
* @function   :Filled a rectangle
* @parameters :x1:the beginning x coordinate of the filled rectangle
y1:the beginning y coordinate of the filled rectangle
x2:the ending x coordinate of the filled rectangle
y2:the ending y coordinate of the filled rectangle
* @retvalue   :None
******************************************************************************/  
void LCD_DrawFillRectangle(u16 x1, u16 y1, u16 x2, u16 y2)
{
LCD_Fill(x1,y1,x2,y2,POINT_COLOR);
}

/*****************************************************************************
* @name       :void _draw_circle_8(int xc, int yc, int x, int y, u16 c)
* @date       :2018-08-09 
* @function   :8 symmetry circle drawing algorithm (internal call)
* @parameters :xc:the x coordinate of the Circular center 
yc:the y coordinate of the Circular center 
x:the x coordinate relative to the Circular center 
y:the y coordinate relative to the Circular center 
c:the color value of the circle
* @retvalue   :None
******************************************************************************/  
void _draw_circle_8(int xc, int yc, int x, int y, u16 c)
{
GUI_DrawPoint(xc + x, yc + y, c);

    GUI_DrawPoint(xc - x, yc + y, c);

    GUI_DrawPoint(xc + x, yc - y, c);

    GUI_DrawPoint(xc - x, yc - y, c);

    GUI_DrawPoint(xc + y, yc + x, c);

    GUI_DrawPoint(xc - y, yc + x, c);

    GUI_DrawPoint(xc + y, yc - x, c);

    GUI_DrawPoint(xc - y, yc - x, c);
}

/*****************************************************************************
* @name       :void gui_circle(int xc, int yc,u16 c,int r, int fill)
* @date       :2018-08-09 
* @function   :Draw a circle of specified size at a specified location
* @parameters :xc:the x coordinate of the Circular center 
yc:the y coordinate of the Circular center 
r:Circular radius
fill:1-filling,0-no filling
* @retvalue   :None
******************************************************************************/  
void gui_circle(int xc, int yc,u16 c,int r, int fill)
{
int x = 0, y = r, yi, d;

    d = 3 - 2 * r;

    if (fill) 
{
// 如果填充(画实心圆)
while (x <= y) {
for (yi = x; yi <= y; yi++)
_draw_circle_8(xc, yc, x, yi, c);

            if (d < 0) {
d = d + 4 * x + 6;
} else {
d = d + 4 * (x - y) + 10;
y--;
}
x++;
}
} else 
{
// 如果不填充(画空心圆)
while (x <= y) {
_draw_circle_8(xc, yc, x, y, c);
if (d < 0) {
d = d + 4 * x + 6;
} else {
d = d + 4 * (x - y) + 10;
y--;
}
x++;
}
}
}

/*****************************************************************************
* @name       :void Draw_Triangel(u16 x0,u16 y0,u16 x1,u16 y1,u16 x2,u16 y2)
* @date       :2018-08-09 
* @function   :Draw a triangle at a specified position
* @parameters :x0:the beginning x coordinate of the triangular edge 
y0:the beginning y coordinate of the triangular edge 
x1:the vertex x coordinate of the triangular
y1:the vertex y coordinate of the triangular
x2:the ending x coordinate of the triangular edge 
y2:the ending y coordinate of the triangular edge 
* @retvalue   :None
******************************************************************************/ 
void Draw_Triangel(u16 x0,u16 y0,u16 x1,u16 y1,u16 x2,u16 y2)
{
LCD_DrawLine(x0,y0,x1,y1);
LCD_DrawLine(x1,y1,x2,y2);
LCD_DrawLine(x2,y2,x0,y0);
}

static void _swap(u16 *a, u16 *b)
{
u16 tmp;
tmp = *a;
*a = *b;
*b = tmp;
}

/*****************************************************************************
* @name       :void Fill_Triangel(u16 x0,u16 y0,u16 x1,u16 y1,u16 x2,u16 y2)
* @date       :2018-08-09 
* @function   :filling a triangle at a specified position
* @parameters :x0:the beginning x coordinate of the triangular edge 
y0:the beginning y coordinate of the triangular edge 
x1:the vertex x coordinate of the triangular
y1:the vertex y coordinate of the triangular
x2:the ending x coordinate of the triangular edge 
y2:the ending y coordinate of the triangular edge 
* @retvalue   :None
******************************************************************************/ 
void Fill_Triangel(u16 x0,u16 y0,u16 x1,u16 y1,u16 x2,u16 y2)
{
u16 a, b, y, last;
int dx01, dy01, dx02, dy02, dx12, dy12;
long sa = 0;
long sb = 0;
if (y0 > y1) 
{
_swap(&y0,&y1); 
_swap(&x0,&x1);
}
if (y1 > y2) 
{
_swap(&y2,&y1); 
_swap(&x2,&x1);
}
if (y0 > y1) 
{
_swap(&y0,&y1); 
_swap(&x0,&x1);
}
if(y0 == y2) 

a = b = x0;
if(x1 < a)
{
a = x1;
}
else if(x1 > b)
{
b = x1;
}
if(x2 < a)
{
a = x2;
}
else if(x2 > b)
{
b = x2;
}
LCD_Fill(a,y0,b,y0,POINT_COLOR);
return;
}
dx01 = x1 - x0;
dy01 = y1 - y0;
dx02 = x2 - x0;
dy02 = y2 - y0;
dx12 = x2 - x1;
dy12 = y2 - y1;

if(y1 == y2)
{
last = y1; 
}
else
{
last = y1-1; 
}
for(y=y0; y<=last; y++) 
{
a = x0 + sa / dy01;
b = x0 + sb / dy02;
sa += dx01;
sb += dx02;
if(a > b)
{
_swap(&a,&b);
}
LCD_Fill(a,y,b,y,POINT_COLOR);
}
sa = dx12 * (y - y1);
sb = dx02 * (y - y0);
for(; y<=y2; y++) 
{
a = x1 + sa / dy12;
b = x0 + sb / dy02;
sa += dx12;
sb += dx02;
if(a > b)
{
_swap(&a,&b);
}
LCD_Fill(a,y,b,y,POINT_COLOR);
}
}

/*****************************************************************************
* @name       :void LCD_ShowChar(u16 x,u16 y,u16 fc, u16 bc, u8 num,u8 size,u8 mode)
* @date       :2018-08-09 
* @function   :Display a single English character
* @parameters :x:the beginning x coordinate of the Character display position
y:the beginning y coordinate of the Character display position
fc:the color value of display character
bc:the background color of display character
num:the ascii code of display character(0~94)
size:the size of display character
mode:0-no overlying,1-overlying
* @retvalue   :None
******************************************************************************/ 
void LCD_ShowChar(u16 x,u16 y,u16 fc, u16 bc, u8 num,u8 size,u8 mode)
{  
u8 temp;
u8 pos,t;
u16 colortemp=POINT_COLOR;      

    num=num-' ';//得到偏移后的值
LCD_SetWindows(x,y,x+size/2-1,y+size-1);//设置单个文字显示窗口
if(!mode) //非叠加方式
{
for(pos=0;pos<size;pos++)
{
if(size==12)temp=asc2_1206[num].dat[pos];//调用1206字体
else temp=asc2_1608[num].dat[pos];         //调用1608字体
for(t=0;t<size/2;t++)
{                 
if(temp&0x01)LCD_WR_DATA_16Bit(fc); 
else LCD_WR_DATA_16Bit(bc); 
temp>>=1; 

}
}    
}else//叠加方式
{
for(pos=0;pos<size;pos++)
{
if(size==12)temp=asc2_1206[num].dat[pos];//调用1206字体
else temp=asc2_1608[num].dat[pos];         //调用1608字体
for(t=0;t<size/2;t++)
{   
POINT_COLOR=fc;              
if(temp&0x01)LCD_DrawPoint(x+t,y+pos);//画一个点    
temp>>=1; 
}
}
}
POINT_COLOR=colortemp;    
LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);//恢复窗口为全屏                      
}

/*****************************************************************************
* @name       :void LCD_ShowString(u16 x,u16 y,u8 size,u8 *p,u8 mode)
* @date       :2018-08-09 
* @function   :Display English string
* @parameters :x:the beginning x coordinate of the English string
y:the beginning y coordinate of the English string
p:the start address of the English string
size:the size of display character
mode:0-no overlying,1-overlying
* @retvalue   :None
******************************************************************************/         
void LCD_ShowString(u16 x,u16 y,u8 size,u8 *p,u8 mode)
{         
while((*p<='~')&&(*p>=' '))//判断是不是非法字符!
{   
if(x>(lcddev.width-1)||y>(lcddev.height-1)) 
return;     
LCD_ShowChar(x,y,POINT_COLOR,BACK_COLOR,*p,size,mode);
x+=size/2;
p++;
}  

/*****************************************************************************
* @name       :u32 mypow(u8 m,u8 n)
* @date       :2018-08-09 
* @function   :get the nth power of m (internal call)
* @parameters :m:the multiplier
n:the power
* @retvalue   :the nth power of m
******************************************************************************/ 
u32 mypow(u8 m,u8 n)
{
u32 result=1;     
while(n--)result*=m;    
return result;
}

/*****************************************************************************
* @name       :void LCD_ShowNum(u16 x,u16 y,u32 num,u8 len,u8 size)
* @date       :2018-08-09 
* @function   :Display number
* @parameters :x:the beginning x coordinate of the number
y:the beginning y coordinate of the number
num:the number(0~4294967295)
len:the length of the display number
size:the size of display number
* @retvalue   :None
******************************************************************************/               
void LCD_ShowNum(u16 x,u16 y,u32 num,u8 len,u8 size)
{             
u8 t,temp;
u8 enshow=0;                           
for(t=0;t<len;t++)
{
temp=(num/mypow(10,(u8)(len-t-1)))%10;
if(enshow==0&&t<(len-1))
{
if(temp==0)
{
LCD_ShowChar(x+(size/2)*t,y,POINT_COLOR,BACK_COLOR,' ',size,0);
continue;
}else enshow=1; 

}
LCD_ShowChar(x+(size/2)*t,y,POINT_COLOR,BACK_COLOR,(u8)(temp+'0'),size,0); 
}

/*****************************************************************************
* @name       :void GUI_DrawFont16(u16 x, u16 y, u16 fc, u16 bc, u8 *s,u8 mode)
* @date       :2018-08-09 
* @function   :Display a single 16x16 Chinese character
* @parameters :x:the beginning x coordinate of the Chinese character
y:the beginning y coordinate of the Chinese character
fc:the color value of Chinese character
bc:the background color of Chinese character
s:the start address of the Chinese character
mode:0-no overlying,1-overlying
* @retvalue   :None
******************************************************************************/ 
void GUI_DrawFont16(u16 x, u16 y, u16 fc, u16 bc, u8 *s,u8 mode)
{
u8 i,j;
u16 k;
u16 HZnum;
u16 x0=x;
HZnum=sizeof(tfont16)/sizeof(typFNT_GB16);    //自动统计汉字数目

for (k=0;k<HZnum;k++) 
{
if ((tfont16[k].txt[0]==*(s))&&(tfont16[k].txt[1]==*(s+1)))
{
LCD_SetWindows(x,y,x+16-1,y+16-1);
for(i=0;i<16*2;i++)
{
for(j=0;j<8;j++)
{    
if(!mode) //非叠加方式
{
if(tfont16[k].dat[i]&(0x80>>j))    LCD_WR_DATA_16Bit(fc);
else LCD_WR_DATA_16Bit(bc);
}
else
{
POINT_COLOR=fc;
if(tfont16[k].dat[i]&(0x80>>j))    LCD_DrawPoint(x,y);//画一个点
x++;
if((x-x0)==16)
{
x=x0;
y++;
break;
}
}
}
}
}                      
continue;  //查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响
}
LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);//恢复窗口为全屏  

/*****************************************************************************
* @name       :void GUI_DrawFont24(u16 x, u16 y, u16 fc, u16 bc, u8 *s,u8 mode)
* @date       :2018-08-09 
* @function   :Display a single 24x24 Chinese character
* @parameters :x:the beginning x coordinate of the Chinese character
y:the beginning y coordinate of the Chinese character
fc:the color value of Chinese character
bc:the background color of Chinese character
s:the start address of the Chinese character
mode:0-no overlying,1-overlying
* @retvalue   :None
******************************************************************************/ 
void GUI_DrawFont24(u16 x, u16 y, u16 fc, u16 bc, u8 *s,u8 mode)
{
u8 i,j;
u16 k;
u16 HZnum;
u16 x0=x;
HZnum=sizeof(tfont24)/sizeof(typFNT_GB24);    //自动统计汉字数目

    for (k=0;k<HZnum;k++) 
{
if ((tfont24[k].txt[0]==*(s))&&(tfont24[k].txt[1]==*(s+1)))
{
LCD_SetWindows(x,y,x+24-1,y+24-1);
for(i=0;i<24*3;i++)
{
for(j=0;j<8;j++)
{
if(!mode) //非叠加方式
{
if(tfont24[k].dat[i]&(0x80>>j))    LCD_WR_DATA_16Bit(fc);
else LCD_WR_DATA_16Bit(bc);
}
else
{
POINT_COLOR=fc;
if(tfont24[k].dat[i]&(0x80>>j))    LCD_DrawPoint(x,y);//画一个点
x++;
if((x-x0)==24)
{
x=x0;
y++;
break;
}
}
}
}
}                      
continue;  //查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响
}
LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);//恢复窗口为全屏  
}

/*****************************************************************************
* @name       :void GUI_DrawFont32(u16 x, u16 y, u16 fc, u16 bc, u8 *s,u8 mode)
* @date       :2018-08-09 
* @function   :Display a single 32x32 Chinese character
* @parameters :x:the beginning x coordinate of the Chinese character
y:the beginning y coordinate of the Chinese character
fc:the color value of Chinese character
bc:the background color of Chinese character
s:the start address of the Chinese character
mode:0-no overlying,1-overlying
* @retvalue   :None
******************************************************************************/ 
void GUI_DrawFont32(u16 x, u16 y, u16 fc, u16 bc, u8 *s,u8 mode)
{
u8 i,j;
u16 k;
u16 HZnum;
u16 x0=x;
HZnum=sizeof(tfont32)/sizeof(typFNT_GB32);    //自动统计汉字数目
for (k=0;k<HZnum;k++) 
{
if ((tfont32[k].txt[0]==*(s))&&(tfont32[k].txt[1]==*(s+1)))
{
LCD_SetWindows(x,y,x+32-1,y+32-1);
for(i=0;i<32*4;i++)
{
for(j=0;j<8;j++)
{
if(!mode) //非叠加方式
{
if(tfont32[k].dat[i]&(0x80>>j))    LCD_WR_DATA_16Bit(fc);
else LCD_WR_DATA_16Bit(bc);
}
else
{
POINT_COLOR=fc;
if(tfont32[k].dat[i]&(0x80>>j))    LCD_DrawPoint(x,y);//画一个点
x++;
if((x-x0)==32)
{
x=x0;
y++;
break;
}
}
}
}
}                      
continue;  //查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响
}
LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);//恢复窗口为全屏  

/*****************************************************************************
* @name       :void Show_Str(u16 x, u16 y, u16 fc, u16 bc, u8 *str,u8 size,u8 mode)
* @date       :2018-08-09 
* @function   :Display Chinese and English strings
* @parameters :x:the beginning x coordinate of the Chinese and English strings
y:the beginning y coordinate of the Chinese and English strings
fc:the color value of Chinese and English strings
bc:the background color of Chinese and English strings
str:the start address of the Chinese and English strings
size:the size of Chinese and English strings
mode:0-no overlying,1-overlying
* @retvalue   :None
******************************************************************************/                  
void Show_Str(u16 x, u16 y, u16 fc, u16 bc, u8 *str,u8 size,u8 mode)
{                    
u16 x0=x;                                    
u8 bHz=0;     //字符或者中文 
while(*str!=0)//数据未结束

if(!bHz)
{
if(x>(lcddev.width-size/2)||y>(lcddev.height-size)) 
return; 
if(*str>0x80)bHz=1;//中文 
else              //字符
{          
if(*str==0x0D)//换行符号
{         
y+=size;
x=x0;
str++; 
}  
else
{
if(size>16)//字库中没有集成12X24 16X32的英文字体,用8X16代替
{  
LCD_ShowChar(x,y,fc,bc,*str,16,mode);
x+=8; //字符,为全字的一半 
}
else
{
LCD_ShowChar(x,y,fc,bc,*str,size,mode);
x+=size/2; //字符,为全字的一半 
}

str++; 
}
}
else//中文 
{   
if(x>(lcddev.width-size)||y>(lcddev.height-size)) 
return;  
bHz=0;//有汉字库    
if(size==32)
GUI_DrawFont32(x,y,fc,bc,str,mode);         
else if(size==24)
GUI_DrawFont24(x,y,fc,bc,str,mode);    
else
GUI_DrawFont16(x,y,fc,bc,str,mode);

str+=2; 
x+=size;//下一个汉字偏移        
}                         
}   
}

/*****************************************************************************
* @name       :void Gui_StrCenter(u16 x, u16 y, u16 fc, u16 bc, u8 *str,u8 size,u8 mode)
* @date       :2018-08-09 
* @function   :Centered display of English and Chinese strings
* @parameters :x:the beginning x coordinate of the Chinese and English strings
y:the beginning y coordinate of the Chinese and English strings
fc:the color value of Chinese and English strings
bc:the background color of Chinese and English strings
str:the start address of the Chinese and English strings
size:the size of Chinese and English strings
mode:0-no overlying,1-overlying
* @retvalue   :None
******************************************************************************/ 
void Gui_StrCenter(u16 x, u16 y, u16 fc, u16 bc, u8 *str,u8 size,u8 mode)
{
u16 len=strlen((const char *)str);
u16 x1=(lcddev.width-len*8)/2;
Show_Str(x+x1,y,fc,bc,str,size,mode);


/*****************************************************************************
* @name       :void Gui_Drawbmp16(u16 x,u16 y,const unsigned char *p)
* @date       :2018-08-09 
* @function   :Display a 16-bit BMP image
* @parameters :x:the beginning x coordinate of the BMP image
y:the beginning y coordinate of the BMP image
p:the start address of image array
* @retvalue   :None
******************************************************************************/ 
void Gui_Drawbmp16(u16 x,u16 y,const unsigned char *p) //显示40*40 QQ图片
{
int i; 
unsigned char picH,picL; 
LCD_SetWindows(x,y,x+40-1,y+40-1);//窗口设置
for(i=0;i<40*40;i++)
{    
picL=*(p+i*2);    //数据低位在前
picH=*(p+i*2+1);                
LCD_WR_DATA_16Bit(picH<<8|picL);                          
}    
LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);//恢复显示窗口为全屏    
}

///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////

///////////////////////////////LCD.C/////////////////////////////////////

/*---------------------------------------------------------------------*/
/* --- Web: www.STCAI.com ---------------------------------------------*/
/* 液晶屏驱动程序参考wiki技术网站提供的开源源码,仅供学习使用          */
/*---------------------------------------------------------------------*/

//=========================================电源接线================================================//
//VDD接DC 3.3V电源
//GND接地
//=======================================液晶屏数据线接线==========================================//
//本模块数据总线类型为8位并口
// LCD_D0~D7     接       P20~P27        //液晶屏8位数据线
//=======================================液晶屏控制线接线==========================================//
// LCD_RS        接        P45           //数据/命令选择控制信号
// LCD_RD        接        P37           //读控制信号
// LCD_RST       接        P47           //复位信号
// LCD_WR        接        P36           //写控制信号
// LCD_CS        接        P05/P53       //片选控制信号
//================================================================================================//
//不使用触摸或者模块本身不带触摸,则可不连接
//触摸屏使用的数据总线类型为SPI
//  T_CS         接        P15          //触摸屏片选控制信号
//  T_CLK        接        P32          //触摸屏SPI时钟信号
//  T_DO         接        P33          //触摸屏SPI读信号
//  T_DIN        接        P34          //触摸屏SPI写信号
//  T_IRQ        接        P14          //触摸屏响应检查信号
//================================================================================================//
// 本实验使用的2.4寸320*240的并口彩屏,由冲哥淘宝店提供:http://e.tb.cn/h.gIlbVqAOj8YXlwo?tk=vFIr3RGTy2n
//**************************************************************************************************/

#include "sys.h"
#include "lcd.h"

//LCD的画笔颜色和背景色       
u16 POINT_COLOR=0x0000;    //画笔颜色
u16 BACK_COLOR=0xFFFF;  //背景色 
//管理LCD重要参数
//默认为竖屏
_lcd_dev lcddev;

/*****************************************************************************
* @name       :void LCM_Config(void)
* @date       :2018-11-13 
* @function   :Config LCM
* @parameters :None
* @retvalue   :None
******************************************************************************/    
void LCM_Config(void)
{
LCMIFCFG = 0x00;    //bit7 1:Enable Interrupt, bit1 0:8bit mode; bit0 0:8080,1:6800
LCMIFCFG2 = 0x25;    //RS:P45,E:P37,RW:P36; Setup Time=1,HOLD Time=1
LCMIFSTA = 0x00;
EA = 1;
}

/*****************************************************************************
* @name       :void LCM_Interrupt(void)
* @date       :2018-11-13 
* @function   :None
* @parameters :None
* @retvalue   :
******************************************************************************/ 
void LCM_Interrupt(void) interrupt 13
{
LCMIFSTA = 0x00;
LCD_CS=1;
}

/*****************************************************************************
* @name       :void LCD_WR_REG(u16 Reg)    
* @date       :2018-08-09 
* @function   :Write an 16-bit command to the LCD screen
* @parameters :data:Command value to be written
* @retvalue   :None
******************************************************************************/
void LCD_WR_REG(u16 Reg)     
{
LCMIFDATL = Reg;
LCD_CS=0;
LCMIFCR = 0x84;        //Enable interface, write command out
while(!LCMIFSTA);
LCMIFSTA = 0x00;
LCD_CS=1;

/*****************************************************************************
* @name       :void LCD_WR_DATA(u16 Data)
* @date       :2018-08-09 
* @function   :Write an 16-bit data to the LCD screen
* @parameters :data:data value to be written
* @retvalue   :None
******************************************************************************/
void LCD_WR_DATA(u16 Data)
{
LCMIFDATL = Data;
LCD_CS=0;
LCMIFCR = 0x85;        //Enable interface, write data out
while(!LCMIFSTA);
LCMIFSTA = 0x00;
LCD_CS=1;
}

/*****************************************************************************
* @name       :u16 LCD_RD_DATA(void)
* @date       :2018-11-13 
* @function   :Read an 16-bit value from the LCD screen
* @parameters :None
* @retvalue   :read value
******************************************************************************/
u16 LCD_RD_DATA(void)
{
u16 d;
//LCM Read
LCD_CS = 0;
LCMIFCR = 0x87;        //Enable interface, Read data
while(!LCMIFSTA);
LCMIFSTA = 0x00;
LCD_CS=1;
d = LCMIFDATL;

    return (d);
}

/*****************************************************************************
* @name       :void LCD_WR_DATA_16Bit(u16 Data)
* @date       :2018-08-09 
* @function   :Write an 16-bit command to the LCD screen
* @parameters :Data:Data to be written
* @retvalue   :None
******************************************************************************/     
void LCD_WR_DATA_16Bit(u16 Data)
{
LCD_WR_DATA((u8)(Data>>8));
LCD_WR_DATA((u8)Data);
}

u16 Color_To_565(u8 r, u8 g, u8 b)
{
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3);
}

/*****************************************************************************
* @name       :u16 Lcd_ReadData_16Bit(void)
* @date       :2018-11-13 
* @function   :Read an 16-bit value from the LCD screen
* @parameters :None
* @retvalue   :read value
******************************************************************************/    
u16 Lcd_RD_DATA_16Bit(void)
{
u16 r,g,b;

    //dummy data
r = LCD_RD_DATA();
//dummy data
r = LCD_RD_DATA();
//8bit:red data
//16bit:red and green data
r = LCD_RD_DATA();
//8bit:green data
//16bit:blue data
g = LCD_RD_DATA();

    b = LCD_RD_DATA();

    return Color_To_565((u8)r, (u8)g, (u8)b);
}

/*****************************************************************************
* @name       :void LCD_WriteReg(u16 LCD_Reg, u16 LCD_RegValue)
* @date       :2018-08-09 
* @function   :Write data into registers
* @parameters :LCD_Reg:Register address
LCD_RegValue:Data to be written
* @retvalue   :None
******************************************************************************/
void LCD_WriteReg(u16 LCD_Reg, u16 LCD_RegValue)
{
LCD_WR_REG(LCD_Reg);
LCD_WR_DATA(LCD_RegValue);
}

/*****************************************************************************
* @name       :u16 LCD_ReadReg(u16 LCD_Reg)
* @date       :2018-11-13 
* @function   :read value from specially registers
* @parameters :LCD_Reg:Register address
* @retvalue   :read value
******************************************************************************/
void LCD_ReadReg(u16 LCD_Reg,u8 *Rval,int n)
{
LCD_WR_REG((u8)LCD_Reg);
while(n--)
{        
*(Rval++) = LCD_RD_DATA();
}
}

/*****************************************************************************
* @name       :void LCD_WriteRAM_Prepare(void)
* @date       :2018-08-09 
* @function   :Write GRAM
* @parameters :None
* @retvalue   :None
******************************************************************************/    
void LCD_WriteRAM_Prepare(void)
{
LCD_WR_REG(lcddev.wramcmd);      
}

/*****************************************************************************
* @name       :void LCD_ReadRAM_Prepare(void)
* @date       :2018-11-13 
* @function   :Read GRAM
* @parameters :None
* @retvalue   :None
******************************************************************************/     
void LCD_ReadRAM_Prepare(void)
{
LCD_WR_REG(lcddev.rramcmd);
}

/*****************************************************************************
* @name       :void LCD_Clear(u16 Color)
* @date       :2018-08-09 
* @function   :Full screen filled LCD screen
* @parameters :color:Filled color
* @retvalue   :None
******************************************************************************/    
void LCD_Clear(u16 Color)
{
u16 i,j;
LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);    
for(i=0;i<lcddev.width;i++)
{
for (j=0;j<lcddev.height;j++)
{
LCD_WR_DATA_16Bit(Color);
}
}
}

/*****************************************************************************
* @name       :void LCD_DrawPoint(u16 x,u16 y)
* @date       :2018-08-09 
* @function   :Write a pixel data at a specified location
* @parameters :x:the x coordinate of the pixel
y:the y coordinate of the pixel
* @retvalue   :None
******************************************************************************/    
void LCD_DrawPoint(u16 x,u16 y)
{
LCD_SetWindows(x,y,x,y);//设置光标位置 
LCD_WR_DATA_16Bit(POINT_COLOR);         
}      

/*****************************************************************************
* @name       :u16 LCD_ReadPoint(u16 x,u16 y)
* @date       :2018-11-13 
* @function   :Read a pixel color value at a specified location
* @parameters :x:the x coordinate of the pixel
y:the y coordinate of the pixel
* @retvalue   :the read color value
******************************************************************************/    
u16 LCD_ReadPoint(u16 x,u16 y)
{
u16 color;
if(x>=lcddev.width||y>=lcddev.height)
{
return 0;    //超过了范围,直接返回    
}
LCD_SetCursor(x,y);//设置光标位置 
LCD_ReadRAM_Prepare();
color = Lcd_RD_DATA_16Bit();
return color;
}

/*****************************************************************************
* @name       :void LCD_Set_GPIO(void)
* @date       :2018-11-13 
* @function   :Set the gpio to push-pull mode
* @parameters :None
* @retvalue   :None
******************************************************************************/    
void LCD_Set_GPIO(void)
{
//P2口设置成准双向口
P2M0=0x00;
P2M1=0x00;

    //P0.4口设置成高阻输入,P0.5推挽输出
P0M0=0x20;
P0M1=0x10;

    //P1.4口设置成高阻输入
P1M0=0x00;
P1M1=0x10;

//    //P6口设置成高阻输入(8bit)
//    P6M0=0x00;
//    P6M1=0xff;

    //P3.3口设置成高阻输入
//P3.7,P3.6,P3.4,P3.2口设置成推挽输出
P3M0=0xd4;
P3M1=0x08;

    //P4.7,P4.5口设置成推挽输出
P4M0=0xa0;
P4M1=0x00;

    //P5.3口设置成推挽输出
P5M0=0x08;
P5M1=0x00;
}

/*****************************************************************************
* @name       :void LCDReset(void)
* @date       :2018-08-09 
* @function   :Reset LCD screen
* @parameters :None
* @retvalue   :None
******************************************************************************/    
void LCDReset(void)
{
delay_ms(50);    
LCD_RESET=0;
delay_ms(50);
LCD_RESET=1;
delay_ms(50);
}

/*****************************************************************************
* @name       :void LCD_Init(void)
* @date       :2018-08-09 
* @function   :Initialization LCD screen
* @parameters :None
* @retvalue   :None
******************************************************************************/          
void LCD_Init(void)
{
LCD_Set_GPIO();
LCM_Config();
LCDReset(); //初始化之前复位
//*************2.4inch ILI9341初始化**********//
LCD_WR_REG(0xCF);  
LCD_WR_DATA(0x00); 
LCD_WR_DATA(0xD9); //0xC1 
LCD_WR_DATA(0X30); 
LCD_WR_REG(0xED);  
LCD_WR_DATA(0x64); 
LCD_WR_DATA(0x03); 
LCD_WR_DATA(0X12); 
LCD_WR_DATA(0X81); 
LCD_WR_REG(0xE8);  
LCD_WR_DATA(0x85); 
LCD_WR_DATA(0x10); 
LCD_WR_DATA(0x7A); 
LCD_WR_REG(0xCB);  
LCD_WR_DATA(0x39); 
LCD_WR_DATA(0x2C); 
LCD_WR_DATA(0x00); 
LCD_WR_DATA(0x34); 
LCD_WR_DATA(0x02); 
LCD_WR_REG(0xF7);  
LCD_WR_DATA(0x20); 
LCD_WR_REG(0xEA);  
LCD_WR_DATA(0x00); 
LCD_WR_DATA(0x00); 
LCD_WR_REG(0xC0);    //Power control 
LCD_WR_DATA(0x1B);   //VRH[5:0] 
LCD_WR_REG(0xC1);    //Power control 
LCD_WR_DATA(0x12);   //SAP[2:0];BT[3:0] 0x01
LCD_WR_REG(0xC5);    //VCM control 
LCD_WR_DATA(0x08);      //30
LCD_WR_DATA(0x26);      //30
LCD_WR_REG(0xC7);    //VCM control2 
LCD_WR_DATA(0XB7); 
LCD_WR_REG(0x36);    // Memory Access Control 
LCD_WR_DATA(0x08);
LCD_WR_REG(0x3A);   
LCD_WR_DATA(0x55); 
LCD_WR_REG(0xB1);   
LCD_WR_DATA(0x00);   
LCD_WR_DATA(0x1A); 
LCD_WR_REG(0xB6);    // Display Function Control 
LCD_WR_DATA(0x0A); 
LCD_WR_DATA(0xA2); 
LCD_WR_REG(0xF2);    // 3Gamma Function Disable 
LCD_WR_DATA(0x00); 
LCD_WR_REG(0x26);    //Gamma curve selected 
LCD_WR_DATA(0x01); 
LCD_WR_REG(0xE0);    //Set Gamma 
LCD_WR_DATA(0x0F); 
LCD_WR_DATA(0x1D); 
LCD_WR_DATA(0x1A); 
LCD_WR_DATA(0x0A); 
LCD_WR_DATA(0x0D); 
LCD_WR_DATA(0x07); 
LCD_WR_DATA(0x49); 
LCD_WR_DATA(0X66); 
LCD_WR_DATA(0x3B); 
LCD_WR_DATA(0x07); 
LCD_WR_DATA(0x11); 
LCD_WR_DATA(0x01); 
LCD_WR_DATA(0x09); 
LCD_WR_DATA(0x05); 
LCD_WR_DATA(0x04);          
LCD_WR_REG(0XE1);    //Set Gamma 
LCD_WR_DATA(0x00); 
LCD_WR_DATA(0x18); 
LCD_WR_DATA(0x1D); 
LCD_WR_DATA(0x02); 
LCD_WR_DATA(0x0F); 
LCD_WR_DATA(0x04); 
LCD_WR_DATA(0x36); 
LCD_WR_DATA(0x13); 
LCD_WR_DATA(0x4C); 
LCD_WR_DATA(0x07); 
LCD_WR_DATA(0x13); 
LCD_WR_DATA(0x0F); 
LCD_WR_DATA(0x2E); 
LCD_WR_DATA(0x2F); 
LCD_WR_DATA(0x05); 
LCD_WR_REG(0x2B); 
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x01);
LCD_WR_DATA(0x3f);
LCD_WR_REG(0x2A); 
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0xef);     
LCD_WR_REG(0x11); //Exit Sleep
delay_ms(120);
LCD_WR_REG(0x29); //display on    

    //设置LCD属性参数
LCD_direction(USE_HORIZONTAL);//设置LCD显示方向 
//    LCD_BL=1;//点亮背光     
}

/*****************************************************************************
* @name       :void LCD_SetWindows(u16 xStar, u16 yStar,u16 xEnd,u16 yEnd)
* @date       :2018-08-09 
* @function   :Setting LCD display window
* @parameters :xStar:the bebinning x coordinate of the LCD display window
yStar:the bebinning y coordinate of the LCD display window
xEnd:the endning x coordinate of the LCD display window
yEnd:the endning y coordinate of the LCD display window
* @retvalue   :None
******************************************************************************/ 
void LCD_SetWindows(u16 xStar, u16 yStar,u16 xEnd,u16 yEnd)
{
LCD_WR_REG(lcddev.setxcmd);    
LCD_WR_DATA(xStar>>8);
LCD_WR_DATA(0x00FF&xStar);        
LCD_WR_DATA(xEnd>>8);
LCD_WR_DATA(0x00FF&xEnd);

    LCD_WR_REG(lcddev.setycmd);    
LCD_WR_DATA(yStar>>8);
LCD_WR_DATA(0x00FF&yStar);        
LCD_WR_DATA(yEnd>>8);
LCD_WR_DATA(0x00FF&yEnd);    

    LCD_WriteRAM_Prepare();    //开始写入GRAM
}

/*****************************************************************************
* @name       :void LCD_SetCursor(u16 Xpos, u16 Ypos)
* @date       :2018-08-09 
* @function   :Set coordinate value
* @parameters :Xpos:the  x coordinate of the pixel
Ypos:the  y coordinate of the pixel
* @retvalue   :None
******************************************************************************/ 
void LCD_SetCursor(u16 Xpos, u16 Ypos)
{
LCD_SetWindows(Xpos,Ypos,Xpos,Ypos);    
}

/*****************************************************************************
* @name       :void LCD_direction(u8 direction)
* @date       :2018-08-09 
* @function   :Setting the display direction of LCD screen
* @parameters :direction:0-0 degree
1-90 degree
2-180 degree
3-270 degree
* @retvalue   :None
******************************************************************************/ 
void LCD_direction(u8 direction)
{
lcddev.setxcmd=0x2A;
lcddev.setycmd=0x2B;
lcddev.wramcmd=0x2C;
lcddev.rramcmd=0x2E;
switch(direction){
case 0:
lcddev.width=LCD_W;
lcddev.height=LCD_H;
LCD_WriteReg(0x36,(1<<3));
break;
case 1:
lcddev.width=LCD_H;
lcddev.height=LCD_W;
LCD_WriteReg(0x36,(1<<3)|(1<<5)|(1<<6));
break;
case 2:
lcddev.width=LCD_W;
lcddev.height=LCD_H;    
LCD_WriteReg(0x36,(1<<3)|(1<<4)|(1<<6)|(1<<7));
break;
case 3:
lcddev.width=LCD_H;
lcddev.height=LCD_W;
LCD_WriteReg(0x36,(1<<3)|(1<<7)|(1<<5)|(1<<4));
break;
default:break;
}
}

/*****************************************************************************
* @name       :u16 LCD_Read_ID(void)
* @date       :2018-11-13 
* @function   :Read ID
* @parameters :None
* @retvalue   :ID value
******************************************************************************/ 
u16 LCD_Read_ID(void)
{
u8 val[5] = {0};
LCD_ReadReg(0xD3,val,5);
return (val[3]<<8)|val[4];
}

///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////

///////////////////////////TOUCH.C/////////////////////////////////////

/*---------------------------------------------------------------------*/
/* --- Web: www.STCAI.com ---------------------------------------------*/
/* 液晶屏驱动程序参考wiki技术网站提供的开源源码,仅供学习使用          */
/*---------------------------------------------------------------------*/

//=========================================电源接线================================================//
//VDD接DC 3.3V电源
//GND接地
//=======================================液晶屏数据线接线==========================================//
//本模块数据总线类型为8位并口
// LCD_D0~D7     接       P20~P27        //液晶屏8位数据线
//=======================================液晶屏控制线接线==========================================//
// LCD_RS        接        P45           //数据/命令选择控制信号
// LCD_RD        接        P37           //读控制信号
// LCD_RST       接        P47           //复位信号
// LCD_WR        接        P36           //写控制信号
// LCD_CS        接        P05/P53       //片选控制信号
//================================================================================================//
//不使用触摸或者模块本身不带触摸,则可不连接
//触摸屏使用的数据总线类型为SPI
//  T_CS         接        P15          //触摸屏片选控制信号
//  T_CLK        接        P32          //触摸屏SPI时钟信号
//  T_DO         接        P33          //触摸屏SPI读信号
//  T_DIN        接        P34          //触摸屏SPI写信号
//  T_IRQ        接        P14          //触摸屏响应检查信号
//================================================================================================//
// 本实验使用的2.4寸320*240的并口彩屏,由冲哥淘宝店提供:http://e.tb.cn/h.gIlbVqAOj8YXlwo?tk=vFIr3RGTy2n
//**************************************************************************************************/
#include "sys.h"
#include "touch.h"
#include "lcd.h"
#include "gui.h"

//***因触摸屏批次不同等原因,默认的校准参数值可能会引起触摸识别不准,建议校准后再使用,不建议使用固定的默认校准参数
u16 vx=15621,vy=11221;  //比例因子,此值除以1000之后表示多少个AD值代表一个像素点 
u16 chx=3890,chy=340;//默认像素点坐标为0时的AD起始值 
//***因触摸屏批次不同等原因,默认的校准参数值可能会引起触摸识别不准,建议校准后再使用,不建议使用固定的默认校准参数

struct tp_pix_  tp_pixad,tp_pixlcd;     //当前触控坐标的AD值,前触控坐标的像素值   

//返回触摸按下的状态
u8 tpstate(void)
{
return Penirq;
}

//SPI开始
void spistar(void)                                     
{
TCS=1;
DCLK=1;
DIN=1;
DCLK=1;
}

//SPI写数据
void WriteCharTo7843(unsigned char num)          
{
unsigned char count=0;
DCLK=0;
for(count=0;count<8;count++)
{
num<<=1;
DIN=CY;
DCLK=0; _nop_();_nop_();_nop_();                //上升沿有效
DCLK=1; _nop_();_nop_();_nop_();
}
}

//SPI 读数据
u16 ReadFromCharFrom7843()             
{
u8 count=0;
u16 Num=0;
for(count=0;count<12;count++)
{
Num<<=1;        
DCLK=1; _nop_();_nop_();_nop_();   //下降沿有效
DCLK=0; _nop_();_nop_();_nop_();
if(DOUT)
{
Num|=1;
}
}

    return(Num);
}

//从7846/7843/XPT2046/UH7843/UH7846读取adc值      
//0x90=y   0xd0-x
u16 ADS_Read_AD(unsigned char CMD)          
{
u16 l;
TCS=0;
WriteCharTo7843(CMD);        //送控制字即用差分方式读X坐标 详细请见有关资料
DCLK=1; _nop_();_nop_();_nop_();_nop_();
DCLK=0; _nop_();_nop_();_nop_();_nop_();
l=ReadFromCharFrom7843();
TCS=1;
return l;
}

//读取一个坐标值
//连续读取READ_TIMES次数据,对这些数据升序排列,
//然后去掉最低和最高LOST_VAL个数,取平均值 
#define READ_TIMES 15 //读取次数
#define LOST_VAL 5      //丢弃值
u16 ADS_Read_XY(u8 xy)
{
u16 i, j;
u16 buf[READ_TIMES];
u16 sum=0;
u16 temp;
for(i=0;i<READ_TIMES;i++)
{                 
buf[i]=ADS_Read_AD(xy);        
}                    
for(i=0;i<READ_TIMES-1; i++)//排序
{
for(j=i+1;j<READ_TIMES;j++)
{
if(buf[i]>buf[j])//升序排列
{
temp=buf[i];
buf[i]=buf[j];
buf[j]=temp;
}
}
}      
sum=0;
for(i=LOST_VAL;i<READ_TIMES-LOST_VAL;i++)sum+=buf[i];
temp=sum/(READ_TIMES-2*LOST_VAL);
return temp;   
}

//带滤波的坐标读取
//最小值不能少于100.
u8 Read_ADS(u16 *x,u16 *y)
{
u16 xtemp,ytemp;                            
xtemp=ADS_Read_XY(CMD_RDX);
ytemp=ADS_Read_XY(CMD_RDY);                                            
if(xtemp<100||ytemp<100)return 0;//读数失败
*x=xtemp;
*y=ytemp;
return 1;//读数成功
}

//2次读取ADS7846,连续读取2次有效的AD值,且这两次的偏差不能超过
//50,满足条件,则认为读数正确,否则读数错误.       
//该函数能大大提高准确度
#define ERR_RANGE 20 //误差范围 
u8 Read_ADS2(u16 *x,u16 *y) 
{
u16 x1,y1;
u16 x2,y2;
u8 flag;    
flag=Read_ADS(&x1,&y1);   
if(flag==0)return(0);
flag=Read_ADS(&x2,&y2);    
if(flag==0)return(0);   
if(((x2<=x1&&x1<x2+ERR_RANGE)||(x1<=x2&&x2<x1+ERR_RANGE))//前后两次采样在+-ERR_RANGE内
&&((y2<=y1&&y1<y2+ERR_RANGE)||(y1<=y2&&y2<y1+ERR_RANGE)))
{
*x=(x1+x2)>>1;
*y=(y1+y2)>>1;        
return 1;
}else return 0;      
}

//精确读取一次坐标,校准的时候用的       
u8 Read_TP_Once(void)
{
u8 re=0;
u16 x1,y1;
while(re==0)
{
while(!Read_ADS2(&tp_pixad.x,&tp_pixad.y));
delay_ms(10);
while(!Read_ADS2(&x1,&y1));
if(tp_pixad.x==x1&&tp_pixad.y==y1)
{
re=1; 
}

return re;
}

//画一个校准用的辅助触摸区域
void Drow_Touch_Point(u16 x,u16 y)
{
POINT_COLOR=RED;
LCD_DrawLine(x-12,y,x+13,y);//横线
LCD_DrawLine(x,y-12,x,y+13);//竖线
LCD_DrawPoint(x+1,y+1);
LCD_DrawPoint(x-1,y+1);
LCD_DrawPoint(x+1,y-1);
LCD_DrawPoint(x-1,y-1);
gui_circle(x,y,POINT_COLOR,6,0);//画中心圈
}

//画一个大点(2*2的点)           
//x,y:坐标
//color:颜色
void TP_Draw_Big_Point(u16 x,u16 y,u16 color)
{       
POINT_COLOR=color;

LCD_DrawPoint(x,y);//中心点 
LCD_DrawPoint(x+1,y);
LCD_DrawPoint(x,y+1);
LCD_DrawPoint(x+1,y+1);               
}

//转换结果
//根据触摸屏的校准参数来决定转换后的结果,保存在tp_pixlcd.x,tp_pixlcd.y中
u8 Convert_Pos(void)
{    
#if USE_HORIZONTAL==1
u16 temp; 
#endif      
u8 l=0;

if(Read_ADS2(&tp_pixad.x,&tp_pixad.y))
{
l=1;
tp_pixlcd.x=tp_pixad.x>chx?((u32)tp_pixad.x-(u32)chx)*1000/vx:((u32)chx-(u32)tp_pixad.x)*1000/vx;
tp_pixlcd.y=tp_pixad.y>chy?((u32)tp_pixad.y-(u32)chy)*1000/vy:((u32)chy-(u32)tp_pixad.y)*1000/vy;

#if USE_HORIZONTAL==0
tp_pixlcd.y=lcddev.height-1-tp_pixlcd.y; //Y坐标镜像 
#elif USE_HORIZONTAL==1
temp=tp_pixlcd.x;
tp_pixlcd.x=tp_pixlcd.y;
tp_pixlcd.y=lcddev.height-temp;
tp_pixlcd.x=lcddev.width-1-tp_pixlcd.x;
#endif 
}
return l;
}

//触摸屏校准代码
//得到四个校准参数
#define tp_pianyi 50   //校准坐标偏移量    
#define tp_xiaozhun 1000   //校准精度
void Touch_Adjust(void)
{    
float vx1,vx2,vy1,vy2;  //比例因子,此值除以1000之后表示多少个AD值代表一个像素点
u16 chx1,chx2,chy1,chy2;//默认像素点坐标为0时的AD起始值
u16 lx,ly;                 
struct tp_pixu32_ p[4];
u8  cnt=0;     
cnt=0;                

    TCS=1;
DCLK=1;
DIN=1;
DCLK=1;

POINT_COLOR=BLUE;
BACK_COLOR =WHITE;
LCD_Clear(WHITE);//清屏   
POINT_COLOR=RED;//红色 
LCD_Clear(WHITE);//清屏 
Drow_Touch_Point(tp_pianyi,tp_pianyi);//画点1 
while(1)
{
if(Penirq==0)//按键按下了
{
if(Read_TP_Once())//得到单次按键值
{                                     
p[cnt].x=tp_pixad.x;
p[cnt].y=tp_pixad.y;
cnt++; 
}             
switch(cnt)
{               
case 1:
LCD_Clear(WHITE);//清屏 
while(!Penirq);  //等待松手
Drow_Touch_Point(lcddev.width-tp_pianyi-1,tp_pianyi);//画点2
break;
case 2:
LCD_Clear(WHITE);//清屏 
while(!Penirq);  //等待松手
Drow_Touch_Point(tp_pianyi,lcddev.height-tp_pianyi-1);//画点3
break;
case 3:
LCD_Clear(WHITE);//清屏 
while(!Penirq);  //等待松手
Drow_Touch_Point(lcddev.width-tp_pianyi-1,lcddev.height-tp_pianyi-1);//画点4
break;
case 4:     //全部四个点已经得到
LCD_Clear(WHITE);//清屏 
while(!Penirq);  //等待松手

#if USE_HORIZONTAL==1
vx1=p[1].y>p[0].y?(p[1].y-p[0].y+1)*1000/(lcddev.width-tp_pianyi-tp_pianyi):(p[0].y-p[1].y-1)*1000/(lcddev.width-tp_pianyi-tp_pianyi);
chx1=p[1].y>p[0].y?p[0].y-(vx1*tp_pianyi)/1000:p[1].y-(vx1*tp_pianyi)/1000;
vy1=p[2].x>p[0].x?(p[2].x-p[0].x-1)*1000/(lcddev.height-tp_pianyi-tp_pianyi):(p[0].x-p[2].x-1)*1000/(lcddev.height-tp_pianyi-tp_pianyi);
chy1=p[2].x>p[0].x?p[2].x+(vy1*tp_pianyi)/1000:p[0].x+(vy1*tp_pianyi)/1000; 

vx2=p[3].y>p[2].y?(p[3].y-p[2].y+1)*1000/(lcddev.width-tp_pianyi-tp_pianyi):(p[2].y-p[3].y-1)*1000/(lcddev.width-tp_pianyi-tp_pianyi);
chx2=p[3].y>p[2].y?p[2].y-(vx2*tp_pianyi)/1000:p[3].y-(vx2*tp_pianyi)/1000;
vy2=p[3].x>p[1].x?(p[3].x-p[1].x-1)*1000/(lcddev.height-tp_pianyi-tp_pianyi):(p[1].x-p[3].x-1)*1000/(lcddev.height-tp_pianyi-tp_pianyi);
chy2=p[3].x>p[1].x?p[3].x+(vy2*tp_pianyi)/1000:p[1].x+(vy2*tp_pianyi)/1000; 
#elif USE_HORIZONTAL==0
vx1=p[1].x>p[0].x?(p[1].x-p[0].x+1)*1000/(lcddev.width-tp_pianyi-tp_pianyi):(p[0].x-p[1].x-1)*1000/(lcddev.width-tp_pianyi-tp_pianyi);
chx1=p[1].x>p[0].x?p[1].x+(vx1*tp_pianyi)/1000:p[0].x+(vx1*tp_pianyi)/1000;
vy1=p[2].y>p[0].y?(p[2].y-p[0].y-1)*1000/(lcddev.height-tp_pianyi-tp_pianyi):(p[0].y-p[2].y-1)*1000/(lcddev.height-tp_pianyi-tp_pianyi);
chy1=p[2].y>p[0].y?p[0].y-(vy1*tp_pianyi)/1000:p[2].y-(vy1*tp_pianyi)/1000; 

vx2=p[3].x>p[2].x?(p[3].x-p[2].x+1)*1000/(lcddev.width-tp_pianyi-tp_pianyi):(p[2].x-p[3].x-1)*1000/(lcddev.width-tp_pianyi-tp_pianyi);
chx2=p[3].x>p[2].x?p[3].x+(vx2*tp_pianyi)/1000:p[2].x+(vx2*tp_pianyi)/1000;
vy2=p[3].y>p[1].y?(p[3].y-p[1].y-1)*1000/(lcddev.height-tp_pianyi-tp_pianyi):(p[1].y-p[3].y-1)*1000/(lcddev.height-tp_pianyi-tp_pianyi);
chy2=p[3].y>p[1].y?p[1].y-(vy2*tp_pianyi)/1000:p[3].y-(vy2*tp_pianyi)/1000; 

#endif

                    if((vx1>vx2&&vx1>vx2+tp_xiaozhun)||(vx1<vx2&&vx1<vx2-tp_xiaozhun)||(vy1>vy2&&vy1>vy2+tp_xiaozhun)||(vy1<vy2&&vy1<vy2-tp_xiaozhun))
{
cnt=0;
LCD_Clear(WHITE);//清屏 
Drow_Touch_Point(tp_pianyi,tp_pianyi);//画点1 
continue;
}
#if USE_HORIZONTAL==1
vx=(vy1+vy2)/2;vy=(vx1+vx2)/2;
chx=(chy1+chy2)/2;chy=(chx1+chx2)/2;    
#elif USE_HORIZONTAL==0
vx=(vx1+vx2)/2;vy=(vy1+vy2)/2;
chx=(chx1+chx2)/2;chy=(chy1+chy2)/2;    
#endif
//显示校准信息
LCD_Clear(WHITE);//清屏 
POINT_COLOR=BLACK;
BACK_COLOR=BLUE;    
lx=50;ly=50;            
LCD_ShowString(lx,ly,16,"VX:",1);lx+=40;LCD_ShowNum(lx,ly,vx,6,16);                    
lx=50;ly+=20;
LCD_ShowString(lx,ly,16,"Vy:",1);lx+=40;LCD_ShowNum(lx,ly,vy,6,16);                    
lx=50;ly+=20; 
LCD_ShowString(lx,ly,16,"CHX:",1);lx+=40;LCD_ShowNum(lx,ly,chx,6,16);                    
lx=50;ly+=20; 
LCD_ShowString(lx,ly,16,"CHY:",1);lx+=40;LCD_ShowNum(lx,ly,chy,6,16);

                    lx=30;ly+=30;
LCD_ShowString(lx,ly,16,"Adjust OK!",1);    
lx=30;ly+=30;
LCD_ShowString(lx,ly,16,"Touch Anywhere To Continue",1);                                          
Read_TP_Once(); //等待任意键后继续

                    LCD_Clear(WHITE);//清屏
return;//校正完成                 
}
}

}

http://www.xdnf.cn/news/20537.html

相关文章:

  • 人工智能学习:基于seq2seq模型架构实现翻译
  • 项目初始化上传git
  • Qemu-NUC980(四):SDRAM Interface Controller
  • 什么是“二合一矫平机”?——一篇技术科普
  • 主流的开源协议(MIT,Apache,GPL v2/v3)
  • Qt编程之信号与槽
  • 吴恩达机器学习(八)
  • make时设置链接器选项的2种方法
  • 【操作系统-Day 25】死锁 (Deadlock):揭秘多线程编程的“终极杀手”
  • Zoom AI 技术架构研究:联合式方法与多模态集成
  • 【LeetCode热题100道笔记】翻转二叉树
  • python炒股
  • C++ 20 新增特性以及代码示例
  • 同态加密库(Google FHE)
  • 神经网络的初始化:权重与偏置的数学策略
  • C# WinForm分页控件实现与使用详解
  • B.50.10.09-RPC核心原理与电商应用
  • MATLAB R2025a安装配置及使用教程(超详细保姆级教程)
  • 什么是云手机?
  • Vue3 - Echarts自定义主题引入(Error:ECharts is not Loaded,Error:default ,Error:module)
  • 攻击服务器的方式有哪些,对应的应对策略有哪些?
  • 联邦学习论文分享:Towards Building the Federated GPT:Federated Instruction Tuning
  • Leetcode hot100 最长连续序列
  • rh134第五章复习总结
  • SDRAM详细分析-08 数据手册解读
  • AI + 办公工具 = 应用案例
  • (论文速读)视觉语言模型评价中具有挑战性的选择题的自动生成
  • 大模型推理时的加速思路?
  • RabbitMq 初步认识
  • 自动化运维之ansible