在不占用大量CPU的情况下读取串行数据 [英] Read serial data without high CPU use

查看:117
本文介绍了在不占用大量CPU的情况下读取串行数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在Linux下以简单的C或C ++程序读取Arduino通过FTDI(串行)接口发送的消息. Arduino发送两个字符的标头",一个命令字节,然后是几个字节的数据,具体取决于命令.

我的第一个尝试是简单地使用open()和read()轮询数据,但是这样做导致大约12%的CPU使用率.这似乎不是做事的适当方法.

第二,我阅读了实现libevent的事件循环,该事件循环在文件描述符中存在数据时触发一个事件.我的CPU使用率几乎为零,但是在调用另一个事件之前,我无法读取整个消息.当接收到整个消息时,事件不会触发,但是一旦文件描述符上的任何/某些数据可用,事件就不会触发.从更多的角度来看,很明显这并不能完全按照我想要的方式工作.这是我的活动代码: http://pastebin.com/b9W0jHjb

第三,我用libevent实现了一个缓冲事件.它似乎工作得更好,但仍将一些消息拆分开了.我的活动代码是: http://pastebin.com/PQNriUCN

第四,我转储了libevent并尝试了Boost的ASIO类.我遵循的示例是 http://www.webalice.it/fede.tft /serial_port/serial_port.html .似乎工作正常,但事件循环"是"while(1){}",这导致CPU使用率再次上升.循环仅在其他线程的回调中进行串行读取时检查错误状态.我在while循环中添加了usleep(1),这使我的CPU使用率达到了2%,这还可以,但是对于这样一个轻量级的程序来说似乎仍然很繁琐.

大多数libevent实例甚至底层epoll都使用TCP套接字,该套接字的行为似乎与串行端口数据不太相同.

所以我的主要问题是:什么是在不进行大量轮询的情况下从串行端口读取消息的良好的轻量级方法? (在Linux中,使用C或C ++)

解决方案

OP可能已经解决了很长时间,但是为了任何被google吸引到这里的人:

#include <sys/poll.h>

struct pollfd fds[1];
fds[0].fd = serial_fd;
fds[0].events = POLLIN ;
int pollrc = poll( fds, 1, 1000);
if (pollrc < 0)
{
    perror("poll");
}
else if( pollrc > 0)
{
    if( fds[0].revents & POLLIN )
    {
        char buff[1024];
        ssize_t rc = read(serial_fd, buff, sizeof(buff) );
        if (rc > 0)
        {
            /* You've got rc characters. do something with buff */
        }
    }
}    

确保串行端口以非阻塞模式打开,因为当没有字符等待时,poll()有时会返回.

I want to read messages sent from an Arduino via the FTDI (serial) interface in a simple C or C++ program under Linux. The Arduino sends a two character 'header', a command byte followed by a few bytes of data depending on the command.

My first attempt was to simply poll the data using open() and read() but doing so causes about 12% CPU use. This didn't seem to be the appropriate way of doing things.

Second I read up on libevent on implemented an event loop that fires an event when data is present on the file descriptor. My cpu usage was next to nothing but I couldn't read the entire message before another event was called. The events didn't fire when an entire message was received but as soon as any/some data was available on the file descriptor. Looking at it more it was obvious that this wouldn't work quite the way I wanted it. This is my event code: http://pastebin.com/b9W0jHjb

Third I implemented a buffered event with libevent. It seemed to work somewhat better but still split some of the messages up. My event code is: http://pastebin.com/PQNriUCN

Fourth I dumped libevent and tried out Boost's ASIO class. The example I was following was http://www.webalice.it/fede.tft/serial_port/serial_port.html. It seemed to work alright but the "event loop" was a "while(1) {}" which caused CPU usage to go up again. The loop just checks for error status while serial reading happens in a callback on a different thread. I added a usleep(1) to the while loop and it brought my CPU usage to 2% which is ok, but still seems heavy for such a light program.

Most of the examples of libevent and even the underlying epoll use TCP sockets which doesn't seem to behave quite the same as serial port data.

So my main question is: what is a good lightweight way to read messages from a serial port without heavy polling? (in linux, using C or C++)

解决方案

The OP has probably long since solved this, but for the sake of anyone who gets here by google:

#include <sys/poll.h>

struct pollfd fds[1];
fds[0].fd = serial_fd;
fds[0].events = POLLIN ;
int pollrc = poll( fds, 1, 1000);
if (pollrc < 0)
{
    perror("poll");
}
else if( pollrc > 0)
{
    if( fds[0].revents & POLLIN )
    {
        char buff[1024];
        ssize_t rc = read(serial_fd, buff, sizeof(buff) );
        if (rc > 0)
        {
            /* You've got rc characters. do something with buff */
        }
    }
}    

Make sure the serial port is opened in nonblocking mode as poll() can sometimes return when there are no characters waiting.

这篇关于在不占用大量CPU的情况下读取串行数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆