s3c2440arm裸机编程之ADC触摸屏
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没有反转 */elsereturn 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 中更牛逼的矫正算法
转载:https://www.cnblogs.com/zongzi10010/p/10023639.html
s3c2440arm裸机编程之ADC触摸屏相关推荐
- 【ARM】Tiny4412裸板编程之ADC
00. 目录 文章目录 00. 目录 01. 开发环境 02. ADC概述 03. ADC特性 04. ADC模块图 05. ADC寄存器 06. ADC电路连接 07. 程序示例 08. 附录 01 ...
- 【ARM】Tiny4412裸机编程之LED(一)
00. 目录 文章目录 00. 目录 01. 控制原理 02. 配置寄存器 03. 程序示例一 04. 程序示例二 05. 程序示例三 06. 附录 01. 控制原理 咱们的LED在核心板上,所以需要 ...
- 【ARM】Tiny4412裸机编程之GPIO简介
00. 目录 文章目录 00. 目录 01. GPIO概述 02. GPIO寄存器 03. GPIO框图 04. 附录 01. GPIO概述 GPIO(General Purpose I/O Port ...
- 异步编程之Promise(2):探究原理
异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...
- cyclicbarrier java_Java并发编程之CyclicBarrier和线程池的使用
原标题:Java并发编程之CyclicBarrier和线程池的使用 下面我们来讲述一下线程池和CyclicBarrier的使用和对比. 一.场景描述 有四个游戏玩爱好者玩游戏,游戏中有三个关卡,每一个 ...
- java线程安全的set_Java并发编程之set集合的线程安全类你知道吗
Java并发编程之-set集合的线程安全类 Java中set集合怎么保证线程安全,这种方式你知道吗? 在Java中set集合是 本篇是<凯哥(凯哥并发编程学习>系列之<并发集合系列& ...
- linux c编程之fcntl
fcntl可实现对指定文件描述符的各种操作,其函数原型如下: int fcntl(int fd, int cmd, ... /* arg */ ); 其中,操作类型由cmd决定.cmd可取如下值: F ...
- python 多线程编程之_thread模块
python 多线程编程之_thread模块 参考书籍:python核心编程 _thread模块除了可以派生线程外,还提供了基本的同步数据结构,又称为锁对象(lock object,也叫原语锁.简单锁 ...
- java 网络编程简单聊天_网络编程之 TCP 实现简单聊天
网络编程之 TCP 实现简单聊天 客户端 1.连接服务器 Socket 2.发送消息 package lesson02;import java.io.IOException;import java.i ...
最新文章
- html javascript 字符串和数组互转 字符串拼接 数组拼接
- 做为一名IT新人,必了解程序员与产品经理的恩怨情仇
- C# 通过pid获取hwnd / 通过pid查找hwnd
- led大屏按实际尺寸设计画面_年会活动要用LED大屏还是投影?专业行家都是看这些数据。...
- python人脸检测与微信小程序_python+requests对app和微信小程序进行接口测试
- 2021年中国车内娱乐和信息系统市场趋势报告、技术动态创新及2027年市场预测
- [20170203]dg磁盘空间不足的处理.txt
- c# 读取写入excel单元格(包括对excel的一些基本操作)
- Fluentd日志处理-tail拉取(三)
- android aysncTask面试解析
- JUC总览,来自汪文君整理
- 用这个玩吃鸡:宏按键加一键恢复加自由移动视角,你想要的功能它都有
- 计算机的内存的材料是什么,内存条到底是干啥的?手把手的告诉你
- Oralce性能优化-绑定变量窥视
- 怎么翻译图片上的英文?图片翻译英文方法分享。
- 全网页都变灰了,这是怎么实现的?
- gateway使用教程
- DHCP服务器是什么?
- Linux篇之解决root密码修改失败报错之Authentication token manipulation error
- 计算机与汽车的论文,汽车计算机网络技术论文