《ESP32-S3使用指南—MicroPython版 V1.0》第三十一章 RGB触摸实验

第三十一章 RGB触摸实验


       本章,作者将介绍如何使用ESP32-S3来驱动触摸屏,我们通过外接带触摸屏的LCD模块(比如正点原子RGBLCD模块),来实现触摸屏控制。在本章中,我们将向大家介绍ESP32-S3控制正点原子RGBLCD模块,实现触摸屏驱动(电容触摸),最终实现一个手写板的功能。

       本章分为如下几个小节:

       31.1 Touch C模块解析

       31.2 硬件设计

       31.3 软件设计

       31.4 下载验证


        31.1 Touch C模块解析

       RGB屏相关内容,可参考正点原子提供的《ATK-MD0430R模块用户手册_V1.0》和《ATK-MD0430R模块使用说明_V1.0》,在这两个手册中,已经详细说明了RGB的工作原理及相关参数信息。

       温馨提示:正点原子ATK-MD0430R 模块搭载了GT9147电容式触摸屏IC,我们可通过IIC协议读取显示屏的触摸点。


       31.1.1 C模块解析

       本章的Touch C模块组件可在资料A盘à6,软件资料à1,软件à2,MicroPython开发工具à01-Windowsà2,正点原子MicroPython驱动àCModules_LibàRGBLCD目录下找到。下面作者将简要介绍正点原子Touch C模块驱动。这个讲解内容会分为几个部分:Touch模块初始化、扫描触摸屏、获取x坐标、获取y坐标和获取触摸状态。


       1,Touch模块初始化模块方法

_m_tp_dev tp_dev =
{{
    tp_init,
    0,
    0,
    0,
    0,
    0,
}};
 
/**
 * @brief       触摸屏初始化
 * @param       无
 * @retval      0,没有进行校准
 *              1,进行过校准
 */
uint8_t tp_init(void)
{
    tp_dev.touchtype = 0;                          /* 默认设置(电阻屏 & 竖屏) */
    tp_dev.touchtype |= ltdc_self->dir & 0X01;    /* 根据LCD判定是横屏还是竖屏 */
 
    if (ltdc_self->id == 0X4342 || ltdc_self->id == 0X4384)
    {
        gt9xxx_init();
        tp_dev.scan = gt9xxx_scan;          /* 扫描函数指向GT9147触摸屏扫描 */
        tp_dev.touchtype |= 0X80;            /* 电容屏 */
        return 0;
    }
 
    return 1;
}
 
/**
 * @brief       触摸初始化
 * @param       无
 * @retval      无
 */
STATIC mp_obj_t mp_touch_init(void)
{
    tp_dev.init();
    return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(touch_init_obj, mp_touch_init);

       在上述源代码中,我们首先初始化tp_dev结构体的成员变量。然后,在tp_init函数中,我们判断RGB显示屏的ID是否为0x4342和0x4384,这两款是RGB屏幕。接着,我们执行触摸IC的初始化操作,并将tp_dev.scan函数指针指向gt9xxx_scan函数,该函数用于扫描触摸,最后,将mp_touch_init函数注册至模块列表当中,使得在MicroPython环境下调用此模块的方法。

       请注意,gt9xxx.c/.h文件与正点原子STM32F429以上开发板提供的触摸IC驱动完全一致,只是将IIC协议通信替换为硬件IIC通信。


       2,扫描触摸屏模块方法

       上述作者提到,RGB显示屏的扫描函数由tp_dev结构体中的tp_dev.scan函数指针指向。因此,如果MicroPython想调用扫描触摸屏方法,可以将tp_dev.scan函数指针注册到模块列表中。如下源代码所示:

/**
 * @brief       扫描触摸屏(采用查询方式)
 * @param       mode : 电容屏未用到次参数, 为了兼容电阻屏
 * @retval      当前触屏状态
 *   @arg       0, 触屏无触摸;
 *   @arg       1, 触屏有触摸;
 */
STATIC mp_obj_t mp_touch_scan(mp_obj_t mode)
{
    int ct_mode = mp_obj_get_int(mode);
    tp_dev.scan(ct_mode);
    return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(touch_scan_obj, mp_touch_scan);

       可以看到,此方法需要传入一个形参,用来设置触摸屏的状态,若此入参为0时,则触摸屏并没有触摸,反次,有触摸。


       3,获取x/y坐标模块方法

/**
 * @brief       获取X轴坐标
 * @param       无
 * @retval      无
 */
STATIC mp_obj_t mp_touch_get_x(void)
{
return mp_obj_new_bytearray_by_ref(sizeof(uint16_t) 
* MP_ARRAY_SIZE(tp_dev.x), tp_dev.x);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(touch_get_x_obj, mp_touch_get_x);
 
/**
 * @brief       获取Y轴坐标
 * @param       无
 * @retval      无
 */
STATIC mp_obj_t mp_touch_get_y(void)
{
return mp_obj_new_bytearray_by_ref(sizeof(uint16_t) 
* MP_ARRAY_SIZE(tp_dev.y), tp_dev.y);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(touch_get_y_obj, mp_touch_get_y);

       上述模块方法中,我们使用MicroPython字节数组来存储触摸屏的X和Y轴坐标,然后,把字节数组返回给用户,这样就可以得到当前触摸的X与Y轴坐标了。


       4,获取触摸状态模块方法

/**
 * @brief       获取触摸状态
 * @param       无
 * @retval      无
 */
STATIC mp_obj_t mp_touch_get_sta(void)
{
    sta[0] = tp_dev.sta;
    
return mp_obj_new_bytearray_by_ref(sizeof(uint16_t)
*MP_ARRAY_SIZE(sta), sta);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(touch_get_sta_obj, mp_touch_get_sta);

       同理,触摸状态方法也是利用MicroPython的字节数组来存储触摸状态数值,然后,返回给用户,来判断当前RGB显示屏触摸状态。


       31.1.2 C模块构造与类的方法

       在上小节中,作者已介绍了RGB触摸C模块的方法,下面是MicroPython引用这些模块方法的原型,如下所示:


       ①:初始化触摸驱动

       其方法原型如下:

touch.init()

       返回值:无。


       ②:扫描触摸

       其方法原型如下:

touch.scan(0)

       返回值:无。


       ③:获取X轴坐标

       其方法原型如下:

touch.get_x()

       返回值:X坐标。


       ④:获取Y轴坐标

       其方法原型如下:

touch.get_y()

       返回值:Y坐标。


       ⑤:获取触摸状态

       其方法原型如下:

touch.get_sta()

       返回值:触摸状态。

       温馨提示:调用触摸模块的方法之前,必须先导入atk_touch模块,后调用此模块的方法,如下是导入模块示例:

import atk_touch as touch


        31.2 硬件设计


       1. 例程功能

       本章实验功能简介:经过一系列的初始化之后,进入电容触摸屏测试程序,用户可在画板上绘画字符、线条等,在测试界面的右上角会有一个清空的操作区域(RST),点击这个地方就会将输入全部清除,恢复白板状态。


       2. 硬件资源


       1)LED灯

              LED-IO1


       2)XL9555

              IIC_INT-IO0(需在P5连接IO0)

              IIC_SDA-IO41

              IIC_SCL-IO42


       3)RGBLCD

              LCD_BL-IO1_3(XL9555)

              LCD_DE-IO4

              LCD_VSYNC-NC

              LCD_HSYNC-NC

              LCD_PCLK-IO5

              LCD_R3-IO45

              LCD_R4-IO48

              LCD_R5-IO47

              LCD_R6-IO21

              LCD_R7-IO14

              LCD_G2-IO10

              LCD_G3-IO9

              LCD_G4-IO46

              LCD_G5-IO3

              LCD_G6-IO8

              LCD_G7-IO18

              LCD_B3-IO17

              LCD_B4-IO16

              LCD_B5-IO15

              LCD_B6-IO7

              LCD_B7-IO6


       3. 原理图

       RGB接口与ESP32-S3的连接关系,如下图所示:


图31.2.1 RGB接口与ESP32-S3的连接电路图


        31.3 软件设计


       31.3.1 程序流程图

       程序流程图能帮助我们更好的理解一个工程的功能和实现的过程,对学习和设计工程有很好的主导作用。下面看看本实验的程序流程图。


图31.3.1.1 程序流程图


       31.3.2 程序解析

       本书籍的代码都在main.py脚本下编写的,读者可在光盘资料下找到对应的源码。RGB触摸实验main.py源码如下:

from machine import Pin,I2C
import atk_xl9555 as io_ex
import atk_ltdc as ltdc
import atk_touch as touch
import time
 
 
# 设置屏幕横竖屏:0为竖屏;1为横屏
atk_dir = 1
 
if atk_dir == 1:
    LCD_WIDTH  = 800
    LCD_HEIGHT = 480
else:
    LCD_WIDTH  = 480
    LCD_HEIGHT = 800
 
"""
 * @brief       清空屏幕并在右上角显示"RST"
 * @param       无
 * @retval      无
"""
def load_draw_dialog():
    
    display.clear(ltdc.WHITE)
    display.string(LCD_WIDTH - 30, 0, 200, 16, 16, "RST", ltdc.BLUE)
 
 
"""
 * @brief       画粗线
 * @param       x1,y1: 起点坐标
 * @param       x2,y2: 终点坐标
 * @param       size : 线条粗细程度
 * @param       color: 线的颜色
 * @retval      无
"""
def lcd_draw_bline(x1,y1,x2,y2,size,color):
    
    t = 0
    xerr = 0
    yerr = 0
    delta_x = 0
    delta_y = 0
    distance = 0
    incx = 0
    incy = 0
    row = 0
    col = 0
 
    delta_x = x2 - x1                       # 计算坐标增量
    delta_y = y2 - y1
    row = x1
    col = y1
 
    if delta_x > 0:
        incx = 1                            # 置单步方向  
    elif delta_x == 0:
        incx = 0                            # 垂直线
    else:
        incx = -1
        delta_x = -delta_x
 
    if delta_y > 0:
        incy = 1
    elif delta_y == 0:
        incy = 0                            # 水平线
    else:
        incy = -1
        delta_y = -delta_y
 
    if delta_x > delta_y:
        distance = delta_x;                 # 选取基本增量坐标轴
    else:
        distance = delta_y
 
    for t in range(0,distance + 1):         # 画线输出
        display.circle(row, col, size, color)   # 画点
        xerr += delta_x
        yerr += delta_y
 
        if xerr > distance:
            xerr -= distance
            row += incx
 
        if yerr > distance:
            yerr -= distance
            col += incy
 
"""
 * @brief       电容屏测试
 * @param       无
 * @retval      无
"""
def ctp_test():
    
    t = 0
    i = 0
    lastpos = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0]]    #最后一次的数据
 
    while True:
        
        touch.scan(0)
        
        x_data = touch.get_x()
        y_data = touch.get_y()
        sta_data = touch.get_sta()
        
        x = (x_data[9] << 8) | x_data[8]
        y = (y_data[9] << 8) | y_data[8]
        sta = (sta_data[1] << 8) | sta_data[0]
        
        for t in range(0,5):
            
            if sta & (1 << t):
                
                if (x < LCD_WIDTH and y < LCD_HEIGHT):
                    
                    if lastpos[t][0] == 0xFFFF:
                        
                        lastpos[t][0] = x
                        lastpos[t][1] = y
                    
                    lcd_draw_bline(lastpos[t][0], lastpos[t][1],x,y,2,ltdc.RED);
                    lastpos[t][0] = x
                    lastpos[t][1] = y
                    
                    if (x > (LCD_WIDTH - 30) and y < 20):
                        
                        load_draw_dialog()
                else:
                    lastpos[t][0] = 0xFFFF
                
        time.sleep_ms(5)
        
        i += 1
        
        if (i % 20 == 0):
            
            led_state = led.value()
            led.value(not led_state)
 
"""
 * @brief       程序入口
 * @param       无
 * @retval      无
"""
if __name__ == '__main__':
   
    x = 0
    # 初始化LED并输出高电平
    led = Pin(1,Pin.OUT,value = 1)
    # IIC初始化
    i2c0 = I2C(0, scl = Pin(42), sda = Pin(41), freq = 400000)
    # XL9555初始化
    xl9555 = io_ex.init(i2c0)
    
    
    # 初始化RGB
    display = ltdc.init(dir = atk_dir)
    # 打开RGB屏背光
    xl9555.write_bit(io_ex.LCD_BL,1)
    time.sleep_ms(100)
    
    # 复位触摸芯片
    xl9555.write_bit(io_ex.CT_RST,0)
    time.sleep_ms(10)
    xl9555.write_bit(io_ex.CT_RST,1)
    time.sleep_ms(10)
    
    # 初始化触摸驱动
    touch.init()
    
    # 清空屏幕并在右上角显示"RST"
    load_draw_dialog()
    
    while True:
        
        ctp_test()

       该示例经过一些列初始化之后,执行ctp_test函数创建白色的画板,用户可在画板上涂鸦,如果xiang 清除画板上的涂鸦,可点击右上角的“RST”按键清除。


        31.4 下载验证

       在代码编译成功之后,我们通过下载代码到开发板上,触摸屏测试如下图所示界面:


图31.4.1 触摸屏测试界面


       图中,作者在触摸板绘画“ALIENTEK”字符串。按右上角的RST标志,可以清屏。


请使用浏览器的分享功能分享到微信等