10-ADC和触摸屏

本文详细介绍了ADC硬件原理及其在S3C2440上的编程,包括初始化ADC、启动转换、读取数据等步骤。随后,文章深入探讨了电阻触摸屏的工作原理,从按下松开检测到ADC中断处理,再到定时器程序的优化。通过实例展示了触摸屏坐标转换的校准方法,以及在实际编程中遇到的问题与解决策略,如坐标不线性、坐标轴反转等问题。最后,实现了触摸屏的校准与画线功能,优化了长按和滑动操作。
摘要由CSDN通过智能技术生成

声明:

本文是本人在韦东山笔记的基础上加了一些注释,方便理解。原文地址:

第01节 ADC硬件原理

ADC的概念:模数转换器即A/D转换器,或简称ADC,通常是指一个将模拟信号转变为数字信号的电子元件。
原理:通常的模数转换器是把经过与标准量比较处理后的模拟量转换成以二进制数值表示的离散信号的转换器。
故任何一个模数转换器都需要一个参考模拟量作为转换的标准,比较常见的参考标准为最大的可转换信号大小。而输出的数字量则表示输入信号相对于参考信号的大小。

如图,是把可变电阻上的电压值变换的模拟信号通过ADC转换,输出数字信号。
在这里插入图片描述
对于数字信号我们需要得到它的几个属性:

  1. 用多少位来存储这个数据(假设10bit)。(这个是你从2440芯片手册得出的)
  2. 最大值0b1111111111(10位的话,那就是10个1来表示)
  3. 它对应的电压是多少伏(模拟信号输入的最大值是多少)我们就可以根据模拟信号(电压)的最大值,来计算出对应的数值。(意思是说,比如你电压最大值为3.3V,则用0b1111111111表示3.3V,而0b0111111111表示1.65V)。
  4. 采样/转换速度。(从2440芯片手册得出)。

2440芯片手册中的相关信息如下图所示:在这里插入图片描述
对于程序员,我们不关心ADC的内部机制(对上面的机理不用深究),我们只关心
1、怎么启动ADC
2、启动之后怎么得到数据,
总之:我们都是通过寄存器操作的。
2440芯片手册有下图:
在这里插入图片描述
从上图可以看出ADC有8个多路选择器,显然,以后我们写程序的时候,我们可以8个多路选择之一, 下面是编写程序要做的步骤:
1、确定是哪一路信号:设置8:1MUX,选择要测量哪一个引脚,(看原理图选择要测量的引脚)—韦东山的是ain0)(对于韦东山的,他的板子原理图ain0什么也没有接,但需要你在空引脚ain0外接一个SPI模块,这个SPI模块里带有ADC,你可以在这个外接的ADC中调节电阻以充当模拟信号。你去看视频吧这一点)。
2、设置工作时钟(从工作时钟,可以算出,转换一次需要多长时间(Conversion time )。计算公式在2440芯片手册如下图:
注:freq是频率的意思。50MHz是GCLK的值。
在这里插入图片描述
3、启动ADC
4、读状态,判断ADC转换是否成功。
5、读数据

第02节 ADC编程

编程步骤:
1、初始化ADC(包括确定哪一路信号、设置工作时钟、启动ADC等等,你去读芯片手册去操作寄存器)
2、读数据,
3、在串口上显示出来。

由韦东山的原理图可知信号为ain0路:
在这里插入图片描述

2.1 初始化ADC

下面的函数实现对ADC的初始化。

03	void adc_init(void)
04	{
   
05	/* [15] : ECFLG,  1 = End of A/D conversion 这个是判断ADC是否在转换的状态的
06	 	* [14] : PRSCEN, 1 = A/D converter prescaler enable 预分频使能,以操作[13:6]
07	 	* [13:6]: PRSCVL, adc clk = PCLK / (PRSCVL + 1) ,从这里往上数,第二幅图片有一个公式,
可以看出PRSCVL为49.
08	 	* [5:3] : SEL_MUX, 000 = AIN 0  确定ain0路信号
09		 * [2]   : STDBM 
10	 	* [0]   : 1 = A/D conversion starts and this bit is cleared after the startup.AD开始转换
11	 	*/
12		ADCCON = (1<<14) | (49<<6) | (0<<3);
13
14		ADCDLY = 0xff;	
15	}12行:配置ADCCON寄存器,使能A/D 转换器预分频器,设置A/D 转换器预分频值,上拉使能。
第14行:设置ADC 转换启动延时值。

第03节_电阻触摸屏硬件原理

3.1 电阻屏的原理

这节课我们来讲电阻触摸屏的硬件原理。
假设有一个比较长的电阻,电阻是R 上面接3.3V电压,下面接地
在这里插入图片描述
假设整个电阻的阻值是R某一个触电它的阻值是R1 根据欧姆定律

3.3v/R = V/R1
V=3.3 *(R1/R)

假设R1是x坐标 R的长度是L这个电阻非常的均匀,那么这个电压就等于 3.3V * (x / L) 这个电压和这个触电的x坐标有一个线性关系 我使用ADC把这个电压算出来,就可以间接得到这个触电的x坐标, 电阻触摸屏就是使用欧姆定律使用电阻原理作出来的。

可以上百度图片搜索触摸屏,就知道了触摸屏的样子,它是一个透明的薄膜:
在这里插入图片描述
注意 :LCD是LCD 触摸屏是触摸屏它是两个设备, 我们只不过是把触摸屏做的和LCD大小一样,粘在LCD上面, 实际上触摸屏是由两层膜组成,他们靠的非常近。如下图所示:
上面这层右边引出来,代表xp ,p代表正极;上面这层左边引出来,代表xm, m代表负极。
下面这层膜 前面这条边引出来为yp,后面这层边为ym。
在这里插入图片描述
假设我们手指要点击触摸屏,那么上下就会粘贴在一起,我怎么算出这个 x y点的坐标呢?
答:
我们先来 测量触电x坐标:让xp接3.3v,xm接GND,让yp,ym不接电源。
测yp电压 。由于某处按压导致上下膜连接在一起,我就可以通过yp测量这个触电的电压, 这个yp就像探测一样(像前面讲的滑动变阻器的滑针一样),从前面的原理我们可以知道,当这个触电越靠近左边这个电压越小,越靠近右边电压越大, 因此这个yp的电压就可以认为是这个触电的坐标(x坐标)。如下图所示:
在这里插入图片描述
类似的我们怎么测量触电y坐标 ?
类似的xp xm不接电源,同样yp接3.3v, ym接GND,这时候电流就从 yp这里流向ym,然后我们就可以测量xp电压 ,当按下屏幕时,上下两层膜链接在一起,这个xp就像探针一样,这个触电越靠近yp电压值越大,越靠近ym电压值越小。yp接3.3V ym接GND,xp xm不接电源 测量xp电压,就是y坐标。如下图所示:
在这里插入图片描述
注意:测得的 x y坐标都是电压值,不是屏幕上480 * 272 这些值,我们需要把电压值转换为坐标值,这需要经过一些转换。我们测量xp yp可以得到触点的两个方向的电压值,这些电压值和坐标是线性关系。

3.2 使用触摸屏的流程

<1>按下触摸屏 按下触摸屏时,对于一个高效的系统,产生中断,这是触摸中断
<2>在触摸中断程序中 ,去启动ADC,目的是获得数据(即xy坐标)。
<3>ADC完成, 又产生一个中断(我们称为ADC中断吧)。
<4>在ADC中断中去读取x y坐标。
好,我们来想想,在这4个流程里,启动触摸屏的源头是按下触摸屏,那如果要是长按触摸屏,我按下之后一直不松开或者滑动手指呢?那么谁来触发后续的多次ADC转换呢 ?不可能只启动一次吧, 为了支持 长按和滑动操作,我们需要启用定时器,因此有了步骤5:
<5> 启动定时器。
<6> 定时器中断发生,判断触摸屏是否仍被按下,如果按下就循环上述过程,即:
<6.1>在触摸中断程序中 启动ADC,以获得数据,即xy坐标。
<6.2>ADC完成, 产生中断
<6.3>在ADC中断 中读取x y坐标
<7> 松开就结束了一个流程
以上这就是整个触摸屏的使用流程。

3.2 触摸屏原理的进一步剖析

在《嵌入式Linux完全开发手册》14章里讲解了触摸屏,他抽象了几张图:

平时的时候上下两层膜并不连接,我们按下触摸屏的时候就会产生中断。
那么你怎么知道产生中断呢?答案肯定是由某个引脚的电平发生变化对不对,
平时 Y_ADC / XP是高电平,按下之后Y_ADC就接地了,就是被拉低了,就产生了低电平即电平发生变化产生了中断。原理图如下面两张图所示:
在这里插入图片描述
在这里插入图片描述
Y_ADC产生低电平后就知道触摸屏被按下了,这个时候就需要测量电压值读取x坐标,XP 、XM通电我就测量YP的电压,这就是 x 点的坐标。
在这里插入图片描述
同理:读取Y坐标:YP YM 通电,按下后XP通电,这就是y点的坐标。
在这里插入图片描述

第04节_S3C2440触摸屏接口

回顾上节触摸屏使用原理:
在不使用触摸屏的时候,必须要把 S1 S2 S3断开,S4 S5闭合,只有这样当我按下触摸屏,上面的电平才能从高变低,会产生一个中断信号:
在这里插入图片描述
而当我去读取X坐标的值时:必须让S1 S3闭合,这样电流才可以通过,同时让S2 S4 S5断开,这时候YP这层膜就相当于探针一样去测量电压:
在这里插入图片描述
当我读取y坐标值:必须让S2 S4闭合,这样电流才可以流 下来,同时S1 S3 S5断开,这个时候XP这层膜就相当于探针一样,我可以来测量这里的电压,从而得到Y坐标的电压值:
在这里插入图片描述
在测量x y坐标时,这个S5上拉电阻都要断开。
我们需要控制这几个开关(S5 ~ S5),实际上2440就提供了这几个开关的控制方法,。
打开2440的芯片手册看触摸屏是怎么操作的,ADC&Touch Screen Interface这一章是 从440到450总共10页不到。
看芯片手册中的ADC与触摸屏接口功能框图,我们看到有一个8:1 MUX的多路选择器,去设置多路选择器从而测量 XP YP 的电压,从而得到了xy的坐标:
在这里插入图片描述
下图是在442页的触摸屏各种的接口模式:
1、正常模式。在上节视频中我们有讲解过;
2、x y分离转换模式。
往上看看我们的X Y坐标原理图,我们可以单独转换X坐标、单独转换Y坐标,换句话说就是逐个去测量X Y坐标,这就是x y分离转换模式
他首先会启动X坐标的ADC转换,转换成功后数据会保存在ADCDAT0里,同时会产生一个中断,在这个中断服务程序里,就可以把X坐标读取出来,然后可以启动Y坐标的转换,转换成功后数据会保存在ADCDAT1,同时会产生一个中断,进入这个中断把Y坐标读取出来 。
这种模式测量一次会产生2个中断,一个是X坐标中断,一个是Y坐标中断。
3、自动的(连续的)X/Y坐标转换模式。
也就是说不需要单独控制,即不需要像上面一样去单独地去读取X坐标Y坐标,而是可以设置寄存器,让它一次性的测量X坐标测量Y坐标,X坐标保存在ADCDAT0,Y坐标保存在ADCDAT1。这种模式最后产生一个中断,也就是读取X/Y坐标只需要产生一次中断。
4、等待中断模式。
所谓等待中断模式,即触屏控制器在触笔放下时产生中断信号。对于从这里往下数的第二幅图(即等待中断模式电路图),我按下的时候XP从高电平变为低电平,松开时,XP从低电平变为高电平,就是说按下松开都可以检测到。
我们要等待按下(等待着,直到你按下屏幕)或者等待松开(等待着知道你松开屏幕)时,需要设置rADCTSC =0xd3这个值。
在这里插入图片描述
在这里插入图片描述
看443页的编程要点如下图:
1、D转换数据时可以通过中断或者查询模式来得到数据,使用中断模式时,从AD转换开始,到得到数据可能会有些延迟,因为中断服务程序的进入和退出需要一定的时间,(也就是说,如果你对数据转换的速度要求的非常高,就可以使用查询方式),可以查询ADCCON[15](ECFLG)来判断是否转换结束。
在这里插入图片描述
从444页往后看, 剩下就是寄存器操作:
ADCCON寄存器:
ECFLG状态位 AD转换是否结束
PRSCEN 使能ADC转换
PRSCVL 设置A/D转换预分频值
SEL_MUX选择输入通道。对于触摸屏,后面我们使用的是自动转换XY坐标模式,所以这里不需要设置。
ENABLE_START 启动转换
在这里插入图片描述
看445页的ADCTSC,这个寄存器是重要的:
UD_SEN Bit8是用来判断触摸屏是被按下还是被松开:0表明被按下,1表明被松开;
YM_SEN Bit7 : YM开关使能控制S4,0表示断开 1闭合,看从这里数的第二幅图;
YP_SEN Bit6 : YP开关 0表示闭合、 1 表示断开;
XM_SEN Bit5 : XM开关 0 断开 、1 闭合;
XP_SEN Bit4: XP开关 0 闭合 、1 断开;
PULL_UP Bit3 :控制S5开关 0 上拉(即S5闭合(上拉电阻即通过一个电阻让一个不确定信号钳在高电平))、1 断开。
AUTO_PST Bit2 :自动连续转换X坐标Y坐标。上节视频里我们设置是 0 即设置正常的ADC转换。如果需要自动连续转换ADC坐标的话,需要设置为1 ,如果需要手动转换ADC坐标的话,需要设置为0。
XY_PST Bit[1:0] :对于手动转换X Y坐标,我们需要手动设置XY_PST 里面的位,以去设置是测量X坐标还是测量Y坐标, 也可以设置这两位等于11 让其等于等待模式, 也就是等待触摸屏被按下或者被松开。

如果想设置自动连续转换的话,则将Bit2 AUTO_PST设置为1 ,将XY_PST Bit[1:0]设置为00。
如果使用手动转换的话设置AUTO_PST为0, XY_PST设置为01 去手动转换X坐标模式 或者XY_PST设置为10 为Y坐标转换模式。
在这里插入图片描述
在这里插入图片描述
往下看,447页ADCDATA0 ADC数据寄存器:
UPDOWN Bit15 :可以读取这一位去判断触摸屏是按下还是松开。
AUTO_PST Bit14 :自动连续转换X坐标Y坐标
XY_PST Bit[13:12]: 手动转换X Y坐标
这和上面ADCTSC寄存器中的 AUTO_PST Bit2 、 XY_PST Bit[1:0]原理相同。
XPDATA Bit[9:0]最低10位用来保存X坐标的值。
在这里插入图片描述
448页ADCDAT1寄存器 和ADCDAT0功能一样的,只不过保存的数据不同:
这个寄存器的低10位YPDATA Bit[9:0]是用来保存 Y坐标的值。
在这里插入图片描述
接下来是ADCUPDN触摸屏按下或者松开检查寄存器:
TST_UP Bit1 触摸屏松开中断产生。1表示松开了。
TST_DN Bit0 触摸屏按下中断产生。1表示按下了。
在这里插入图片描述
好,手册看完了,涉及到中断,我们看一下这个图:
在这里插入图片描述上图,它会涉及两个中断,一个是按下或者松开,触摸笔的状态中断,另外一个启动ADC以后,ADC结束时也会产生一个中断。
但是这个手册里我们没有看到这两个中断的使能寄存器。
那我们猜测一下,ADC模块、触摸屏模块一定会发出中断,这是一定的对吧。
首先是ADC或者触摸屏产生中断,然后通过中断控制器发送中断给CPU:
我们猜测,肯定有在中断控制器中肯定有寄存器去禁止/使能 ADC、触摸屏 中断。
在这里插入图片描述
我们来看看中断控制器芯片手册中都需要设置什么
从芯片手册中断控制器往下翻,看到下面的流程图,我们先放这,没准待会得用:
在这里插入图片描述
再往下翻,果然,看到了INT_ADC中断源,如下图。
INT_ADC的Descritions是:ADC结束中断和触摸屏中断。也就是说在这个芯片手册里看到了INT_ADC中断源就代表ADC结束中断、触摸屏中断。
看来ADC结束中断或者触摸屏中断合起来共用一个中断 。
既然合并必然还会有一个寄存器来分辨到底是ADC还是触摸屏发生的中断变化。
在这里插入图片描述
再往下看
是SRCPND寄存器 ,其31位为INT_ADC。
注意,该寄存器作用是指示哪个中断源正在等待服务请求。在这里插入图片描述
在这里插入图片描述
再往下看
INTMOD寄存器 ,用来决定是普通中断还是快中断模式,设置Bit[31:
在这里插入图片描述
在这里插入图片描述
再往下看
INTMSK寄存器 ,用来表示是否屏蔽这个中断。设置Bit[31]:
在这里插入图片描述
在这里插入图片描述
再往下看,是优先级寄存器PRIORITY,我们不需要设置。

再往下看,是INTPND寄存器
中断挂起寄存器的32位在经过优先级逻辑之后,在INTPND寄存器中只有一个位可以设置为1(即只通过某一个中断),并且该中断请求生成IRQ到CPU。你可以读取这个寄存器状态以判断哪个中断正在执行(处理)。
我们设置Bit[31]表示中断是否正在处理
在这里插入图片描述
在这里插入图片描述
再往下看是中断偏移寄存器INTOFFSET ,中断偏移寄存器中的值显示哪个IRQ模式的中断请求在INTPND寄存器中。设置Bit[31]。
在这里插入图片描述
好,看到这里我们还没有发现到底是ADC中断还是触摸屏中断,但肯定有其他寄存器可以设置,我们接着往下看。
再往下看
发现了SUBSRCPND寄存器,其作用是读取指示中断请求状态。
INT_ADC_S Bit[10]表示ADC中断
INT_TC Bit[9]表示触摸屏中断
在这里插入图片描述
再往下看
INTSUBMSK ,中断子掩码(INTSUBMSK)寄存器
这个寄存器有11位,每一位都与中断源有关。如果特定位设置为1,则来自相应中断源的中断请求不由CPU提供服务(注意,即使在这种情况下,SUBSRCPND寄存器的相应位也设置为1)。如果掩码位为0,中断请求可以被服务。

也是设置同样的位:
INT_ADC_S Bit[10]表示ADC中断激活/屏蔽
INT_TC Bit[9]表示触摸屏中断激活/屏蔽
在这里插入图片描述
我们可以通过INTSUBMSK来屏蔽ADC中断或者TouchScreen中断, 当然也可以使能某个中断。
可以通过SUBSRCPND来分辨到底产生那个中断。
INTSUBMSK 和SUBSOURCPND这两个寄存器都会汇集到一起 ,变成一个叫做INT_ADC的中断来发送给CPU。
框图就是这样:
在这里插入图片描述
我们怎么写程序? 写出一个框架步骤

1、 初始化ADC/TouchScreen接口ADCCON时钟接口;
2、 一开始触摸屏是没有被按下的,设置TS处于等待中断模式;
3 、设置中断:
	3.1、INTSUBMSK使能ADC中断和触摸屏中断
	3.2、还有INTMSK设置这个寄存器**使能INT_ADC中断**,让他能够发给CPU。(INT_ADC中断来自于ADC中断
	和触摸屏中断的合并)。
4 、按下触摸屏,进入TS中断
	4.1 进入自动采集模式(自动转换XY坐标)
	4.2 启动ADC
5、转换完之后产生ADC中断
	5.1 读数据
	5.2 再次进入 “'等待中断”'模式
	5.3 启动定时器,处理长按或者滑动
6 定时器中断
    6.1 判断是否松开,若松开结束
    6.2 若按下重新执行  4.2的 启动ADC步骤

第05节 触摸屏编程_按下松开检测

从这节课开始触摸屏编程。
关于触摸屏编程大概会分为以下3个小节:
第05节 触摸屏编程_按下松开检测
第006节_触摸屏编程_ADC中断
第007节_触摸屏编程_定时器程序优化
参考资料是韦东山的《嵌入式Linux应用开发完全手册》第14章 ADC和触摸屏接口

现在进行按下松开检测实验。
可以参考下面这张图,其是第4节最后的框架步骤的一个形象表达,只是其没有说定时器的事。
对这张图进行解释:
看懂这张图的关键点在于 :里面有个中断程序 AdcTsIntHandle ,它是总的中断,这里面要用if语句分辨 是ADC中断还是触摸屏中断。如果是ADC中断 那么就调用Isr_adc函数来处理中断。 else if, 如果是触摸屏中断,那么就调用Isr_tc函数中断,。这俩都是总中断具体的中断。
我们看看是怎么做的:

/*---------------------编程框架--------------------------------*/
一开始设置中断
初始化触摸屏控制器,进入等待中断模式
这个时候如果按下触摸屏就会进入Pen Down中断
就会进入AdcTsIntHandle这个总中断函数
这里面分辨出,你是按下了触摸屏,调用Isr_Tc函数
然后进入自动(连续) X/Y轴坐标转换模式,启动ADC
ADC结束之后会产生一个ADC中断
又再次进入这个AdcTsIntHandle总中断
这里面分辨出是ADC中断,这里面调用Isr_Adc函数
我可以 读出 这里面的数据,再次设置寄存器
进入等待Pen UP中断模式
松开触摸笔会再次产生一个中断
进入总中断AdcTsIntHandle这里面分辨,原来是松开了触摸笔,再次调用Isr_tc
这里面又会设置进入等待Pen Down中断模式    

在这里插入图片描述
我们开始写代码,再上一个视频ADC代码上进行修改.我们在adc_touchscreen目录下添加几个文件
:touchscreen_test.c、touchscreen.c

现在我们写touchscreen.c文件:
下面这个是touchscreen.c源码:

#include "../s3c2440_soc.h"

#define ADC_INT_BIT (10)
#define TC_INT_BIT  (9)

#define INT_ADC_TC   (31)


/* ADCTSC's bits */
#define WAIT_PEN_DOWN    (0<<8)
#define WAIT_PEN_UP      (1<<8)

#define YM_ENABLE        (1<<7)
#define YM_DISABLE       (0<<7)

#define YP_ENABLE        (0<<6)
#define YP_DISABLE       (1<<6)

#define XM_ENABLE        (1<<5)
#define XM_DISABLE       (0<<5)

#define XP_ENABLE        (0<<4)
#define XP_DISABLE       (1<<4)

#define PULLUP_ENABLE    (0<<3)
#define PULLUP_DISABLE   (1<<3)

#define AUTO_PST         (1<<2)

#define WAIT_INT_MODE    (3)
#define NO_OPR_MODE      (0)

/*----------------第六步-------------------*/
/*要知道,对于触摸屏,其有down和up两种中断信号*/
void enter_wait_pen_down_mode(void)
{
   
	ADCTSC = WAIT_PEN_DOWN | PULLUP_ENABLE | YM_ENABLE | YP_DISABLE | XP_DISABLE | XM_DISABLE | WAIT_INT_MODE;
	//即设置ADCTSC寄存器,即设置了相应的开关(即上面电路图的S1 - S5),设置s1和s5闭合。
	//这个模式是等待着down,
	//WAIT_INT_MODE即等待中断模式
	//WAIT_PEN_DOWN即告诉硬件去检测笔down的中断信号。一旦检测出你down了,硬件便会发出down中断,从而执AdcTsIntHandle()中的Isr_Tc(),并判断出中断为down,从而进入enter_wait_pen_up_mode();一直循环。
}

void enter_wait_pen_up_mode(void)
{
   
	ADCTSC = WAIT_PEN_UP | PULLUP_ENABLE | YM_ENABLE | YP_DISABLE | XP_DISABLE | XM_DISABLE | WAIT_INT_MODE;
	//即设置ADCTSC寄存器,即设置了相应的开关(即上面电路图的S1 - S5),故设置s1和s5闭合。
	//这个模式是等待着up
	//WAIT_INT_MODE即等待中断模式
	//WAIT_PEN_DOWN即告诉硬件去检测笔up的中断信号。一旦检测出你up了,硬件便会发出up中断,从而执行
	AdcTsIntHandle()中的Isr_Tc(),并判断出中断为up,从而进入enter_wait_pen_down_mode();一直循环。
}

/*------------------------------------第五步---------------------------------*/
void Isr_Tc(void)
{
   
	if (ADCDAT0 & (1<<15))//ADCDAT0 [15]判断笔down or up的状态。1表示笔up
	{
   
		printf("pen up\n\r");
		enter_wait_pen_down_mode();//即现在是up,等待着down
	}
	else	
	{
   
		printf("pen down\n\r");

		/* 进入"等待触摸笔松开的模式" */
		enter_wait_pen_up_mode();//即现在是down,等待着up
	}
}
/*---------------------第四步-------------------------*/
void AdcTsIntHandle(int irq)
{
   
	if (SUBSRCPND & (1<<TC_INT_BIT))  /* 如果是触摸屏中断 */
		Isr_Tc();

//	if (SUBSRCPND & (1<<ADC_INT_BIT))
  /* 这节课先不讲ADC中断(本节只测试,pen笔 点到屏幕上即打
印pen down),抬起则打印pen up */
//		Isr_Adc();

	SUBSRCPND = (1<<TC_INT_BIT) | (1<<ADC_INT_BIT);/*清SUBSRCPND寄存器。记住,这个寄存器清的时候是
	置1是清除。你记住就行了。并且芯片手册上也有解释。*/
	/*以我的理解就是,对SUBSRCPND读取的时候相应位的1表示中断请求。而清寄存器的时候1表示清,0表示不清。这两个功能不关联。一个是对寄存器读,一个是对寄存器写*/
}

/*---------------------第三步-------------------*/
void adc_ts_int_init(void)
{
   
	SUBSRCPND = (1<<TC_INT_BIT) | (1<<ADC_INT_BIT);//读取ADC中断和TC中断的状态

	/* 注册中断处理函数 */
	register_irq(31, AdcTsIntHandle);//register_irq()函数在interrupt.c里面;irq在2440手册里查得为31
	/*
	void register_irq(int irq, irq_func fp)
	{
		irq_array[irq] = fp;
	
		INTMSK &= ~(1<<irq);
}
*/	

	/* 使能中断 */
	INTSUBMSK &= ~((1<<ADC_INT_BIT) | (1<<TC_INT_BIT));//INTSUBMSK 某位为0即请求相应位的中断被服务
	//INTMSK    &= ~(1<<INT_ADC_TC);/*这个语句是让合并后的中断INT_ADC使能的,但是在register_irq()
	函数 里已经有了这个语句,因此这一句话不用要了*/
}

/*---------------------第二步----------------------*/
void adc_ts_reg_init(void)
{
   
	/* [15] : ECFLG,  1 = End of A/D conversion
	 * [14] : PRSCEN, 1 = A/D converter prescaler enable
	 * [13:6]: PRSCVL, adc clk = PCLK / (PRSCVL + 1)
	 * [5:3] : SEL_MUX, 000 = AIN 0
	 * [2]   : STDBM
	 * [0]   : 1 = A/D conversion starts and this bit is cleared after the startup.
	 */
	ADCCON = (1<<14) | (49<<6) | (0<<3);

	ADCDLY = 0xff;	
}

/*-------------------第一步-----------------*/
void touchscreen_init(void)
{
   
	/* 设置触摸屏接口:寄存器 */
	adc_ts_reg_init();

	/* 设置中断 */
	adc_ts_int_init();

	/* 让触摸屏控制器进入"等待中断模式" */
	enter_wait_pen_down_mode();
}

第06节_触摸屏编程_ADC中断

这节课我们加上ADC中断,目的是把触点的xy坐标读出来。

打开touchscreen.c,写出这个自动测量的函数

void enter_auto_measure_mode(void)
{
   
/*现在是自动测量,我们没有机会(不用)分别设置这些ADCTSC 中的开关(即电路图的S1 - S5)。
我们需要做的是:
1、设置AUTO_PST =1   即1 = Auto Sequential measurement of X-position, Y-position.即自动检测xy坐标模式
2、XY_PST = 00  即No operation mode
*/
	ADCTSC = AUTO_PST | NO_OPR_MODE;
}

根据上一节写的程序,我们知道,一旦按下屏幕就会触发down中断,执行AdcTsIntHandle()中的Isr_Tc(),并判断出中断为down,从而进入enter_wait_pen_up_mode(),一旦检测出up中断就又进入AdcTsIntHandle()中的Isr_Tc(),一直循环。

现在我们来加入ADC中断,将AdcTsIntHandle()中原来注释掉的ADC中断部分给取消注释:

void AdcTsIntHandle(int irq)
{
   
	if (SUBSRCPND & (1<<TC_INT_BIT))  /* 如果是触摸屏中断 */
		Isr_Tc();

	if (SUBSRCPND & (1<<ADC_INT_BIT))  /* ADC中断,则会进入Adc中断处理函数 */
		Isr_Adc();
	
	SUBSRCPND = (1<<TC_INT_BIT) | (1<<ADC_INT_BIT);//清寄存器
}

修改上节课的Isr_Tc(),即让进入触摸屏中断处理函数

void Isr_Tc(void)
{
   
	//printf("ADCUPDN = 0x%x, ADCDAT0 = 0x%x, ADCDAT1 = 0x%x, ADCTSC = 0x%x\n\r", ADCUPDN, ADCDAT0, ADCDAT1, ADCTSC);
	
	if (ADCDAT0 & (1<<15))
	{
   
		//printf("pen up\n\r");
		enter_wait_pen_down_mode();
	}
	else	//就是说一旦down中断,就开始启动ADC中断,如下:
	{
   
		/* 进入"自动测量"模式 */
		enter_auto_measure_mode();

		/* 启动ADC */
		/*从而触发了ADC中断信号,然后执行AdcTsIntHandle()中的Isr_Adc()*/
		/*ENABLE_START = 1就可以了
		*1 = A/D conversion starts and this bit is cleared after the startup.
		*/
		ADCCON |= (1<<0);
	}
}

写Adc中断处理函数Isr_Adc():

void Isr_Adc(void)
{
   
	//进入adc中断后,等待触摸笔松开
	int x = ADCDAT0 & 0x3ff;//取x坐标
	int y = ADCDAT1 & 0x3ff;//取y坐标
		
	printf("x = %08d, y = %08d\n\r", x, y);

	//等待触摸笔松开模式
	enter_wait_pen_up_mode();/*进入等待uo状态,以达up则又发出up信号,执行AdcTsIntHandle()中的
	Isr_Adc(),并执行enter_wait_pen_down_mode();。一旦按下发出doen则又发出
	down信号...... 如此循环往复,以让你可以一直连续的按屏幕甚至滑动屏幕
	*/
}

好,程序写完。
烧写 ,实验发现打印一堆乱码。如下图所示:
在这里插入图片描述
来解决这个问题:
应该是printf函数出了问题,现在我们来 打开my_printf.c文件,找到printf函数, 应该是处理第二个数据即y的时候,没有设置初始值。

/*reference :   int vprintf(const char *format, va_list ap); */
static int my_vprintf(const char *fmt, va_list ap) 
{
   
	char lead=' ';
	int  maxwidth=0;
	
	 for(; *fmt != '\0'; fmt++)
	 {
   
			if (*fmt != '%') {
   
				outc(*fmt);
				c
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值