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;//校正完成
}
}
}
}