触摸屏(裸机/驱动)编程思想—JZ2440

参考资料:

1.【韦东山】嵌入式Linux应用开发完全手册(旧内核未包含新协议和新API接口——本文的实验平台电阻式触摸屏)
2.【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.4——目前主流开发流程:电容式触摸屏
3.触摸屏-测试过程

触摸屏的种类

  触摸屏主要有电容式、电阻式、红外线式、超声波式。目前较多应用的是电容式。

电阻式触摸屏

  电阻式触摸屏其实就是一种传感器,虽然已经用的不多了,但是还是有过很多的LCD模块采用电阻式触摸屏,这种屏幕可以用四线、五线、七线或八线来产生屏幕偏置电压,同时读回触摸点的电压(A/D转换)。由于其只能一个点响应操作,电阻屏就是单点触摸。 (电阻式触摸屏电压值和坐标值成正比的,所以需要去校准它。校准就是去计算(0, 0)坐标点的电压值是多少)


电阻式硬件接口主要分为两种:1.SoC内置电阻式触摸屏控制器(与ADC模块有关),2. 通过I2C接口发送给主机Soc。


电容式触摸屏

  电容式触摸屏可以支持多点触摸(也可以单点触摸)。多个区块支持多点触摸让电容触摸屏坐标计算变复杂了,但是这个复杂性被电容触摸IC吸收了,还是通过数字接口和主机SoC通信报告触摸信息(触摸点数、每个触摸点的坐标等)。


电容式硬件接口:电容式触摸屏其实是一个I2C从设备,通过I2C接口发送给主机Soc。




触摸屏裸机程序

      在这里插入图片描述

  1. 初始化ADC/TS指令
  2. 设置TS处于等待中断模式
  3. 设置中断寄存器INTSUBMSK和INTMSK
  4. 按下,进入TS中断:a. 进入自动采集模式 ,b. 启动ADC
  5. ADC中断:a. 读数据 ,b. 再次进入“等待中断模式”,c. 启动定时器处理长按或滑动
  6. 定时器中断:a. 若松开,结束, b. 若按下,重新启动

具体源码参考韦东山第一期视频


以下对视频中涉及的难度和编程架构进行分析:

  1. 由于2440硬件只能把nand flash前4K内容复制到片内RAM中,故需修改Makefile将重定位前的代码前移。
objs = start.o init.o nand_flash.o \   /* start.o init.o nand_flash.o 文件大小总和小于4K,后续程序才会成功执行 */
led.o uart.o main.o exception.o interrupt.o timer.o nor_flash.o my_printf.o string_utils.o lib1funcs.o
  1. 定时器中断的注册与卸载框架(操作系统任务调度的一种思想,与时间片的轮询类似)
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];  // 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 unregister_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;
}

/* 定时器中断执行函数 */
void timer_irq(void)
{
	int i;
	for (i = 0; i < TIMER_NUM; i++)
	{
		if (timer_array[i].fp)
		{
			timer_array[i].fp();
		}
	}	
}
  1. 触摸屏的校准(可参考tslib开源库)
        在这里插入图片描述
    tslib中的5点校准法是上述3点校准法的延伸。

     														  五点校准法
     												----------------------------
     												|                          |
     												|  +(A)              (B)+  |
     												|                          |
     												|                          |
     												|                          |
     												|            +(E)          |
     												|                          |
     												|                          |
     												|                          |
     												|  +(D)              (C)+  |
     												|                          |
     												----------------------------
    
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;

// 主要为获取以下全局变量,为后续公式(参考三点校准图) :tmp_x = g_kx * (ts_x - g_ts_xc) + g_lcd_xc;
// tmp_y = g_ky * (ts_y - g_ts_yc) + g_lcd_yc;  全局变量的计算原理参考视频

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

  1. 电阻触摸屏通过ADC时,需AD 芯片的常用滤波处理,使触摸值到达稳定状态。
    a. 对于触摸屏要多次测量求平均值
    b. 要丢弃非法值(以LCD分辨率作为判断准备)
    c. 校准时一定要点准



触摸屏驱动程序

  1. 按下,产生中断
  2. 在中断处理程序里,启动ADC转换X,Y坐标(电压值)
  3. ADC结束,产生ADC中断
  4. 在ADC中断处理函数里,上报(input_event),启动定时器
  5. 定时器时间到,启动ADC转换X,Y坐标(电压值),处理长按和滑动
  6. 松开

通用Touch_Screen代码框架:

static struct input_dev *s3c_ts_dev;
static int s3c_ts_init(void)
{
	/* 1. 分配一个input_dev结构体 */
	s3c_ts_dev = input_allocate_device();

	/* 2. 设置 */
	/* 2.1 能产生哪类事件 */
	set_bit(EV_KEY, s3c_ts_dev->evbit);
	set_bit(EV_ABS, s3c_ts_dev->evbit);

	/* 2.2 能产生这类事件里的哪些事件 */
	set_bit(BTN_TOUCH, s3c_ts_dev->keybit);

	input_set_abs_params(s3c_ts_dev, ABS_X, 0, 0x3FF, 0, 0);
	input_set_abs_params(s3c_ts_dev, ABS_Y, 0, 0x3FF, 0, 0);
	input_set_abs_params(s3c_ts_dev, ABS_PRESSURE, 0, 1, 0, 0);


	/* 3. 注册 */
	input_register_device(s3c_ts_dev);

	/* 4. 硬件相关的操作 */
	
	return 0;
}

static void s3c_ts_exit(void)
{
}

module_init(s3c_ts_init);
module_exit(s3c_ts_exit);
MODULE_LICENSE("GPL");

tslib校准(直接将上传的电压值通过校准转换成坐标值)




  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值