来源:百问网_嵌入式Linux wiki_jz2440 新1期视频维基教程 (视频笔墨版)
作者:韦东山

本笔墨数:2725,阅读时长:3.5分钟
第018课 ADC和触摸屏 第012节_触摸屏编程_完善
触摸屏编程_完善我们触摸屏校准虽然可以正常运行,但是有些问题,比如在触摸屏上点一个点,同时屏幕上面会显示另一个点,我们按住屏幕不动的同时将其转换成LCD坐标并且描点,就表明数值不大稳定问题
我们第一次点击触摸屏会涌现两个点长按,LCD上的点会越来越大根源在于我们得到的LCD坐标值不稳定,根源ADC转换出来的xy坐标值不稳定我们打开touchscreen.c问题涌如今这里面
#include "../s3c2440_soc.h"#define ADC_INT_BIT (10)#define TC_INT_BIT (9)#define INT_ADC_TC (31)/ ADCTSC's bits /#define WAIT_PEN_DOWN (0<<8)#define WAIT_PEN_UP (1<<8)#define YM_ENABLE (1<<7)#define YM_DISABLE (0<<7)#define YP_ENABLE (0<<6)#define YP_DISABLE (1<<6)#define XM_ENABLE (1<<5)#define XM_DISABLE (0<<5)#define XP_ENABLE (0<<4)#define XP_DISABLE (1<<4)#define PULLUP_ENABLE (0<<3)#define PULLUP_DISABLE (1<<3)#define AUTO_PST (1<<2)#define WAIT_INT_MODE (3)#define NO_OPR_MODE (0)static volatile int g_ts_timer_enable = 0;static int g_ts_x;static int g_ts_y;static int g_ts_pressure;static int g_ts_data_valid = 0;//定义测试数据16static int test_x_array[16];static int test_y_array[16];void report_ts_xy(int x, int y, int pressure);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;}void enter_auto_measure_mode(void){ADCTSC = AUTO_PST | NO_OPR_MODE;}int is_in_auto_mode(void){return ADCTSC & AUTO_PST;}void Isr_Tc(void){//printf("ADCUPDN = 0x%x, ADCDAT0 = 0x%x, ADCDAT1 = 0x%x, ADCTSC = 0x%x\n\r", ADCUPDN, ADCDAT0, ADCDAT1, ADCTSC);if (ADCDAT0 & (1<<15)){//按下状态启用触摸屏//启动丈量模式,转换结束产生adc中断//printf("pen up\n\r");enter_wait_pen_down_mode();report_ts_xy(0, 0, 0);}else{//printf("pen down\n\r");/ 进入"自动丈量"模式 /enter_auto_measure_mode();/ 启动ADC /ADCCON |= (1<<0);}}static void ts_timer_enable(void){g_ts_timer_enable = 1;}static void ts_timer_disable(void){g_ts_timer_enable = 0;}static int get_status_of_ts_timer(void){return g_ts_timer_enable;}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;}}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;}/ 每10ms该函数被调用一次 /void touchscreen_timer_irq(void){/ 如果触摸屏仍被按下, 进入"自动丈量模式", 启动ADC /if (get_status_of_ts_timer() == 0)return;if (is_in_auto_mode())return;/ 只有在"等待中断模式"下才可以利用ADCDAT0'BIT 15来判断触摸笔状态 /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 / 按下状态 /{/ 进入"自动丈量"模式 /enter_auto_measure_mode();/ 启动ADC /ADCCON |= (1<<0);}}void Isr_Adc(void){int x = ADCDAT0;int y = ADCDAT1;static int adc_cnt = 0;static int adc_x = 0;static int adc_y = 0;/ 进入ADC中断时, TS处于"自动丈量模式" // 只有在"等待中断模式"下才可以利用ADCDAT0'BIT 15来判断触摸笔状态 /enter_wait_pen_up_mode();if (!(ADCDAT0 & (1<<15))) / 如果仍旧按下才打印 /{#if 0x &= 0x3ff;y &= 0x3ff;//printf("x = %08d, y = %08d\n\r", x, y);report_ts_xy(x, y, 1);/ 启动定时器以再次读取数据 /ts_timer_enable();#endif/ 第1次启动ADC后: a. 要连续启动N次, 得到N个数据, 求均匀值并上报 b. 得到N次数据后, 再启动TIMER /adc_x += (x & 0x3ff);adc_y += (y & 0x3ff);//定义一个函数把这些值打印出来test_x_array[adc_cnt] = (x & 0x3ff);test_y_array[adc_cnt] = (y & 0x3ff);adc_cnt++;if (adc_cnt == 16){adc_x >>= 4;adc_y >>= 4;report_ts_xy(adc_x, adc_y, 1);adc_cnt = 0;adc_x = 0;adc_y = 0;/ 启动定时器以再次读取数据 // 先设置TS进入"等待中断模式" ///有按下就会有松开enter_wait_pen_up_mode();ts_timer_enable();}else{/ 再次启动ADC // 进入"自动丈量"模式 /enter_auto_measure_mode();/ 启动ADC /ADCCON |= (1<<0);}}else{adc_cnt = 0;adc_x = 0;adc_y = 0;printf("adc report pen down\n\r");ts_timer_disable();enter_wait_pen_down_mode();report_ts_xy(0, 0, 0);}//enter_wait_pen_up_mode(); / 启动ADC时不应该进入这个模式, 它会影响数据 /}void AdcTsIntHandle(int irq){if (SUBSRCPND & (1<<TC_INT_BIT)) / 如果是触摸屏中断 /Isr_Tc();if (SUBSRCPND & (1<<ADC_INT_BIT)) / ADC中断 /Isr_Adc();SUBSRCPND = (1<<TC_INT_BIT) | (1<<ADC_INT_BIT);}void adc_ts_int_init(void){SUBSRCPND = (1<<TC_INT_BIT) | (1<<ADC_INT_BIT);/ 注册中断处理函数 /register_irq(31, AdcTsIntHandle);/ 使能中断 /INTSUBMSK &= ~((1<<ADC_INT_BIT) | (1<<TC_INT_BIT));//INTMSK &= ~(1<<INT_ADC_TC);}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);/ 按下触摸屏, 延时一会再发出TC中断 延时时间 = ADCDLY 晶振周期 = ADCDLY 1 / 12000000 = 5ms /ADCDLY = 60000;}void touchscreen_init(void){/ 设置触摸屏接口:寄存器 /adc_ts_reg_init();printf("ADCUPDN = 0x%x, SUBSRCPND = 0x%x, SRCPND = 0x%x\n\r", ADCUPDN, SUBSRCPND, SRCPND);/ 设置中断 /adc_ts_int_init();/ 注册定时器处理函数 /register_timer("touchscreen", touchscreen_timer_irq);/ 让触摸屏掌握器进入"等待中断模式" /enter_wait_pen_down_mode();}//打印数组定义的那些值void print_test_array(void){int i;printf("test array x : ");for (i = 0; i < 16; i++)printf("%08d ", test_x_array[i]);printf("\n\r");printf("test array y : ");for (i = 0; i < 16; i++)printf("%08d ", test_y_array[i]);printf("\n\r");}void ts_read_raw_test(int px, int py, int ppressure){while (g_ts_data_valid == 0);px = g_ts_x;py = g_ts_y;ppressure = g_ts_pressure;print_test_array();g_ts_data_valid = 0;}
tslib.c利用了ts_read_raw函数
void get_calibrate_point_data(int lcd_x, int lcd_y, int px, int py){int pressure;int x, y;int sum_x = 0, sum_y = 0;int cnt = 0;fb_disp_cross(lcd_x, lcd_y, 0xffffff);/ 等待点击 /do {//ts_read_raw(&x, &y, &pressure); //我们利用测试程序去读这些值ts_read_raw_test(&x, &y, &pressure);} while (pressure == 0);do {if (cnt < 128){sum_x += x;sum_y += y;cnt++;}//ts_read_raw(&x, &y, &pressure);//ts_read_raw_test(&x, &y, &pressure);printf("get raw data: x = %08d, y = %08d, cnt = %d\n\r", x, y, cnt);} while (pressure);px = sum_x / cnt;py = sum_y / cnt;printf("return raw data: x = %08d, y = %08d\n\r", px, py);/ 直到松开才返回 /fb_disp_cross(lcd_x, lcd_y, 0);}
我们来看点击一下是不是得到了间隔非常远的两个值
对付同一个点得到的是255 945 945 944
创造 945 944常常涌现
我们查一下缘故原由,进入touchscreen.c中
void Isr_Adc(void){int x = ADCDAT0;int y = ADCDAT1;static int adc_cnt = 0;static int adc_x = 0;static int adc_y = 0;/ 进入ADC中断时, TS处于"自动丈量模式" // 只有在"等待中断模式"下才可以利用ADCDAT0'BIT 15来判断触摸笔状态 /enter_wait_pen_up_mode();if (!(ADCDAT0 & (1<<15))) / 如果仍旧按下才打印 /{#if 0x &= 0x3ff;y &= 0x3ff;//printf("x = %08d, y = %08d\n\r", x, y);report_ts_xy(x, y, 1);/ 启动定时器以再次读取数据 /ts_timer_enable();#endif/ 第1次启动ADC后: a. 要连续启动N次, 得到N个数据, 求均匀值并上报 b. 得到N次数据后, 再启动TIMER /adc_x += (x & 0x3ff);adc_y += (y & 0x3ff);test_x_array[adc_cnt] = (x & 0x3ff);test_y_array[adc_cnt] = (y & 0x3ff);adc_cnt++;if (adc_cnt == 16){adc_x >>= 4;adc_y >>= 4;report_ts_xy(adc_x, adc_y, 1);adc_cnt = 0;adc_x = 0;adc_y = 0;/ 启动定时器以再次读取数据 // 先设置TS进入"等待中断模式" /enter_wait_pen_up_mode();ts_timer_enable();}else{/ 再次启动ADC // 进入"自动丈量"模式 /enter_auto_measure_mode();/ 启动ADC /ADCCON |= (1<<0);}}else{adc_cnt = 0;adc_x = 0;adc_y = 0;printf("adc report pen down\n\r");ts_timer_disable();enter_wait_pen_down_mode();report_ts_xy(0, 0, 0);}//启动ADC后又再次进入enter_wait_pen_up_mode电阻上拉,多次一举//enter_wait_pen_up_mode(); / 启动ADC时不应该进入这个模式, 它会影响数据 /}
创造这些值中还有944,我须要连续查找缘故原由, 在touchscreen.c时钟处理函数中添加打印信息
/ 每10ms该函数被调用一次 /void touchscreen_timer_irq(void){/ 如果触摸屏仍被按下, 进入"自动丈量模式", 启动ADC /if (get_status_of_ts_timer() == 0)return;if (is_in_auto_mode())return;/ 只有在"等待中断模式"下才可以利用ADCDAT0'BIT 15来判断触摸笔状态 /if (ADCDAT0 & (1<<15)) / 如果松开 /{//添加打印信息printf("timer set pen down\n\r");ts_timer_disable();//进入enter_wait_pen_down_mode,来判断触摸笔是按下还是松开enter_wait_pen_down_mode();report_ts_xy(0, 0, 0);return;}else / 按下状态 /{/ 进入"自动丈量"模式 /enter_auto_measure_mode();/ 启动ADC /ADCCON |= (1<<0);}}
非常频繁打印timer set pen down
我们的判断有问题打开芯片手册,搜索这个寄存器,Bit15确实是判断按下或者松开
只有在中断模式下,这一位才可以精确反应是按下还是松开的状态,修正touchscreen_timer_irq函数
/ 每10ms该函数被调用一次 /void touchscreen_timer_irq(void){/ 如果触摸屏仍被按下, 进入"自动丈量模式", 启动ADC /if (get_status_of_ts_timer() == 0)return;//如果定时器中断在ADC中间产生,该当急速返回啥都不做,不须要timer去做任何操作//我们须要写出这个函数//如果不是自动模式,那么便是等待中断模式if (is_in_auto_mode())return;//中断处理函数,/ 只有在"等待中断模式"下才可以利用ADCDAT0'BIT 15来判断触摸笔状态 /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 / 按下状态 /{/ 进入"自动丈量"模式 /enter_auto_measure_mode();/ 启动ADC /ADCCON |= (1<<0);}}//判断是否是模式模式的函数int is_in_auto_mode(void){return ADCTSC & AUTO_PST;}
我们接其实验
创造并没有捕捉到笔的松开模式 , 修正tslib,取消ts_read_raw_test 重新进行测试.
void get_calibrate_point_data(int lcd_x, int lcd_y, int px, int py){int pressure;int x, y;int sum_x = 0, sum_y = 0;int cnt = 0;fb_disp_cross(lcd_x, lcd_y, 0xffffff);/ 等待点击 /do {ts_read_raw(&x, &y, &pressure); //ts_read_raw_test(&x, &y, &pressure);} while (pressure == 0);do {if (cnt < 128){sum_x += x;sum_y += y;cnt++;}ts_read_raw(&x, &y, &pressure); //ts_read_raw_test(&x, &y, &pressure);printf("get raw data: x = %08d, y = %08d, cnt = %d\n\r", x, y, cnt);} while (pressure);px = sum_x / cnt;py = sum_y / cnt;printf("return raw data: x = %08d, y = %08d\n\r", px, py);/ 直到松开才返回 /fb_disp_cross(lcd_x, lcd_y, 0);}
现在创造点点不准确
创造校准的值和我们之前的不一样,修正我们的tslib校准程序
void get_calibrate_point_data(int lcd_x, int lcd_y, int px, int py){int pressure;int x, y;int sum_x = 0, sum_y = 0;int cnt = 0;fb_disp_cross(lcd_x, lcd_y, 0xffffff);/ 等待点击 /do {ts_read_raw(&x, &y, &pressure); //ts_read_raw_test(&x, &y, &pressure);} while (pressure == 0);do {//我们把求和的次数限定为128次if (cnt < 128){sum_x += x;sum_y += y;cnt++;}ts_read_raw(&x, &y, &pressure); //ts_read_raw_test(&x, &y, &pressure);printf("get raw data: x = %08d, y = %08d, cnt = %d\n\r", x, y, cnt);} while (pressure);px = sum_x / cnt;py = sum_y / cnt;printf("return raw data: x = %08d, y = %08d\n\r", px, py);/ 直到松开才返回 /fb_disp_cross(lcd_x, lcd_y, 0);}
我们可以参考tslib
利用矩阵进行校准,适用性更强利用多种方法肃清偏差,多次丈量求均匀值判断相邻点的间隔,如果溘然变革很大,就有可能是缺点值
...第一期的视频在于裸机基本操作
视频的要点在于
修正要点
启动ADC时不应该进入等待中断模式,它会影响数据只有在"等待中断模式"下才可以利用ADCDAT0'BIT 15来判断触摸笔状态校准非常主要,以是在程序中多次丈量求均匀值(不仅仅是在adc中断种求均匀值)「新品首发」STM32MP157开拓板火爆预售!
首批仅300套









