【ARM裸板】S3C2440下的ADC操作和觸摸屏的詳解 && 根據寄存器編程編程

001 ADC硬件原理

硬件特性

ADC特性

s3c2440的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

ADCCON

ADCTSC

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時不用改進入等待中斷模式,它會影響數據
    1. 只有在”等待中斷"模式下纔可以使用ADCDATA0’bit15來判斷觸摸筆狀態
  • 3.校準非常重要,多以在程序中多次測量求平均值你(不僅是在ADC中斷中求平均值)。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章