📄 touchpad.c
字号:
/***************************************************************************************
****************************************************************************************
* FILE : TouchPad.c
* Description :
*
* Copyright (c) 2003~2008 by 创易电子(Design Easy). All Rights Reserved.
*
* History:
* Version Name Date Description
1.0 Wang Shaowei 2008/12/17 Initial Version (For DesignEasy LCM MCU board)
1.1 Liu Ying 2008/12/22 Comments
1.2 zha sheng 2009/1/12 For msp430
****************************************************************************************
****************************************************************************************/
#include "TouchPad.h"
#include "lcd.h"
/*
考虑到非校准情况下的触摸屏,通常都是写字、画画等连续的,
在我们的系统中,对于触摸功能是这样处理的:
首次触摸是由中断检测得到,之后响应中断进行处理;
处理完后开启一个5ms定时器,
定时器到时处理时主动读取触摸坐标,
若是有效坐标则处理,处理完后同样开启一个5ms定时器
若是无效坐标则表示没有触摸,此时再清除中断标记、
重新打开中断响应,等待下一次触摸中断
注意不要太早打开中断,一则因为系统中断不宜太频繁,二者避免误触发
*/
typedef struct
{
U16 X;
U16 Y;
}TP_POS;
/*记录在两次校准中得到的触摸坐标*/
TP_POS TPposA, TPposB;
typedef struct
{
U16 K;
U16 A;
}TP_ARG;
/*坐标转化参数,从触摸获得的数值到LCD的坐标之间需要进行映射转换*/
TP_ARG TPargX, TPargY;
/*
校准说明:
Xt = Kx * Xl + Ax
Yt = Ky * Yl + Ay
Xt: TP ADC 触摸获得的坐标
Kx: X arg
Xl: LCD pos lcd的坐标
Ax: X offset
Yt: TP ADC 触摸获得的坐标
Ky: Y arg
Yl: LCD pos lcd的坐标
Ay: Y offset
lcd和触摸屏的坐标之间的转换就是上面这两个公式,
用于校准,(从两组Xl Yl Xt Yt求出Kx Ky Ax Ay)
也用于转化得到lcd的坐标(从Xt Yt Kx Ky Ax Ay求出Xl Yl )
*/
/*==================================================================
* Function : tp_pos_adjust
* Description : 校准屏幕
* Input Para : void 屏幕上的校准坐标由宏定义TP_ADJUEST_POS_X1,
TP_ADJUEST_POS_Y1,TP_ADJUEST_POS_X2,TP_ADJUEST_POS_Y2
步骤为:1,画第一个点推出。校准标记置1;
2,由中断调用触发第一个点,同时清除第一个点画第二个点。点数标记为1;
3,中断调用得第二个点坐标,同时清除第二个点的显示,复位标记
注意: 每次推出开中断。
* Output Para : void
* Return Value : unsigned char 是否错误 (获得TPargX, TPargY)
===================================================================*/
U8 tp_pos_adjust(void)
{
if((!bTP_adjust)&&(!bTP_adjust_count))
{
TP_INT_CLOSE;
bTP_adjust = true;
lcd_display_adjust(TP_ADJUEST_POS_X1,TP_ADJUEST_POS_Y1);//调用绘图函数,在屏幕上绘制校准用图形。
TP_INT_OPEN;
return 0;
}
else if(!bTP_adjust_count)
{
TPposA.X = TP_X;
TPposA.Y = TP_Y;
lcd_display_rectangle_color(TP_ADJUEST_POS_X1-3, TP_ADJUEST_POS_Y1-3,TP_ADJUEST_POS_X1+3,TP_ADJUEST_POS_Y1+3,0xFFFF);
delay_ms(50000);//使操作延时
delay_ms(50000);
delay_ms(50000);
delay_ms(50000);
delay_ms(50000);
lcd_display_adjust(TP_ADJUEST_POS_X2,TP_ADJUEST_POS_Y2);
delay_ms(50000);
bTP_adjust_count = true;
TP_INT_OPEN;
return 0;
}
else
{
TPposB.X = TP_X;
TPposB.Y = TP_Y;
/*坐标转换函数*/
TPargX.K = (TPposA.X - TPposB.X) / (TP_ADJUEST_POS_X2-TP_ADJUEST_POS_X1);
TPargY.K = (TPposA.Y - TPposB.Y) / (TP_ADJUEST_POS_Y2-TP_ADJUEST_POS_Y1);
TPargX.A = TPposB.X -(TPargX.K * ((TP_ADJUEST_POS_X2-TP_ADJUEST_POS_X1)/2));
TPargY.A = TPposB.Y -(TPargY.K * ((TP_ADJUEST_POS_Y2-TP_ADJUEST_POS_Y1)/2));
lcd_display_rectangle_color(TP_ADJUEST_POS_X2-3, TP_ADJUEST_POS_Y2-3,TP_ADJUEST_POS_X2+3,TP_ADJUEST_POS_Y2+3,0xFFFF);
bTP_adjust_count = false;
bTP_adjust = false;
TP_INT_OPEN;
return 0;
}
}
/*==================================================================
* Function : tp_pos_display
* Description : 获得触摸轨迹,或其他图形
* Input Para : void
* Output Para : void
* Return Value: void
==================================================================*/
void tp_pos_display(void)
{
//画点
lcd_display_dot( TP_end_x, TP_end_y);
return;
}
/*==================================================================
* Function : serial_write_bit_high
* Description : 写bit1,TP_nCS 之前已经拉低
* Input Para : void
* Output Para : void
* Return Value: void
==================================================================*/
void serial_write_bit_high(void)
{
TP_DIN_set;//拉高
TP_DCLK_cle; //模拟一个时钟脉冲,所存数据
TP_DCLK_set;
TP_DCLK_cle;
return;
}
/*==================================================================
* Function : serial_write_bit_low
* Description : 写bit0,TP_nCS 之前已经拉低
* Input Para : void
* Output Para : void
* Return Value: void
==================================================================*/
void serial_write_bit_low(void)
{
TP_DIN_cle;
TP_DCLK_cle;
TP_DCLK_set;
TP_DCLK_cle;
return;
}
/*
关于TP_nCS何时置1何时置0的说明:
因为对触摸屏控制电路的控制,都是先写命令、然后读数据的,
所以下面的serial_write_data、serial_read_data总是成对出现,
我们总是在serial_write_data开始时将TP_nCS置0,
在serial_read_data结束时将TP_nCS置1,
这部分请看触摸控制电路芯片时序图
*/
/*==================================================================
* Function : serial_write_bit_low
* Description : 写8bit字节,开始将TP_nCS置0
* Input Para : U8 SendData
* Output Para : void
* Return Value: void
==================================================================*/
void serial_write_data(U8 SendData)
{
U8 i,c=0x80;
TP_DCLK_cle;
TP_nCS_cle;
/*从bit7到bit0依次传送*/
for (i=8; i>0; i--)
{
if (SendData & c)
{
serial_write_bit_high();
}
else
{
serial_write_bit_low();
}
c>>=1;
}
TP_DIN_cle;
return;
}
/*==================================================================
* Function : serial_read_data
* Description : 读12bit数据,TP_nCS 之前已经置零,结束时需将TP_nCS置1
* Input Para : void
* Output Para : void
* Return Value: U16 读到的数据,只有12bit有效
==================================================================*/
U16 serial_read_data(void)
{
U8 i;
U16 c=0x800;
U16 RcvData=0;
unsigned long int retry=0;
TP_DCLK_cle;
TP_DCLK_set;
/*等待一段时间*/
while(TP_nBUSY)
{
TP_DCLK_cle;
TP_DCLK_set;
retry++;
if(retry>100)
{
return 0;
}
};
for(i=12; i>0; i--)
{
TP_DCLK_set;
if(TP_DOUT)
{
RcvData |= c;
}
c>>=1;
TP_DCLK_cle;
}
TP_nCS_set;
return(RcvData);
}
/*==================================================================
* Function : tp_init
* Description : 初始化tp
* Input Para : void
* Output Para : void
* Return Value: void
==================================================================*/
void tp_init(void)
{
U8 cmd = 0;
/*初始化常数值*/
bTP_INT = false;
bTP_adjust = false;
bTP_adjust_count = false;
bTP_touch= false;
/*在校准之前也可以使用触摸屏,用这一组默认参数。
校准之后用校准得到的参数*/
TPargX.K = TOUCH_PANEL_ARG_X_K;
TPargX.A = TOUCH_PANEL_ARG_X_A;
TPargY.K = TOUCH_PANEL_ARG_Y_K;
TPargY.A = TOUCH_PANEL_ARG_Y_A;
/*送初始化命令*/
cmd=TOUCH_PANEL_START_BIT|TOUCH_PANEL_Y_PLUS|TOUCH_PANEL_12BIT_SAMPLE| TOUCH_PANEL_DIFF_MODE;
serial_write_data(cmd);
serial_read_data();
return;
}
/*==================================================================
* Function : tp_read_adc
* Description : 得到触摸坐标
* Input Para : U16 * X, U16 * Y,若全为0表示获得坐标不成功
* Output Para : void
* Return Value: void
==================================================================*/
void tp_read_adc(U16 * X, U16 * Y)
{
U8 cmd = 0;
/*读取X 坐标X ADC*/
cmd=TOUCH_PANEL_START_BIT|TOUCH_PANEL_Y_PLUS|TOUCH_PANEL_12BIT_SAMPLE| TOUCH_PANEL_DIFF_MODE;
serial_write_data(cmd);
*X=serial_read_data();
TP_to_LED_x=(*X - TPargX.A) / TPargX.K;
cmd = 0;
/*读取Y 坐标Y ADC*/
cmd=TOUCH_PANEL_START_BIT|TOUCH_PANEL_X_PLUS|TOUCH_PANEL_12BIT_SAMPLE| TOUCH_PANEL_DIFF_MODE ;
serial_write_data(cmd);
*Y=serial_read_data();
/*坐标转化*/
/*触摸屏和LCD屏幕的原点不同,一个在左下,一个在左上,需要将Y坐标转化一下*/
*Y = 4096 - *Y;
TP_to_LED_y=(*Y - TPargY.A) / TPargY.K;
/*触摸屏的范围大于LCD屏幕范围,判断是否超出了四周的边框*/
/*if(*X < 0x0080 || *Y < 0x0080 || *X > 0xF80 || *Y > 0xF80)
{
*X = 0;
*Y = 0;
// check_err();///////////////////////////////for test
}
// lcd_display_full_screen_color(0xffff);
U16 test1,test2;
U8 temp,a,b,c,d;
test1 = *X;test2 = *Y;
temp = test1&0x00ff;;
a=temp & 0x0f;
if(a>=10)
a=a+'A';
else
a=a+'0';
b=temp>>4;
if(b>=10)
b=b+'A';
else
b=b+'0';
temp=test1>>8;
c=temp & 0x0f;
if(c>=10)
c=c+'A';
else
c=c+'0';
d=temp>>4;
if(d>=10)
d=d+'A';
else
d=d+'0';
lcd_show_text(50,50,&a,0xFFFF,0x0000);
lcd_show_text(70,50,&b,0xFFFF,0x0000);
lcd_show_text(90,50,&c,0xFFFF,0x0000);
lcd_show_text(110,50,&d,0xFFFF,0x0000);
temp = test2;
a=temp & 0x0f;
if(a>=10)
a=a+'A';
else
a=a+'0';
b=temp>>4;
if(b>=10)
b=b+'A';
else
b=b+'0';
temp=test2>>8;
c=temp & 0x0f;
if(c>=10)
c=c+'A';
else
c=c+'0';
d=temp>>4;
if(d>=10)
d=d+'A';
else
d=d+'0';
lcd_show_text(50,80,&a,0xFFFF,0x0000);
lcd_show_text(70,80,&b,0xFFFF,0x0000);
lcd_show_text(90,80,&c,0xFFFF,0x0000);
lcd_show_text(110,80,&d,0xFFFF,0x0000);*/
return;
}
/*==================================================================
* Function : tp_pos_task
* Description : 处理由中断出发的触摸屏操作,区别是校验还是触摸操作,
由触摸屏中断调用,调用前请关闭中断,调用后请开中断
* Input Para : U16 * X, U16 * Y,若全为0表示获得坐标不成功
* Output Para : void
* Return Value: void
==================================================================*/
void tp_pos_task(void)
{
if(bTP_INT)//中断调用
{
/*一笔的起点,坐标从中断中获得*/
bTP_INT = false;
bTP_touch = true;//触摸中
TP_end_x=TP_start_x=TP_to_LED_x;
TP_end_y=TP_start_y=TP_to_LED_y;//记录开始坐标,初始化结束坐标
// if(TP_drawenable_start_x<=TP_end_x||TP_drawenable_start_y<=TP_end_y||TP_drawenable_end_x>=TP_end_x||TP_drawenable_end_y>=TP_end_y)
// tp_pos_display();
// 调用timer 5ms;
delay_ms(500);
tp_pos_task();
//TP_INT_OPEN;
return;
}
else
{
tp_read_adc(&TP_X, &TP_Y);
if(TP_X > 0)
{
signed char temp1,temp2;
temp1 = TP_to_LED_x-TP_end_x;//相邻点坐标的绝对值
temp2 = TP_to_LED_y-TP_end_y;
if(temp1<0)
temp1=-temp1;
if(temp2<0)
temp2=-temp2;
if(temp1<3&&temp2<3)//消除噪点
{
if(TP_drawenable_start_x<=TP_end_x&&TP_drawenable_start_y<=TP_end_y&&TP_drawenable_end_x>=TP_end_x&&TP_drawenable_end_y>=TP_end_y)
tp_pos_display();
delay_ms(500);
}
TP_end_x=TP_to_LED_x;//记录当前坐标为结束坐标
TP_end_y=TP_to_LED_y;
//调用timer 5ms;
tp_pos_task();
return;
}
else
{
/*没有读到有效的坐标,一笔结束,重新打开中断*/
bTP_touch = false;//触摸结束
TP_INT_OPEN;
return;
}
}
}
/*==================================================================
* Function : xx
* Description : MSp430中断函数,捕捉触摸屏操作。
* Input Para : void
* Output Para : void
* Return Value : void
==================================================================*/
#pragma vector = PORT2_VECTOR
__interrupt void Port_2(void)
{
TP_INT_CLOSE;// 禁止中断
// P2IFG &= 0xFB;//清除中断标志寄存器
tp_read_adc(&TP_X,&TP_Y);
bTP_INT = true;
// check_err();
if(bTP_adjust)
tp_pos_adjust();
else
tp_pos_task();
P2IFG = 0x00;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -