一。更高效的使用触摸屏
PENIRQ引脚在没有触摸时都是高电平,只要有触摸就是低电平,直到没有触摸。用中断检测PENIRQ引脚,当产生下降沿中断时就去读取坐标。但是触摸屏也会象按键一样发生抖动,会产生很多上升沿或下降沿,会引起误判。这里我们使用状态机的方式去处理,使用状态机还有一个好处就是可以很方便的去判断长按,短按,双击等状态。
当触摸屏有触点按下时,PENIRQ 引脚会输出低电平,直到没有触摸的时候,它才会输出高电平;而且 STM32 的中断只支持边沿触发(上升沿或下降沿),不支持电平触发,在触摸屏上存在类似机械按键的信号抖动,所以如果使用中断的方式来检测触摸状态并不适合,难以辨别触摸按下及释放的情况。
状态机编程是一种非常高效的编程方式,它非常适合应用在涉及状态转换的过程控制中,上述代码采用状态机的编程方式对触摸状态进行检测,主要涉及触摸的按下、消抖及释放这三种状态转换。在应用时,本函数需要在循环体里调用,或定时调用(如每隔 10ms调用一次)。
通过读取PENIRQ引脚,内部有三种状态,当触摸还没有被按下的时候的状态为:RELEASE状态,是高电平,被按下后PENIRQ引脚变成低电平,进入消抖状态,还要等待一段时间,也就是消抖的过程,当第一次变成低电平的时候记录一个标志i ,记录它变成低电平一次了,然后等待一下,过了一段时间再去检测,如果还是低电平,就确认是从高电平变成低电平,确认触摸被持续按下,进入PRESSED状态,达到了消抖的目的。
这个等待的状态叫做WAITING状态。PRESSED状态就是低电平的状态。会在这三种状态之间转换,同时对外输出最终的结果。
如果在PRESSED状态再来检测可以检测触摸是否是一直被按下,这时候可以判断长按或短按。如果在PRESSED状态下检测到PENIRQ变成高电平,就转入RELEASE状态,同时对外输出这个触摸没有被按下。在消抖以后检测到PENIRQ是低电平或在PRESSED状态检测到PENIRQ是低电平,对外输出TOUCH_PRESSED。
程序:
1. touch.h头文件
代码语言:javascript复制 //用状态机编程处理触摸屏操作
//检测:触摸屏的按下和释放
#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文件
代码语言:javascript复制 //用状态机编程处理触摸屏操作
//检测:触摸屏的按下和释放
#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
代码语言:javascript复制 #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("rn 触摸被按下");
}
else
{
printf("rn 触摸未被按下");
}
delay_ms(2); //在这里使用了延时函数每2ms检测一次状态,实际使用中要用定时器
i ;
if(i==200)
{
i=0;
LED0=!LED0;
}
}
}