一。更高效的使用触摸屏
PENIRQ引脚在没有触摸时都是高电平,只要有触摸就是低电平,直到没有触摸。用中断检测PENIRQ引脚,当产生下降沿中断时就去读取坐标。但是触摸屏也会象按键一样发生抖动,会产生很多上升沿或下降沿,会引起误判。这里我们使用状态机的方式去处理,使用状态机还有一个好处就是可以很方便的去判断长按,短按,双击等状态。
当触摸屏有触点按下时,PENIRQ 引脚会输出低电平,直到没有触摸的时候,它才会输出高电平;而且 STM32 的中断只支持边沿触发(上升沿或下降沿),不支持电平触发,在触摸屏上存在类似机械按键的信号抖动,所以如果使用中断的方式来检测触摸状态并不适合,难以辨别触摸按下及释放的情况。
状态机编程是一种非常高效的编程方式,它非常适合应用在涉及状态转换的过程控制中,上述代码采用状态机的编程方式对触摸状态进行检测,主要涉及触摸的按下、消抖及释放这三种状态转换。在应用时,本函数需要在循环体里调用,或定时调用(如每隔 10ms调用一次)。
通过读取PENIRQ引脚,内部有三种状态,当触摸还没有被按下的时候的状态为:RELEASE状态,是高电平,被按下后PENIRQ引脚变成低电平,进入消抖状态,还要等待一段时间,也就是消抖的过程,当第一次变成低电平的时候记录一个标志i++,记录它变成低电平一次了,然后等待一下,过了一段时间再去检测,如果还是低电平,就确认是从高电平变成低电平,确认触摸被持续按下,进入PRESSED状态,达到了消抖的目的。
这个等待的状态叫做WAITING状态。PRESSED状态就是低电平的状态。会在这三种状态之间转换,同时对外输出最终的结果。
如果在PRESSED状态再来检测可以检测触摸是否是一直被按下,这时候可以判断长按或短按。如果在PRESSED状态下检测到PENIRQ变成高电平,就转入RELEASE状态,同时对外输出这个触摸没有被按下。在消抖以后检测到PENIRQ是低电平或在PRESSED状态检测到PENIRQ是低电平,对外输出TOUCH_PRESSED。
程序:
1. touch.h头文件
//用状态机编程处理触摸屏操作 //检测:触摸屏的按下和释放 #define TOUCH_NOT_PRESSED 0 //释放的时候返回0 #define TOUCH_PRESSED 1 //按下时返回1 typedef enum { XPT2046_STATE_RELEASE = 0, //定义一个枚举变量,代表三种状态 XPT2046_STATE_WAITING, XPT2046_STATE_PRESSED, }Touch_State; //触摸检测状态机 u8 touch_dectect(void); //用状态机编程进行处理
2. touch.c文件
//用状态机编程处理触摸屏操作 //检测:触摸屏的按下和释放 #define TOUCH_NOT_PRESSED 0 //释放的时候返回0 #define TOUCH_PRESSED 1 //按下时返回1 //触摸检测状态机 u8 touch_dectect(void) { static Touch_State touch_state = XPT2046_STATE_RELEASE; u8 result; //用了记录状态的输出 static u8 i; //记录检测到PENIRQ引脚为低电平 switch(touch_state) //状态处理 { case XPT2046_STATE_RELEASE: if(PEN == 0) { touch_state = XPT2046_STATE_WAITING; //切换到消抖等待的状态 result = TOUCH_NOT_PRESSED; //在消抖等待状态仍输出没有被按下 } else { touch_state = XPT2046_STATE_RELEASE; //切换到消抖等待的状态 result = TOUCH_NOT_PRESSED; //在消抖等待状态仍输出没有被按下 } break; case XPT2046_STATE_WAITING: if(PEN == 0) { i++; //在while循环中使用,比如间隔2ms检测一次 if( i > 10) //如果检测10次以后PENIRQ还是低电平,相当于检测20ms之内一直处于低电平,消抖。 { touch_state = XPT2046_STATE_PRESSED; //切换到触摸屏被按下的状态 result = TOUCH_PRESSED; //输出触摸屏被按下 } else { touch_state = XPT2046_STATE_WAITING; //切换到消抖等待的状态 result = TOUCH_NOT_PRESSED; //在消抖等待状态仍输出没有被按下 } } else //检测到PENIRQ为高电平 { i = 0; touch_state = XPT2046_STATE_RELEASE; //切换到触摸屏没有被按下的状态 result = TOUCH_NOT_PRESSED; //输出没有被按下 } break; case XPT2046_STATE_PRESSED: if(PEN == 0) { touch_state = XPT2046_STATE_PRESSED; //一直处于被按下状态,在这里可以检测是否长按 result = TOUCH_PRESSED; //输出触摸屏被按下 } else { touch_state = XPT2046_STATE_RELEASE; //如果检测到高电平就认为被释放了 result = TOUCH_NOT_PRESSED; //输出没有被按下 } break; } return result; }
3.main.c
#include "stdio.h" #include "led.h" #include "delay.h" #include "key.h" #include "sys.h" #include "lcd.h" #include "usart.h" #include "24cxx.h" #include "flash.h" #include "touch.h" //ALIENTEK战舰STM32开发板实验26 //触摸屏 实验 //技术支持:www.openedv.com //广州市星翼电子科技有限公司 void Load_Drow_Dialog(void) { LCD_Clear(WHITE);//清屏 POINT_COLOR=BLUE;//设置字体为蓝色 LCD_ShowString(216,0,200,16,16,"RST");//显示清屏区域 POINT_COLOR=RED;//设置画笔蓝色 } int main(void) { u8 key; u8 i=0; delay_init(); //延时函数初始化 NVIC_Configuration(); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 uart_init(9600); //串口初始化为9600 LED_Init(); //LED端口初始化 LCD_Init(); KEY_Init(); POINT_COLOR=RED;//设置字体为红色 LCD_ShowString(60,50,200,16,16,"WarShip STM32"); LCD_ShowString(60,70,200,16,16,"TOUCH TEST"); LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK"); LCD_ShowString(60,110,200,16,16,"2012/9/11"); LCD_ShowString(60,130,200,16,16,"Press KEY0 to Adjust"); tp_dev.init(); delay_ms(1500); Load_Drow_Dialog(); while(1) { if( touch_dectect() == TOUCH_PRESSED) { printf("\r\n 触摸被按下"); } else { printf("\r\n 触摸未被按下"); } delay_ms(2); //在这里使用了延时函数每2ms检测一次状态,实际使用中要用定时器 i++; if(i==200) { i=0; LED0=!LED0; } } }
分享:
释放潜能:学习效率提升、编程能力提升
http://www.makeru.com.cn/live/3507_1276.html?s=45051
软硬通吃,嵌入式高薪人才的必杀技
http://www.makeru.com.cn/live/5413_2000.html?s=45051
(stm32串口应用)
http://www.makeru.com.cn/live/1392_1164.html?s=45051
老司机倾囊相授-PCB大牛修炼秘籍
http://www.makeru.com.cn/live/3472_1296.html?s=45051