📄 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
****************************************************************************************
****************************************************************************************/
#include "touchpad.h"
#ifdef _DESIGN_EASY_LCM_MCU_PLATFORM_
sbit TP_nCS = P1^2;
sbit TP_DCLK = P1^3;
sbit TP_DIN = P1^4;
sbit TP_nBUSY = P1^5;
sbit TP_DOUT = P1^6;
#else
//add your own code here
#endif
#ifdef _DESIGN_EASY_TP_TYPE_ET2046_
/*该部分宏,参看触摸屏控制电路芯片文档中命令时序格式的介绍*/
#define TOUCH_PANEL_START_BIT 0x80
#define TOUCH_PANEL_TEMP0 0x00
#define TOUCH_PANEL_X_PLUS 0x10
#define TOUCH_PANEL_VBAT 0x20
#define TOUCH_PANEL_Z1_POS 0x30
#define TOUCH_PANEL_Z2_POS 0x40
#define TOUCH_PANEL_Y_PLUS 0x50
#define TOUCH_PANEL_TEMP1 0x70
#define TOUCH_PANEL_ADC3 0x20
#define TOUCH_PANEL_ADC4 0x60
#define TOUCH_PANEL_12BIT_SAMPLE 0x0
#define TOUCH_PANEL_8BIT_SAMPLE 0x8
#define TOUCH_PANEL_DIFF_MODE 0x0
#define TOUCH_PANEL_SINGLE_MODE 0x4
#define TOUCH_PANEL_PWD_ENBLE 0x0
#define TOUCH_PANEL_IRQ_DISABLE 0x1
#define TOUCH_PANEL_PWD_DISABLE 0x3
#define TOUCH_PANEL_PWD_RESET 0x2
/*坐标转化参数的默认值,可以直接使用*/
/*
AX=0B 86 AY=0A FE BX=04 9E BY=04 44
XK=00 14 XA=01 2E YK=00 0F YA=01 0B
*/
#define TOUCH_PANEL_ARG_X_K 0x14
#define TOUCH_PANEL_ARG_X_A 0x12E
#define TOUCH_PANEL_ARG_Y_K 0x0F
#define TOUCH_PANEL_ARG_Y_A 0x10B
#endif
/*
考虑到非校准情况下的触摸屏,通常都是写字、画画等连续的,
在我们的系统中,对于触摸功能是这样处理的:
首次触摸是由中断检测得到,之后响应中断进行处理;
处理完后开启一个5ms定时器,
定时器到时处理时主动读取触摸坐标,
若是有效坐标则处理,处理完后同样开启一个5ms定时器
若是无效坐标则表示没有触摸,此时再清除中断标记、
重新打开中断响应,等待下一次触摸中断
注意不要太早打开中断,一则因为系统中断不宜太频繁,二者避免误触发
bTP_INT用于标记该次处理是否由中断触发,
true: 是中断触发,
false: 是定时器主动读取
*/
bool bTP_INT = FALSE;
/*
bTP_Cali用于标记是否处于校准界面,
true: 处于校准界面
false: 非校准界面
*/
bool bTP_Cali = FALSE;
/*
最近一次得到的触摸坐标,
包括中断响应中或者定时器中得到的两种情况,
都记录在这里
*/
U16 TP_X = 0, TP_Y = 0;
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 : 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 = 1;
TP_DCLK = 0;
TP_DCLK = 1;
TP_DCLK = 0;
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 = 0;
TP_DCLK = 0;
TP_DCLK = 1;
TP_DCLK = 0;
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)
{
S8 i;
TP_DCLK = 0;
TP_nCS = 0;
/*从bit7到bit0依次传送*/
for (i=7; i>=0; i--)
{
if (SendData & (1<<i))
{
serial_write_bit_high();
}
else
{
serial_write_bit_low();
}
}
TP_DIN = 0;
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)
{
S8 i;
U16 RcvData=0;
U32 retry=0;
TP_DCLK = 0;
TP_DCLK = 1;
/*等待一段时间*/
while(TP_nBUSY)
{
TP_DCLK = 0;
TP_DCLK = 1;
retry++;
if(retry>100000)
{
return 0;
}
};
for(i=11; i>=0; i--)
{
TP_DCLK = 1;
if(TP_DOUT)
{
RcvData |= (1<<i);
}
TP_DCLK = 0;
}
TP_nCS = 1;
return(RcvData);
}
/*==================================================================
* Function : tp_init
* Description : 初始化tp
* Input Para : void
* Output Para : void
* Return Value: void
==================================================================*/
void tp_init(void)
{
U8 cmd = 0;
/*在校准之前也可以使用触摸屏,用这一组默认参数。
校准之后用校准得到的参数*/
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 : void
* Output Para : U16 * X, U16 * Y,若全为0表示获得坐标不成功
* 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();
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;
/*触摸屏的范围大于LCD屏幕范围,判断是否超出了四周的边框*/
if(*X < 0x0080 || *Y < 0x0080 || *X > 0xF80 || *Y > 0xF80)
{
*X = 0;
*Y = 0;
}
return;
}
/*
由于触摸部分的应用和各自系统紧密相关,
单纯的触摸屏驱动只需提供tp_init()和tp_read_adc()两个函数即可。
用户可以用类似下面的函数打印函数或者触摸坐标,以此知道是否调试成功:
void TestTP(void)
{
U16 XPos = 0;
U16 YPos = 0;
while (1)
{
tp_read_adc(&XPos, &YPos);
if ((XPos == 0) || (YPos == 0))
{
uty_delay(0x1000);
}
else
{
XPos = (XPos - TPargX.A) / TPargX.K;
YPos = (YPos - TPargY.A) / TPargY.K;
uprintf("\nX=");
uputchar(XPos >> 8);
uputchar(XPos& 0xFF);
uprintf(" Y=");
uputchar(YPos >> 8);
uputchar(YPos & 0xFF);
break;
}
}
return;
}
在设计各自的触摸应用程序时,可以参考以下3个函数,
完成校准和显示轨迹
*/
#ifdef _DESIGN_EASY_TP_TEST_
/*以下两部分,在创易demo系统中放在别的文件中,这里拷贝过来,供参考*/
#if 0
/*==================================================================
* Function : extern_interrupt1
* Description : 触摸中断处理函数,检测到触摸后需要调用tp_task
* Input Para :
* Output Para :
* Return Value:
==================================================================*/
void extern_interrupt1(void) interrupt 2
{
EX1 = 0;
tp_read_adc(&TP_X, &TP_Y);
if(TP_X > 0)
{
/*一笔的开始*/
bTP_INT = TRUE;
MSTimerStart(MSTIMERMODE_HANDLE_IN_MSG, 10, tp_task);
}
else
{
IE1 = 0;
EX1 = 1;
}
}
/*==================================================================*/
extern void lcd_display(EColor color);
/*case LCD_TP_CALI: 分支,显示了校准的界面*/
#endif
U8 Cali_Cnt = 0;
/*==================================================================
* Function : tp_task
* Description : 触摸应用的主要函数,在触摸中断处理中需要调用这个函数
在5ms定时器处理中也需要调用这个函数
* Input Para : void
* Output Para : void
* Return Value: void
==================================================================*/
void tp_task(void)
{
if(bTP_Cali == TRUE)
{
/*校准,需要先后采集两个点,都是从中断处理中获得的坐标,
所以处理完不要完了开中断*/
if(Cali_Cnt == 0)
{
/*采集第一个点*/
#if 0
/*大致判断是否在非左下*/
if(TP_X < 2048 || TP_Y < 2048)
{
IE1 = 0;
EX1 = 1;
return;
}
#endif
TPposA.X= TP_X;
TPposA.Y = TP_Y;
Cali_Cnt++;
/* 清除第一个点,画第二个点??? */
lcd_display_rectangle_color(42, 53, 46, 57, BLUE);
lcd_display_rectangle_color(130, 163, 134, 167, WHITE);
}
else
{
/*采集第二个点*/
#if 0
/*大致判断是否在非右上*/
if(TP_X > 2048 || TP_Y > 2048)
{
IE1 = 0;
EX1 = 1;
return;
}
#endif
TPposB.X= TP_X;
TPposB.Y = TP_Y;
/*校准结束,恢复标志变量*/
Cali_Cnt = 0;
bTP_Cali = FALSE;
/*清除第二个点*/
lcd_display_rectangle_color(42, 53, 46, 57, WHITE);
/*重新计算参数??? */
TPargX.K = (TPposA.X - TPposB.X) / 88;
TPargY.K = (TPposA.Y - TPposB.Y) / 110;
TPargX.A = TPposB.X -(TPargX.K * 44);
TPargY.A = TPposB.Y -(TPargY.K * 55);
/*用户可以自己考虑校验失败的可能,
最简单的方法就是限定TPargX TPargY的四个值在一定范围内*/
}
IE1 = 0;
EX1 = 1;
}
else
{
/*显示触摸轨迹*/
if(bTP_INT)
{
/*一笔的起点,坐标从中断中获得*/
lcd_display_dot((TP_X - TPargX.A) / TPargX.K, (TP_Y - TPargY.A) / TPargY.K);
bTP_INT = FALSE;
/*5ms之后再次调用tp_task*/
MSTimerStart(MSTIMERMODE_HANDLE_IN_MSG, 5, tp_task);
}
else
{
/*定时器处理,需要主动读取坐标*/
tp_read_adc(&TP_X, &TP_Y);
if(TP_X > 0)
{
lcd_display_dot((TP_X - TPargX.A) / TPargX.K, (TP_Y - TPargY.A) / TPargY.K);
/*5ms之后再次调用tp_task*/
MSTimerStart(MSTIMERMODE_HANDLE_IN_MSG, 5, tp_task);
}
else
{
/*没有读到有效的坐标,一笔结束,重新打开中断*/
IE1 = 0;
EX1 = 1;
}
}
}
return;
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -