來(lái)源:百問(wèn)網(wǎng)_嵌入式linux wiki_jz2440 新1期視頻維基教程 (視頻文字版)
作者:韋東山
本文字?jǐn)?shù):2725,閱讀時(shí)長(zhǎng):3.5分鐘
第018課 ADC和觸摸屏 第006節(jié)_觸摸屏編程_ADC中斷
這節(jié)課我們加上ADC中斷把觸點(diǎn)的xy坐標(biāo)讀出來(lái)
查看touchscreen.c
寫出這個(gè)自動(dòng)測(cè)量的函數(shù)
void enter_auto_measure_mode(void)
{
//現(xiàn)在是自動(dòng)測(cè)量,我們沒(méi)有機(jī)會(huì)分別設(shè)置這些開關(guān)
設(shè)置AUTO_PST =1
XY_PST = 00
ADCTSC = AUTO_PST | NO_OPR_MODE;
}
現(xiàn)在是自動(dòng)測(cè)量,我們沒(méi)有機(jī)會(huì)分別設(shè)置這些開關(guān)

進(jìn)入中斷處理函數(shù)
void AdcTsIntHandle(int irq)
{
if (SUBSRCPND & (1<<TC_INT_BIT)) /* 如果是觸摸屏中斷 */
Isr_Tc();
if (SUBSRCPND & (1<<ADC_INT_BIT)) /* ADC中斷,則會(huì)進(jìn)入Adc中斷處理函數(shù) */
Isr_Adc();
SUBSRCPND = (1<<TC_INT_BIT) | (1<<ADC_INT_BIT);
}
進(jìn)入觸摸屏中斷處理函數(shù)
void Isr_Tc(void)
{
//printf("ADCUPDN = 0x%x, ADCDAT0 = 0x%x, ADCDAT1 = 0x%x, ADCTSC = 0x%xnr", ADCUPDN, ADCDAT0, ADCDAT1, ADCTSC);
if (ADCDAT0 & (1<<15))
{
//printf("pen upnr");
enter_wait_pen_down_mode();
}
else
{
/* 進(jìn)入"自動(dòng)測(cè)量"模式 */
enter_auto_measure_mode();
/* 啟動(dòng)ADC */
ENABLE_START = 1就可以了
ADCCON |= (1<<0);
}
}
啟動(dòng)ADC

Adc中斷處理函數(shù)
void Isr_Adc(void)
{
進(jìn)入adc中斷后,等待觸摸筆松開
int x = ADCDAT0 & 0x3ff;
int y = ADCDAT1 & 0x3ff;
printf("x = %08d, y = %08dnr", x, y);
//等待觸摸筆松開模式
enter_wait_pen_up_mode();
}
燒寫
實(shí)驗(yàn)發(fā)現(xiàn)打印一堆亂碼

應(yīng)該是printf函數(shù)出了問(wèn)題打開my_printf.c文件,找到printf函數(shù)應(yīng)該是處理第二個(gè)數(shù)據(jù)的時(shí)候,沒(méi)有設(shè)置初始值
/*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 != ''; fmt++)
{
if (*fmt != '%') {
outc(*fmt);
continue;
}
//碰到 % 就重新處理, 初始值應(yīng)該重新設(shè)置初始值上去
lead=' ';
maxwidth=0;
//format : %08d, %8d,%d,%u,%x,%f,%c,%s
fmt++;
if(*fmt == '0'){
lead = '0';
fmt++;
}
while(*fmt >= '0' && *fmt <= '9'){
maxwidth *=10;
maxwidth += (*fmt - '0');
fmt++;
}
switch (*fmt) {
case 'd': out_num(va_arg(ap, int), 10,lead,maxwidth); break;
case 'o': out_num(va_arg(ap, unsigned int), 8,lead,maxwidth); break;
case 'u': out_num(va_arg(ap, unsigned int), 10,lead,maxwidth); break;
case 'x': out_num(va_arg(ap, unsigned int), 16,lead,maxwidth); break;
case 'c': outc(va_arg(ap, int )); break;
case 's': outs(va_arg(ap, char *)); break;
default:
outc(*fmt);
break;
}
}
return 0;
}
重新燒寫執(zhí)行,發(fā)現(xiàn)數(shù)據(jù)變化幅度很大,但至少Adc已經(jīng)有輸出

我們需要解決輸出值不線性的問(wèn)題
到底是觸摸屏質(zhì)量問(wèn)題,還是Adc轉(zhuǎn)化精度問(wèn)題,覺(jué)得應(yīng)該是觸摸屏電壓不穩(wěn)定之前不知道DELAY寄存器是用來(lái)干嘛的

等待中斷模式時(shí),當(dāng)觸摸筆按下時(shí)我們會(huì)產(chǎn)生中斷,但是可以通過(guò) DELAY來(lái)延時(shí)產(chǎn)生中斷
在前面有一張圖

按下觸摸筆,延遲A才可以產(chǎn)生中斷,你才可以測(cè)量X Y坐標(biāo)A = D(晶振的周期)D就是 DELAY就是那個(gè)寄存器的值晶振周期時(shí)12M我們需要設(shè)置一下
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);
/* 按下觸摸屏, 延時(shí)一會(huì)再發(fā)出TC中斷
* 10ms為120000
* 延時(shí)時(shí)間 = ADCDLY * 晶振周期 = ADCDLY * 1 / 12000000 = 5ms
*/
ADCDLY = 60000;
}
再次燒寫,發(fā)現(xiàn)數(shù)據(jù)并不規(guī)律我們需要再次改進(jìn)程序
我們按下觸摸屏?xí)a(chǎn)生觸摸屏中斷,啟動(dòng)自動(dòng)測(cè)量,啟動(dòng)Adc,Adc成功后會(huì)進(jìn)入Adc中斷,在函數(shù)中打印數(shù)據(jù)
也許測(cè)量過(guò)程很長(zhǎng)我們就需要判斷
void Isr_Adc(void)
{
int x = ADCDAT0;
int y = ADCDAT1;
//松開的話打印也是錯(cuò)誤的值,所以如果仍然按下才打印
if (!(x & (1<<15))) /* 如果仍然按下才打印 */
{
x &= 0x3ff;
y &= 0x3ff;
//打印10進(jìn)制
printf("x = %08d, y = %08dnr", x, y);
}
enter_wait_pen_up_mode();
}
燒寫執(zhí)行
發(fā)現(xiàn)X Y軸輸出有問(wèn)題

廠家把X Y軸搞反了
電路圖中TSYP TSXP接反TSYM TSXM接反

我們后面使用觸摸屏?xí)r會(huì)使用軟件處理這點(diǎn),不會(huì)導(dǎo)致任何問(wèn)題
有一個(gè)缺點(diǎn)我們按下觸摸屏?xí)敵鲆粋€(gè)數(shù)據(jù),再按下觸摸屏又輸出一個(gè)數(shù)據(jù)我長(zhǎng)按并沒(méi)有輸出數(shù)據(jù),我滑動(dòng)也沒(méi)有輸出數(shù)據(jù)我們需要使用定時(shí)器改進(jìn)這個(gè)問(wèn)題
各種方向的旋轉(zhuǎn)都可以由軟件轉(zhuǎn)換

我們需要把觸摸屏的坐標(biāo)TS XY坐標(biāo)轉(zhuǎn)換成LCD的XY坐標(biāo)需要用應(yīng)用程序做我們常使用Tslib庫(kù)來(lái)做,這些旋轉(zhuǎn)倒置都沒(méi)有問(wèn)題