來源:百問網(wǎng)_嵌入式linux wiki_jz2440 新1期視頻維基教程 (視頻文字版)
作者:韋東山
本文字數(shù):2725,閱讀時長:3.5分鐘
第018課 ADC和觸摸屏 第006節(jié)_觸摸屏編程_ADC中斷
這節(jié)課我們加上ADC中斷把觸點的xy坐標讀出來
查看touchscreen.c
寫出這個自動測量的函數(shù)
void enter_auto_measure_mode(void)
{
//現(xiàn)在是自動測量,我們沒有機會分別設置這些開關
設置AUTO_PST =1
XY_PST = 00
ADCTSC = AUTO_PST | NO_OPR_MODE;
}
現(xiàn)在是自動測量,我們沒有機會分別設置這些開關
進入中斷處理函數(shù)
void AdcTsIntHandle(int irq)
{
if (SUBSRCPND & (1<<TC_INT_BIT)) /* 如果是觸摸屏中斷 */
Isr_Tc();
if (SUBSRCPND & (1<<ADC_INT_BIT)) /* ADC中斷,則會進入Adc中斷處理函數(shù) */
Isr_Adc();
SUBSRCPND = (1<<TC_INT_BIT) | (1<<ADC_INT_BIT);
}
進入觸摸屏中斷處理函數(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
{
/* 進入"自動測量"模式 */
enter_auto_measure_mode();
/* 啟動ADC */
ENABLE_START = 1就可以了
ADCCON |= (1<<0);
}
}
啟動ADC
Adc中斷處理函數(shù)
void Isr_Adc(void)
{
進入adc中斷后,等待觸摸筆松開
int x = ADCDAT0 & 0x3ff;
int y = ADCDAT1 & 0x3ff;
printf("x = %08d, y = %08dnr", x, y);
//等待觸摸筆松開模式
enter_wait_pen_up_mode();
}
燒寫
實驗發(fā)現(xiàn)打印一堆亂碼
應該是printf函數(shù)出了問題打開my_printf.c文件,找到printf函數(shù)應該是處理第二個數(shù)據(jù)的時候,沒有設置初始值
/*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;
}
//碰到 % 就重新處理, 初始值應該重新設置初始值上去
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)有輸出
我們需要解決輸出值不線性的問題
到底是觸摸屏質(zhì)量問題,還是Adc轉(zhuǎn)化精度問題,覺得應該是觸摸屏電壓不穩(wěn)定之前不知道DELAY寄存器是用來干嘛的
等待中斷模式時,當觸摸筆按下時我們會產(chǎn)生中斷,但是可以通過 DELAY來延時產(chǎn)生中斷
在前面有一張圖
按下觸摸筆,延遲A才可以產(chǎn)生中斷,你才可以測量X Y坐標A = D(晶振的周期)D就是 DELAY就是那個寄存器的值晶振周期時12M我們需要設置一下
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);
/* 按下觸摸屏, 延時一會再發(fā)出TC中斷
* 10ms為120000
* 延時時間 = ADCDLY * 晶振周期 = ADCDLY * 1 / 12000000 = 5ms
*/
ADCDLY = 60000;
}
再次燒寫,發(fā)現(xiàn)數(shù)據(jù)并不規(guī)律我們需要再次改進程序
我們按下觸摸屏會產(chǎn)生觸摸屏中斷,啟動自動測量,啟動Adc,Adc成功后會進入Adc中斷,在函數(shù)中打印數(shù)據(jù)
也許測量過程很長我們就需要判斷
void Isr_Adc(void)
{
int x = ADCDAT0;
int y = ADCDAT1;
//松開的話打印也是錯誤的值,所以如果仍然按下才打印
if (!(x & (1<<15))) /* 如果仍然按下才打印 */
{
x &= 0x3ff;
y &= 0x3ff;
//打印10進制
printf("x = %08d, y = %08dnr", x, y);
}
enter_wait_pen_up_mode();
}
燒寫執(zhí)行
發(fā)現(xiàn)X Y軸輸出有問題
廠家把X Y軸搞反了
電路圖中TSYP TSXP接反TSYM TSXM接反
我們后面使用觸摸屏時會使用軟件處理這點,不會導致任何問題
有一個缺點我們按下觸摸屏會輸出一個數(shù)據(jù),再按下觸摸屏又輸出一個數(shù)據(jù)我長按并沒有輸出數(shù)據(jù),我滑動也沒有輸出數(shù)據(jù)我們需要使用定時器改進這個問題
各種方向的旋轉(zhuǎn)都可以由軟件轉(zhuǎn)換
我們需要把觸摸屏的坐標TS XY坐標轉(zhuǎn)換成LCD的XY坐標需要用應用程序做我們常使用Tslib庫來做,這些旋轉(zhuǎn)倒置都沒有問題