百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

ADC触摸屏编程_测试

itomcoil 2025-04-29 01:22 27 浏览


来源:百问网_嵌入式Linux wiki_jz2440 新1期视频维基教程 (视频文字版)

作者:韦东山

本文字数:5890,阅读时长:4.5分钟

第018课 ADC和触摸屏 第011节_触摸屏编程_测试

发现程序有bug,点击坐标一次,程序就完成执行,我们需要修改触摸屏文件tsib.c

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;


static unsigned int fb_base;
static int xres, yres, bpp;


void get_calibrate_point_data(int lcd_x, int lcd_y, int *px, int *py)
{
	int pressure;
	int x, y;
	
	fb_disp_cross(lcd_x, lcd_y, 0xffffff);

	/* 等待点击 */

	do {
//如果pressure一直是0的话我们丢掉这些数据
		ts_read_raw(&x, &y, &pressure); 
	} while (pressure == 0);

//让后再次读
	do {
		*px = x;
		*py = y;
		ts_read_raw(&x, &y, &pressure); 
		printf("get raw data: x = %08d, y = %08d\n\r", x, y);
	} while (pressure);

	printf("return raw data: x = %08d, y = %08d\n\r", *px, *py);

	/* 直到松开才返回 */
	fb_disp_cross(lcd_x, lcd_y, 0);
}

修改touchcreen.c文件添加压力值相关信息

//定义压力值全局变量
static int g_ts_pressure;
void report_ts_xy(int x, int y, int pressure);

//发现不能画线,修改 ts_read
//我们需要判断触摸笔是按下还是松开,需要添加压力值参数
/*
 * 读TS原始数据, 转换为LCD坐标
 * 我们需要加上压力值lcd_pressure
 */
int ts_read(int *lcd_x, int *lcd_y, int *lcd_pressure)
{
	int ts_x, ts_y, ts_pressure;
	int tmp_x, tmp_y;
//添加压力值参数	
	ts_read_raw(&ts_x, &ts_y, &ts_pressure);

	if (g_ts_xy_swap)
	{
		swap_xy(&ts_x, &ts_y);
	}

	/* 使用公式计算 */
	tmp_x = g_kx * (ts_x - g_ts_xc) + g_lcd_xc;
	tmp_y = g_ky * (ts_y - g_ts_yc) + g_lcd_yc;

//如果值超出了LCD范围返回-1
	if (tmp_x < 0 || tmp_x >= xres || tmp_y < 0 || tmp_y >= yres)
		return -1;
	
	*lcd_x = tmp_x;
	*lcd_y = tmp_y;
//压力值等于全局变量ts_pressure
	*lcd_pressure = ts_pressure;
	return 0;
}


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;
}


//我们需要report上报压力值数据
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 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))
	{
		//printf("pen up\n\r");

		enter_wait_pen_down_mode();
//如果松开就上报数据xy坐标00 压力值0
		report_ts_xy(0, 0, 0);
		
	}
	else	
	{
		//printf("pen down\n\r");

		/* 进入"自动测量"模式 */
		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;

	if (!(x & (1<<15))) /* 如果仍然按下才打印 */
	{
#if 0		
		x &= 0x3ff;
		y &= 0x3ff;
		
		//printf("x = %08d, y = %08d\n\r", x, y);
//当我得到触电数据以后,如果当前仍是按下状态,会上报XY坐标值并且上报压力值,压力值等于1
		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);
		adc_cnt++;
//我们取16的话右移4位比较容易操作
		if (adc_cnt == 16)
		{
//右移4位
			adc_x >>= 4;
			adc_y >>= 4;
//上报
			report_ts_xy(adc_x, adc_y, 1);

//恢复到初始值0
			adc_cnt = 0;
			adc_x = 0;
			adc_y = 0;
			
			/* 启动定时器以再次读取数据 */
			ts_timer_enable();
		}
		else
		{
			/* 否则再次启动ADC */
			/* 进入"自动测量"模式 */
			enter_auto_measure_mode();
			
			/* 启动ADC */
			ADCCON |= (1<<0);
		}
		
	}
	else
	{
		adc_cnt = 0;
		adc_x = 0;
		adc_y = 0;

		ts_timer_disable();
		enter_wait_pen_down_mode();
//如果数据转换完之前再次松开,这里我也会上报数据,0,0,0
		report_ts_xy(0, 0, 0);
	}

	enter_wait_pen_up_mode();
}

那么我们的tslib.c

void get_calibrate_point_data(int lcd_x, int lcd_y, int *px, int *py)
{
	int pressure;
	int x, y;
	
	fb_disp_cross(lcd_x, lcd_y, 0xffffff);

	/* 等待点击 */

	do {
//读取ts坐标值也加上压力值
		ts_read_raw(&x, &y, &pressure); 
//直到压力等于0的时候才返回
	} while (pressure == 0);


	do {
		*px = x;
		*py = y;
//压力值存在的情况下表示按下状态,就一直读取数据
		ts_read_raw(&x, &y, &pressure); 
		printf("get raw data: x = %08d, y = %08d\n\r", x, y);
	} while (pressure);
//打印坐标值
	printf("return raw data: x = %08d, y = %08d\n\r", *px, *py);

	/* 直到松开才返回 */
//我们操作完成后消除 +  
	fb_disp_cross(lcd_x, lcd_y, 0);
}

//我们确定校准为什么不对,我们校准涉及 原始数据 校准公式

//我们把公式使用函数来表示
int get_lcd_x_frm_ts_x(int ts_x)
{
	return g_kx * (ts_x - g_ts_xc) + g_lcd_xc;
}

int get_lcd_y_frm_ts_y(int ts_y)
{
	return g_ky * (ts_y - g_ts_yc) + g_lcd_yc;
}


void ts_calibrate(void)
{

	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的参数: fb_base, xres, yres, bpp */
	get_lcd_params(&fb_base, &xres, &yres, &bpp);

	/* 对于ABCDE, 循环: 显示"+"、点击、读ts原始值 */
	/* A(50, 50) */
	get_calibrate_point_data(50, 50, &a_ts_x, &a_ts_y);	

	/* B(xres-50, 50) */
	get_calibrate_point_data(xres-50, 50, &b_ts_x, &b_ts_y);

	/* C(xres-50, yres-50) */
	get_calibrate_point_data(xres-50, yres-50, &c_ts_x, &c_ts_y);

	/* D(50, yres-50) */
	get_calibrate_point_data(50, yres-50, &d_ts_x, &d_ts_y);
	
	/* E(xres/2, yres/2) */
	get_calibrate_point_data(xres/2, yres/2, &e_ts_x, &e_ts_y);

	/* 确定触摸屏数据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;
//打印ABCDE的坐标值
	printf("A lcd_x = %08d, lcd_y = %08d\n\r", get_lcd_x_frm_ts_x(a_ts_x), get_lcd_y_frm_ts_y(a_ts_y));
	printf("B lcd_x = %08d, lcd_y = %08d\n\r", get_lcd_x_frm_ts_x(b_ts_x), get_lcd_y_frm_ts_y(b_ts_y));
	printf("C lcd_x = %08d, lcd_y = %08d\n\r", get_lcd_x_frm_ts_x(c_ts_x), get_lcd_y_frm_ts_y(c_ts_y));
	printf("D lcd_x = %08d, lcd_y = %08d\n\r", get_lcd_x_frm_ts_x(d_ts_x), get_lcd_y_frm_ts_y(d_ts_y));
	printf("E lcd_x = %08d, lcd_y = %08d\n\r", get_lcd_x_frm_ts_x(e_ts_x), get_lcd_y_frm_ts_y(e_ts_y));
}
  • 我们转换出的XY坐标值不是特别稳定
/* 每10ms该函数被调用一次 
 */
void touchscreen_timer_irq(void)
{
	/* 如果触摸屏仍被按下, 进入"自动测量模式", 启动ADC */
	if (get_status_of_ts_timer() == 0)
		return;

	if (ADCDAT0 & (1<<15)) /* 如果松开 */
	{
		ts_timer_disable();
		enter_wait_pen_down_mode();
		//report_ts_xy(0, 0, 0);
		return;
	}
	else  /* 按下状态 */
	{
		/* 进入"自动测量"模式 */
		enter_auto_measure_mode();

		/* 启动ADC */
		ADCCON |= (1<<0);
	}
}
  • 修改touchscreen-test.c文件
void touchscreen_test(void)
{
	unsigned int fb_base;
	int xres, yres, bpp;

	int x, y, pressure;

	/* 获得LCD的参数: fb_base, xres, yres, bpp */
	get_lcd_params(&fb_base, &xres, &yres, &bpp);

	touchscreen_init();

	/* 清屏 */
	clear_screen(0);

	/* 显示文字提示较准 */
	fb_print_string(70, 70, "Touc cross to calibrate touchscreen", 0xffffff);
	ts_calibrate();

	/* 显示文字提示绘画 */
	fb_print_string(70, yres - 70, "OK! To draw!", 0xffffff);

	while (1)
	{
//如果结果=0则继续执行下面操作
		if (ts_read(&x, &y, &pressure) == 0)
		{
			printf(" x = %d, y = %d\n\r", x, y);
//如果是按下状态,才会描点
			if (pressure)
			{

				fb_put_pixel(x, y, 0xff00);
			}
		}
	}
}

把LCD的电压值,成功转化成屏幕的坐标 要点

  1. 对于触摸屏要多次测量,求平均值
  2. 要丢弃非法值(以LCD分辨率作为判断标准)
  3. 校准时一定要点准

参考tslib库,

「新品首发」STM32MP157开发板火爆预售!首批仅300套

相关推荐

最强聚类模型,层次聚类 !!_层次聚类的优缺点

哈喽,我是小白~咱们今天聊聊层次聚类,这种聚类方法在后面的使用,也是非常频繁的~首先,聚类很好理解,聚类(Clustering)就是把一堆“东西”自动分组。这些“东西”可以是人、...

python决策树用于分类和回归问题实际应用案例

决策树(DecisionTrees)通过树状结构进行决策,在每个节点上根据特征进行分支。用于分类和回归问题。实际应用案例:预测一个顾客是否会流失。决策树是一种基于树状结构的机器学习算法,用于解决分类...

Python教程(四十五):推荐系统-个性化推荐算法

今日目标o理解推荐系统的基本概念和类型o掌握协同过滤算法(用户和物品)o学会基于内容的推荐方法o了解矩阵分解和深度学习推荐o掌握推荐系统评估和优化技术推荐系统概述推荐系统是信息过滤系统,用于...

简单学Python——NumPy库7——排序和去重

NumPy数组排序主要用sort方法,sort方法只能将数值按升充排列(可以用[::-1]的切片方式实现降序排序),并且不改变原数组。例如:importnumpyasnpa=np.array(...

PyTorch实战:TorchVision目标检测模型微调完

PyTorch实战:TorchVision目标检测模型微调完整教程一、什么是微调(Finetuning)?微调(Finetuning)是指在已经预训练好的模型基础上,使用自己的数据对模型进行进一步训练...

C4.5算法解释_简述c4.5算法的基本思想

C4.5算法是ID3算法的改进版,它在特征选择上采用了信息增益比来解决ID3算法对取值较多的特征有偏好的问题。C4.5算法也是一种用于决策树构建的算法,它同样基于信息熵的概念。C4.5算法的步骤如下:...

Python中的数据聚类及可视化分析实践

探索如何通过聚类分析揭露糖尿病预测数据集的特征!我们将运用Python的强力工具,深入挖掘数据,以直观的可视化揭示不同特征间的关系。一同探索聚类分析在糖尿病预测中的实践!所有这些可视化都可以通过数据操...

用Python来统计大乐透号码的概率分布

用Python来统计大乐透号码的概率分布,可以按照以下步骤进行:导入所需的库:使用Python中的numpy库生成数字序列,使用matplotlib库生成概率分布图。读取大乐透历史数据:从网络上找到大...

python:支持向量机监督学习算法用于二分类和多分类问题示例

监督学习-支持向量机(SVM)支持向量机(SupportVectorMachine,简称SVM)是一种常用的监督学习算法,用于解决分类和回归问题。SVM的目标是找到一个最优的超平面,将不同类别的...

25个例子学会Pandas Groupby 操作

groupby是Pandas在数据分析中最常用的函数之一。它用于根据给定列中的不同值对数据点(即行)进行分组,分组后的数据可以计算生成组的聚合值。如果我们有一个包含汽车品牌和价格信息的数据集,那么可以...

数据挖掘流程_数据挖掘流程主要有哪些步骤

数据挖掘流程1.了解需求,确认目标说一下几点思考方法:做什么?目的是什么?目标是什么?为什么要做?有什么价值和意义?如何去做?完整解决方案是什么?2.获取数据pandas读取数据pd.read.c...

使用Python寻找图像最常见的颜色_python 以图找图

如果我们知道图像或对象最常见的是哪种颜色,那么可以解决图像处理中的几个用例,例如在农业领域,我们可能需要确定水果的成熟度。我们可以简单地检查一下水果的颜色是否在预定的范围内,看看它是成熟的,腐烂的,还...

财务预算分析全网最佳实践:从每月分析到每天分析

原文链接如下:「链接」掌握本文的方法,你就掌握了企业预算精细化分析的能力,全网首发。数据模拟稍微有点问题,不要在意数据细节,先看下最终效果。在编制财务预算或业务预算的过程中,通常预算的所有数据都是按月...

常用数据工具去重方法_数据去重公式

在数据处理中,去除重复数据是确保数据质量和分析准确性的关键步骤。特别是在处理多列数据时,保留唯一值组合能够有效清理数据集,避免冗余信息对分析结果的干扰。不同的工具和编程语言提供了多种方法来实现多列去重...

Python教程(四十):PyTorch深度学习-动态计算图

今日目标o理解PyTorch的基本概念和动态计算图o掌握PyTorch张量操作和自动求导o学会构建神经网络模型o了解PyTorch的高级特性o掌握模型训练和部署PyTorch概述PyTorc...