第三十一章 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标志,可以清屏。