多输入之轮询
多输入之轮询
代码仓库
方式一
https://gitee.com/layty/project_for_linux/tree/master/03-ebook/02_input_by_query
方式二
https://gitee.com/layty/project_for_linux/tree/master/03-ebook/03_input_by_query_select
引入
这里我们采用两种方式的输入,使用查询的方式来读取具体的输入,轮询的前提就是所有输入设备都是非阻塞的
- 触摸屏
- 标准输入
关于这里的io模型,select参考《嵌入式Linux应用程序开发标准教程》
里面的第六章
触摸屏
对于触摸屏的库tslib
,支持非阻塞打开,也就是传递参数1
即可
struct tsdev *ts_open(const char *name, int nonblock)
{
if (nonblock)
flags |= O_NONBLOCK;
}
O_NONBLOCK (non-blocking) 它在读取不到数据时会回传-1,并且设置errno为 EAGAIN
具体的使用代码可以参考tslib-1.4.tar.gz/tests/ts_print.c
标准输入
标准输入这里可以有两种方式:
方式一 设置终端输入为非阻塞
struct termios tTTYState;
//get the terminal state
tcgetattr(STDIN_FILENO, &tTTYState);
//turn off canonical mode
tTTYState.c_lflag &= ~ICANON;
//minimum of number input read.
tTTYState.c_cc[VMIN] = 0;
// 立即返回
tTTYState.c_cc[TIME] = 0;
//set the terminal attributes.
tcsetattr(STDIN_FILENO, TCSANOW, &tTTYState);
然后从流中读取
int num_read,ch;
char buf_read[10];
num_read = fread(buf_read, 1, 1, stdin);
if(num_read)
{
ch=buf_read[0];
....
}
方式二 :使用阻塞一个字符,然后使用select的超时为0来达到非阻塞的效果
static int StdinDevInit(void)
{
struct termios tTTYState;
//get the terminal state
tcgetattr(STDIN_FILENO, &tTTYState);
//turn off canonical mode
tTTYState.c_lflag &= ~ICANON;
//minimum of number input read.
tTTYState.c_cc[VMIN] = 1; /* 这里其实是阻塞的有一个数据时就立刻返回 */
//set the terminal attributes.
tcsetattr(STDIN_FILENO, TCSANOW, &tTTYState);
return 0;
}
然后读取输入的时候用select
来监视读取的流,select的超时为0也就是没有数据就马上退出
int StdGet(T_InputEvent* out_input_event)
{
struct timeval time_out;
//这里的串口读取是阻塞的,select可以设置出一个超时时间,如果设置超时为0,则也就是非阻塞的了
fd_set uart_fd_set;
time_out.tv_sec = 0;
time_out.tv_usec = 0;
FD_ZERO(&uart_fd_set);
FD_SET(STDIN_FILENO, &uart_fd_set); //注意这里使用的文件句柄,而不是File*
/* fd+1,readfds,writefds,exceptfds,timeout */
select(STDIN_FILENO+1, &uart_fd_set, NULL, NULL, &time_out);//这里就是监控 STDIN_FILENO 下的读的操作
// 有数据返回
if(FD_ISSET(STDIN_FILENO,&uart_fd_set))
{
char ch;
ch=fgetc(stdin);
if(ch)
....
}
}
BUGS
在老师的视频处理触摸屏的时候,代码如下,这里判断的iRet=0
的时候也去返回数据,这里应该是有问题的,但是老师在使用select机制来使终端的时候触摸屏不会有问题,而使用我的直接设置终端不阻塞就有问题,希望高手帮忙分析一下
iRet = ts_read(g_tTSDev, &tSamp, 1);
if (iRet < 0) { //这里应该是 if (iRet <= 0) 0也是没有有效数据的
return -1;
}
还有就是判断超时,没有判断大小,所以应该先判断大小先,这里应该没什么关系
static int isOutOf500ms(struct timeval *ptPreTime, struct timeval *ptNowTime)
{
int iPreMs;
int iNowMs;
iPreMs = ptPreTime->tv_sec * 1000 + ptPreTime->tv_usec / 1000;
iNowMs = ptNowTime->tv_sec * 1000 + ptNowTime->tv_usec / 1000;
return (iNowMs > iPreMs + 500);
}
static int isOutOf500ms(struct timeval *ptPreTime, struct timeval *ptNowTime)
{
int iPreMs;
int iNowMs;
int ret;
iPreMs = ptPreTime->tv_sec * 1000 + ptPreTime->tv_usec / 1000;
iNowMs = ptNowTime->tv_sec * 1000 + ptNowTime->tv_usec / 1000;
ret=iPreMs-iNowMs;
if(ret>500 || ret <-500)
{
return 1;
}
else
{
return 0;
}
}
实验
-
tslib库,这里如果有问题看之前的触摸屏驱动文章
-
修改
/etc/ts.conf
第1行(去掉#号和第一个空格),# module_raw input
改为module_raw input
-
设置环境变量
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
-
-
开启telnet
telnetd -l /bin/sh
-
运行程序
./show_file -f simsun1.ttc -s 12 main.c
-
pc上可以使用telnet再登录开发板查看cpu