正点原子STM32连载第42章:触摸屏实验(摘自正点原子APM32E103最小系统板使用指南)

1)实验平台:正点原子APM32E103最小系统板
2)平台购买地址:https://detail.tmall.com/item.htm?id=609294757420
3)全套实验源码+手册+视频下载地址: http://www.openedv.com/docs/boards/xiaoxitongban

第四十二章 触摸屏实验

本章将介绍使用APM32E103驱动TFTLCD模块上的触摸屏,实现一个类似画板的应用。通过本章的学习,读者将学习到使用GPIO模拟IIC和SPI时序以及触摸屏的驱动。
本章分为如下几个小节:
42.1 硬件设计
42.2 程序设计
42.3 下载验证

42.1 硬件设计
42.1.1 例程功能

  1. 程序运行后,先显示实验信息,随后在LCD上绘制出触摸屏被触摸的轨迹
  2. 可通过触摸屏幕右上角的“RST”来清空屏幕
  3. 使用电阻式触摸屏的时候,可按下KEY0按键,进行触摸校准
  4. LED0闪烁,指示程序正在运行
    42.1.2 硬件资源
  5. LED
    LED0 – PB5
  6. 按键
    KEY0 – PE4
  7. 正点原子 2.8/3.5/4.3/7/10寸TFTLCD模块(仅限MCU屏,16位8080并口驱动)
  8. TFTLCD模块上的触摸屏(电阻式、电容式)
    42.1.3 原理图
    本章实验使用了正点原子的TFTLCD模块(兼容正点原子 2.8/3.5/4.3/7/10寸TFTLCD模块),该模块需通过LCD转接板与板载的TFTLCD接口进行连接,该接口与板载MCU的连接原理图,如下所示:

图42.1.3.1 TFTLCD模块与MCU的连接原理图
如上图所示,TFTLCD模块上的触摸屏使用T_MISO、T_MOSI、T_PEN、T_CS、T_SCK信号与MCU进行通讯,正点原子的TFTLCD模块采用了两种触摸屏,分别为:电阻式触摸屏和电容式触摸屏,其中电阻式触摸屏使用SPI协议与MCU进行通信,而电容式触摸屏则是使用IIC协议与MCU进行通讯,因此TFT模块上的触摸屏引脚对于不同的触摸屏有不同的引脚定义,请读者自行查看TFTLCD模块的用户手册查看具体的引脚定义。
42.2 程序设计
42.2.1 触摸屏驱动
本章实验的触摸屏驱动主要负责向应用层提供触摸屏的初始化和获取触摸屏触摸坐标等函数。本章实验中,触摸屏的驱动代码包括touch.c、touch.h、ctiic.c、ctiic.h、ft5206.c、ft5206.h、gt9xxx.c、gt9xxx.h八个文件。
触摸屏驱动中,触摸屏的初始化函数,如下所示:

/**
 * @brief       初始化触摸屏
 * @param       无
 * @retval      触摸屏是否校准
 *              0: 否
 *              1: 是
 */
uint8_t tp_init(void)
{
    GPIO_Config_T gpio_init_struct;
    
    tp_dev.touchtype = 0;					/* 默认设置(电阻屏、竖屏) */
tp_dev.touchtype |= lcddev.dir & 0x01;	/* 根据LCD判断是横屏还是竖屏 */

    /* 电容触摸屏,4.3寸/10.1寸屏 */
    if ((lcddev.id == 0x5510) ||
        (lcddev.id == 0x9806) ||
        (lcddev.id == 0x7796) ||
        (lcddev.id == 0x4342) ||
        (lcddev.id == 0x4384) ||
        (lcddev.id == 0x1018))
    {
        gt9xxx_init();
        tp_dev.scan = gt9xxx_scan; 		/* 设置触摸屏扫描函数 */                                                     
        tp_dev.touchtype |= 0x80;			/* 电容屏 */                                                     
        return 0;
}
/* SSD1963 7寸屏或7寸800*480/1024*600 RGB屏 */
else if ((lcddev.id == 0x1963) ||
             (lcddev.id == 0x7084) ||
             (lcddev.id == 0x7016))  
    {
        ft5206_init();
        tp_dev.scan = ft5206_scan;   		/* 设置触摸屏扫描函数 */                                                   
        tp_dev.touchtype |= 0x80;    		/* 电容屏 */                                                   
        return 0;
    }
    else                             		/* 电阻屏 */                                                   
    {
        /* 使能时钟 */
        T_PEN_GPIO_CLK_ENABLE();     		/* 使能T_PEN引脚端口时钟 */                                                   
        T_CS_GPIO_CLK_ENABLE();      		/* 使能T_CS引脚端口时钟 */                                                   
        T_MISO_GPIO_CLK_ENABLE();    		/* 使能T_MISO引脚端口时钟 */                                                   
        T_MOSI_GPIO_CLK_ENABLE();    		/* 使能T_MOSI引脚端口时钟 */                                                   
        T_CLK_GPIO_CLK_ENABLE();     		/* 使能T_CLK引脚端口时钟 */                                                   
        
        /* 配置T_PEN引脚 */
        gpio_init_struct.pin = T_PEN_GPIO_PIN;				/* T_PEN引脚 */                                         
        gpio_init_struct.mode = GPIO_MODE_IN_PU;			/* 上拉输入 */                                       
        GPIO_Config(T_PEN_GPIO_PORT, &gpio_init_struct);	/* 配置T_PEN引脚 */                               
        
        /* 配置T_CS引脚 */
        gpio_init_struct.pin = T_CS_GPIO_PIN;				/* T_CS引脚 */                                           
        gpio_init_struct.speed = GPIO_SPEED_50MHz;			/* 高速 */                                     
        gpio_init_struct.mode = GPIO_MODE_OUT_PP;			/* 推挽输出 */                                      
        GPIO_Config(T_CS_GPIO_PORT, &gpio_init_struct);	/* 配置T_CS引脚 */                               
        
        /* 配置T_MISO引脚 */
        gpio_init_struct.pin = T_MISO_GPIO_PIN;			/* T_MISO引脚 */                                        
        gpio_init_struct.mode = GPIO_MODE_IN_PU;			/* 上拉输入 */                                       
        GPIO_Config(T_MISO_GPIO_PORT, &gpio_init_struct); /* 配置T_MISO引脚 */                               
        
        /* 配置T_MOSI引脚 */
        gpio_init_struct.pin = T_MOSI_GPIO_PIN; 			/* T_MOSI引脚 */                                        
        gpio_init_struct.speed = GPIO_SPEED_50MHz;			/* 高速 */                                      
        gpio_init_struct.mode = GPIO_MODE_OUT_PP;			/* 推挽输出 */                                     
        GPIO_Config(T_MOSI_GPIO_PORT, &gpio_init_struct);	/* 配置T_MOSI引脚 */                              
        
        /* 配置T_CLK引脚 */
        gpio_init_struct.pin = T_CLK_GPIO_PIN;				/* T_CLK引脚 */                                         
        gpio_init_struct.speed = GPIO_SPEED_50MHz;			/* 高速 */                                     
        gpio_init_struct.mode = GPIO_MODE_OUT_PP;			/* 推挽输出 */                                     
        GPIO_Config(T_CLK_GPIO_PORT, &gpio_init_struct);	/* 配置T_CLK引脚 */                              
        
        tp_read_xy(&tp_dev.x[0], &tp_dev.y[0]);  			/* 第一次读取初始化 */                                       
        at24cxx_init();                           			/* 初始化AT24CXX */                                      
        
        if (tp_get_adjust_data())   						/* 已校准触摸 */                                                    
        {
            return 0;
        }
        else            									/* 未校准触摸 */                                                                
        {
            tp_adjust();    								/* 触摸屏校准 */                                                            
            tp_save_adjust_data();  						/* 保存校准参数 */                                                    
        }
        tp_get_adjust_data();     							/* 获取触摸屏校准参数 */                                                      
    }
    return 1;
}

从上面的代码中可以看出,触摸屏的初始化会读取TFTLCD模块LCD的ID号,来判断触摸屏的型号,因此在使用本触摸屏驱动初始化触摸屏前,需要先进行LCD的初始化。触摸屏的初始化函数会依据LCD的ID对不同型号的触摸屏进行初始化。
对于触摸屏驱动中的其他内容,请读者自行结合实际使用的TFTLCD的用户手册产看本章配套实验例程的源码。
42.2.2 实验应用代码
本章实验的应用代码,如下所示:

int main(void)
{
    NVIC_ConfigPriorityGroup(NVIC_PRIORITY_GROUP_4);  /* 设置中断优先级分组为组4 */
    sys_apm32_clock_init(15);                         /* 配置系统时钟 */
    delay_init(120);                                  /* 初始化延时功能 */
    usart_init(115200);                               /* 初始化串口 */
    led_init();                                       /* 初始化LED */
    key_init();                                       /* 初始化按键 */
    lcd_init();                                       /* 初始化LCD */
    tp_dev.init();                                    /* 初始化触摸屏 */
    
    lcd_show_string(30, 50, 200, 16, 16, "APM32", RED);
    lcd_show_string(30, 70, 200, 16, 16, "TOUCH TEST", RED);
    lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
    
    if ((tp_dev.touchtype & 0x80) == 0)               /* 电阻屏才显示 */
    {
        lcd_show_string(30, 110, 200, 16, 16, "Press KEY0 to Adjust", RED);
    }
    delay_ms(1500);
    load_draw_dialog();
    
    if (tp_dev.touchtype & 0x80)
    {
        ctp_test();                                   /* 电容屏测试 */
    }
    else
    {
        rtp_test();                                   /* 电阻屏测试 */
    }
}

在进行完触摸屏的初始化后,便根据触摸屏的不同类型调用了不同的测试函数,这是因为电容屏是支持多点触控的,而电阻屏并不支持。
电容屏测试测试函数,如下所示:

/**
 * @brief       电容触摸屏测试
 * @param       无
 * @retval      无
 */
static void ctp_test(void)
{
    uint8_t t = 0;
    uint8_t i = 0;
    uint16_t lastpos[10][2];
    uint8_t maxp = 5;
    
    if (lcddev.id == 0x1018)
    {
        maxp = 10;
    }
    
    while (1)
    {
        tp_dev.scan(0);
        for (t=0; t<maxp; t++)
        {
            if ((tp_dev.sta) & (1 << t))
            {
                if ((tp_dev.x[t] < lcddev.width) && (tp_dev.y[t] < lcddev.height))                  /* 坐标在屏幕范围内 */
                {
                    if (lastpos[t][0] == 0xFFFF)
                    {
                        lastpos[t][0] = tp_dev.x[t];
                        lastpos[t][1] = tp_dev.y[t];
                    }
                    /* 画线 */
                    lcd_draw_bline(lastpos[t][0],
lastpos[t][1],
tp_dev.x[t],
tp_dev.y[t], 
2,
POINT_COLOR_TBL[t]);  
                    lastpos[t][0] = tp_dev.x[t];
                    lastpos[t][1] = tp_dev.y[t];
                    /* 清除 */
                    if (tp_dev.x[t] > (lcddev.width - 24) && tp_dev.y[t] < 20)
                    {
                        load_draw_dialog();                                                                         
                    }
                }
            }
            else 
            {
                lastpos[t][0] = 0xFFFF;
            }
        }
        
        delay_ms(5);
        i++;
        if ((i % 20) == 0)
        {
            LED0_TOGGLE();
        }
    }
}

电阻触摸屏就相对简单,因为电阻触摸屏仅支持单点触控,因此仅需将触摸的1个触摸点对应LCD屏幕上坐标的点进行绘制即可,同时因为电阻触摸屏是需要校准的,因此当检测到KEY0按键被按下时,便会进行电阻触摸屏校准。
42.3 下载验证
在完成编译和烧录操作后,可以看到LCD上显示了本实验的实验信息,随后便进入“白板”界面,此时便可在LCD上通过触摸屏绘制出任意的图案,若是电容屏,还支持多点触控,若是电阻屏出现触摸点与LCD上显示的绘制点坐标不吻合,可以按下KEY0按键进行电阻触摸屏的校准。

物联沃分享整理
物联沃-IOTWORD物联网 » 正点原子STM32连载第42章:触摸屏实验(摘自正点原子APM32E103最小系统板使用指南)

发表评论