读取串行数据,无需高CPU使用

时间:2011-08-12 04:15:52

标签: linux serial-port

我希望在Linux下的简单C或C ++程序中通过FTDI(串行)接口读取从Arduino发送的消息。 Arduino发送一个两个字符的“标题”,一个命令字节,后跟几个字节的数据,具体取决于命令。

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

其次我读了libevent on实现了一个事件循环,当文件描述符上存在数据时触发事件。我的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 ++)

1 个答案:

答案 0 :(得分:13)

OP可能早已解决了这个问题,但是为了任何通过谷歌来到这里的人:

#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()有时会返回。