/*---------------------------------------------------------------------*/
/* --- 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.pswp.cn/news/921466.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/921466.shtml
英文地址,请注明出处:http://en.pswp.cn/news/921466.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

最大似然估计:损失函数的底层数学原理

引言当你第一次看到线性回归时&#xff0c;你是否注意到了作为参数优化关键的损失函数&#xff08;均方损失&#xff09;&#xff0c;你是否能够理解它的本质和由来。其实&#xff0c;在我第一次接触时&#xff0c;我是感到有些惊讶的&#xff0c;然后试着去强行理解它&#xf…

使用 n8n 结合通义千问大模型构建业务数据库分析智能体

一、项目概述 本项目致力于构建一个结合 n8n 工作流引擎 与 通义千问大模型 的智能体&#xff0c;旨在对庞大的业务数据库进行自动化分析、语义建模及自然语言问答。通过不同工作流的迭代构建&#xff0c;实现了表结构解析、业务含义提取、关系可视化、问答服务等能力&#xff…

css margin外边距重叠/塌陷问题

一、定义 相邻块级元素或父子元素的垂直外边距会合并&#xff08;折叠&#xff09;为单个边距&#xff0c;其大小为单个边距的最大值&#xff08;或如果他们相等&#xff0c;则仅为其中的一个&#xff09;&#xff0c;这种行为称为边距折叠 <div style"margin-bottom: …

可重复读 是否“100%”地解决幻读?

这是一个非常深刻的问题&#xff0c;答案是&#xff1a;几乎解决了&#xff0c;但在一个非常特殊且罕见的边界场景下&#xff0c;理论上仍然可能出现幻读。 因此&#xff0c;严格来说&#xff0c;它并非被“彻底”或“100%”地解决。下面我们来详细分解这个结论&#xff1a;1. …

从零开始的云计算生活——第五十八天,全力以赴,Jenkins部署

目录 一.故事背景 二.安装Jenkins必要插件 1.安装Publish Over SSH 2.安装maven integration插件 3. 配置jenkins并发执行数量 4. 配置邮件地址 三. 基于Jenkins部署PHP环境 1. 下载ansible插件 2. 下载ansible应用 3. 构建项目 ​编辑 使用Jenkins账户生成ssh密钥 …

串口HAL库发送问题

想了很久&#xff0c;不知道该标题起的是否合适&#xff0c;该篇Blog用于记录在使用HAL库的USART模块时实际遇到的一个涉及发送方式的问题&#xff0c;用于提醒自身同时也希望能帮到各位。程序问题叙述先来看一段代码&#xff1a;void CusUSART_SendByte_IT( uint8_t Byte ) { …

CUDA默认流的同步行为

默认流 对于需要指定 cudaStream_t参数的 cuda API&#xff0c;如果将 0作为实参传入&#xff0c;则视为使用默认流&#xff1b;对于不需要指定 cudaStream_t参数的 cuda API&#xff0c;则也视为使用默认流。 在 cuda中&#xff0c;默认流有两种类型&#xff0c;一种是 legacy…

「数据获取」《中国电力统计年鉴》(1993-2024)(含中国电力年鉴)

01、数据简介一、《中国电力统计年鉴》作为全面系统反映中国电力领域发展状况的权威性年度统计资料&#xff0c;涵盖了电力建设、生产、消费及供需等全链条关键信息。其编制工作有着深厚的历史积淀&#xff0c;可追溯至 20 世纪 50 年代&#xff0c;历经数十年的积累与完善&…

《AI大模型应知应会100篇》第68篇:移动应用中的大模型功能开发 —— 用 React Native 打造你的语音笔记摘要 App

&#x1f4f1; 第68篇&#xff1a;移动应用中的大模型功能开发 —— 用 React Native 打造你的语音笔记摘要 App &#x1f3af; 核心目标&#xff1a;零门槛集成大模型&#xff0c;5步开发跨平台智能功能 &#x1f9e9; 适用人群&#xff1a;前端开发者、产品经理、独立开发者 …

FPGA ad9248驱动

ad9248的最高时钟频率65mhz&#xff0c;采用cmos3.3v电压的并行io接口&#xff0c;做成电子模块后一般为双通道adc&#xff0c;有两个对外输出时钟cha_clk与chb_clk&#xff0c;一个并行输入端口&#xff0c;14分辨率的ddr_data&#xff0c;其模块逻辑如下&#xff0c;首先向ad…

Spring MVC 处理请求的流程

Spring MVC 处理请求的流程流程步骤详解第1步&#xff1a;发起请求 (HTTP Request)第2步&#xff1a;映射处理器 (Handler Mapping)第3步&#xff1a;获取适配器 (Handler Adapter)第4步&#xff1a;执行拦截器前置处理 (Interceptors - preHandle)第5步&#xff1a;真正调用处…

敏捷scrum管理实战经验总结

1.敏捷 敏捷的构成 敏捷由实践来源、应用场景、组织文化、领导力、团队、需求、管理、技术、质量、度量、交付、过程改进、大型项目组合管理以及受监管行业中的敏捷等构成 敏捷开发的特点 短发布周期小批量的方式、开展从需求到实现的开发工作高层级的预先规划结合详细的即时规…

南科大适应、协同与规划的完美融合!P³:迈向多功能的具身智能体

作者&#xff1a;Shengli Zhou1^{1}1, Xiangchen Wang1^{1}1, Jinrui Zhang1^{1}1, Ruozai Tian2^{2}2, Rongtao Xu2,3^{2,3}2,3, Feng Zheng1,2^{1,2}1,2单位&#xff1a;1^{1}1南方科技大学&#xff0c;2^{2}2时空智能&#xff0c;3^{3}3穆罕默德本扎耶德人工智能大学论文标题…

自动化流水线

import React, { useState, useEffect } from ‘react’; import { ChevronRight, CheckCircle, Circle, AlertCircle, Clock, Play, Pause, Settings, Code, Server, Shield, Database, Globe, Zap, FileText, Users, GitBranch, Package, Monitor, ChevronDown } from ‘luci…

【高等数学】第十一章 曲线积分与曲面积分——第三节 格林公式及其应用

上一节&#xff1a;【高等数学】第十一章 曲线积分与曲面积分——第二节 对坐标的曲线积分 总目录&#xff1a;【高等数学】 目录 文章目录1. 格林公式2. 平面上曲线积分与路径无关的条件3. 二元函数的全微分求积4. 曲线积分的基本定理1. 格林公式 单连通与复连通区域 设 DDD …

Boost电路:平均状态空间建模

电路特征介绍如图所示是一个非理想情况下的boost电路&#xff0c;其中L1L_{1}L1​和RL1R_{L1}RL1​是分别是电感和串联电阻&#xff1b;C1C_{1}C1​和RC1R_{C1}RC1​是输出电容和串联电阻&#xff1b;Q1Q_{1}Q1​是MOS管&#xff0c;其导通电阻是RonR_{on}Ron​&#xff1b;D1D…

免费网站模板/网站模板建站的优势/如何下载网站模板搭建网站?

在网站建设领域&#xff0c;“网站模板” 是降低技术门槛、提升建站效率的核心工具&#xff0c;尤其适合非专业开发者或追求低成本、快上线的需求场景。下面从定义、核心优势两方面展开详细解析&#xff0c;帮助你全面理解其价值。 一、什么是网站模板&#xff1f; 网站模板&am…

【MATLAB例程】平面上的组合导航例程,使用EKF融合IMU和GNSS数据,8维状态量和2维观测量,附代码下载链接

文章目录程序详解概述系统架构核心数学模型性能评估算法特点运行结果MATLAB源代码程序详解 概述 本代码实现基于扩展卡尔曼滤波器&#xff08;EKF&#xff09;的二维组合导航系统&#xff0c;融合IMU&#xff08;惯性测量单元&#xff09;和GNSS&#xff08;全球导航卫星系统…

react生命周期,详细版本

React 组件的生命周期分为三个阶段:挂载(Mounting)、更新(Updating) 和 卸载(Unmounting)。以下是类组件生命周期的详细说明(基于 React 16.3+ 版本): 一、挂载阶段(Mounting) 组件实例被创建并插入 DOM 时的流程: constructor(props) ○ 用途:初始化状态(this…

腾讯最新开源HunyuanVideo-Foley本地部署教程:端到端TV2A框架,REPA策略+MMDiT架构,重新定义视频音效新SOTA!

一、模型介绍HunyuanVideo-Foley 是腾讯混元团队在2025年8月底开源的一款端到端视频音效生成模型。它旨在解决AI生成视频“有画无声”的痛点&#xff0c;通过输入视频和文本描述&#xff0c;就能自动生成电影级别的同步音效&#xff0c;显著提升视频的沉浸感。它是专为视频内容…