一、触摸控制器

        LCD是一种最常见的输出设备,事实上,LCD屏搭载了一个多点触摸IC控制器,用于实现人机互交时的输入设备。触摸屏很早就有了,一开始是电阻触摸屏,电阻触摸屏只能单点触摸,在以前的学习机、功能机时代被广泛使用。2007 年 1 月 9 日苹果发布了划时代的第一代 Iphone,也就是 Iphone 2G,Iphone 2G 上使用了多点电容触摸屏,而当时的手机基本都是使用的电阻触摸屏。电容触摸屏优秀的触摸品质和手感瞬间征服了消费者,带来了手机触摸屏的大变革,后面新出的手机也都采用了多点电容触摸屏。和电阻触摸屏相比,电容触摸屏最大的优点是支持多点触摸(后面的电阻屏也支持多点触摸,但是为时已晚),电容屏只需要手指轻触即可,而电阻屏是需要手指给予一定的压力才有反应,而且电容屏不需要校准。如今多点电容触摸屏已经得到了广泛的应用,手机、平板、电脑、广告机等等,如果要做人机交互设备的开发,多点电容触摸屏基本是不可能绕过去的。
        我们使用的开发板是由正点原子提供的ATK-7016RGB LCD,其实是由 TFT LCD+触摸屏组合起来的。底下是 LCD 面板,上面是触摸面板,将两个封装到一起就成了带有触摸屏的 LCD 屏幕。电容触摸屏也是需要一个驱动 IC的,驱动 IC 一般会提供一个 I2C 接口给主控制器,主控制器可以通过 I2C 接口来读取驱动 IC里面的触摸坐标数据。ATK-7016使用的触摸控制 IC 是 GT9147。
         GT9147 这款驱动 IC 采用 15*28 的驱动结构,也就是 15 个感应通道,28 个驱动通道,最多支持 5 点电容触摸。ATK-7016 的电容触摸屏部分有 4 个 IO 用于连接主控制器:SCL、SDA、RST 和 INT,SCL 和 SDA 是 I2C 引脚,RST 是复位引脚,INT 是中断引脚。一般通过 INT 引脚来通知主控制器有触摸点按下,然后在 INT 中断服务函数中读取触摸数据。也可以不使用中断功能,当然也可以采用轮询的方式不断查询是否有触摸点按下,本次实验我们使用中断方式来获取触摸数据。 

        由俩款触摸屏,他们的驱动不同,唯一的区别是使用I2C时,设备地址不同。

        标识                        使用驱动        设备地址      

        ALIENTEK 4.3'        GT9147        0X14

        4.3''                          GT1148        0X5D        

二、寄存器

         1.引脚设置

        

        2.通信时序

                

        3.坐标信息

        前四位为设备地址

        中断方式

0x8150, 0x8158, 0x8160, 0x8168, 0x8170:这5个寄存器保存的是触摸事件发生后每个点的坐标。前俩位为y,后俩位为x。

        4.设备地址选择

                复位引脚从低到高的变化时,中断引脚是低电平(设定地址为 0xBA/0xBB )

三、代码

        1.ts.h

#ifndef _TS_H_
#define _TS_H_

extern void init_ts(void);

struct TS_Device
{
    int available;
    int num;
    unsigned short x[5];
    unsigned short y[5];
};

extern struct TS_Device ts_dev;

#endif

        2.ts.c

#include "ts.h"
#include "MCIMX6Y2.h"
#include "fsl_iomuxc.h"
#include "gpio.h"
#include "delay.h"
#include "i2c.h"
#include "stdio.h"
#include "interrupt.h"
#include "core_ca7.h"

void ts_read(unsigned short reg_addr, unsigned char *data, int len)
{
    struct I2C_MSG msg = 
    {
        .dev_address = 0x14,
        .reg_address = reg_addr,
        .reg_len = 2,
        .data = data,
        .len = len,
        .deiection = I2C_Read
    };

    xfer(I2C2, &msg);
}

void ts_write(unsigned short reg_addr, unsigned char *data, int len)
{
    struct I2C_MSG msg = 
    {
        .dev_address = 0x14,
        .reg_address = reg_addr,
        .reg_len = 2,
        .data = data,
        .len = len,
        .deiection = I2C_Write
    };

    xfer(I2C2, &msg);
}

struct TS_Device ts_dev;
const unsigned short ts_regs[5] = {0x8150, 0x8158, 0x8160, 0x8168, 0x8170};

void read_points(void)
{
    unsigned char buffer[16];
    ts_read(0x814E, buffer, 1);
    ts_dev.num = buffer[0] & 0x0F;
    
    int i;
    for(i = 0;i < ts_dev.num;++i)
    {
        ts_read(ts_regs[i], buffer, 4);
        ts_dev.x[i] = buffer[1] << 8 | buffer[0];
        ts_dev.y[i] = buffer[3] << 8 | buffer[2];
    }
    if(ts_dev.num == 0)
    {
        ts_dev.available = 0;
    }
    else
    {
        ts_dev.available = 1;
    }

    buffer[0] = 0;
    ts_write(0x814E, buffer, 1);
}

void ts_int_interrupt_handler(void)
{
    if((GPIO1->ISR & (1 << 9)) != 0)
    {
        read_points();
        GPIO1->ISR |= (1 << 9);
    }
}

void init_ts(void)
{
    IOMUXC_SetPinMux(IOMUXC_GPIO1_IO09_GPIO1_IO09, 0);  //INT
    IOMUXC_SetPinMux(IOMUXC_SNVS_SNVS_TAMPER9_GPIO5_IO09, 0); //RST

    IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO09_GPIO1_IO09, 0x10B0);
    IOMUXC_SetPinConfig(IOMUXC_SNVS_SNVS_TAMPER9_GPIO5_IO09, 0x10B0);

    struct GPIO_Type_t t = 
    {
        .direction = gpio_output,
        .defalut_value = 1
    };
    init_gpio(GPIO1, 9, &t);
    init_gpio(GPIO5, 9, &t);

    write_gpio(GPIO1, 9, 0);
    write_gpio(GPIO5, 9, 0);    

    delayms(10);
    write_gpio(GPIO5, 9, 1);
    delayms(100);

    t.direction = gpio_input;
    init_gpio(GPIO1, 9, &t);
    IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO09_GPIO1_IO09, 0xF080);

    unsigned char buffer[16] = {0};
    ts_read(0x8140, buffer, 4);
    printf("TS id = %s\n", (const char *)buffer);

    ts_read(0x8056, buffer, 1);
    printf("interrupt way = %d\n", buffer[0] & 0x03);//0000 0011

    GPIO1->ICR1 |= (3 << 18);//GPIO1_IO09 falling
    GPIO1->IMR |= (1 << 9);
    system_interrupt_register(GPIO1_Combined_0_15_IRQn, ts_int_interrupt_handler);
    GIC_EnableIRQ(GPIO1_Combined_0_15_IRQn);
}

        3.main.c        

#include "string.h"
#include "led.h"
#include "beep.h"
#include "MCIMX6Y2.h"
#include "key.h"
#include "interrupt.h"
#include "clock.h"
#include "epit.h"
#include "gpt.h"
#include "delay.h"
#include "uart.h"
#include "stdio.h"
#include "i2c.h"
#include "lm75.h"
#include "adc.h"
#include "spi.h"
#include "adxl345.h"
#include "lcd.h"
#include "framebuffer.h"
#include "pwm.h"
#include "ts.h"

int main(void)
{
    
    init_clock();
    system_interrupt_init();
    init_led();
    init_beep();
    // init_key();
//    init_epit1();
    init_gpt1();
    init_uart1(); 
    init_i2c1();
    init_i2c2();
    init_adc1_channle1();
    init_spi3();
//    init_adxl345();
    init_lcd();
    lcd_clear(0x00FFFFFF);
    init_pwm1();
    init_ts();
    while(1)
    {
        char s[32];
        if(ts_dev.available != 0)
        {
            printf("num = %d\n", ts_dev.num);
            int i;
            for(i = 0;i < ts_dev.num;++i)
            {
                sprintf(s, "x = %d, y = %d         ", ts_dev.x[i], ts_dev.y[i]);
                lcd_show_string(100, 100 + 32 * i, 16 * strlen(s), 32, 32, s);
            }
        }
    }
    return 0;
}

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐