5、数码相框之使用多种方法支持多输入
文章目录
- 1、轮询方式
- 1.1、代码编写
- 初始化函数TouchScreenDevInit
- 关于获取时间的函数TouchScreenGetInputEvent
- 向上注册结构体
- 程序执行过程
- 1.2、配置tslib
- 在线安装
- 手动安装
- 编译tslib
- 使用tslib
- 测试运行
- 2、select方式
- select函数介绍
- 程序编写流程
- 具体代码
- 3、多线程方式
- 三种输入方式的流程比较
- 多线程介绍
- 编写代码
- 测试
- 实现滑动翻页
- 具体代码
上一节:4、数码相框之编写通用的Makefile
下一节:6、数码相框之网络编程
1、轮询方式
1.1、代码编写
关于stdin.c
部分参照touchscreen
部分来修改,关于touchscreen.c
部分:
初始化函数TouchScreenDevInit
参照tslib里面的ts_test.c中的main函数
1、先以非阻塞的方式打开设备
2、配置ts
3、获取ts的分辨率
之所以要获取分辨率是因为我们ts
是根据触点触发的位置来判断对应的翻页动作,由于我们的ts
实际上是贴在LCD
的上的,其实就是获取LCD
的分辨率,而LCD
的分辨率我们在之前的display
模块中已经有定义。
并且在draw
层已经提供了接口函数:
关于获取时间的函数TouchScreenGetInputEvent
思路:
a、我们就是想通过获取触摸屏触发的事件来判断对应的事件类型,并且来做相应的操作;
b、由于触摸可能会有抖动,,致多次触发,所以我们要做个延时,500ms
以内的重复动作不进行处理
参照ts_test.c
中的main
里面的ts_read
的步骤。
1、首先是读ts的动作
我们知道ts_read
的结果是保存在了tSamp
中,我们通过去tslib
里面的源码知道这个结构体的内容如下:
也就是说ts_read
返回了触点的坐标,而我们要的就是根据触点的y坐标
来执行翻页的动作。
2、根据触点的坐边处理事件类型,并且初始化操作的结构体
3、防抖动处理
定义两个参数,一个记录前一个的事件触发时的时间
,一个记录当前的事件的触发时间
,每次都可以在ts_read
中可以获取。
向上注册结构体
关于input_manager.c
部分:
直接复制一个其他模块的manager.c
,然后修改名字。
关于修改main.c
:
增加初始化函数和获取事件的函数
关于makefile
:
将新增的文件添加如makefile
,输入模块如下:
程序执行过程
从 main 函数开始
-> 各种初始化
-> 调用 GetInputEvent
-> 显示
,不断在调用GetInputEvent
-> 显示
,之间循环 。
1.2、配置tslib
在线安装
sudo apt-get install autoconf
sudo apt-get install automake
sudo apt-get install libtool
手动安装
将tslib
相关文件解压在usr/local
目录下:
1、安装m4
wget http://mirrors.kernel.org/gnu/m4/m4-1.4.13.tar.gz \
&& tar -xzvf m4-1.4.13.tar.gz \
&& cd m4-1.4.13 \
&& ./configure -prefix=/usr/local
sudo make
sudo make install
2、安装autoconf
wget http://mirrors.kernel.org/gnu/autoconf/autoconf-2.65.tar.gz \
&& tar -xzvf autoconf-2.65.tar.gz \
&& cd autoconf-2.65 \
&& ./configure -prefix=/usr/local
sudo make
sudo make install
3、安装automake
wget http://mirrors.kernel.org/gnu/automake/automake-1.11.tar.gz \
&& tar xzvf automake-1.11.tar.gz \
&& cd automake-1.11 \
&& ./configure -prefix=/usr/local
sudo make
sudo make install
4、安装libtool
wget http://mirrors.kernel.org/gnu/libtool/libtool-2.2.6b.tar.gz \
&& tar xzvf libtool-2.2.6b.tar.gz \
&& cd libtool-2.2.6b \
&& ./configure -prefix=/usr/local
sudo make
sudo make install
编译tslib
编译:
tar xzf tslib-1.4.tar.gz
cd tslib
./autogen.sh
mkdir tmp
echo "ac_cv_func_malloc_0_nonnull=yes" >arm-linux.cache./configure --host=arm-linux --cache-file=arm-linux.cache --prefix=$(pwd)/tmp
make
make install
安装:
cd tmp
cp * -rf /nfs_root_first_fs
tslib
出错解决方法:
使用tslib
1、装在触摸屏模块
insmod s3c_ts.ko //确定是哪个设备节点对应触摸屏
修改 /etc/ts.conf第1行(去掉#号和第一个空格):
# module_raw input
改为:
module_raw input
2、设置参数
export TSLIB_TSDEVICE=/dev/event0
export TSLIB_CALIBFILE=/etc/pointercal
export TSLIB_CONFFILE=/etc/ts.conf
export TSLIB_PLUGINDIR=/lib/ts
export TSLIB_CONSOLEDEVICE=none
export TSLIB_FBDEVICE=/dev/fb0
3、较准触摸屏
ts_calibrate
测试运行
4、运行应用程序
./show_file -s 24 -d fb -f ./MSYH.TTF ./utf8_novel.txt
5、运行telnetd查看cpu使用率
telnetd -l /bin/sh //启动telnet服务,为了登录进去观察CPU占用率
6、telnet上开发板执行top命令观察
在 SecureCRT
新建一个连接,远程登录开发板:
查看进程:
运行 top
命令:
发现 CPU
占用率达到了 86.4%
(点击时 99%
),非常地高:
2、select方式
select函数介绍
关于 select
函数,详见《UNIX 环境高级编程》IO 多路转接内容。
使用select,poll:CPU占用率低,适用于很多简单场合
监测多个文件,只要有某一个文件可读/可写/异常或超时,即返回int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);最大文件句柄+1 被监测是否可读的文件 超时时间被监测是否可写的文件被监测是否有异常的文件
我们select
的最后一个参数超时时间设置为NULL
,表示无限等待知道有可读的文件
select
函数机制和 poll
函数机制是一样的,如果想要具体了解的话,看第一期:
程序编写流程
我们现在要使用阻塞的方式来控制触摸屏的输入,用select
的方法:
- 1、由于当前我们有
stdin
和ts
两种终端输入方式,打开每种终端方式都会得到一个文件描述符fd
。 - 2、
select
的方法首先要定义一个fd_set
类型变量,这个变量其实就是一个由很多二进制位构成的数组,其中的每个bit
都代表一个文件描述符。 - 3、我们要将我们要检测的两个文件描述符放到这个
fd_set
类型的变量中,通过int FD_SET(int fd, fd_set *fd_set);
来实现,由于我们在mian
中会调用AllInputDevicesInit
来初始化ts
和stdin
设备,这个函数就是通过遍历链表的方式,来调用每个终端对应的初始化函数,我们就在这个函数里面依次调用对应的初始化的时候来执行FD_SET
函数将每个终端的文件描述符放到fd_set
类型变量中,所以我们还要在inputopr
结构体里加上一个成员fd
,用来获取每个终端对应的描述符以便在AllInputDevicesInit
中使用:
上面的方框1:
我们在使用fd_set
类型变量前一般都需要通过FD_ZERO
来将一个fd_set
类型变量的所有位都设为 0。
上面的方框2:
就是利用了input_opr
中新增的成员ifd
,在依次遍历链表的时候将他们写入到对应的fd_set
类型变量的bit
位中。
上面的方框3:
这个g_iMaxFd
是个全局变量,每次遍历时最终获得了所有监控的文件的fd
的最大值,最终自加一次,是因为select
函数的第一个参数就是最大的fd + 1
。 - 4、然后我们还需要在
对应的终端的.c
中去将每个终端的fd
成员初始化获得自己的fd
。
Stdin.c:
Touchscreen.c:
- 5、最后就是由于我们
mian
中是while
里面一直循环调用获取事件的函数GetInputEvent
我们就是要在GetInputEvent
中实现select
的方法。
程序执行过程:从 main 函数开始
-> 各种初始化
-> 调用 GetInputEvent
-> select 函数休眠(等待内核把它唤醒)
-> 显示
。
程序会不断在 调用 GetInputEvent -> select 函数休眠(等待内核把它唤醒)
-> 显示
,之间循环。
代码在 8.show_file_多种方法支持多输入\10.show_file_input\02.show_file_input_select
中。
具体代码
在input_manager.h
中:
在stdin.c
的StdinDevInit
函数中:
在touchscreen.c
的TouchScreenDevInit
函数中:
在input_manager.c
中,定义全局变量:
在AllInputDevicesInit
函数中:
在GetInputEvent
函数中:
3、多线程方式
三种输入方式的流程比较
法一:查询方式
// CPU 占用率高
法二:select
机制 // CPU 占用率低,适用于很多简单的场合
法三:使用多线程
// CPU 占用率低,非常灵活,使用的场合非常地广泛
多线程介绍
在使用多线程之前,我们先来看一个文档,第 1 个 项 目 数 码 相 框全 部 源 码 _ 图片 _ 文档 \ 源码 ( 含 讲 课 过 程 中 即 时 编 写 的 文 档 ) \ 0 8 . s h o w _ f i l e_ 多种方法支持多输入\doc
。
参考 Unix_Linux_Windows_OpenMP 多线程编程.pdf
的第18页 3.3.2 条件变量
:
主线程: 主体是一个死循环。谁来把 GetInputEvent
唤醒另外一个线程。
stdin 线程: 它的主体是一个死循环。调用获得字符(getch)函数,如果没有获得字符的话就休眠。获得字符之后去唤醒休眠状态的主线程。
touchscreen 线程: 它的主体也是一个死循环。读取触摸屏,读到触摸屏数据之后也是去唤醒休眠的主线程。
代码在第 1 个 项 目 数 码 相 框全 部 源 码 _ 图片 _ 文档 \ 源码 ( 含 讲 课 过 程 中 即 时 编 写 的 文 档 ) \ 0 8 . s h o w _ f i l e _ 多种方法支持多输入\10.show_file_input\03.show_file_input_thread
中。
编写代码
C 语言关于函数的指针语法补充:
int (*p1)(char a,char b,int c); // 定义一个函数指针
void (*p2)(void); // 定义一个函数指针
p1 = (int (*)(char, char ,int))p2; // 对函数指针进行强制类型转换
互斥地访问一个变量:
同一时间,一个全局变量只能被一个线程访问。
如果有多个线程同时访问一个全局变量,可能就会出问题
互斥量:
你想去访问一个全局变量的时候,这个全局变量可能有三个线程同时访问。
我们怎么能够让这三个线程互斥地访问这个全局变量呢?设置一个锁,获得锁才能访问。
修改代码的步骤:
由于我们要实现多线程的编程,其中一个主线程。
对于主线程我们要做的是:
1、在初始化输入设备的时候创建线程,每初始化一个输入设备就创建一个线程。
创建完线程之后由于我们有两个输入设备stdin
和ts
,也就是说加上主线程一共三个线程,三个线程同时运行。
我们先继续说主线程:
主线程之后就要进入while(1)
等待输入事件,然后显示,由于我们要等待输入事件,所以我们要在主线程等待输入时间的时候让主线程挂起,而这个输入事件是通过子线程来通知唤醒主线程的,这就涉及到了线程间的通信,线程间的通信的方法:
这样我们就要用到一个条件变量,当条件变量被设置之后,主线程才能继续执行,而条件变量最好放到一个互斥体mutex
中,这是为了防止主线程在真正进入等待状态之前别的线程有可能设置该条件变量而产生竞争。
所以我们修改等待时间的函数:
需要注意的是,现在这个是等待事件的函数已经和我们之前的等待事件函数完全不同了,之前是在这个函数里面分别调用对应输入设备的GetInputEvent
函数,然后返回事件的类型,而我们现在由于每个事件都是独立的线程,所以我们要在每个独立线程里面去通过对应的GetInputEvent
函数获取事件类型值,然后去唤醒主线程,把每个输入设备的返回的事件类型传递给主线程,所以现在的这个函数的功能仅仅是让主线程挂起,等待子线程唤醒,接收子线程提供的事件类型。
下面分析子线程的代码:
当主线程创建完子线程之后,子线程就开始运行了。
子线程就会跳到InputEventTreadFunction
去执行;
那我们在InputEventTreadFunction
中应该干什么事情呢?
我们要去自己对应的输入设备中的PT_InputEvent
结构体中通过GetInputEvent
函数来获取对应的事件;
然后获取到事件后,唤醒主线程,传递参数给主线程;
由于我们要调用对应的PT_InputEvent
结构体中的GetInputEvent
成员,我们可以在创建线程的时候就把这个成员当作参数传递给对应的子线程。
然后要进行类型转行,接着就是while(1)
里面去读取对应的事件,如果读取到了,就去获得锁,并唤醒主线程,之后释放锁。
测试
1、装在触摸屏模块
insmod s3c_ts.ko //确定是哪个设备节点对应触摸屏
修改 /etc/ts.conf第1行(去掉#号和第一个空格):
# module_raw input
改为:
module_raw input
2、设置参数
export TSLIB_TSDEVICE=/dev/event0
export TSLIB_CALIBFILE=/etc/pointercal
export TSLIB_CONFFILE=/etc/ts.conf
export TSLIB_PLUGINDIR=/lib/ts
export TSLIB_CONSOLEDEVICE=none
export TSLIB_FBDEVICE=/dev/fb0
3、较准触摸屏
ts_calibrate
4、运行应用程序
./show_file -s 24 -d fb -f ./MSYH.TTF ./utf8_novel.txt
5、运行telnetd查看cpu使用率
telnetd -l /bin/sh //启动telnet服务,为了登录进去观察CPU占用率
6、telnet上开发板执行top命令观察
在 SecureCRT
新建一个连接,远程登录开发板:
查看进程:
运行 top
命令:
平时都在休眠状态:
查看 ps
用法:
显示所有线程:
主线程 , stdin 线程 , touchscreen 线程:
再用 top 命令观察 CPU 占用率:
0% 因为他们都在休眠状态
在开发板上进行翻页操作时:
停止操作一段时间后,又变为休眠状态:
实现滑动翻页
触摸点在X方向的位移差值超过x分辨率的5分之1,就翻页
代码在:第 1 个 项 目 数 码 相 框全 部 源 码 _ 图片 _ 文档 \ 源码 ( 含 讲 课 过 程 中 即 时 编 写 的 文 档 ) \ 0 8 . s h o w _ f i l e _ 多种方法支持多输入\10.show_file_input\04.show_file_input_slip
中。
具体代码
- 1、在
input_manager.h
中:
- 2、在
main
函数中:
- 3、在
input_manager.c
中:
定义全局变量:
创建子线程:
获得输入事件:
在mian
函数中:
- 4、在
input_manager.c
中:
- 5、在
stdin.c
中:
- 6、在
touchscreen.c
中:
处理滑动翻页:
- 7、在
touchscreen.c
中:
上一节:4、数码相框之编写通用的Makefile
下一节:6、数码相框之网络编程
5、数码相框之使用多种方法支持多输入相关推荐
- python怎么读文件内容-Python读取文件内容为字符串的方法(多种方法详解)
以下笔记是我在 xue.cn 学习群之数据分析小组所整理分享的心得.相关背景是:我选择中文词频统计案例作为考察大家python基础功掌握程度. 以小见大,下面是2个小技能的具体实战: 如何灵活地处理文 ...
- 多种方法教你破解电信共享上网的限制
现在很多家庭都有不止一台电脑,多台电脑要实现共享上网,以前大家一般都是通过路由器来实现多台电脑共享上网,但是随着宽带用户的增加,各地的电信开始纷纷封杀家庭用户的多机共享上网,让不少消费者伤透了头脑,难 ...
- 多种方法巧妙优化数据库
多种方法巧妙优化数据库 日期:2011/12/24 16:18:01 来源:本站 点击率:330 我要评论(0)字号:T T T 1.没有索引或者没有用到索引(这是查询慢最常见的问题, ...
- html下拉框变长,改变HTML下拉框SELECT选项的多种方法
原标题:改变HTML下拉框SELECT选项的多种方法 提交表单后返回的HTML页面重新渲染,SELECT控件的value和selectedIndex属性都无法使下拉框保留提交表单前的状态. 复制代码 ...
- python判断字母数字_Python判断字符串是否为字母或者数字(浮点数)的多种方法
str为字符串s为字符串 str.isalnum() 所有字符都是数字或者字母 str.isalpha() 所有字符都是字母 str.isdigit() 所有字符都是数字 str.isspace() ...
- python去重语句_Python对列表去重的多种方法(四种方法)
无聊统计了下列表去重到底有多少种方法.下面小编给大家总结一下,具体内容详情如下: 开发中对数组.列表去重是非常常见的需求,对一个list中的id进行去重,有下面几种方法,前面两种方法不能保证顺序, 后 ...
- python清空集合_python集合删除多种方法详解
这篇文章主要介绍了python集合删除多种方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 删除指定的元素 A={'a','c','b','d ...
- vue点击网页全屏_vue中实现点击变成全屏的多种方法
项目中有点击按钮实现全屏功能 方式一:js实现全屏 全屏 data: data() { return { fullscreen: false }; }, methods: screen() { let ...
- 多种方法让你在PC上使用iCloud服务
多种方法让你在Windows上优雅的使用iCloud服务 我平时习惯使用 日历.待办事项+2Do 等App,而在Windows上无法使用它们. 由于我爱好各种大型单机游戏,所以短时间内不会选择更换Ma ...
最新文章
- 『高级篇』docker容器来说什么是微服务(三)
- 穿着健美裤的美女,她们身材好是锻炼出来的
- 重拾IP路由选择:CCNA学习指南中的IP路由选择
- Windows内存管理学习笔记(三)—— 无处不在的缺页异常
- (转)科学是怎样产生的
- 【转】_declspec(naked) 使用
- webpack 读取文件夹下的文件_webpack基本介绍及使用
- js空格占位符_灵活使用 console 让 js 调试更简单
- PAT_1056_组合数的和(15)
- 推荐一款优雅的 Android 学习 App
- 网速提高学习周——软件篇
- 从零开始学WEB前端——VUE介绍
- Lwip的udp编程
- 机器学习丨如何理解正定矩阵和半正定矩阵
- MQL5 中如何调用指标
- C++程序设计图书信息管理系统(页面)
- 开源mysql执行平台_MySQL自动化审核平台部署说明
- SparkConf 配置的概念和用法
- 使用sketchfab下载artstation资源导入到UE流程
- 全国计算机一级考试网上题,全国计算机一级考试精选习题及答案