s3c2440arm裸机编程之ADC触摸屏
ADC觸摸屏
硬件原理
s3c2440有8通道的ADC,一次同時(shí)只能查詢一個(gè)通道。分為A0~A7。這里的P(positive)表示的是正的意思
| A4 | TSYM | -Y |
| A5 | TSYP | +Y |
| A6 | TSXM | -X |
| A7 | TSXP | +X |
觸摸屏采樣有3種方式:
- 自動(dòng)反轉(zhuǎn)XY軸相關(guān)開關(guān)采樣
- 手動(dòng)切換開關(guān)采樣
- 等待中斷模式,這個(gè)是平時(shí)沒按下的狀態(tài)
電阻屏的觸摸原理,其實(shí)就是在一個(gè)均勻的電阻上采樣后得到電壓,然后基于vcc算出相對(duì)偏移.假設(shè)電阻總長(zhǎng)為L(zhǎng),采樣電壓為V1,那么長(zhǎng)度偏移則是V/DVDD*L.
基于此在X方向和Y方向均有均勻電阻.所以觸摸屏實(shí)際是兩片透明且均勻的電阻,不按下的時(shí)候中間并不導(dǎo)通.轉(zhuǎn)換選擇導(dǎo)通X方向與Y方向依次測(cè)的X坐標(biāo)與Y坐標(biāo).也就是先連接Xm--Xp,側(cè)的Yp的采樣,就能獲得X的偏移.
板載電路
這里X軸和Y軸接反了,尅使用Tslib庫旋轉(zhuǎn)倒置等
等效電路
關(guān)閉模式:斷開上拉電阻與4線電路,防止漏電流
空閑等待中斷:這個(gè)狀態(tài)是平時(shí)沒有按下觸摸屏,等待按下觸發(fā)一個(gè)按下的中斷,當(dāng)左右兩邊電阻觸發(fā)的時(shí)候,導(dǎo)通了XP到Y(jié)M到GND,這將使Y_ADC=0,--↓__產(chǎn)生一個(gè)下降沿等待中斷模式設(shè)置值為 ADCTSC=0xd3; // XP_PU, XP_Dis, XM_Dis,YP_Dis,YM_En同樣的,當(dāng)按下后,還是同樣的等效電路,當(dāng)松開的時(shí)候,會(huì)有一個(gè)上升延中斷.配置ADCTSC的BIT8即可.
X軸采樣:這里連通XP-XM,采樣X_ADC
Y軸采樣:這里連通YP-YM,采樣Y_ADC
測(cè)量邏輯
觸摸屏實(shí)際有兩層,按下的時(shí)候,導(dǎo)通了上下兩個(gè)平面,通過等效電路,可以看出通過切換開關(guān),能夠得到兩種阻值。
程序設(shè)計(jì)(一)獲得ADC
寄存器初始化
這里的DELAY 可以用作穩(wěn)定ADC輸出,也就是按下后多長(zhǎng)時(shí)間開始采樣
/* 1. 設(shè)置允許分配,分配系數(shù)為49+1,時(shí)鐘為100M/50=2 2. 選擇A0通道,因?yàn)楹竺孢x擇自動(dòng)轉(zhuǎn)換,可以不考慮通道 */ ADCCON = (1<<14) | (49<<6) | (0<<3);/* 按下觸摸屏, 延時(shí)一會(huì)再發(fā)出TC中斷* 延時(shí)時(shí)間 = ADCDLY * 晶振周期 = ADCDLY * 1 / 12000000 = 5ms*/ ADCDLY = 60000;中斷初始化
//清除掛起標(biāo)志 SUBSRCPND = (1<<TC_INT_BIT) | (1<<ADC_INT_BIT); //取消次級(jí)屏蔽 INTSUBMSK &= ~((1<<ADC_INT_BIT) | (1<<TC_INT_BIT)); //注冊(cè)中斷函數(shù),INTMSK &= ~(1<<irq); 取消源的mask register_irq(31, AdcTsIntHandle);void register_irq(int irq, irq_func fp) {irq_array[irq] = fp;INTMSK &= ~(1<<irq); }ADC模式(中斷、測(cè)量)
ADC在工作中存在3個(gè)模式的切換,空閑的時(shí)候進(jìn)入等待按下中斷的模式,然后進(jìn)入自動(dòng)測(cè)量的模式,在測(cè)量完成后需要進(jìn)入等待松開的中斷模式.此時(shí)可以設(shè)置定時(shí)器等待觸發(fā)下一次的自動(dòng)測(cè)量
// 空閑下等待觸發(fā)落下中斷 void enter_wait_pen_down_mode(void) {ADCTSC = WAIT_PEN_DOWN | PULLUP_ENABLE | YM_ENABLE | YP_DISABLE | XP_DISABLE | XM_DISABLE | WAIT_INT_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; } //自動(dòng)測(cè)量模式 void enter_auto_measure_mode(void) {ADCTSC = AUTO_PST | NO_OPR_MODE; }中斷函數(shù)
備注:可以發(fā)現(xiàn),松開狀態(tài)下進(jìn)入中斷,都進(jìn)入空閑等待按下中斷模式
觸摸屏中斷
if 松開中斷關(guān)閉一切,進(jìn)入等待按下模式 else 按下中斷進(jìn)入自動(dòng)測(cè)量模式打開adc定時(shí)器中斷
if 松開關(guān)閉定時(shí)器進(jìn)入等待按下模式 else 按下進(jìn)入自動(dòng)測(cè)量模式打開adcADC中斷
if 松開關(guān)閉定時(shí)器進(jìn)入等待按下模式 else 按下打印adc值*進(jìn)入等待中斷模式打開定時(shí)器//這里可以優(yōu)化做平均值 if 松開關(guān)閉定時(shí)器進(jìn)入等待按下模式上報(bào)數(shù)據(jù) else 按下if 測(cè)量計(jì)數(shù)到達(dá)16次返回平均值,開啟定時(shí)器else 直接進(jìn)入自動(dòng)測(cè)量模式優(yōu)化版本
進(jìn)入adc中斷 進(jìn)入觸摸屏中斷 進(jìn)入定時(shí)器中斷后 都先關(guān)閉定時(shí)器進(jìn)入adc中斷后 if按下滿16次采樣后打開定時(shí)器,進(jìn)入等待松開中斷未滿16次繼續(xù)打開adc采樣 else 松開進(jìn)入等待按下中斷上報(bào)0進(jìn)入觸摸屏中斷 if 按下 打開adc開始采樣 else 松開進(jìn)入等待按下中斷上報(bào)0進(jìn)入定時(shí)器中斷且當(dāng)前定時(shí)器狀態(tài)為open if 按下 打開adc采樣 else 松開進(jìn)入等待按下中斷上報(bào)0程序設(shè)計(jì)(二)獲得坐標(biāo)
同理,Y軸的坐標(biāo)也按照相同的方式計(jì)算.程序設(shè)計(jì)中依次畫出5個(gè)十字架,用戶點(diǎn)擊后計(jì)算K與b偏差
生產(chǎn)者與消費(fèi)者
生產(chǎn)者:這里ADC完成測(cè)量后上報(bào)ADC采樣,可以理解為生產(chǎn)者.在ADC采樣完成16次并且依然按下的情況下上報(bào)實(shí)際adc,其他情況上報(bào)0.這里設(shè)置一個(gè)標(biāo)志,只有等消費(fèi)者取出數(shù)據(jù)之后,再上傳數(shù)據(jù).這里都是在中斷中上報(bào)數(shù)據(jù)
void report_ts_xy(int x, int y, int pressure) {//printf("x = %08d, y = %08d\n\r", x, y);if (g_ts_data_valid == 0){g_ts_x = x;g_ts_y = y;g_ts_pressure = pressure;g_ts_data_valid = 1;} }消費(fèi)者:中斷中生產(chǎn)數(shù)據(jù),循環(huán)中獲取數(shù)據(jù),取得數(shù)據(jù)后清除標(biāo)志允許生產(chǎn)者上傳數(shù)據(jù).
void ts_read_raw(int *px, int *py, int *ppressure) {while (g_ts_data_valid == 0);*px = g_ts_x;*py = g_ts_y;*ppressure = g_ts_pressure;g_ts_data_valid = 0; }狀態(tài)標(biāo)志:?g_ts_data_valid是標(biāo)志.0表示消費(fèi)者已經(jīng)取走數(shù)據(jù),無新數(shù)據(jù)產(chǎn)生
ADC獲取
程序優(yōu)化
視頻教學(xué)修改要點(diǎn)
寄存器ADCDAT0只有在等待中斷的模式中才能用來判斷是按下還是松開狀態(tài),所以定時(shí)器中斷中不能用該寄存器.所以當(dāng)定時(shí)器中斷發(fā)生在ADC采樣中的時(shí)候,不應(yīng)該打斷adc采樣.韋東山的優(yōu)化是先判斷是否是自動(dòng)采樣模式,如果是在采樣則退出.
void touchscreen_timer_irq(void) {//定時(shí)器開關(guān)if (get_status_of_ts_timer() == 0)return; /*------------------------------------------------------------ 定時(shí)器開關(guān)只會(huì)被ADC采樣16次完成后打開,其他狀態(tài)下均會(huì)關(guān)閉定時(shí)器, 包括進(jìn)入本函數(shù)這里的按下狀態(tài)后進(jìn)入自動(dòng)測(cè)量模式***************************************************************/ if (is_in_auto_mode())return;/* 只有在"等待中斷模式"下才可以使用ADCDAT0'BIT 15來判斷觸摸筆狀態(tài) */if (ADCDAT0 & (1<<15)) /* 如果松開 */{printf("timer set pen down\n\r");ts_timer_disable();enter_wait_pen_down_mode();report_ts_xy(0, 0, 0);return;}else /* 按下狀態(tài) */{/* 進(jìn)入"自動(dòng)測(cè)量"模式 */enter_auto_measure_mode();/* 啟動(dòng)ADC */ADCCON |= (1<<0);} }個(gè)人修改意見
我覺得更應(yīng)該更改為如果開啟了adc的采樣,應(yīng)該是去關(guān)閉定時(shí)器的標(biāo)志.防止碰撞.定時(shí)器中斷必須在采樣16次完成之后才會(huì)發(fā)生.然后進(jìn)入定時(shí)器中斷處理的時(shí)候就能確保不會(huì)與adc中斷沖突,也就是一定是在等待中斷模式,上述的is_in_auto_mode也是可以去除的.
if (is_in_auto_mode())return;所以我的優(yōu)化方案是
進(jìn)入adc中斷 進(jìn)入觸摸屏中斷 進(jìn)入定時(shí)器中斷后 都先關(guān)閉定時(shí)器進(jìn)入adc中斷后 if按下滿16次采樣后打開定時(shí)器,進(jìn)入等待松開中斷未滿16次繼續(xù)打開adc采樣 else 松開進(jìn)入等待按下中斷上報(bào)0進(jìn)入觸摸屏中斷 if 按下 打開adc開始采樣 else 松開進(jìn)入等待按下中斷上報(bào)0進(jìn)入定時(shí)器中斷且當(dāng)前定時(shí)器狀態(tài)為open if 按下 打開adc采樣 else 松開進(jìn)入等待按下中斷上報(bào)0總結(jié)
TODO
參考tslib 中更牛逼的矯正算法
轉(zhuǎn)載:https://www.cnblogs.com/zongzi10010/p/10023639.html
總結(jié)
以上是生活随笔為你收集整理的s3c2440arm裸机编程之ADC触摸屏的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: u-boot分析之两阶段代码分析(三)
- 下一篇: 从0写bootloader