触摸屏手指滑动方向检测

摘要:
参考:不会编写移动应用程序滑屏方向确定解决方案的底层芯片驱动程序。每个芯片的寄存器是不同的,但最终得到的是相同的——触摸坐标。底部芯片驱动器提供了一个可以返回触摸坐标的接口。中层触摸检测的思路是:1.判断是否有手指接触=1.进入手指接触处理,否则进入无手指接触处理;2.手指接触处理:首先判断当前接触和先前接触是否在误差范围内(#defineTP_error_RANGE20);

参考:移动应用滑动屏幕方向判断解决方案

 底层芯片驱动就不写了,每款芯片的寄存器不一样,可是最终要获取的东西都是一样的--触摸坐标。

底层芯片驱动提供能返回触摸坐标的接口就行。

中间层触摸检测的思路是:

1、判断是否有手指触点,当手指触点>=1,进入有手指触点处理,否则进入无手指触点处理;

2、有手指触点处理:首先判断当前触点与上一个触点是否在误差范围内(#define TP_ERR_RANGE 20);

a、在误差范围内并且在防抖时间之外,则确认为手指按下状态;

b、不在误差范围内并且在防抖时间之外,如果上一状态为手指按下状态,则为手指滑动ing状态;否则不做处理,使相应变量及状态复位;

3、无手指触点处理:在有手指触点处理进入到无手指触点处理的第一次为手指松开状态处理;

a、手指松开的坐标与手指按下时的坐标在在误差范围内,确认为手指松开状态;

b、手指松开的坐标与手指按下时的坐标在在误差范围内,确认为手指滑动状态;

最终通过接口返回给应用层4种状态:手指按下,手指松开,手指滑动中,手指滑动。

滑动方向检测的核心在于方向的判断:

#include "math.h"

#define PI                3.1415926f


//返回角度
float GetSlideAngle(int dx, int dy) 
{
/*
atan2()接受两个参数x和y:

angel=Math.atan2(y,x)
x 指定两个点横坐标的差
y 指定两个点纵坐标的差

计算出来的结果angel是一个弧度值,要换算成角度,也必须乘以180/PI。
*/
    return(atan2(dy, dx) * 180 / PI);
}

//根据起点和终点返回方向 1:向上,2:向下,3:向左,4:向右, 0:未滑动
MMP_UBYTE GetSlideDirection(MMP_USHORT startX, MMP_USHORT startY, MMP_USHORT endX, MMP_USHORT endY) 
{
    MMP_UBYTE result = TP_SlideDirection_NONE;
    int dy = startY - endY;
    int dx = endX - startX; 
    float angle;
 
    //如果滑动距离太短
    if (abs(dx) < 2 && abs(dy) < 2) 
    {
        return result;
    }
 
    angle = GetSlideAngle(dx, dy);
    if (angle >= -45 && angle < 45) 
    {
        result = TP_SlideDirection_RIGHT;// 4;
    } else if (angle >= 45 && angle < 135) 
    {
        result = TP_SlideDirection_UP;// 1;
    } else if (angle >= -135 && angle < -45) 
    {
        result = TP_SlideDirection_DOWN;// 2;
    }
    else if ((angle >= 135 && angle <= 180) || (angle >= -180 && angle < -135)) 
    {
        result = TP_SlideDirection_LEFT;// 3;
    }
 
    return result;
}

注意:没有 #include "math.h" 也能编译通过,却不能产生正确的结果。

TouchPanel.c

#include "math.h"


#define PI                3.1415926f

#define TP_ERR_RANGE    20 //误差范围 

STPBUTTON TPButton = {TOUCH_PANEL_PRESS, TOUCH_PANEL_REL, 0, 15, KEYPAD_NONE, 0, 0, 0, 0, TP_ERR_RANGE, "TouchPanel"};



//返回角度
float GetSlideAngle(int dx, int dy) 
{
/*
atan2()接受两个参数x和y:

angel=Math.atan2(y,x)
x 指定两个点横坐标的差
y 指定两个点纵坐标的差

计算出来的结果angel是一个弧度值,要换算成角度,也必须乘以180/PI。
*/
    return(atan2(dy, dx) * 180 / PI);
}

//根据起点和终点返回方向 1:向上,2:向下,3:向左,4:向右, 0:未滑动
MMP_UBYTE GetSlideDirection(MMP_USHORT startX, MMP_USHORT startY, MMP_USHORT endX, MMP_USHORT endY) 
{
    MMP_UBYTE result = TP_SlideDirection_NONE;
    int dy = startY - endY;
    int dx = endX - startX; 
    float angle;
 
    //如果滑动距离太短
    if (abs(dx) < 2 && abs(dy) < 2) 
    {
        return result;
    }
 
    angle = GetSlideAngle(dx, dy);
    if (angle >= -45 && angle < 45) 
    {
        result = TP_SlideDirection_RIGHT;// 4;
    } else if (angle >= 45 && angle < 135) 
    {
        result = TP_SlideDirection_UP;// 1;
    } else if (angle >= -135 && angle < -45) 
    {
        result = TP_SlideDirection_DOWN;// 2;
    }
    else if ((angle >= 135 && angle <= 180) || (angle >= -180 && angle < -135)) 
    {
        result = TP_SlideDirection_LEFT;// 3;
    }
 
    return result;
}

AHC_BOOL AHC_TouchPanel_CheckUpdate(MMP_ULONG* pulKeyEvent, MMP_ULONG* pulPosition, MMP_UBYTE dir, MMP_UBYTE* finger, MMP_UBYTE* pucSlideDirection)
{
    MMP_ERR status = MMP_ERR_NONE;
    static MMP_ULONG ulPosition = 0;
    MMP_ULONG ulNow;  
    
    if (*pulKeyEvent == TOUCH_PANEL_PRESS   ||
        *pulKeyEvent == TOUCH_PANEL_REL     ||
        *pulKeyEvent == TOUCH_PANEL_MOVE)
    {
        // Read position
        MMP_USHORT uwX = 0;
        MMP_USHORT uwY = 0;
        UINT16 x1, y1;//last pos
        UINT16 x2, y2;//now pos
        
        *finger = AHC_TouchPanel_ReadPosition(&uwX, &uwY, dir);

        *pulKeyEvent = KEYPAD_NONE;
        
        MMPF_OS_GetTime(&ulNow);
        
        if (*finger != 0)
        {
            x1 = TPButton.uwLastPosX;
            y1 = TPButton.uwLastPosY;
            x2 = uwX;
            y2 = uwY;

            if ((((x2 <= x1) && (x1 < x2 + TPButton.uwErrRange)) || ((x1 <= x2) && (x2 < x1 + TPButton.uwErrRange))) && 
                (((y2 <= y1) && (y1 < y2 + TPButton.uwErrRange)) || ((y1 <= y2) && (y2 < y1 + TPButton.uwErrRange))))    
               {    //前后两次采样在+-20内
                if (ulNow - TPButton.ulKeyLastTime > TPButton.ulDebounceTime)
                {
                    if (TPButton.ulKeyLastEvent == KEYPAD_NONE)
                    {
                        *pulKeyEvent = TOUCH_PANEL_PRESS;
                        TPButton.ulKeyLastEvent = *pulKeyEvent;
                        
                        TPButton.uwPressPosX = (x1 + x2) >> 1;
                        TPButton.uwPressPosY = (y1 + y2) >> 1;

                        printc("--Harry-- PRESS: xPos = %d, yPos = %d --1
", TPButton.uwPressPosX, TPButton.uwPressPosY);
                    }

                    TPButton.uwLastPosX = x2;
                    TPButton.uwLastPosY = y2;                    

                    TPButton.ulKeyLastTime = ulNow;
                }
               }
               else
               {    //前后两次采样大于+-20
                if ((ulNow - TPButton.ulKeyLastTime) > (TPButton.ulDebounceTime >> 1))
                {
                    //printc("--Harry-- MOVE: xPos = %d, yPos = %d --2
", uwX, uwY);
                    if (TPButton.ulKeyLastEvent == TOUCH_PANEL_PRESS)
                    {        
                    #if 0//Moveing
                        x1 = TPButton.uwPressPosX;
                        y1 = TPButton.uwPressPosY;

                        if ((x1 > (x2 + TPButton.uwErrRange * 2)) || (x2 > (x1 + TPButton.uwErrRange * 2)) || 
                            (y1 > (y2 + TPButton.uwErrRange * 2)) || (y2 > (y1 + TPButton.uwErrRange * 2)))
                           {
                            *pulKeyEvent = TOUCH_PANEL_MOVE;
                            TPButton.ulKeyLastEvent = *pulKeyEvent;

                            TPButton.uwPressPosX = (x1 + x2) >> 1;
                            TPButton.uwPressPosY = (y1 + y2) >> 1;                            
                           }
                    #endif
                    }
                    else
                    {
                        *pulKeyEvent = KEYPAD_NONE;
                        TPButton.ulKeyLastEvent = *pulKeyEvent;

                        TPButton.uwPressPosX = 0;
                        TPButton.uwPressPosY = 0;    
                    }            

                    TPButton.uwLastPosX = x2;
                    TPButton.uwLastPosY = y2;                
                    
                    TPButton.ulKeyLastTime = ulNow;            
                }        
               }
           }
        else
        {    //按键松开
            x1 = TPButton.uwPressPosX;
            y1 = TPButton.uwPressPosY;
            x2 = TPButton.uwLastPosX;
            y2 = TPButton.uwLastPosY;
        
            if (TPButton.ulKeyLastEvent == TOUCH_PANEL_PRESS)
            {
                if ((((x2 <= x1) && (x1 < x2 + TPButton.uwErrRange)) || ((x1 <= x2) && (x2 < x1 + TPButton.uwErrRange))) && 
                    (((y2 <= y1) && (y1 < y2 + TPButton.uwErrRange)) || ((y1 <= y2) && (y2 < y1 + TPButton.uwErrRange))))    
                {    //按下时的点与松开时的点小于容错范围
                    *pulKeyEvent = TOUCH_PANEL_REL;

                    uwX = (x1 + x2) >> 1;
                    uwY = (y1 + y2) >> 1;
                }
                else
                {    //按下时的点与松开时的点大于容错范围
                    *pulKeyEvent = TOUCH_PANEL_MOVE;

                    //printc("--Harry-- MOVE: x1=%d, y1=%d x2=%d, y2=%d --22
", x1, y1, x2, y2);
                    *pucSlideDirection = GetSlideDirection(x1, y1, x2, y2);
                    
                    uwX = x2;
                    uwY = y2;                    
                }
            }
            else
            {
                *pulKeyEvent = KEYPAD_NONE;
            }

            TPButton.uwLastPosX = 0;
            TPButton.uwLastPosY = 0;
            TPButton.uwPressPosX = 0;
            TPButton.uwPressPosY = 0;            
            TPButton.ulKeyLastTime = ulNow;
            TPButton.ulKeyLastEvent = *pulKeyEvent;
        }

        if (*pulKeyEvent != KEYPAD_NONE)
        {
            ulPosition = uwY;
            ulPosition = (ulPosition << 16) + uwX;

            *pulPosition = ulPosition;
            status = AHC_TOUCHPANEL_RET_TRUE;
        }
        else
        {
            *pulPosition = 0;
            status = AHC_TOUCHPANEL_RET_FALSE;
        }

    }
    
    AHC_TOUCHPANEL_CHECK_RETURE_VALUE(status, AHC_TOUCHPANEL_NO_ERROR, AHC_TOUCHPANEL_RET_TRUE, AHC_TOUCHPANEL_RET_FALSE)
}

TouchPanel.h

typedef enum
{
    TP_SlideDirection_NONE    = 0,
    TP_SlideDirection_UP,
    TP_SlideDirection_DOWN,
    TP_SlideDirection_LEFT,
    TP_SlideDirection_RIGHT
    
} TP_SlideDirection_Enum;

/* For Touch Panel Button */
typedef struct tagTPButton
{
    int            iPressId;
    int            iReleaseId;
    unsigned int   ulKeyLastTime;
    unsigned int   ulDebounceTime;
    unsigned int   ulKeyLastEvent;
    unsigned short uwLastPosX;
    unsigned short uwLastPosY;
    unsigned short uwPressPosX;
    unsigned short uwPressPosY;
    unsigned short uwErrRange;
    unsigned char  ubkeyname[16];
} STPBUTTON;

应用层通过接口获取中间层所得的触摸状态做相应事件处理。

typedef struct _TP_Position
{
    unsigned short xPos;
    unsigned short yPos;
} TP_Position;

/* For Touch Panel Event */
typedef struct _TouchPanel
{
    TP_Position   PrevPosition;
    TP_Position   CurrPosition;
    unsigned char SlideDirection;
    void (*PressEvent)(void);
    void (*ReleaseEvent)(void);
    void (*MoveEvent)(void);
} TouchPanelEvent;

static TouchPanelEvent TouchPanel;



static void TouchPanel_PressEvent(void)
{
    printc("--Harry-- %s Line:%d
", __func__, __LINE__);

    TouchPanel.PrevPosition.xPos = TouchPanel.CurrPosition.xPos;
    TouchPanel.PrevPosition.yPos = TouchPanel.CurrPosition.yPos;    
}

static void TouchPanel_ReleaseEvent(void)
{
    printc("--Harry-- %s Line:%d
", __func__, __LINE__);
    

    TouchPanel.PrevPosition.xPos = TouchPanel.CurrPosition.xPos;
    TouchPanel.PrevPosition.yPos = TouchPanel.CurrPosition.yPos;
}

static void TouchPanel_MoveEvent(void)
{
    //printc("--Harry-- %s Line:%d
", __func__, __LINE__);
    
}

static void TouchPanelEventInit(void)
{
    TouchPanel.PrevPosition.xPos = 0;
    TouchPanel.PrevPosition.yPos = 0;
    TouchPanel.CurrPosition.xPos = 0;
    TouchPanel.CurrPosition.yPos = 0;
    TouchPanel.SlideDirection = 0;
    TouchPanel.PressEvent = TouchPanel_PressEvent;
    TouchPanel.ReleaseEvent = TouchPanel_ReleaseEvent;
    TouchPanel.MoveEvent = TouchPanel_MoveEvent;
}

void UIKeyTask(void)
{
    MMP_ULONG      ulKeyEvent;
    MMPF_OS_FLAGS  flags;
    MMPF_OS_FLAGS  waitflags;
    MMP_ULONG      ulNow;
    MMP_ULONG      ulPosition;

#if (KEYPAD_DETECT_METHOD == KEYPAD_DETECT_TASK)
    UITaskReady = MMP_TRUE;
#endif

#if (TASK_MONITOR_ENABLE)
    memcpy(&gsTaskMonitorUIKey.TaskName[0], __func__, TASK_MONITOR_MAXTASKNAMELEN);
    gsTaskMonitorUIKey.sTaskMonitorStates = MMPF_TASK_MONITOR_STATES_WAITING;
    gsTaskMonitorUIKey.ulExecTime = 0;
    memset((void *)gsTaskMonitorUIKey.ParaArray, 0x0, sizeof(gsTaskMonitorUIKey.ParaArray)); 
    gsTaskMonitorUIKey.ulParaLength = 0;    
    gsTaskMonitorUIKey.pTimeoutCB = (TASK_MONITOR_TimeoutCallback *)NULL;       
    MMPF_TaskMonitor_RegisterTask(&gsTaskMonitorUIKey);
#endif

    waitflags = CDV_KEYPAD_FLAG | CDV_TIME_FLAG;
#if (UPDATE_UI_USE_MULTI_TASK)
    waitflags |= CDV_UI_FLAG;
#endif

#if (SUPPORT_TOUCH_PANEL)
    TouchPanelEventInit();
#endif
    
    while(1){
        MMPF_OS_WaitFlags(CDV_UI_Flag, waitflags, MMPF_OS_FLAG_WAIT_SET_ANY|MMPF_OS_FLAG_CONSUME, 0, &flags);

    #if (TASK_MONITOR_ENABLE)
        MMPF_OS_GetTime(&gsTaskMonitorUIKey.ulExecTime);
        gsTaskMonitorUIKey.sTaskMonitorStates = MMPF_TASK_MONITOR_STATES_RUNNING;    
        *(MMP_ULONG *)(gsTaskMonitorUIKey.ParaArray) = (MMP_ULONG)flags;
        gsTaskMonitorUIKey.ulParaLength = sizeof(MMP_ULONG); 
    #endif

        if (flags & CDV_TIME_FLAG) {
            // The KeyTask priority is higher then NETWORK to update Video Time Stamp for better performance.
            UpdateVideoCurrentTimeStamp();
        }

    #if (UPDATE_UI_USE_MULTI_TASK)
        if (flags & CDV_UI_FLAG) {
            DrawStateVideoRecUpdate(EVENT_VIDREC_UPDATE_MESSAGE);
        }        
    #endif

        if (flags & CDV_KEYPAD_FLAG) {
            MMPF_OS_GetTime(&ulNow);

            GetKeyPadEvent(&ulKeyEvent);

        #if (SUPPORT_TOUCH_PANEL)
            if ((ulKeyEvent == TOUCH_PANEL_PRESS) || (ulKeyEvent == TOUCH_PANEL_REL))
            {
                UINT32 dir;
                MMP_UBYTE finger;
                MMP_ERR status;
                MMP_UBYTE slide = 0;

                AHC_GetParam(PARAM_ID_LCD_STATUS, &dir);
                status = AHC_TouchPanel_CheckUpdate(&ulKeyEvent, &ulPosition, dir, &finger, &slide);

                if (ulKeyEvent != KEYPAD_NONE) 
                {            
                    if (ulKeyEvent == TOUCH_PANEL_PRESS)
                    {
                        TouchPanel.CurrPosition.xPos = ulPosition & 0x0000FFFF;
                        TouchPanel.CurrPosition.yPos = ulPosition >> 16;    
                    
                        TouchPanel.PressEvent();
                    }
                    else if (ulKeyEvent == TOUCH_PANEL_REL)
                    {                        
                        TouchPanel.CurrPosition.xPos = ulPosition & 0x0000FFFF;
                        TouchPanel.CurrPosition.yPos = ulPosition >> 16;
                        
                        TouchPanel.ReleaseEvent();
                    }
                    else if (ulKeyEvent == TOUCH_PANEL_MOVE)
                    {
                        TouchPanel.CurrPosition.xPos = ulPosition & 0x0000FFFF;
                        TouchPanel.CurrPosition.yPos = ulPosition >> 16;

                        TouchPanel.SlideDirection = slide;
                        
                        TouchPanel.MoveEvent();                        
                    }
                    ulKeyEvent = KEYPAD_NONE;
                } 
            }
        #endif

            if (ulKeyEvent != KEYPAD_NONE) {
                AHC_SendAHLMessage(AHLM_GPIO_BUTTON_NOTIFICATION, ulKeyEvent, ulNow);
            }
        }

#if (TASK_MONITOR_ENABLE)
        gsTaskMonitorUIKey.sTaskMonitorStates = MMPF_TASK_MONITOR_STATES_WAITING;
#endif
    }
}

 注意:TouchPanel 事件在调用前必须先初始化 TouchPanelEventInit();

免责声明:文章转载自《触摸屏手指滑动方向检测》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇lua二进制操作函数多个yml文件的读取方式下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

android 电容屏(一):电容屏基本原理篇

关键词:android 电容屏 tp ITO平台信息:内核:linux2.6/linux3.0系统:android/android4.0平台:S5PV310(samsung exynos 4210) 作者:xubin341719(欢迎转载,请注明作者) android 电容屏(一):电容屏基本原理篇 android 电容屏(二):驱动调试之基本概念篇 and...

触摸屏驱动

硬件配置 硬件原理 ADC AND TOUCH SCREEN INTERFACE SPECIAL REGISTERS                       程序框架 软件架构:输入子系统       优化措施 ①问题:ADC转换出来的值变化太大,不稳定; 原因1:触摸屏被"触摸",触摸点电压值尚未稳定,已经被ADC转...

关于PLC

学电气的一方面是单片机,一方面是PLC,,,,常常看到说选择比努力更重要,,单片机都很熟悉了,我就来介绍一下PLC..... 然后呢我先吹吹牛,,,目的是让大家相信我介绍的PLC绝对是亲身体验..... 吹牛开始: 首先:PLC适合学习能力强的人学习,PLC考验的是实际解决问题的能力,PLC和单片机不一样更多的是"使用"而非"开发" 自己呢大一的时候开始学...

ThinkPad笔记本无法禁用触摸屏【亲测,有用】

现在有一部分新款笔记本电脑无法禁用触摸屏,禁用键灰色,如图。像ThinkPad E470等,但办公起来又很容易碰到下面的触摸屏,很不方便,下面介绍这类电脑如何禁用触摸屏。 一、打开控制面板,找到鼠标, 二、点击硬件--ps/2兼容鼠标--属性 三、点击驱动程序--驱动程序详细信息,会看到两个sys文件的路径,一个是i8042prt.sys,另一个是m...

Linux学习 : 移植qt 5.6.3 及 tslib 1.4

                             (一) 移植 qt5.6.3 一、qt简介:   Qt是一个1991年由Qt Company开发的跨平台C++图形用户界面应用程序开发框架。它既可以开发GUI程序,也可用于开发非GUI程序,比如控制台工具和服务器。Qt是面向对象的框架,使用特殊的代码生成扩展(称为元对象编译器(Meta Object...

linux6410触摸屏驱动

要: 目前,市面上很多6410开发板都存在触摸屏抖动的问题,tiny6410也不例外,友善的解决方法是采用一线触摸,即在LCD板上,用一个单片机控制ADS7846芯片AD转换,再将数据通过单总线的方式与6410通讯。可是,我这里没有一线触摸板,于是就开始移植ADS7846驱动到tiny6410。 介绍: 可能有人会问,6410的触摸屏为什么会抖动呢,是不...