文章目錄
- 001 ADC硬件原理
- 硬件特性
- s3c2440的ADC硬件原理圖![s3c2440的ADC硬件原理圖](https://img-blog.csdnimg.cn/20200212151829301.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mjg4MTQxOQ==,size_16,color_FFFFFF,t_70)
- s3c2440的ADC框圖
- 002 ADC編程
- 003 電阻觸摸屏硬件原理
- 003 S3C2440觸摸屏接口
- 005觸摸屏編程_按下鬆開檢測
- 006ADC中斷
- 007定時器程序優化
- 009校準原理
- 010校準與畫線
- 012 編程完善
001 ADC硬件原理
硬件特性
s3c2440的ADC硬件原理圖
s3c2440的ADC框圖
- 怎麼設置:
- a.設置8:1mux,選中要測量哪個引腳
- b.設置工作時鐘
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-FpI2iF6S-1581491700386)(en-resource://database/2384:1)] - c.啓動
- d.讀狀態,判斷ADC成功
- e.讀數據
002 ADC編程
- 目標:
- a.初始化ADC
- b.讀數據
- c.在串口上顯示出來
- d.在LCD上顯示出來
設置ADC寄存器
ADCCON
ADCTSC
ADCDLY
ADCDATA0
void adc_init(void)
{
/* [15] :ECFLG ,1 = End of A/D conversion
* [14] : PRSCEN ,1 = A/D converter prescaler enable
* [13:6]: PRSCVL ,adc clk = PCK / (PRSCVL + 1)
* [5:3] : SEL_MUX ,000 = AIN 0
* [2] : STDBM ,1 = Standby mode
* [1] : READ_ START ,0 = Disable start by read operation
* [0] : ENABLE_START,1 = A/D conversion starts and this bit is cleared after the startup.
*/
ADCCON = (1<<14) | (49<<6) | (0<<3) ;
ADCDLY = 0xff;
}
int adc_read_ain0(void)
{
/* 啓動adc */
ADCCON |= (1<<0);
while(ADCCON & (1<<15)); /* 等待ADC結束 */
return ADCDAT0 & 0x3ff;
}
003 電阻觸摸屏硬件原理
觸摸屏示意圖
測量觸點X座標 | 測量觸點Y座標 |
---|---|
Xp接3.3v,Xm接地,Yp、Ym不接電源 | Yp接3.3v,Ym接地,Xp、Xm不接電源 |
測Yp電壓(就是X座標) | 測Xp電壓(就是Y座標) |
使用觸摸屏流程
- 1.按下觸摸屏,產生觸摸中斷
- 2.在觸摸屏中斷程序中,啓動ADC(目的:獲得x,y座標)
- 3.ADC完成,產生中斷
- 4.在ADC中斷中,讀取x,y座標
- 5.啓動定時器
- 6.定時器中斷發生,判斷觸摸屏仍被按下,回到第2步。
- 7.鬆開,結束。
003 S3C2440觸摸屏接口
編程要點
ADC轉化中斷時,可以通過中斷或者查詢來得到數據
- 使用中斷模式時,從AD轉換開始到得到數據可能有些延遲,因爲中斷的進入和退出需要浪費一些時間。
- 如果像要立刻得到數據,可以使用ADC的查詢方式,查詢ADCCON[15],判斷轉化是否結束 。
ADCTSC設置與觸摸屏等效電路圖
- 觸摸屏等待按下接口程序
void enter_wait_pen_dowm_mode(void)
{
ADCTSC = PULLUP_ENABLE | YM_ENABLE | YP_DISABLE | XP_DISABLE | XP_DISABLE | WAIT_INT_MODE ;
}
ADC/TS與中斷的控制流程
怎麼編程
- 1.初始化ADC/TS接口
- 2.設置TS處於等到中斷
- 3.設置中斷
- 4.按下,進去TS中斷
- a.進入自動採集模式
- b.啓動ADC
- 5.ADC中斷
- a.讀數據
- b.再次進入”等待中斷模式“
- c.啓動定時器
- 6.定時器中斷
- a.若鬆開,結束
- b.若按下,進入4.b
005觸摸屏編程_按下鬆開檢測
- 狀態轉換圖
- 注意:adc和觸摸屏公用一箇中斷,利用SUBSRCPND中的位,判斷是哪種中斷
void AdcTsIntHandle(int irq)
{
if(SUBSRCPND & (1<<ADC_INT_BIT)) /* 如果是觸摸屏中斷 */
Tsr_Tc();
if(SUBSRCPND & (1<<TC_INT_BIT)) /* ADC中斷 */
Isr_Adc();
}
判斷按下鬆開
void Tsr_Tc(void)
{
if(ADCUPDN & (1<<1))
printf("pen up\n\r");
if(ADCUPDN & (1<<0))
printf("pen dowm\n\r");
}
006ADC中斷
007定時器程序優化
在timer.c中,在中斷服務函數中,應該讓他從某個數組中,把需要定時器處理的函數依次執行。
- 函數指針數組:往數組中寫函數。
typedef void(*timer_func)(void);
typedef struct timer_desc{
char *name;
timer_func fp;
}timer_desc,*p_timer_desc;
timer_desc timer_array[TIMER_NUM];
int register_timer(char *name, timer_func fp)
{
int i;
for(i = 0; i < TIMER_NUM ; i++)
{
if(!timer_array[i].fp)
{
timer_array[i].name = name;
timer_array[i].fp = fp;
return 0;
}
}
return -1;
}
void register_timer(char *name)
{
int i;
for(i = 0; i < TIMER_NUM ; i++)
{
if(!strcmp(timer_array[i].name,name))
{
timer_array[i].name = NULL;
timer_array[i].fp = NULL;
return 0;
}
}
return -1;
}
#define NULL ((void *)0)
009校準原理
- 問題:得到觸點的(x,y)怎麼換算出LCD的(x,y)
- 1.利用比例
- 2.但是由於邊界點不準,因此選點
- 3.由於製作工藝不均勻,上下左右都有差異
010校準與畫線
程序思路:
- 一
- 1.在A點顯示“+”
fb_disp_cross(int x, int y)
- 2.客戶點擊“+”
ts_read_raw()//讀到原始數據
- 3.記錄觸摸屏座標
- 二在B、C、D、E、上循環操作:顯示、點擊、讀取操作
- 三、根據數據,確定公式
ts_calibrate()//構造公式
- 四、以後得到TS觸點時,可以轉換出LCD座標
ts_read()//
- 1.根據思路寫出基本函數
static double g_kx;
static double g_ky;
static int g_ts_xc,g_ts_yc;
static int g_lcd_xc,g_lcd_yc;
static int g_ts_xy_swap = 0;
void get_calibrate_point_data(int lcd_x, int lcd_y, int *px, int *py)
{
fb_disp_cross(lcd_x, lcd_ y, 0xffffff);
/* 等待點擊 */
ts_read_raw(px, py);
}
int is_ts_xy_swap(int a_ts_x, int a_ts_y, int b_ts_x, int b_ts_y)
{
int dx = b_ts_x - a_ts_x;
int dy = b_ts_y - b_ts_x;
if(dx < 0)
dx = 0 - dx;
if(dy < 0)
dy = 0 - dy;
if(dx > dy)
return 0; /* xym沒有反轉 */
else
return 1; /* xy反了 */
}
void swap_xy(int *px, int *py)
{
int tmp = *px;
*px = *py;
*py = tmp;
}
/*
---------------------------------
| |
| +(A) +(B) |
| |
| +(E) |
| |
| +(C) +(D) |
| |
---------------------------------
*/
void ts_calibrate(void)
{
unsigned int fb_base;
int xres, yres, bpp;
int a_ts_x,a_ts_y;
int b_ts_x,b_ts_y;
int c_ts_x,c_ts_y;
int d_ts_x,d_ts_y;
int e_ts_x,e_ts_y;
/* x軸方向 */
int ts_s1,ts_s2;
int lcd_s;
/* y軸方向 */
int ts_d1,ts_d2;
int lcd_d;
/* 獲得LCD的參數 */
get_lcd_params(&fb_base,&xres,&yres,&bpp);
/* 對於ABCDE,循環:顯示“+"、點擊、讀ts原始值 */
/* A(50, 50) */
get_calibrate_point_data(50, 50, &a_ts_x, &a_ts_x);
/* B(xres-50, 50) */
get_calibrate_point_data(xres-50, 50, &b_ts_x, &b_ts_x);
/* C(xres-50, yres-50) */
get_calibrate_point_data(xres-50, yres-50, &c_ts_x, &c_ts_x);
/* D(50, yres-50) */
get_calibrate_point_data(50, yres-50, &d_ts_x, &d_ts_x);
/* E(xres/2, yres/2) */
get_calibrate_point_data(xres/2, yres/2, &e_ts_x, &e_ts_x);
/* 確定觸摸屏數據XY是否反轉 */
g_ts_xy_swap = is_ts_xy_swap(a_ts_x, a_ts_y, b_ts_x, b_ts_y);
if(g_ts_xy_swap)
{
/* 對調所有點的xy座標 */
swap_xy(&a_ts_x,&a_ts_y);
swap_xy(&b_ts_x,&b_ts_y);
swap_xy(&c_ts_x,&c_ts_y);
swap_xy(&d_ts_x,&d_ts_y);
swap_xy(&e_ts_x,&e_ts_y);
}
/* 確定公式的參數並保存 */
ts_s1 = b_ts_x - a_ts_x;
ts_s2 = c_ts_x - d_ts_x;
lcd_s = xres-50 - 50;
ts_d1 = d_ts_y - a_ts_y;
ts_d2 = c_ts_y - b_ts_y;
lcd_d = yres-50 -50;
g_kx = (double) (2*lcd_s)/(ts_s1 + ts_s2);
g_ky = (double) (2*lcd_d)/(ts_d1 + ts_d2);
g_ts_xc = e_ts_x;
g_ts_yc = e_ts_y;
g_lcd_xc = xres/2;
g_lcd_yc = yres/2;
}
/*
*讀TS原始數據,轉換爲LCD座標
*/
void ts_read(int *lcd_x,int *lcd_y)
{
int ts_x,ts_y;
ts_read_raw(&ts_x, &ts_y);
if(g_ts_xy_swap)
{
swap_xy(&ts_x, &ts_y);
}
/* 使用公式計算 */
*lcd_x = g_kx * (ts_x - g_ts_xc) + g_lcd_xc;
*lcd_y = g_kx * (ts_y - g_ts_yc) + g_lcd_yc;
}
- 2.第二個問題:觸摸屏上報的x軸y軸相反,
int is_ts_xy_swap(int a_ts_x, int a_ts_y, int b_ts_x, int b_ts_y)
{
int dx = b_ts_x - a_ts_x;
int dy = b_ts_y - b_ts_x;
if(dx < 0)
dx = 0 - dx;
if(dy < 0)
dy = 0 - dy;
if(dx > dy)
return 0; /* xym沒有反轉 */
else
return 1; /* xy反了 */
}
/* 確定觸摸屏數據XY是否反轉 */
g_ts_xy_swap = is_ts_xy_swap(a_ts_x, a_ts_y, b_ts_x, b_ts_y);
- 3.第三個問題:如何對調XY的座標–對調函數
void swap_xy(int *px, int *py)
{
int tmp = *px;
*px = *py;
*py = tmp;
}
/* 確定觸摸屏數據XY是否反轉 */
g_ts_xy_swap = is_ts_xy_swap(a_ts_x, a_ts_y, b_ts_x, b_ts_y);
if(g_ts_xy_swap)
{
/* 對調所有點的xy座標 */
swap_xy(&a_ts_x,&a_ts_y);
swap_xy(&b_ts_x,&b_ts_y);
swap_xy(&c_ts_x,&c_ts_y);
swap_xy(&d_ts_x,&d_ts_y);
swap_xy(&e_ts_x,&e_ts_y);
}
- 總結:
- a.對於觸摸屏要多次測量求平均值
- b.要丟棄非法值(以lcd分辨率作爲判斷條件)
- c.校準時一定要點準
012 編程完善
- 問題:
- 第一次點擊觸摸屏,會出現2個點
- 長按,LCD上的點越來越大。
根源:使用ADC得到的座標值不穩定。
- 方法
- 參考tslib :
- a.使用矩陣進行校準,適用性更強
- b.使用多種方法消除誤差:多次測量,判斷相鄰點的距離,如果突然變化很大,可能就是錯誤值。
- 修改要點:
- 1.啓動ADC時不用改進入等待中斷模式,它會影響數據
-
- 只有在”等待中斷"模式下纔可以使用ADCDATA0’bit15來判斷觸摸筆狀態
- 3.校準非常重要,多以在程序中多次測量求平均值你(不僅是在ADC中斷中求平均值)。