欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ADC和触摸屏

程序员文章站 2022-07-14 09:37:38
...

一、ADC和触摸屏介绍

这节内容我们来介绍S3c2440上边的ADC和触摸屏,ADC,Analog-to-Digital Converter的缩写,是一种把模拟信号转换为数字信号的转换器,比如我们要测量接有一个变阻器的电路的电压,2可以通过ADC进行转换,把电路的模拟信号转换为方便我们阅读的数字信号,
S3c2440上的ADC是一个10位的转换器,可以接收8路的模拟输入信号,触摸屏的模拟电压信号也是接到了ADC转换器上面
ADC和触摸屏
从上边的图可以看出来,触摸屏总共有4路模拟信号,分别是XP、XM、YP、YM、通过ADC转换器和触摸屏相连,触摸屏和ADC都有中断机制,中断信号接到了中断控制器上边,输出两路中断信号INT_ADC和INT_TC,它们之间的框架图并不复杂,那接下来就要了解一些触摸屏是怎么通过ADC测试触摸坐标的,下边的内容是我从《入式Linux应用完全开发手册》中截取出来的,想要了解更加详细的触摸屏原理的话需要自己去搜索相关资料
触摸屏的等效电路如下所示,图中粗黑线表示相互绝缘的两层导电层,当按压时,它们在触点处相连,不同的触点在x和y方向上的分压不一样,将这两个电压值经过转换,就可以得到x y的坐标
ADC和触摸屏
s4 s5闭合,s1 s2 s3断开,YM接地,XP上拉,XP和XP作为模拟输入,平时触摸屏没有被按下的时候,由于上拉电阻的关系,Y_ADC为高电平,当x轴和x轴收到挤压而接触导通时,Y_ADC的电压由于接到了y轴接地而变成了低电平,此低电平可以中断信号来通知CPU发生了按压事件,这在s3c2440中被称为等待中断模式。当采集坐标时,类似于如下的等效电路
ADC和触摸屏
s1 s2闭合,s3 s4 s4断开,即XP接到电源,XM接地,YP作为模拟输入,YM高阻,XP禁止上拉,这时,YP即X_ADC就是x轴的分压点,进行AD转换后就是x轴的坐标,同样的采集y点的坐标和x的坐标类似,等效电路如下所示,在这里就不再多讲了
ADC和触摸屏
二、编写程序
在写程序之前,先来梳理一下程序的逻辑和流程

使用触摸屏的流程
1、按下触摸屏,发生触摸中断,启动ADC转换
2、启动ADC之后,获取x y坐标
3、ADC转换完成之后,产生中断,在ADC中断里读取x y 坐标
后续进行改进
读取一次x y坐标之后,打开一个定时器,再去判断触摸屏是否被按下,如果按下再去启动ADC读取数

ADC和触摸屏的寄存器配置和中断部分

/* ADC的寄存器配置 */
void  adc_ts_reg_init()
{
	/*
	  [15]  ECFLG  0 正在转换 1 转换结束
	  [14]  PRSCEN   预分频 1启用
	  [13:6] PRSCVL  预分频系数
	  [5:3] SEL_MUX  选择要读取的信号 000 = AIN 0
	*/
	 ADCCON = (1 << 14) | (49 << 6) | (0 << 3); 
	/*  按下触摸屏, 延时一会再发出TC中断
	*  延时时间 = ADCDLY * 晶振周期 = ADCDLY * 1 / 12000000 = 5ms
	*/
	 ADCDLY = 60000;
}

/* 打开ADC和触摸屏的中断 */
void adc_ts_int_init()
{
	/* 先清一次中断 */
	 SUBSRCPND = (1 << 9) | (1 << 10);  
	/* 注册中断处理函数 */
	register_irq(31, AdcTsIntHandle);
 	 /* 打开第9、10位的ADC和触摸屏的中断 */
	 INTSUBMSK &= ~((1<<9) | (1<<10));
}

/* 中断处理函数 */
void AdcTsIntHandle(int irq)
{
	 if (SUBSRCPND & (1<<9))  /* 如果是触摸屏中断 */
		Isr_Tc();
	 if (SUBSRCPND & (1<<10))  /* ADC中断 */	
		  Isr_Adc();
	 SUBSRCPND = (1<<9) | (1<<10)}
/* 触摸屏中断 */
void Isr_Tc(void)
{
	/* ADCDAT0寄存器的第15位表示现在是按下还是松开的 */
	 if (ADCDAT0 & (1<<15))
 	{
 	 //printf("pen up\n\r");
 	 /* 如果已经松开了,则期待下一次的按下操作 */
  	enter_wait_pen_down_mode();
 	}
 	 else 	
 	{
		  //printf("pen down\n\r");
		    /* 按下之后需要开启自动测量模式,然后开启ADC */
		  ADCTSC |= (1 << 2) | (0 << 0);
		  ADCCON |= (1 << 0);
	}
}

/* ADC中断 */
void Isr_Adc()
{
	 int x = ADCDAT0;
	 int y = ADCDAT1;
	  /* 如果仍然是按下的,则打印 */
	   if (!((x << 15) & 0x1)) {
	     printf("\n\rx = %d y = %d",x & 0x3ff,y & 0x3ff); 
	   }
	   /* 等待松开时发生的中断 */
	    enter_wait_pen_up_mode();
}

/* 等待按下中断 */
void enter_wait_pen_down_mode(void)
{
	 /*	
	  [8] UD_SEN 0期待出现按下的中断信号 1抬起
	  [7] YM_SEN 0关闭YM开关 1关闭
	  [6] YP_SEN 0打开YP开关 1打开
	 [5] XM_SEN 0关闭XM开关  1关闭
  	[4] XP_SEN  0打开XP开关  1打开
  	[3] PULL_UP 0打开上拉     1打开
  	[1:0] XY_PST 11等待中断模式
  	*/
  	/* YM关闭,YP打开 XM打开 XP打开 关闭上拉,现在的状态
  	   就是上边的等待中断的那张图的状态,通过第8位选择期待
  	   发生的中断时按下还是抬起
  	 */
  	 ADCTSC = (0 << 8) | (1 << 7) | (1 << 6) | (0 << 5) | (1 << 4) | (0 << 3) | (3 << 0);
}
/* 等待抬起中断 */
void enter_wait_pen_up_mode(void)
{
 ADCTSC = (1 << 8) | (1 << 7) | (1 << 6) | (0 << 5) | (1 << 4) | (0 << 3) | (3 << 0);
}

测试

void adc_ts_test()
{
 touchscreen_init();
}

void touchscreen_init(void)
{
 /* 设置触摸屏接口:寄存器 */
 adc_ts_reg_init();
  /* 设置中断 */
 adc_ts_int_init();
  /* 让触摸屏控制器进入"等待中断模式" */
 enter_wait_pen_down_mode();
}

梳理

1、在测试函数里调用触摸屏和AD的初始化函数,进入等待中断模式
2、发生中断之后,通过判断SUBSRCPND的第9位和第10位来区分中断,  
  如果发生的是触摸屏的中断就进入处理函数Isr_Tc中
3、在处理函数中通过ADCDAT0的第15位来判断函数触摸屏是按下还是松开 
  如果已经松开了,则期待下一次的按下操作,如果还是在按下状态,则启动
  ADC进行测量,打开ADC的自动测量模式,启动ADC
4、ADC测量完成进入中断函数,判断中断类型,进入Isr_Adc
5、在ADC的中断处理函数中,再一次判断,如果还是按下的话,就读取xy坐标
 保存在ADCDAT0和ADCDAT1寄存器里,打印信息,期待触摸屏松开操作。

好了,到这里触摸屏的代码功能已经写完了,并且经过实际的测量,是可以检测到触摸屏的按下操作,打印出在屏幕上按下的位置,
但是不足的是,此时的触摸屏代码不支持长按操作,为了支持触摸屏的长按,我们要使用定时器来进行检测
三、改进
开始之前,先来梳理一下使用定时器的代码逻辑

1、按下屏幕,出发触摸屏中断,在中断函数里启动ADC进行测量
2、ADC转换完毕后引发ADC中断,在ADC中断函数里判断屏幕是否还是
  处于按下的操作,如果还是被按下的话,启动定时器
3、在定时器处理函数中进行判断,如果屏幕已经被松开了的话
   就退出,期待下一次的按下操作
4、在定时器函数里判断如果还是被按下的话,就再一次的启动ADC转换     
5、进入上面第2步,循环

代码

void touchscreen_init(void)
{
	/* 省去和上面一样的代码 */
	 /* 注册用于触摸屏的定时器中断函数 */
	 time_func_register("touchscreen",ts_timer_func);
	 /* 省去和上面一样的代码 */
}

/* ADC的处理函数重写 */
void Isr_Adc()
{	
 int x = ADCDAT0;
 int y = ADCDAT1;
 /* 如果还是按下的 */
  if (!((x << 15) & 0x1)) {
 	 printf("\n\rx = %d y = %d",x & 0x3ff,y & 0x3ff);  
    	/* 开启定时器,定义的一个标记 */
  	ts_status = ENABLE;
  } else { //如果已经松开了
	  ts_status = DISABLE;	//标记位被禁止
       enter_wait_pen_down_mode();//期待下一次的按下操作
}

/* 定时器处理函数 */
void ts_timer_func()
{
	 /* 定时器函数是一直会进入的,在ADC中断处理函数中判断,如果
	 已经松开了就不在使能,这里直接退出, */
	 if (ts_status == DISABLE)
	  return;

	/* 进入到这里,说明已经进行了一次ADC转化,并且在ADC函数里判断还是被按下的
	   标记位被置位,进入定时器,开始下一次的数据读取
	 */
	 /* 如果已经松开 */
	  if (ADCDAT0 & (1<<15)) /* 如果松开 */
	 { 
 		 ts_status == DISABLE;//标记位禁止
 		   enter_wait_pen_down_mode();//期待下一次的按下
 	   	  return;
	} else {	//如果还是在按下的话
		  /* 如果是还在按下,进入自动测量模式,开启ADC */
	  ADCTSC |= (1 << 2) | (0 << 0);
	  ADCCON |= (1 << 0);
	 }
}

好了,在上面的程序里添加了使用定时器的程序,已经测试过了,当你长按在屏幕上的话,是一直会打印出触点的坐标。

相关标签: Linux裸机