嵌入式系统应用-触摸屏输入 LVGL 9.3版本
文章目录
- 需求分析
- 1 触摸输入
- 1.1 触摸屏介绍
- 1.2 芯片介绍
- 1.3 芯片电路图
- 1.4 驱动开发
- 1.4.1 检测思路
- 1.4.2 校正
- 2 lvgl 输入移植
- 2.1 加载输入固件
- 2.2 使能模组
- 2.3 保留触摸屏输入,屏幕用不到输入
- 2.4 加载硬件触摸屏初始化代码
- 2.4 加入扫描代码
- 2.5 把输入初始化代码加载屏幕初始化线程。
- 3 效果
- 3.1 测试代码
- 3.2 效果
- 3.3 疑问
- 4 展望
需求分析
前期完成lvgl的显示部分的移植和应用,但是我们希望能通过触摸输入来调整显示内容或者控制硬件。
1 触摸输入
1.1 触摸屏介绍
触摸屏又称触控面板,它是一种把触摸位置转化成坐标数据的输入设备,根据触摸屏的检测原理,主要分为电阻式触摸屏和电容式触摸屏。下面我们就分别来介绍下这两种触摸屏。
1. 阻式触摸屏介绍
电阻式触摸屏是一种传感器,它将矩形区域中触摸点(X,Y)的物理位置转换为代表X坐标和Y坐标的电压。很多LCD模块都采用了电阻式触摸屏。使用时需要用一定的压力才会能检测到电压,即触摸。
电阻式触摸屏基本上是薄膜加上玻璃的结构,薄膜和玻璃相邻的一面上均涂有ITO(纳米铟锡金属氧化物)涂层,ITO具有很好的导电性和透明性。当触摸操作时,薄膜下层的ITO会接触到玻璃上层的ITO,经由感应器传出相应的电信号,经过转换电路送到处理器,通过运算转化为屏幕上的 X、Y 值,而完成点选的动作,并呈现在屏幕上。
阻触摸屏的工作原理主要是通过压力感应原理来实现对屏幕内容的操作和控制的,这种触摸屏屏体部分是一块与显示器表面非常配合的多层复合薄膜,其中第一层为玻璃或有机玻璃底层,第二层为隔层,第三层为多元树脂表层,表面还涂有一层透明的导电层,上面再盖有一层外表面经硬化处理、光滑防刮的塑料层。在多元脂表层表面的传导层及玻璃层感应器是被许多微小的隔层所分隔电流通过表层,轻触表层压下时,接触到底层,控制器同时从四个角读出相称的电流及计算手指位置的距离。这种触摸屏利用两层高透明的导电层组成触摸屏,两层之间距离仅为 2.5 微米。当手指触摸屏幕时,平常相互绝缘的两层导电层就在触摸点位置有了一个接触,因其中一面导电层接通 Y 轴方向的电源均匀电压场,使得侦测层的电压由零变为非零,控制器侦测到这个接通后,进行 A/D 转换,并将得到的电压值与参考电压相比,即可得触摸点的 Y 轴坐标,同理得出 X 轴的坐标,这就是所有电阻技术触摸屏共同的最基本原理。
电阻触摸屏的优点:精度高、价格便宜、抗干扰能力强、稳定性好。
电阻触摸屏的缺点:容易被划伤、透光性不太好、不支持多点触摸。
2. 电容式触摸屏介绍
(1)表面电容式电容触摸屏。
表面电容式触摸屏技术是利用 ITO(铟锡氧化物,是一种透明的导电材料导电膜,通过电场感应方式感测屏幕表面的触摸行为进行。但是表面电容式触摸屏有一些局限性,它只能识别一个手指或者一次触摸。
(2)投射式电容触摸屏。
投射式电容触摸屏却具有多指触控的功能。这两种电容式触摸屏都具有透光率高、反应速度快、寿命长等优点,缺点是:随着温度、湿度的变化,电容值会发生变化,导致工作稳定性差,时常会有漂移现象,需要经常校对屏幕,且不可佩戴普通手套进行触摸定位。
1.2 芯片介绍
笔者这里用的是电阻屏,芯片信号是:XPT2046。
- 一款 4 导线制触摸屏控制器,采用 SPI 模式进行通信。
- 内含 12 位分辨率 125KHz 转换速率逐步逼近型 A/D 转换器。
- 支持从 1.5V 到 5.25V 的低电压 I/O 接口。
4)只需执行两次 A/D 转换即可查出被按的屏幕位置。
5)可以测量加在触摸屏上的压力
6)芯片内部自带温度检测、电池电压(0-6V)监测等等
1.3 芯片电路图
1.4 驱动开发
电阻触摸屏由上下两层透明电阻薄膜构成:
检测 X 坐标:X+、X- 两端加电压,触点处的 Y 电极输出电压与 X 坐标成比例。
检测 Y 坐标:Y+、Y- 两端加电压,触点处的 X 电极输出电压与 Y 坐标成比例。
Z 值(压力):通过检测 X、Y 电阻层的接触电阻,判断是否有触摸。
XPT2046 内部切换不同的驱动通道,交替采样 X、Y 坐标。
1.4.1 检测思路
-
检测 PENIRQ(低电平表示有触摸)。
-
SPI 发送控制字节(指定读取 X、Y、Z 还是其他通道)。
-
XPT2046 返回 12 位数据。
-
进行多次采样 + 滤波(如中值滤波、均值滤波),提高稳定性。
-
映射到屏幕分辨率(如 0–4095 → 0–480)。
1.4.2 校正
XPT2046 读出来的坐标值是 原始 ADC 值 (0~4095),它和屏幕像素坐标(比如 480×320)不直接对应,还可能存在 偏移、缩放、旋转、甚至轻微的非线性。所以需要 校正 (Calibration)。
常用的是 线性校正法,通过触摸屏幕上已知位置的几个点,计算变换系数,把触摸原始坐标 (Xraw, Yraw) 映射到屏幕坐标 (Xdisp, Ydisp)。
线性变换公式(2D 仿射变换):
x = xraw * fx + foff
y = yraw * fy + yoff
2 lvgl 输入移植
2.1 加载输入固件
勾选Porting-》Input
2.2 使能模组
把0 修改成为1 ,包括输入indev.h 和 indev.c 两个文件。
2.3 保留触摸屏输入,屏幕用不到输入
2.4 加载硬件触摸屏初始化代码
笔者这里空着,主要是笔者初始化初始化代码已经在rt-thread 早期初始化。
2.4 加入扫描代码
static bool touchpad_is_pressed(void)
{/*Your code comes here*/if( TP_Scan(0) ){return true;}else{// rt_kprintf("touch pad\r\n");return false;}}/*Get the x and y coordinates if the touchpad is pressed*/
static void touchpad_get_xy(int32_t * x, int32_t * y)
{/*Your code comes here*/(*x) =tp_dev.x[0];(*y)=tp_dev.y[0];// rt_kprintf("press %d,%d",*x, *y);
// (*x) = 0;
// (*y) = 0;
}
2.5 把输入初始化代码加载屏幕初始化线程。
#include "lv_port_indev_template.h"int sys_lvgl_init(void)
{lv_init();lv_port_disp_init();lv_port_indev_init();TIM1_Init_5ms();lv_mutex_init(&lv_mutex);lv_thread_init(&lv_task_thread,"lv_task",10,lvgl_thread_entry,4098,NULL); return 0;
}INIT_COMPONENT_EXPORT(sys_lvgl_init);
3 效果
3.1 测试代码
static void btn_event_handler(lv_event_t * e)
{rt_kprintf("button is down\r\n");
}
void lvgl_thread_entry(void *args){lv_obj_set_style_bg_color(lv_scr_act(), lv_palette_main(LV_PALETTE_RED), 0);lv_obj_set_style_bg_opa(lv_scr_act(), LV_OPA_COVER, 0);// 播放按钮lv_obj_t * play_btn = lv_btn_create(lv_scr_act());lv_obj_set_size(play_btn, 50, 50);lv_obj_t * play_label = lv_label_create(play_btn);lv_label_set_text(play_label, LV_SYMBOL_PLAY);lv_obj_center(play_label);lv_obj_add_event_cb(play_btn, btn_event_handler, LV_EVENT_PRESSED, NULL); // 添加事件while(1) {lv_mutex_lock(&lv_mutex);lv_task_handler();lv_mutex_unlock(&lv_mutex);rt_thread_mdelay(10);}
}
3.2 效果
8-2 触摸异常
3.3 疑问
笔者这里遗留技术问题,就是如果把缓存移植到外部内存,导致按键显示异常。
8-1 触摸效果
4 展望
4.1 可以解决外设缓存问题;
4.2 考虑使用电容屏;
4.3 考虑使用dma2d的芯片;