ADC和触摸屏

一、ADC和触摸屏介绍

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

使用触摸屏的流程
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);
	 }
}

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值