文章目录
- 001 ADC硬件原理
- 硬件特性
- s3c2440的ADC硬件原理图![s3c2440的ADC硬件原理图](https://img-blog.csdnimg.cn/20200212151829301.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mjg4MTQxOQ==,size_16,color_FFFFFF,t_70)
- s3c2440的ADC框图
- 002 ADC编程
- 003 电阻触摸屏硬件原理
- 003 S3C2440触摸屏接口
- 005触摸屏编程_按下松开检测
- 006ADC中断
- 007定时器程序优化
- 009校准原理
- 010校准与画线
- 012 编程完善
001 ADC硬件原理
硬件特性
s3c2440的ADC硬件原理图
s3c2440的ADC框图
- 怎么设置:
- a.设置8:1mux,选中要测量哪个引脚
- b.设置工作时钟
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FpI2iF6S-1581491700386)(en-resource://database/2384:1)] - c.启动
- d.读状态,判断ADC成功
- e.读数据
002 ADC编程
- 目标:
- a.初始化ADC
- b.读数据
- c.在串口上显示出来
- d.在LCD上显示出来
设置ADC寄存器
ADCCON
ADCTSC
ADCDLY
ADCDATA0
void adc_init(void)
{
/* [15] :ECFLG ,1 = End of A/D conversion
* [14] : PRSCEN ,1 = A/D converter prescaler enable
* [13:6]: PRSCVL ,adc clk = PCK / (PRSCVL + 1)
* [5:3] : SEL_MUX ,000 = AIN 0
* [2] : STDBM ,1 = Standby mode
* [1] : READ_ START ,0 = Disable start by read operation
* [0] : ENABLE_START,1 = A/D conversion starts and this bit is cleared after the startup.
*/
ADCCON = (1<<14) | (49<<6) | (0<<3) ;
ADCDLY = 0xff;
}
int adc_read_ain0(void)
{
/* 启动adc */
ADCCON |= (1<<0);
while(ADCCON & (1<<15)); /* 等待ADC结束 */
return ADCDAT0 & 0x3ff;
}
003 电阻触摸屏硬件原理
触摸屏示意图
测量触点X座标 | 测量触点Y座标 |
---|---|
Xp接3.3v,Xm接地,Yp、Ym不接电源 | Yp接3.3v,Ym接地,Xp、Xm不接电源 |
测Yp电压(就是X座标) | 测Xp电压(就是Y座标) |
使用触摸屏流程
- 1.按下触摸屏,产生触摸中断
- 2.在触摸屏中断程序中,启动ADC(目的:获得x,y座标)
- 3.ADC完成,产生中断
- 4.在ADC中断中,读取x,y座标
- 5.启动定时器
- 6.定时器中断发生,判断触摸屏仍被按下,回到第2步。
- 7.松开,结束。
003 S3C2440触摸屏接口
编程要点
ADC转化中断时,可以通过中断或者查询来得到数据
- 使用中断模式时,从AD转换开始到得到数据可能有些延迟,因为中断的进入和退出需要浪费一些时间。
- 如果像要立刻得到数据,可以使用ADC的查询方式,查询ADCCON[15],判断转化是否结束 。
ADCTSC设置与触摸屏等效电路图
- 触摸屏等待按下接口程序
void enter_wait_pen_dowm_mode(void)
{
ADCTSC = PULLUP_ENABLE | YM_ENABLE | YP_DISABLE | XP_DISABLE | XP_DISABLE | WAIT_INT_MODE ;
}
ADC/TS与中断的控制流程
怎么编程
- 1.初始化ADC/TS接口
- 2.设置TS处于等到中断
- 3.设置中断
- 4.按下,进去TS中断
- a.进入自动采集模式
- b.启动ADC
- 5.ADC中断
- a.读数据
- b.再次进入”等待中断模式“
- c.启动定时器
- 6.定时器中断
- a.若松开,结束
- b.若按下,进入4.b
005触摸屏编程_按下松开检测
- 状态转换图
- 注意:adc和触摸屏公用一个中断,利用SUBSRCPND中的位,判断是哪种中断
void AdcTsIntHandle(int irq)
{
if(SUBSRCPND & (1<<ADC_INT_BIT)) /* 如果是触摸屏中断 */
Tsr_Tc();
if(SUBSRCPND & (1<<TC_INT_BIT)) /* ADC中断 */
Isr_Adc();
}
判断按下松开
void Tsr_Tc(void)
{
if(ADCUPDN & (1<<1))
printf("pen up\n\r");
if(ADCUPDN & (1<<0))
printf("pen dowm\n\r");
}
006ADC中断
007定时器程序优化
在timer.c中,在中断服务函数中,应该让他从某个数组中,把需要定时器处理的函数依次执行。
- 函数指针数组:往数组中写函数。
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];
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 register_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;
}
#define NULL ((void *)0)
009校准原理
- 问题:得到触点的(x,y)怎么换算出LCD的(x,y)
- 1.利用比例
- 2.但是由于边界点不准,因此选点
- 3.由于制作工艺不均匀,上下左右都有差异
010校准与画线
程序思路:
- 一
- 1.在A点显示“+”
fb_disp_cross(int x, int y)
- 2.客户点击“+”
ts_read_raw()//读到原始数据
- 3.记录触摸屏座标
- 二在B、C、D、E、上循环操作:显示、点击、读取操作
- 三、根据数据,确定公式
ts_calibrate()//构造公式
- 四、以后得到TS触点时,可以转换出LCD座标
ts_read()//
- 1.根据思路写出基本函数
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;
void get_calibrate_point_data(int lcd_x, int lcd_y, int *px, int *py)
{
fb_disp_cross(lcd_x, lcd_ y, 0xffffff);
/* 等待点击 */
ts_read_raw(px, py);
}
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 - b_ts_x;
if(dx < 0)
dx = 0 - dx;
if(dy < 0)
dy = 0 - dy;
if(dx > dy)
return 0; /* xym没有反转 */
else
return 1; /* xy反了 */
}
void swap_xy(int *px, int *py)
{
int tmp = *px;
*px = *py;
*py = tmp;
}
/*
---------------------------------
| |
| +(A) +(B) |
| |
| +(E) |
| |
| +(C) +(D) |
| |
---------------------------------
*/
void ts_calibrate(void)
{
unsigned int fb_base;
int xres, yres, bpp;
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的参数 */
get_lcd_params(&fb_base,&xres,&yres,&bpp);
/* 对于ABCDE,循环:显示“+"、点击、读ts原始值 */
/* A(50, 50) */
get_calibrate_point_data(50, 50, &a_ts_x, &a_ts_x);
/* B(xres-50, 50) */
get_calibrate_point_data(xres-50, 50, &b_ts_x, &b_ts_x);
/* C(xres-50, yres-50) */
get_calibrate_point_data(xres-50, yres-50, &c_ts_x, &c_ts_x);
/* D(50, yres-50) */
get_calibrate_point_data(50, yres-50, &d_ts_x, &d_ts_x);
/* E(xres/2, yres/2) */
get_calibrate_point_data(xres/2, yres/2, &e_ts_x, &e_ts_x);
/* 确定触摸屏数据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;
}
/*
*读TS原始数据,转换为LCD座标
*/
void ts_read(int *lcd_x,int *lcd_y)
{
int ts_x,ts_y;
ts_read_raw(&ts_x, &ts_y);
if(g_ts_xy_swap)
{
swap_xy(&ts_x, &ts_y);
}
/* 使用公式计算 */
*lcd_x = g_kx * (ts_x - g_ts_xc) + g_lcd_xc;
*lcd_y = g_kx * (ts_y - g_ts_yc) + g_lcd_yc;
}
- 2.第二个问题:触摸屏上报的x轴y轴相反,
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 - b_ts_x;
if(dx < 0)
dx = 0 - dx;
if(dy < 0)
dy = 0 - dy;
if(dx > dy)
return 0; /* xym没有反转 */
else
return 1; /* xy反了 */
}
/* 确定触摸屏数据XY是否反转 */
g_ts_xy_swap = is_ts_xy_swap(a_ts_x, a_ts_y, b_ts_x, b_ts_y);
- 3.第三个问题:如何对调XY的座标–对调函数
void swap_xy(int *px, int *py)
{
int tmp = *px;
*px = *py;
*py = tmp;
}
/* 确定触摸屏数据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);
}
- 总结:
- a.对于触摸屏要多次测量求平均值
- b.要丢弃非法值(以lcd分辨率作为判断条件)
- c.校准时一定要点准
012 编程完善
- 问题:
- 第一次点击触摸屏,会出现2个点
- 长按,LCD上的点越来越大。
根源:使用ADC得到的座标值不稳定。
- 方法
- 参考tslib :
- a.使用矩阵进行校准,适用性更强
- b.使用多种方法消除误差:多次测量,判断相邻点的距离,如果突然变化很大,可能就是错误值。
- 修改要点:
- 1.启动ADC时不用改进入等待中断模式,它会影响数据
-
- 只有在”等待中断"模式下才可以使用ADCDATA0’bit15来判断触摸笔状态
- 3.校准非常重要,多以在程序中多次测量求平均值你(不仅是在ADC中断中求平均值)。