【S3C2440】第18课、ADC与触摸屏之学习笔记


课十八、ADC和触摸屏
节二、ADC编程
1、vol = (double)val/1023*3.3;    /* 0xff=1023--3.3v */
需要强制类型转换,不然会打印为0.000!
例如:
视频打印:
vol: 1.125v
我的打印:
NOr:vol: 0.000000V00V
Nand:vol: 0.000000Vv0000V
修改后打印:
vol: 1.270V25V
vol: 1.154V25V
补:多出来的部分为printf()函数的问题。

2、编译时,gcc编译警告: 
lcd/font.c: In function `fb_print_char':
lcd/font.c:24: warning: initialization discards qualifiers from pointer target type
错误代码:
font.c>>24行:unsigned char * dots = &fontdata_8x16[c*16];
引用位置:const unsigned char fontdata_8x16[FONTDATAMAX] = {...};
原因查找:
const unsigned char 被赋值给unsigned char 类型,丢掉了const qualifier。如果非要这样用,你需要把const void * 给cast为void *类型:
unsigned char * c = (unsigned char *)str;

节4:s3c2440触摸屏接口
ADCDAT0[15][14][13:12] = ADCDAT1[15][14][13:12] = ADCTSC[8][2][1:0]【成立!】
判断触摸笔落下与抬起状态:ADCDAT0[15] = ADCDAT1[15] = ADCTSC[8]【?=】ADCUPDN[1][0];【未知】

节5:编程_按下/松开检测
1、刚进入enter_wait_pen_up/down_mode()函数时,ADCTSC寄存器的设置和开关的关系,以及联想触摸屏的内部结构!

2、当程序持续出现bug而找不到原因时,可以把每个进程使用到的寄存器都打印出来,如此更方便观察每个进程的运行状况(通用异步收发器
UART的作用即在此),更方便查找问题的原因!
使用技巧:    a.在每个不同的进程做标号;
            b.打印全部关键使用到的寄存器(尤其在进程开始和结束的位置);

3、ADC/TC中断,使用触摸屏期间不需要清中断吗?触摸屏中断的函数调用(即中断处理)流程是什么?
答:
while(1);→点击触屏→异常向量表→跳转指令→handle_irq()→AdcTsIntHandle()→SubInt_Ts_irq()→printf("pen up/pen down")+enter_wait_pen_down/up_mode()→
返回SubInt_Ts_irq()→返回AdcTsIntHandle()清中断→handle_irq()→返回执行跳转指令的下条指令,退出中断→while(1);→→→


4、对于ADC的A/D转换之后的数据读取,需要指令序列:
    ADCCON |= (1<<0);                  # 手动启动ADC的A/D转换;
    while(!(ADCCON & (1<<15)));     # 判断A/D转换的进程状态,等待A/D转换结束;
    return ADCDAT0 & 0x3ff;            # 读A/D转换数据后X方向的转换数值;
但对于TC的数据的读取呢?其需要的指令序列呢?
对于本节课程只是判断触摸笔按下/松开的状态,并未涉及到读取坐标数据,猜测:对于数据的读取的指令和寄存器读取并未使用;

5、指令序列:
    ADCCON = (1<<14) | (49<<6) | (0<<3);
    ADCDLY = 0xff;
1)于目前检测触摸屏的笔按下/松开状态检测的意义?
答:设置AD的工作模式,开启A/D转换;目前可以去掉?为何不并入ADCCON寄存器初始化;
2)对于后期触摸屏工作的意义?


6、在main()函数内,同时存在指令序列:
    touchscreen_test();
    while(1){adc_test();}
触摸屏的笔按下/松开状态检测,将不成功!
答:实验是成功的!之前没有成功是因为串口工具MobaXterm的问题!旧版10.4工具刚打开可以正常打印,使用十几分钟之后就不能打印了!
重新安装新串口工具就好了!


节六:
1、疑问代码如下:
    void enter_auto_measure_mode(void)
    {
        ADCTSC = AUTO_PST | NO_OPR_MODE;
    }
问题:ADCTSC[1:0]为什么不是【0b11 = 等待中断模式】而是【0b00 = 等待中断模式】?
还有对于测量坐标反转的问题是不是该条指令初始化的问题?是否应该修改为:
    ADCTSC |= (AUTO_PST | NO_OPR_MODE);
    或者    ADCTSC = WAIT_PEN_DOWN | PULLUP_ENABLE | YM_ENABLE | YP_DISABLE | XP_DISABLE | XM_DISABLE | AUTO_PST | NO_OPR_MODE;
答:实验验证,不是该条指令导致的反转问题,当 void enter_wait_auto_measure_mode(void){ADCTSC |= AUTO_PST;}时,亦可以正常读取触点
坐标 X,Y 的值;  视频程序应该是为了再读取A/D转换之后的数据时,不再进行触摸屏中断?

2、打印x,y坐标不线性的问题的解决,添加代码如下:
    if (!(x & (1<<15))) /* 如果仍然按下才打印 */
    {
        x &= 0x3ff;
        y &= 0x3ff;
        
        printf("x = %08d, y = %08d\n\r", x, y);
    }

3、/* 功能: adc/tc总中断处理函数; adc/tc同时发生,同时处理 
    */
    void AdcTcIntHandle(int irq){...}
tc中断,是基于检测触摸笔按下或者松开是否发生, 并紧接着处理ADC中断;
ADC中断处理是基于测量触电电压的X/Y双向(测量两次)的A/D转换值;
问题1:是不是触摸笔“按下”“松开”两种状态都可以触发 INT_TC 中断?若是,为何只有在“按下”中断时才可且有读取且打印A/D转化的数据,
“松开”却不会读数据并且也没有打印数据?
答1:通过在点击屏幕的同时main()内while(1){}内的LCD程序的几何图案的正常显示可知,在触摸笔保持“按下”尚未“松开”时,程序未在 INT_ADC 中断之中;
但是,当“松开”中断时,并不打印 X,Y 且第二次“按下”打印依然正常有效,因此可以断定:“松开”中断并不触发INT_AD中断(仅触发INT_TC中断)!不会进入
SubInt_Adc_irq()中断处理函数!
而“按下”“松开”两种操作两次进入SubInt_Tc_irq()函数;
问题2:INT_AD触发的条件?INT_TC触发的条件?
4、测试INT_AD触发的条件?INT_TC触发的条件?

测试文件:touchscreen_with_timer文件包;
main.c:
    while(1)
    {
        /* ADC测试 */
        enter_auto_measure_mode();

        /* 使能ADC转换 */
        ADCCON |= (1<<0);
        x = ADCDAT0 & 0x3ff;
        y = ADCDAT1 & 0x3ff;
        
        printf("\n\r00, x = %08d, y = %08d\n\r", x, y);
        enter_wait_pen_down_mode();
    }
touchscreen.c:
    void SubInt_Tc_irq(void)
    {
        if(ADCDAT0 & (1<<15))                //此时触摸笔为抬起状态;
        {
            enter_wait_pen_down_mode();
        }    
        else                                //此时触摸笔为落下状态;
        {
            enter_auto_measure_mode();
            /* 使能ADC转换 */
            ADCCON |= (1<<0);
        }
        printf("\n\r 11_2_SubInt_Tc_irq! \n\r");
    }
    void SubInt_Adc_irq(void)
    {
        int x, y;
        if(!(ADCDAT0 & (1<<15)))                
        {
            x = ADCDAT0 & 0x3ff;
            y = ADCDAT1 & 0x3ff;
            printf("11, x = %08d, y = %08d\n\r", x, y);
        }    
        else
        {
            printf("\n\r11_3_SubInt_Adc_irq_enable");
        }
        printf("\n\r 11_2_SubInt_Adc_irq \n\r");
        enter_wait_pen_up_mode();
    }


实验及现象及结果:
    实验1:如上代码; 不做任何触摸屏幕操作;
    目的:探究 INT_AD 与 INT_TC 中断,的真正的中断产生条件或者产生的方法的种类;
    打印1:    
        00, x = 00000000, y = 00011, x = 00000000, y = 00001016

         11_2_SubInt_Adc_irq
        00000

         11_2_SubInt_Tc_irq!
    结论1:使能    ADCCON[0]启动A/D转换和ADCTSC = AUTO_PST | NO_OPR_MODE; 就会产生INT_ADC中断!进入【SubInt_Adc_irq()函数】【SubInt_Tc_irq()函数】;
    实验2:屏蔽main.c中while(1)内的代码; 慢动作触摸屏幕;
    打印2:下笔:     11_2_SubInt_Tc_irq!
                    11, x = 00000418, y = 00000662

                    11_2_SubInt_Adc_irq
            抬笔:
                    11_2_SubInt_Tc_irq!
    结论2:触笔"按下"可以触发INT_AD、INT_TC中断,"松开"只可以触发INT_TC中断;
    实验3:代码如实验2,操作闪击触摸屏;
    现象3:无打印结果!
    结论3:

    实验4:main()中的指令enter_auto_measure_mode();更换为下面指令之一,不做触摸屏幕操作;
            a.//ADCTSC = AUTO_PST | NO_OPR_MODE;
            b.//ADCTSC = AUTO_PST;        //1 = 自动顺序 X 方向和 Y 方向测量(AUTO_PST);    0 = 正常 ADC 转换;  
            c.//ADCTSC = NO_OPR_MODE;    //00 = 无操作模式(NO_OPR_MODE);    11 = 等待中断模式;
    打印4:使用a.并屏蔽,打印如打印4.a:
                    不触摸:00, x = 0000
                            11_3_SubInt_Adc_irq_enable
                             11_2_SubInt_Adc_irq
                            0000, y = 00000000    
                    触摸屏幕:
                    第一次:11_2_SubInt_Tc_irq!
                    第二次:11_2_SubInt_Tc_irq!
                            11, x = 00000391, y = 00000747

                             11_2_SubInt_Adc_irq

                             11_2_SubInt_Tc_irq!
            小结a:     INT_AD次级中断的触发只受寄存器ADCCON[0]A/D转换启动位的影响,不受ADCTSC = AUTO_PST | NO_OPR_MODE位的影响;
                    点击屏幕,可以同时触发INT_AD/TC次级中断;
            开启b.,打印如打印4.b:    
                    不触摸:00, x = 00000000, y = 00011, x = 00000000, y = 00001019

                             11_2_SubInt_Adc_irq
                            00000

                             11_2_SubInt_Tc_irq!
                    触摸屏幕:     11_2_SubInt_Tc_irq!
                                11, x = 00000330, y = 00000652

                                 11_2_SubInt_Adc_irq

                                 11_2_SubInt_Tc_irq!
            小结b: 开启b指令的作用和指令enter_auto_measure_mode()的作用相同,实验结果如同实验1的结果!
            开启c.,打印如打印4.c:
                    不触摸:    
                            00, x = 0000
                            11_3_SubInt_Adc_irq_enable
                             11_2_SubInt_Adc_irq
                            0945, y = 00000624
                    触摸屏幕:
                    第一次:11_2_SubInt_Tc_irq!
                    第二次:11_2_SubInt_Tc_irq!
                            11, x = 00000399, y = 00000624

                             11_2_SubInt_Adc_irq

                             11_2_SubInt_Tc_irq!
            小结c:  当不对寄存器ADCTSC初始化时,其自动取用默认值,
测试结果:

答:INT_AD/TC产生的【共同前提条件:】a.使能INT_ADC_TC中断; b.配置并初始化触摸屏/ADC接口寄存器;
【INT_AD触发的前提条件:】 c.配置寄存器ADCTSC'[1:0]=等待中断模式/无操作模式, 自动顺序X方向和Y方向测量; d.配置ADCCON寄存器,使能 A/D 转换启动;
e.自动(顺序)X/Y 方向转换模式:设置 ADCCON(ADC 控制寄存器)初始化,在自动方向转变模式中触摸控制器在写入 X 测量数值到 ADCDAT0 和写入 
Y 测量数值到 ADCDAT1 后,触摸屏接口产生中断源给中断控制器。
【INT_TC触发的前提条件:】 c.配置寄存器ADCTSC'[1:0]=等待中断模式,通道开关,等待检测的中断信号; d.物理条件:触笔“按下”“松开”操作;
【INT_AD触发的方式:】1.硬件法:触摸屏幕,产生INT_ADC/INT_AD,TC中断; 2.软件法:使能    ADCCON[0]启动A/D转换和
【INT_TC触发的方式:】1.硬件法:触摸屏幕,产生INT_ADC/INT_AD,TC中断;

节六:
1、编译错误:
    if(timer_array[i])        //error!
    if(timer_array[i].fp)    


节八/九:
1.触点的TC坐标计算所用之公式,若触摸屏X轴方向或者Y轴方向,左右或者上下两边的触摸屏有问题,则校准有用吗?会不会导致更大的问题?
触摸屏校准和使用的前提是触摸屏的任意一边是均匀介质?
程序SubInt_Adc_irq()直接读取的 A/D 转换之后的 ts__x/y 坐标:
左上角:
x = 00000182, y = 00000098
x = 00000180, y = 00000100
x = 00000177, y = 00000101
右上角:
x = 00000148, y = 00000939
x = 00000149, y = 00000939
x = 00000157, y = 00000993
左下角:
x = 00000888, y = 00000086
x = 00000888, y = 00000086
x = 00000885, y = 00000089
右下角:
x = 00000889, y = 00000947
x = 00000889, y = 00000947
x = 00000888, y = 00001014
中心:
x = 00000518, y = 00000515
x = 00000515, y = 00000517
x = 00000510, y = 00000520

节十/十一:
1.所谓的校准函数,就是求公式:
X_lcd = K_x*(X_tc - X_c_tc) + X_c_lcd;
Y_lcd = K_y*(Y_tc - Y_c_tc) + Y_c_lcd;
中的各个参数,并利用这些参数求解需要的解的过程!
1)点击触摸屏的校准点 ABCD ,求参数 K_x/y: 利用校准点 ABCD 的 LCD 坐标和得到的 TC 坐标,求平均斜率K_x/y;
2)点击触摸屏的中心校准点 E ,得到参数 X/Y_c_tc;
3)点击触摸屏任意一点,根据 A/D 转换得到的 X/Y_tc,求解其对应的 LCD 像素坐标 X/Y_lcd;
4)根据需求,对所得LCD像素坐标 X/Y_lcd 对应的像素进行操作,如:填充颜色形成一条线等等;
    a.所谓画线就是对连续捕捉到的单个像素填充颜色,即使用fb_put_pixel()函数;


问题:/* 获得LCD的参数: fb_base, xres, yres, bpp */
    get_lcd_params(&fb_base, &xres, &yres, &bpp);
代码放在 ts_calibrate()函数内可以正常编译;
放在文件 tslib.c 的开头则会出现编译错误:
-march=armv4  -c -o adc_touchscreen/tslib.o   adc_touchscreen/tslib.c
adc_touchscreen/tslib.c:34: error: syntax error before '&' token
adc_touchscreen/tslib.c:34: warning: data definition has no type or storage class
Makefile:24: recipe for target 'adc_touchscreen/tslib.o' failed
答:不知;

我的代码现象:
1.点一次松开后校准点还没有消失,松开捕捉有问题
void SubInt_Adc_irq(void)
{enter_wait_pen_up_mode();//放到外面}

2.get raw ts_xy data: x = 00000350, y = 00000866
get raw ts_xy data: x = 00000342, y = 00000867
get raw ts_xy data: x = 00000348, y = 00000867
get raw ts_xy data: x = 00000000, y = 00000000
return raw ts_xy data: x = 00000348, y = 00000867
为什么一直最后一个值会读到0?不是while(pressure){}中0值无法采集到吗?


节十二:
程序笔记>>
2018-08-23
File:    touchscreen.c
功能:     1. 初始化TC,使得其可以正常工作;
         2. 上报并记录任意未知触点的坐标, 并在松开后清除上报标志位;
            a.校准时,直到有触点按下,才会跳出函数read_ts_xy();
            b.有触点按下,就会触发INT_ADC,并最终触发 SubInt_Adc_irq(), report_ts_xy() 函数;
              且仅仅在 SubInt_Adc_irq() 函数中使用了report_ts_xy()函数的上报功能;
              且 report_ts_xy() 的g_ts_x/y数据有效标记位 g_ts_valid 也只有在"按下"操作并触发
              INT_ADC 中断后才会置位为 1 !一旦数据被读走(即调用ts_read_raw()函数),则g_ts_x/y
              数据有效标记位 g_ts_valid 就会归0;
            c.当LCD坐标被函数read_ts_xy()读走之后,清除标志位使g_ts_valid = 0; 
              便于再次点击(或者定时器SubInt_Adc_irq中断)时,可以再次上报并读取走触点的lcd坐标;

2018-08-31
File:    tslib.c
功能:     1. 五点校准法,校准屏幕;
           公式: 
           X轴: x_lcd = (x_ts - x_c_ts)*Kx + x_c_lcd;
                   Kx = (2S_lcd)/(S1_ts + S2_ts);
           Y轴: y_lcd = (y_ts - y_c_ts)*Ky + y_c_lcd;
                  Ky = (2D_lcd)/(D1_ts + D2_ts);
        2. 在LCD屏幕上显示出五个校准点;
        3. 点击触摸屏上的五个校准点,读取ts坐标;
            a.用平均法求单个校准点的ts坐标;
            b.根据坐标计算: D1, D2, S1, S2, D, S, Kx, Ky;
        4. 根据公式把测试中得到的未知触点的ts坐标,计算出其LCD坐标,并返回给主调函数; 
            a.ts_calibrate();函数的作用为计算斜率并上传到静态全局变量: Kx/Ky;
            b.ts_read();函数的功能是运用指针对这个触点的LCD坐标所在的像素进行操作;
        5. 具体流程: 出对话--五点校准点五次--出对话--点任一点--LCD自动捕捉并填充颜色;

说明: 整体程序分为校准部分: get_calibrate_point_data(), ts_calibrate(), 
                            get_lcd_x_frm_ts_x(), get_lcd_y_frm_ts_y();
              正常工作部分: ts_read();
              无关部分三类: 各全局变量参数, is_ts_xy_swap(), swap_xy();

问题:
static volatile int g_pressure;     //必须volatile!!!!!!!!!!!否则数据有时候不会更新!!!!
未解决问题:
1.为什么SubInt_Adc_irq()中:    
        enter_wait_pen_up_mode();
        if(ADCDAT0 & (1<<15)){...}
的松开判断总是无用?是因为刚刚设置了工作模式寄存器ADCTSC,然后就立马读寄存器ADCDAT0“等待中断模式”中笔尖的起落状态,是不是
硬件尚未反应过来的原因?
但为什么touchscreen_timer_irq()中:
        if(ADCDAT0 & (1<<15))        //触笔抬起状态;
的判断非常好用呢?
答:归根到底还是反应速度问题吗?不再实验了,已经耗费了太多的时间了!

猜你喜欢

转载自blog.csdn.net/weixin_39420903/article/details/82414967