Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
LittlevGL_LVGL
N9H30 HMI开发板触摸屏误触发问题,及解决办法
发布于 2022-06-26 21:24:25 浏览:1674
订阅该版
[tocm] # N9H30 HMI开发板触摸屏误触发问题,及解决办法 最近在用N9H30的开发板学习LVGL。用于参加嵌入式GUI竞赛。我的这块开发板一直有触摸屏误触发的问题。控件少了还好,无所谓。控件一多就会误触发某些功能。这对于设计一款产品来说肯定是不太合适的。今天在测试键盘功能的时候,就发现一直在自己输入字符。于是就着此机会,初步研究了一下N9H30的触摸屏底层驱动。并优化解决了此问题。先看现象,如下两张图片,分别是闲置大概10分钟的结果,终端消息打印了几十条触摸屏触发信息,其中有8次触发在了键盘的‘r’键上面,输入框内自动输入了8个‘r’字符。在这次测试之前,还看到过误触发的‘i’键,'j'键等。误触发范围还挺广的。 ![触摸屏误触发现象1.png](https://oss-club.rt-thread.org/uploads/20220626/3c7b7adc5bd4975cc94440090a4cf741.png.webp "触摸屏误触发现象1.png") ![触摸屏误触发现象2.png](https://oss-club.rt-thread.org/uploads/20220626/a88c12e26884a85e69a63abd70ec5e68.png "触摸屏误触发现象2.png") 为了方便后面的分析,这里先给出一张从网上截取的四线电阻触摸屏原理的简图,如下: ![四线电阻触摸屏原理简图.png](https://oss-club.rt-thread.org/uploads/20220626/ffccc0c8941607ba330793483942c329.png "四线电阻触摸屏原理简图.png") N9H30芯片内部的ADC,硬件支持四线电阻触摸屏或5线触摸板驱动。由于没有具体的用户手册,不太清楚ADC内部四线触摸屏驱动的具体原理。但推测,应该是把上图中的X-和Y-称为Z0和Z1。X+和Y+称为X和Y。分别把Y+接正电压,Y-接地,读取X+的AD值,把X+接正电压,X-接地,读取Y+的AD值。从而来计算X和Y两层介质的接触点坐标,即触摸点。 这里不对底层驱动做详细解析,只表述我最终分析的结果。对于触摸屏的底层驱动,开启了一个40ms的软件定时器,用于触发ADC采样。下面是ADC转换完成中断的回调函数。其中,`nu_adc_touch_detect()`函数应该是用来切换施压方向的。在enable的时候使能detect。在`PenDownCallback()`函数中,开启采样定时器。失能detect,即换方向采集。在`AdcMenuStartCallback()`回调函数中,通过Z0的AD值是否为0,来判断是否完成了一个检测周期,是则关闭定时器,再次使能detect,开启下一个检测周期。然后把ADC数据通过邮箱发出去,并释放信号量。 这里的优化是把判断Z0等于零的条件改成了小于等于某阈值,这个阈值可通过宏定义修改。我设置的是2,已经能够完全解决此问题了。这个参数过大,可能会影响有效探测的触摸屏范围。此优化,起因是探测的毕竟是模拟信号,就算直接接地,也很难保证不会有一些小毛刺干扰。加入一个小的阈值,可以有效解决Z0信号状态判断错误引起的误触发。 ```C #define ADC_TOUCH_Z0_ACTIVE 2 static int32_t PenDownCallback(uint32_t status, uint32_t userData) { nu_adc_touch_detect(RT_FALSE); rt_timer_start(g_sNuADC.psRtTouchMenuTimer); return 0; } static int32_t AdcMenuStartCallback(uint32_t status, uint32_t userData) { nu_adc_t psNuAdc = (nu_adc_t)userData; #if defined(BSP_USING_ADC_TOUCH) static struct nu_adc_touch_data point; static rt_bool_t bDrop = RT_FALSE; static uint32_t u32LastZ0 = 0xffffu; if (psNuAdc->psRtTouch != RT_NULL) { uint32_t value; value = inpw(REG_ADC_XYDATA); point.u32X = (value & 0x0ffful); point.u32Y = ((value >> 16) & 0x0ffful); value = inpw(REG_ADC_ZDATA); point.u32Z0 = (value & 0x0ffful); point.u32Z1 = ((value >> 16) & 0x0ffful); /* Trigger next or not. */ if (point.u32Z0 <= ADC_TOUCH_Z0_ACTIVE) { /* Stop sampling procedure. */ rt_timer_stop(g_sNuADC.psRtTouchMenuTimer); /* Re-start pendown detection */ nu_adc_touch_detect(RT_TRUE); bDrop = RT_TRUE; } else { bDrop = RT_FALSE; } /* Notify upper layer. */ if ((!bDrop || (u32LastZ0 > ADC_TOUCH_Z0_ACTIVE)) && rt_mq_send(psNuAdc->m_pmqTouchXYZ, (const void *)&point, sizeof(struct nu_adc_touch_data)) == RT_EOK) { rt_hw_touch_isr(psNuAdc->psRtTouch); } u32LastZ0 = point.u32Z0; } else #endif { rt_err_t result = rt_sem_release(psNuAdc->m_psSem); RT_ASSERT(result == RT_EOK); } return 0; } ``` 如下是rtthread用于处理触摸事务的线程。这里等待信号量,并读取邮箱数据,获得触摸ADC值。转换成坐标值(`nu_adc_touch_readpoint()`函数中)。然后调用`nu_touch_inputevent_cb()`回调函数向后级驱动提交数据。原始驱动,这里来什么信号就提交什么信号。个人感觉对于这种类似按键的输入设备,还是加一个消抖的好。于是加入了`touch_active_cnt`触摸有效计数的变量。有效触发值也可以用宏定义修改。我用的也是2。响应速度和稳定度都让人很满意。 ```C static void adc_touch_entry(void *parameter) { struct rt_touch_data touch_point; rt_err_t result; rt_device_t pdev; int max_range; int16_t touch_active_cnt=0; BOOL touch_active_flag = FALSE; adc_touch_sem = rt_sem_create("adc_touch_sem", 0, RT_IPC_FLAG_FIFO); RT_ASSERT(adc_touch_sem != RT_NULL); pdev = rt_device_find("adc_touch"); if (!pdev) { rt_kprintf("Not found\n"); return ; } if (rt_memcmp((void *)&g_sCalMat, (void *)&g_sCalZero, sizeof(S_CALIBRATION_MATRIX)) != 0) g_u32Calibrated = 1; nu_adc_touch_readfile(); result = rt_device_open(pdev, RT_DEVICE_FLAG_INT_RX); RT_ASSERT(result == RT_EOK); result = rt_device_set_rx_indicate(pdev, adc_touch_rx_callback); RT_ASSERT(result == RT_EOK); max_range = BSP_LCD_WIDTH; result = rt_device_control(pdev, RT_TOUCH_CTRL_SET_X_RANGE, (void *)&max_range); RT_ASSERT(result == RT_EOK); max_range = BSP_LCD_HEIGHT; result = rt_device_control(pdev, RT_TOUCH_CTRL_SET_Y_RANGE, (void *)&max_range); RT_ASSERT(result == RT_EOK); result = rt_device_control(pdev, RT_TOUCH_CTRL_POWER_ON, RT_NULL); RT_ASSERT(result == RT_EOK); while (adc_touch_worker_run) { if (!g_u32Calibrated) { rt_kprintf("Start ADC touching calibration.\n"); nu_touch_do_calibration(pdev); rt_kprintf("Stop ADC touching calibration.\n"); continue; } if (adc_request_point(pdev, &touch_point) == RT_EOK) { if (touch_point.event == RT_TOUCH_EVENT_DOWN || touch_point.event == RT_TOUCH_EVENT_UP || touch_point.event == RT_TOUCH_EVENT_MOVE) { if(touch_point.event == RT_TOUCH_EVENT_DOWN || touch_point.event == RT_TOUCH_EVENT_MOVE) { if(touch_active_cnt < ADC_TOUCH_FILTER_VAL) { touch_active_cnt++; } else { touch_active_flag = TRUE; } } else { if(touch_active_cnt < ADC_TOUCH_FILTER_VAL) { rt_kprintf("err touch:%d\r\n",touch_active_cnt); } touch_active_cnt = 0; } if(touch_active_flag) { nu_touch_inputevent_cb(touch_point.x_coordinate, touch_point.y_coordinate, touch_point.event); rt_kprintf("x=%d y=%d event=%s%s%s\n", touch_point.x_coordinate, touch_point.y_coordinate, (touch_point.event == RT_TOUCH_EVENT_DOWN) ? "DOWN" : "", (touch_point.event == RT_TOUCH_EVENT_UP) ? "UP" : "", (touch_point.event == RT_TOUCH_EVENT_MOVE) ? "MOVE" : ""); } if(touch_active_cnt == 0) { touch_active_flag = FALSE; } } } else { if(touch_active_cnt) { rt_kprintf("err touch:%d\r\n",touch_active_cnt); } touch_active_cnt = 0; } } result = rt_device_control(pdev, RT_TOUCH_CTRL_POWER_OFF, RT_NULL); RT_ASSERT(result == RT_EOK); result = rt_device_close(pdev); RT_ASSERT(result == RT_EOK); } ``` 整体改动不多,是一个小优化,有遇到相同问题的小伙伴可以自己把上面的逻辑加到代码中。
4
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
吉利咕噜2022
国防科大-军品研发
文章
18
回答
3
被采纳
2
关注TA
发私信
相关文章
1
LittlevGL + DMA2D 显示图案扭曲
2
LittleVGL2RTT软件包还有在维护吗,测试遇到一些问题求解
3
使用littlevgl2rtt软件包实例运行不成功,emwin正常
4
关于littlevgl2rtt软件包刷频慢的解决方案?
5
移植了littlevGUI之后,用动态 线程去跑例程会卡死
6
lvgl的字体、图片文件如何升级?
7
qemu-vexpress-a9bsp下的littvgl工程可以实现触屏操作吗?
8
LVGL控件刷新死机问题
9
在lvgl上设置一个时间显示的label,一段时间后所有控件消失。
10
littlevgl2rtt和littlevgl的pc模拟器源码不兼容吗?
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
freemodbus
PWM
flash
cubemx
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
flashDB
GD32
socket
中断
编译报错
Debug
SFUD
rt_mq_消息队列_msg_queue
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
a1012112796
10
个答案
1
次被采纳
踩姑娘的小蘑菇
4
个答案
1
次被采纳
红枫
4
个答案
1
次被采纳
张世争
4
个答案
1
次被采纳
Ryan_CW
4
个答案
1
次被采纳
本月文章贡献
catcatbing
3
篇文章
5
次点赞
YZRD
2
篇文章
5
次点赞
qq1078249029
2
篇文章
2
次点赞
xnosky
2
篇文章
1
次点赞
Woshizhapuren
1
篇文章
5
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部