S3C2440芯片内部共有8路A/D转换通道,AIN0-AIN7,转换器只有一个,转换精度为10位,最大转换率为2.5MHzA/D转换器时钟下的500KSPS。A/D转换器支持片上采样-保持功能和掉电模式的操作。在常见的设计中,一般AIN4,AIN5,AIN6,AIN7被用作四线电阻触摸屏的YM、YP、XM、XP通道,剩余的AIN0~AIN3被引出,其中AI0外接一个可调电阻。ADC的配置流程如下:
本文引用地址:https://www.eepw.com.cn/article/201611/322615.htm
1、ADCDLY(P446)
rADCDLY=50000;//Normalconversionmodedelayabout(1/3.6864M)*50000=13.56ms

2、ADCCON(P444)的设置,选择转换通道和设置转换频率
ADCCON[0],AD转换开始有效,1转换开始且该位在转换开始后变为0,通过这个特点可以判断是否开始转换。什么意思呢,设为1只是认为地让它转换开始,但是未必开始转换,还必须通过while循环查询方式判断该位是否变为0,变为0表示转换开始。
ADCCON[1],AD转换通过读取有效,1通过读取操作有效;ADCCON[2],备用操作模式选择,0普通操作模式,1,备用操作模式;
ADCCON[5:3]:转换通道选择;
000=AIN0
001=AIN1
010=AIN2
011=AIN3
100=YM
101=YP
110=XM
111=XP
ADCCON[13:6],AD转换器预分频器值0~255,ADC频率应该小于PCLK的1/5;
ADCCON[14],AD转换器预分频器使能,1使能;
ADCCON[15],AD转换结束标志,0:转化过程中,1:转换结束;
ADC初始化程序示例如下:
#defineADC_FREQ2500000//希望的ADC转换频率
volatileU32preScaler;
volatileU32adc_value=0;//在程序开始处声明
voidadc_init(void)
{
//选择输入通道,AIN0,对应开发板上W1可调电阻
intchannel=0;
preScaler=ADC_FREQ;
preScaler=50000000/ADC_FREQ-1;//PCLK=50M
rADCCON=(1<<14)"(preScaler<<6)|(channel<<3);//setupchannel
delay(1000);
}
3、ADCDAT0(ADCDAT1)P447,读取转换值
ADCDAT0[9:0],X坐标转换结果值,包括普通模ADC转换结果值;
(ADCDAT1[9:0],Y坐标转换结果;)
ADC转换程序示例,通过轮询方式
voidMain(void)
{
Set_Clk();
adc_init();
while(1)
{
adc_value=ReadAdc(0);
delay(1000);
}
}
intReadAdc(intchannel)
{
rADCCON|=0x01;//startADC
while(rADCCON&0x1);//checkifEnable_startislow
while(!(rADCCON&0x8000));//checkifEC(EndofConversion)flagishigh
return((int)rADCDAT0&0x3ff);
}
ADC通过中断方式读取转换值
注意ADC的中断有两个子中断,INT_ADC_S和INT_TC需要先处理一下子中断INT_ADC_S,再处理INT_ADC。
voidadc_init(void)
{
intchannel=0;/选择输入通道,AIN0,对应开发板上W1可调电阻
preScaler=ADC_FREQ;//设置分频时钟
preScaler=50000000/ADC_FREQ-1;//PCLK=50M
rADCCON=(1<<14)|(preScaler<<6)|(channel<<3);
ClearSubPending(BIT_SUB_ADC);//清子中断处理寄存器ClearPending(BIT_ADC);//清中断处理寄存器
pISR_ADC=(U32)adc_ISR;
EnableSubIrq(BIT_SUB_ADC);//开AD子中断
EnableIrq(BIT_ADC);//开AD中断
delay(1000);
}
void__irqadc_ISR(void)
{
intadc_value;//adc_value应该设为全局变量,这里放这里以便分析
ClearSubPending(BIT_SUB_ADC);//清子中断处理寄存器ClearPending(BIT_ADC);//清中断处理寄存器
adc_value=(int)rADCDAT0&0x3ff;
}
触摸屏工作流程以及程序设计流程:
一、触摸屏初始化:
1、ADCTSC设置(P445),
[1:0]:11设置触摸屏接口为中断等待模式,等待触摸笔按下
[2]:0ADC普通转换模式,1自动连续测量X坐标和Y坐标
[3]:0XP上拉有效,1XP上拉无效
2、ClearSubPending(BIT_SUB_ADC);//清子中断处理寄存器ClearPending(BIT_ADC);//清中断处理寄存器
ClearSubPending(BIT_SUB_TC);
清除源挂起寄存器(SRCPND)、中断挂起寄存器(INTPND)、子源挂起寄存器(SUBSRCPND)。注意有两个中断,触摸屏中断:当触摸笔按下或抬起产生的中断,ADC中断:触摸屏坐标AD转换结束产生的中断。
3、EnableSubIrq(BIT_SUB_ADC);//开AD子中断
EnableIrq(BIT_ADC);//开AD中断
EnableSubIrq(BIT_SUB_TC);//开AD子中断TC
关中断屏蔽寄存器和子中断屏蔽寄存器(INTMSK,INTSUBMSK)。4、pISR_ADC=(U32)AdcTsAuto;
程序入口函数,中断模式和中断优先级默认即可。
二、触摸屏中断服务子程序:
一)触摸笔按下中断
4、如果中断发生,设置x,y坐标为自动转换模式
rADCTSC=(1<<3)|(1<<2);
[2]:0ADC普通转换模式,1自动连续测量X坐标和Y坐标
[3]:0XP上拉有效,1XP上拉无效
5、启动AD转换,然后检测AD转换是否启动
rADCCON|=0x1;//startADC
while(rADCCON&0x1);//checkifEnable_startislow
6、检测AD转换是否结束,若结束,获取x,y坐标的值
通过轮询方式,也可以是中断方式判断转换结束。
while(!(rADCCON&0x8000));//checkifEC(EndofConversion)flagishigh,Thislineisnecessary~!!
while(!(rSRCPND&0x80000000));//checkifADCisfinishedwithinterruptbit
xdata=(rADCDAT0&0x3ff);
ydata=(rADCDAT1&0x3ff);
7、对几个寄存器写1清零,防止反复发生中断(这里的中断是笔尖按下中断)
ClearSubPending(BIT_SUB_TC);
ClearPending(BIT_ADC);
/rSRCPND=0x80000000;rINTPND=0x80000000;也可以
8、再次允许中断
允许触摸笔被弹起的中断
EnableSubIrq(BIT_SUB_TC);
EnableIrq(BIT_ADC);//rINTMSK=0x7fffffff;
二)触摸笔抬起中断
9、设置触摸屏即可为等待中断模式,等待触摸笔抬起(ADCTSC,关键是要设置触摸笔抬起中断信号)
rADCTSC=0xd3;//Waitingforinterrupt
rADCTSC=rADCTSC|(1<<8);//Detectstylusupinterruptsignal.
10、如果发生中断,不做任何操作,只打印出一句触摸笔抬起中断信息
while(1)//tocheckPen-upstate
{
if(rSUBSRCPND&(BIT_SUB_TC))//checkifADCisfinishedwithinterruptbit
{
Uart_Printf("StylusUpInterrupt~!");
break;//ifStylusisup(1)state
}
}
Uart_Printf("count=dXP=d,YP=d",count++,xdata,ydata);
11、触摸笔抬起之后,把得到的x,y坐标值发送给PC机,显示出具体数值
三)再次设置触摸屏为等待中断模式,等待下次触摸屏被按下
rADCTSC=0xd3;//Waitingforinterrupt
ClearSubPending(BIT_SUB_TC);
ClearPending(BIT_ADC);
EnableSubIrq(BIT_SUB_TC);
EnableIrq(BIT_ADC);
示例程序如下:
#defineGLOBAL_CLK1
#include
#include
#include"def.h"
#include"option.h"
#include"2440addr.h"
#include"2440lib.h"
#include"2440slib.h"
#include"mmu.h"
#include"profile.h"
#include"memtest.h"
#defineADC_FREQ2500000
intcount=0;
volatileU32preScaler;
intxdata,ydata;
voidTest_Touchpanel(void);
staticvoid__irqAdcTsAuto(void);
staticvoidcal_cpu_bus_clk(void);
voidSet_Clk(void);
voiddelay(inttimes)
{
inti,j;
for(i=0;i
for(j=0;j<400;j++);
}
评论