ADC触摸屏
title: ADC触摸屏
tags: ARM
date: 2018-11-02 18:35:45
ADC触摸屏
硬件原理
s3c2440有8通道的ADC,一次同时只能查询一个通道。分为A0~A7。这里的P(positive)表示的是正的意思
ADC通道 | ||
---|---|---|
A4 | TSYM | -Y |
A5 | TSYP | +Y |
A6 | TSXM | -X |
A7 | TSXP | +X |
触摸屏采样有3种方式:
- 自动反转XY轴相关开关采样
- 手动切换开关采样
- 等待中断模式,这个是平时没按下的状态
电阻屏的触摸原理,其实就是在一个均匀的电阻上采样后得到电压,然后基于vcc
算出相对偏移.假设电阻总长为L
,采样电压为V1
,那么长度偏移则是V/DVDD*L
.
基于此在X方向和Y方向均有均匀电阻.所以触摸屏实际是两片透明且均匀的电阻,不按下的时候中间并不导通.转换选择导通X方向与Y方向依次测的X坐标与Y坐标.也就是先连接Xm--Xp
,侧的Yp
的采样,就能获得X的偏移.
板载电路
这里X轴和Y轴接反了,尅使用Tslib库
旋转倒置等
等效电路
关闭模式:断开上拉电阻与4线电路,防止漏电流
空闲等待中断:这个状态是平时没有按下触摸屏,等待按下触发一个按下的中断,当左右两边电阻触发的时候,导通了XP
到YM
到GND
,这将使Y_ADC=0,--↓__
产生一个下降沿等待中断模式设置值为 ADCTSC=0xd3; // XP_PU, XP_Dis, XM_Dis,YP_Dis,YM_En
同样的,当按下后,还是同样的等效电路,当松开的时候,会有一个上升延中断.配置ADCTSC
的BIT8
即可.
X轴采样:这里连通XP-XM
,采样X_ADC
Y轴采样:这里连通YP-YM
,采样Y_ADC
测量逻辑
触摸屏实际有两层,按下的时候,导通了上下两个平面,通过等效电路,可以看出通过切换开关,能够得到两种阻值。
- 按下触摸屏触发中断,打开ADC采样,等待ADC采样完成中断
- 松开触摸屏触发中断,退出流程
- ADC中断中获得
XY
的坐标,然后依然需要采样输出,这里可以采用打开定时器,定时采样 - 定时器中断到后,判断是否抬起,如果依然按下,触发ADC采样,这里关闭定时器自身的处理函数(关闭定时器中断).如果抬起,触摸屏转换到等待状态,关闭自身中断.
- 流程图在这里
程序设计(一)获得ADC
寄存器初始化
这里的DELAY 可以用作稳定ADC输出,也就是按下后多长时间开始采样
/*
1. 设置允许分配,分配系数为49+1,时钟为100M/50=2
2. 选择A0通道,因为后面选择自动转换,可以不考虑通道
*/
ADCCON = (1<<14) | (49<<6) | (0<<3);
/* 按下触摸屏, 延时一会再发出TC中断
* 延时时间 = ADCDLY * 晶振周期 = ADCDLY * 1 / 12000000 = 5ms
*/
ADCDLY = 60000;
中断初始化
//清除挂起标志
SUBSRCPND = (1<<TC_INT_BIT) | (1<<ADC_INT_BIT);
//取消次级屏蔽
INTSUBMSK &= ~((1<<ADC_INT_BIT) | (1<<TC_INT_BIT));
//注册中断函数,INTMSK &= ~(1<<irq); 取消源的mask
register_irq(31, AdcTsIntHandle);
void register_irq(int irq, irq_func fp)
{
irq_array[irq] = fp;
INTMSK &= ~(1<<irq);
}
ADC模式(中断、测量)
ADC在工作中存在3个模式的切换,空闲的时候进入等待按下中断的模式,然后进入自动测量的模式,在测量完成后需要进入等待松开的中断模式.此时可以设置定时器等待触发下一次的自动测量
// 空闲下等待触发落下中断
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;
}
中断函数
- 定时器中断函数
- adc中断函数,包括adc采样完成中断和触摸屏触发中断
备注:可以发现,松开状态下进入中断,都进入空闲等待按下中断模式
触摸屏中断
if 松开中断
关闭一切,进入等待按下模式
else 按下中断
进入自动测量模式
打开adc
定时器中断
if 松开
关闭定时器
进入等待按下模式
else 按下
进入自动测量模式
打开adc
ADC中断
if 松开
关闭定时器
进入等待按下模式
else 按下
打印adc值
*进入等待中断模式
打开定时器
//这里可以优化做平均值
if 松开
关闭定时器
进入等待按下模式
上报数据
else 按下
if 测量计数到达16次
返回平均值,开启定时器
else
直接进入自动测量模式
优化版本
进入adc中断
进入触摸屏中断
进入定时器中断后 都先关闭定时器
进入adc中断后
if按下
满16次采样后打开定时器,进入等待松开中断
未满16次继续打开adc采样
else 松开
进入等待按下中断
上报0
进入触摸屏中断
if 按下
打开adc开始采样
else 松开
进入等待按下中断
上报0
进入定时器中断且当前定时器状态为open
if 按下
打开adc采样
else 松开
进入等待按下中断
上报0
程序设计(二)获得坐标
同理,Y轴的坐标也按照相同的方式计算.程序设计中依次画出5个十字架,用户点击后计算K与b偏差
生产者与消费者
生产者:这里ADC完成测量后上报ADC采样,可以理解为生产者.在ADC采样完成16次并且依然按下的情况下上报实际adc,其他情况上报0.这里设置一个标志,只有等消费者取出数据之后,再上传数据.这里都是在中断中上报数据
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;
}
状态标志: g_ts_data_valid
是标志.0表示消费者已经取走数据,无新数据产生
ADC获取
- 等待点击,直到按键按下
- 按下后检测弹开,后上报数据坐标
/* 等待点击 */
do {
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);
- 判断
XY
是否颠倒.取X轴上的两个坐标A-----B
,那么BX-AX
应大于BY-AY
,BY-AY
约等于0
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 - a_ts_y;
if (dx < 0)
dx = 0 - dx;
if (dy < 0)
dy = 0 - dy;
if(dx > dy)
return 0; /* xy没有反转 */
else
return 1; /* xy反了 */
}
- 如果颠倒的话,需要将每个点的X与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)+ |
| |
| |
| |
| +(E) |
| |
| |
| |
| +(D) (C)+ |
| |
----------------------------
*/
/* 确定公式的参数并保存 */
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;
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));
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;
}
程序优化
视频教学修改要点
- 启动ADC时不应该进入等待中断模式,它会影响数据,视频教程中会有adc中断和定时器中断碰撞的问题,也就是adc采样未完成,可能先发生定时器中断的问题,然后定时器中断去触发等待中断的模式
- 只有在"等待中断模式"下才可以使用ADCDAT0'BIT 15来判断触摸笔状态
- 校准非常重要,所以在程序种多次测量求平均值(不仅仅是在adc中断中求平均值)
寄存器ADCDAT0
只有在等待中断的模式中才能用来判断是按下还是松开状态,所以定时器中断中不能用该寄存器.所以当定时器中断发生在ADC采样中的时候,不应该打断adc采样.韦东山的优化是先判断是否是自动采样模式,如果是在采样则退出.
void touchscreen_timer_irq(void)
{
//定时器开关
if (get_status_of_ts_timer() == 0)
return;
/*------------------------------------------------------------
定时器开关只会被ADC采样16次完成后打开,其他状态下均会关闭定时器,
包括进入本函数这里的按下状态后进入自动测量模式
***************************************************************/
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);
}
}
个人修改意见
我觉得更应该更改为如果开启了adc的采样,应该是去关闭定时器的标志.防止碰撞.定时器中断必须在采样16次完成之后才会发生.然后进入定时器中断处理的时候就能确保不会与adc中断冲突,也就是一定是在等待中断模式,上述的is_in_auto_mode
也是可以去除的.
if (is_in_auto_mode())
return;
所以我的优化方案是
进入adc中断
进入触摸屏中断
进入定时器中断后 都先关闭定时器
进入adc中断后
if按下
满16次采样后打开定时器,进入等待松开中断
未满16次继续打开adc采样
else 松开
进入等待按下中断
上报0
进入触摸屏中断
if 按下
打开adc开始采样
else 松开
进入等待按下中断
上报0
进入定时器中断且当前定时器状态为open
if 按下
打开adc采样
else 松开
进入等待按下中断
上报0
总结
- 处理好各种中断下的模式
- 判断断开还是按下应该是在等待中断模式下的
- 校准值应该求平均
- 采样画点值也该求平均
TODO
参考tslib 中更牛逼的矫正算法
ADC触摸屏的更多相关文章
- linux设备驱动归纳总结(十三):1.触摸屏与ADC时钟【转】
本文转载自:http://blog.chinaunix.net/uid-25014876-id-119723.html linux设备驱动归纳总结(十三):1.触摸屏与ADC时钟 xxxxxxxxxx ...
- JZ2440 裸机驱动 第14章 ADC和触摸屏接口
本章目标: 了解S3C2410/S3C2440和触摸屏的结构: 了解电阻触摸屏的工作原理和等效电路图: 了解S3C2410/S3C2440触摸屏控制器的多种工作模式: ...
- 【Linux开发】linux设备驱动归纳总结(十三):1.触摸屏与ADC时钟
linux设备驱动归纳总结(十三):1.触摸屏与ADC时钟 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...
- FL2440驱动添加(5)ADC驱动学习笔记
由图可知,模拟ADC分为两部分功能,一部分是触屏功能,另一部分就是普通ADC功能.分别可以产生INT_TC和INT_ADC 两个中断.该ADC模块总共有8个通道可以进行模拟信号的输入,分别是AIN0. ...
- ARM-Linux驱动-触摸屏驱动分析
出处:http://blog.csdn.net/geekcome/article/details/6580981 硬件平台:FL2440 内核版本:2.6.28 主机平台:Ubuntu 11.04 内 ...
- S3C2440触摸屏驱动实例开发讲解
出处:http://www.embeddedlinux.org.cn/html/yingjianqudong/ 一.开发环境 主 机:VMWare--Fedora 9 开发板:Mini2440--6 ...
- linux 触摸屏驱动
目录 linux 触摸屏驱动 输入子系统怎么写? 触摸屏事件 事件分类 事件设置 硬件配置 设计思路 完整程序 测试 ts_lib 使用 问题小结 title: linux 触摸屏驱动 tags: l ...
- jz_2440_电阻屏触摸驱动
驱动中: 入口函数init内: /* 1. 分配一个input_dev结构体 */ s3c_ts_dev = input_allocate_device(); /*------------------ ...
- linu触摸屏幕
一..前提知识 1.Linux输入子系统(Input Subsystem): 在Linux中,输入子系统是由输入子系统设备驱动层.输入子系统核心层(Input Core)和输入子系统事件处理层(Eve ...
随机推荐
- Nginx grpc反向代理
L111 首先Grpc 默认编译进Nginx 但是依赖http_v2模块 需要编译进nginx 具体指令可以参考Nginx http 反向代理 指令都类似 分布式反向代理 server { serve ...
- Django-urls路由系统
Django的路由系统 Django 1.11版本 URLConf官方文档 URL配置(URLconf)就像Django 所支撑网站的目录.它的本质是URL与要为该URL调用的视图函数之间的映射表. ...
- C++:如何正确的定义一个接口类
C++中如何定义接口类?首先给接口类下了定义:接口类应该是只提供方法声明,而自身不提供方法定义的抽象类.接口类自身不能实例化,接口类的方法定义/实现只能由接口类的子类来完成. 而对于C++,其接口类一 ...
- Editor markdown编辑器
代码示例网址:http://pandao.github.io/editor.md/examples/index.html 引入文件 <link rel="stylesheet" ...
- 洛谷P1226 【模板】快速幂||取余运算
题目描述 输入b,p,k的值,求b^p mod k的值.其中b,p,k*k为长整型数. 输入输出格式 输入格式: 三个整数b,p,k. 输出格式: 输出“b^p mod k=s” s为运算结果 S1: ...
- DRF 视图和路由
Django Rest Feamework 视图和路由 DRF的视图 APIView 我们django中写CBV的时候继承的是View,rest_framework继承的是APIView,那么他们两个 ...
- BZOJ5203 [NEERC2017 Northern] Grand Test 【dfs树】【构造】
题目分析: 首先观察可知这是一个无向图,那么我们构建出它的dfs树.由于无向图的性质我们可以知道它的dfs树只有返祖边.考虑下面这样一个结论. 结论:若一个点的子树中(包含自己)有两个点有到它祖先的返 ...
- Matplotlib学习---用matplotlib和sklearn画拟合线(line of best fit)
在机器学习中,经常要用scikit-learn里面的线性回归模型来对数据进行拟合,进而找到数据的规律,从而达到预测的目的.用图像展示数据及其拟合线可以非常直观地看出拟合线与数据的匹配程度,同时也可用于 ...
- Visible Trees HDU - 2841
Visible Trees Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Tot ...
- CSAPC2008 skyline
一座山的山稜线由许多片段的45度斜坡构成,每一个片段不是上坡就是下坡. * * * /\* /\ /\/ \/\/ \/ \ 在我们眼前的所见的任何宽度为n个单位的 ...