原理:
8通道的AD输入,转换为10位的二进制数据。在2.5MHZ的最大A/D转换时钟下,可以达到500KSPS。
2440的XP XM YP YM直接和触摸屏直接相连。ADC和触摸屏接口公用一个A/D转换器。
触摸屏接口模式:
1. 正常转换模式,就是普通的AD转换,通过读写ADCDAT0即可。
2. 分离的X/Y位置转换模式。X位置写往ADCDAT0,Y位置写往ADCDAT1。都会产生中断。
3. 连续的X/Y位置转换模式。触摸屏控制器连续转换X、Y位置。都写完后,产生一个中断。
ADC的操作规范:
ADC的启动包括手动操作和读结果时自动启动下一次转换。两种方法查询是否结束,查询状态位和转换结束时中断。
ADC编程步骤
1. 设置ADCCON,选择输入通道,设置AD转换时钟。
2. 设置ADCTSC,设为普通转换,不使用触摸屏。
3. 设置ADCCON启动AD转换,两种方式。
4. 转换结束时,读ADCDAT0获取结果。可以查询,也可以利用中断。
触摸屏操作规范:
XP YP要么作为模拟输入,要么接电源;XM YM要么接地,要么高阻。
1. 设置等待中断模式,设置ADCSTC寄存器即可,此时还需要设置第8位表明是pen down还是pen up中断。
2. 中断产生后,就会进入转换阶段,转换又分为X/Y分别转换和X/Y连续转换模式,在等待模式中上拉电阻有效,在触发中断后,上拉电阻无效。
可以为X.Y分别转换,设置ADCSTC=0x69 0x9a即可,X转换完会进入ADC中断,Y转换完也会进入ADC中断。
也可以设置连续的X.Y转换。此时ADCSTC的低2位设置为00,3位设置为AUTO_PST。
程序:
int main(void)
{
char ch;
init_uart0();
while (1)
{
printf("\r\n##### Test ADC and Touch Screem #####\r\n");
printf("[A] Test ADC\n\r");
printf("[T] Test Touch Screem\n\r");
printf("Enter your selection: ");
putchar((ch = getchar()));
switch (ch)
{
case 'a':
case 'A':
{
Test_Adc();
break;
}
case 't':
case 'T':
{
Test_Ts();
break;
}
default:
break;
}
}
}
// ADCCON
#define PRESCALE_DIS (0 << 14)
#define PRESCALE_EN (1 << 14)
#define PRSCVL(x) ((x) << 6)
#define ADC_INPUT(x) ((x) << 3)
#define ADC_START (1 << 0)
#define ADC_ENDCVT (1 << 15)
// ADCTSC
#define UD_SEN (1 << 8)
#define DOWN_INT (UD_SEN*0)
#define UP_INT (UD_SEN*1)
#define YM_SEN (1 << 7)
#define YM_HIZ (YM_SEN*0)
#define YM_GND (YM_SEN*1)
#define YP_SEN (1 << 6)
#define YP_EXTVLT (YP_SEN*0)
#define YP_AIN (YP_SEN*1)
#define XM_SEN (1 << 5)
#define XM_HIZ (XM_SEN*0)
#define XM_GND (XM_SEN*1)
#define XP_SEN (1 << 4)
#define XP_EXTVLT (XP_SEN*0)
#define XP_AIN (XP_SEN*1)
#define XP_PULL_UP (1 << 3)
#define XP_PULL_UP_EN (XP_PULL_UP*0)
#define XP_PULL_UP_DIS (XP_PULL_UP*1)
#define AUTO_PST (1 << 2)
#define CONVERT_MAN (AUTO_PST*0)
#define CONVERT_AUTO (AUTO_PST*1)
#define XP_PST(x) (x << 0)
#define NOP_MODE 0
#define X_AXIS_MODE 1
#define Y_AXIS_MODE 2
#define WAIT_INT_MODE 3
/* ÉèÖýøÈëµÈ´ýÖжÏģʽ£¬XP_PU,XP_Dis,XM_Dis,YP_Dis,YM_En
¶ÔÓÚS3C2440£¬Î»[8]Ϊ0¡¢1ʱ·Ö±ð±íʾµÈ´ýPen DownÖжϻòPen UpÖжÏ
*/
/* ½øÈë"µÈ´ýÖжÏģʽ"£¬µÈ´ý´¥ÃþÆÁ±»°´Ï */
#define wait_down_int() { rADCTSC = DOWN_INT | XP_PULL_UP_EN | \
XP_AIN | XM_HIZ | YP_AIN | YM_GND | \
XP_PST(WAIT_INT_MODE); }
/* ½øÈë"µÈ´ýÖжÏģʽ"£¬µÈ´ý´¥ÃþÆÁ±»ËÉ¿ª */
#define wait_up_int() { rADCTSC = UP_INT | XP_PULL_UP_EN | XP_AIN | XM_HIZ | \
YP_AIN | YM_GND | XP_PST(WAIT_INT_MODE); }
/* ½øÈë×Ô¶¯(Á¬Ðø) X/YÖá×ø±êת»»Ä£Ê½ */
#define mode_auto_xy() { rADCTSC = CONVERT_AUTO | XP_PULL_UP_DIS | XP_PST(NOP_MODE); }
/*
* ʹÓòéѯ·½Ê½¶ÁÈ¡A/Dת»»Öµ
* ÊäÈë²ÎÊý£º
* ch: Ä£ÄâÐźÅͨµÀ£¬È¡ÖµÎª0~7
*/
static int ReadAdc(int ch)
{
// Ñ¡ÔñÄ£ÄâͨµÀ£¬Ê¹ÄÜÔ¤·ÖƵ¹¦ÄÜ£¬ÉèÖÃA/Dת»»Æ÷µÄʱÖÓ = PCLK/(49+1)
rADCCON = PRESCALE_EN | PRSCVL(49) | ADC_INPUT(ch);
// Çå³ýλ[2]£¬ÉèΪÆÕͨת»»Ä£Ê½
rADCTSC &= ~(1<<2);
// ÉèÖÃλ[0]Ϊ1£¬Æô¶¯A/Dת»»
rADCCON |= ADC_START;
// µ±A/Dת»»ÕæÕý¿ªÊ¼Ê±£¬Î»[0]»á×Ô¶¯Çå0
while (rADCCON & ADC_START);
// ¼ì²âλ[15]£¬µ±ËüΪ1ʱ±íʾת»»½áÊø
while (!(rADCCON & ADC_ENDCVT));
// ¶ÁÈ¡Êý¾Ý
return (rADCDAT0 & 0x3ff);
}
/*
* ²âÊÔADC
* ͨ¹ýA/Dת»»£¬²âÁ¿¿É±äµç×èÆ÷µÄµçѹֵ
*/
void Test_Adc(void)
{
float vol;
int t;
printf("\r\nMeasuring the voltage of AIN2, press any key to exit\n\r");
while (!awaitkey(0)) // ´®¿ÚÎÞÊäÈ룬Ôò²»¶Ï²âÊÔ
{
vol = ((float)ReadAdc(1)*3.3)/1024.0; // ¼ÆËãµçѹֵ
t = (vol - (int)vol) * 1000; // ¼ÆËãСÊý²¿·Ö, ±¾´úÂëÖеÄprintfÎÞ·¨´òÓ¡¸¡µãÊý
printf("AIN2 = %d.%-3dV\r\n", (int)vol, t);
}
printf("\r\n");
}
/*
* INT_TCµÄÖжϷþÎñ³ÌÐò
* µ±´¥ÃþÆÁ±»°´ÏÂʱ£¬½øÈë×Ô¶¯(Á¬Ðø) X/YÖá×ø±êת»»Ä£Ê½£»
* µ±´¥ÃþÆÁ±»ËÉ¿ªÊ±£¬½øÈëµÈ´ýÖжÏģʽ£¬ÔٴεȴýINT_TCÖжÏ
*/
static void Isr_Tc(void)
{
if (rADCDAT0 & 0x8000)
{
printf("Stylus Up!!\n\r");
wait_down_int(); /* ½øÈë"µÈ´ýÖжÏģʽ"£¬µÈ´ý´¥ÃþÆÁ±»°´Ï */
}
else
{
printf("Stylus Down: ");
mode_auto_xy(); /* ½øÈë×Ô¶¯(Á¬Ðø) X/YÖá×ø±êת»»Ä£Ê½ */
/* ÉèÖÃλ[0]Ϊ1£¬Æô¶¯A/Dת»»
* ×¢Ò⣺ADCDLYΪ50000£¬PCLK = 50MHz£¬
* Òª¾¹ý(1/50MHz)*50000=1msÖ®ºó²Å¿ªÊ¼×ª»»X×ø±ê
* ÔÙ¾¹ý1msÖ®ºó²Å¿ªÊ¼×ª»»Y×ø±ê
*/
rADCCON |= ADC_START;
}
// ÇåINT_TCÖжÏ
rSUBSRCPND |= BIT_SUB_TC;
rSRCPND |= BIT_ADC;
rINTPND |= BIT_ADC;
}
/*
* INT_ADCµÄÖжϷþÎñ³ÌÐò
* A/Dת»»½áÊøʱ·¢Éú´ËÖжÏ
* ÏȶÁÈ¡X¡¢Y×ø±êÖµ£¬ÔÙ½øÈëµÈ´ýÖжÏģʽ
*/
static void Isr_Adc(void)
{
// ´òÓ¡X¡¢Y×ø±êÖµ
printf("xdata = %4d, ydata = %4d\r\n", (int)(rADCDAT0 & 0x3ff), (int)(rADCDAT1 & 0x3ff));
wait_up_int(); /* ½øÈë"µÈ´ýÖжÏģʽ"£¬µÈ´ý´¥ÃþÆÁ±»ËÉ¿ª */
// ÇåINT_ADCÖжÏ
rSUBSRCPND |= BIT_SUB_ADC;
rSRCPND |= BIT_ADC;
rINTPND |= BIT_ADC;
}
/*
* ADC¡¢´¥ÃþÆÁµÄÖжϷþÎñ³ÌÐò
* ¶ÔÓÚINT_TC¡¢INT_ADCÖжϣ¬·Ö±ðµ÷ÓÃËüÃǵĴ¦Àí³ÌÐò
*/
void __irq AdcTsIntHandle(void)
{
if (rSUBSRCPND & BIT_SUB_TC)
Isr_Tc();
if (rSUBSRCPND & BIT_SUB_ADC)
Isr_Adc();
}
/*
* ²âÊÔ´¥ÃþÆÁ£¬´òÓ¡´¥µã×ø±ê
*/
void Test_Ts(void)
{
pHandleADC = AdcTsIntHandle; // ÉèÖÃADCÖжϷþÎñ³ÌÐò
rINTMSK &= ~BIT_ADC; // ¿ªÆôADC×ÜÖжÏ
rINTSUBMSK &= ~(BIT_SUB_TC); // ¿ªÆôINT_TCÖжϣ¬¼´´¥ÃþÆÁ±»°´Ï»òËÉ¿ªÊ±²úÉúÖжÏ
rINTSUBMSK &= ~(BIT_SUB_ADC); // ¿ªÆôINT_ADCÖжϣ¬¼´A/Dת»»½áÊøʱ²úÉúÖжÏ
// ʹÄÜÔ¤·ÖƵ¹¦ÄÜ£¬ÉèÖÃA/Dת»»Æ÷µÄʱÖÓ = PCLK/(49+1)
rADCCON = PRESCALE_EN | PRSCVL(49);
/* ²ÉÑùÑÓʱʱ¼ä = (1/3.6864M)*50000 = 13.56ms
* ¼´°´Ï´¥ÃþÆÁºó£¬ÔÙ¹ý13.56ms²Å²ÉÑù
*/
rADCDLY = 50000;
wait_down_int(); /* ½øÈë"µÈ´ýÖжÏģʽ"£¬µÈ´ý´¥ÃþÆÁ±»°´Ï */
printf("\r\nTouch the screem to test, press any key to exit\n\r");
getchar();
// ÆÁ±ÎADCÖжÏ
rINTSUBMSK |= BIT_SUB_TC;
rINTSUBMSK |= BIT_SUB_ADC;
rINTMSK |= BIT_ADC;
}