在Linux上的多线程程序中读取串口

时间:2011-03-14 15:00:20

标签: c linux multithreading serial-port

我正在linux中编写一个程序,通过串口与一块硬件进行接口。该设备以大约10Hz的频率发送大约30-40字节的数据包。该软件模块将与其他人连接并通过IPC进行通信,因此它必须执行特定的IPC休眠,以允许它在没有做任何有用的事情时接收它所订阅的消息。

目前我的代码类似于:

while(1){
  IPC_sleep(some_time);
  read_serial();
  process_serial_data();
}

问题在于,有时读取将在串口上只有下一个数据包的一小部分可用的情况下执行,这意味着直到下一次循环才会读取它。对于特定的应用程序,最好在数据可用时立即读取,并且程序在读取时不会阻塞。

这个问题的最佳解决方案是什么?

4 个答案:

答案 0 :(得分:3)

将你到目前为止所获得的内容存储在某种缓冲区中。

如果您不想在等待新数据时阻止,请使用select() on the serial port之类的内容检查是否有更多数据可用。如果没有,您可以继续进行一些处理或需要做的任何事情,而不是阻塞,直到有数据要提取。

当其余数据到达时,添加到缓冲区并检查是否有足够的数据来构成完整的消息。如果有,请处理它并将其从缓冲区中删除。

答案 1 :(得分:3)

最好的解决方案是不要睡觉!我的意思是一个好的解决方案可能是混合 IPC事件和串行事件。选择是一个很好的工具来做到这一点。然后你必须找到和选择兼容的IPC机制。

  • 基于套接字的IPC select()能够
  • 基于管道的IPC select()能够
  • posix消息队列也是可选择的

然后你的循环看起来像这样

while(1) {
    select(serial_fd | ipc_fd); //of course this is pseudo code
    if(FD_ISSET(fd_set, serial_fd)) {
        parse_serial(serial_fd, serial_context);
        if(complete_serial_message)
            process_serial_data(serial_context)
    }
    if(FD_ISSET(ipc_fd)) {
        do_ipc();
    }
}

read_serial替换为parse_serial,因为如果您将所有时间都花在等待完整的串行数据包上,那么选择的所有好处都将丢失。但是从您的问题来看,您似乎已经在这样做,因为您提到了在两个不同的循环中获取串行数据 使用所提出的架构,您在IPC和串行端都具有良好的反应性。您可以在串行数据可用时立即读取,但无需停止处理IPC。

当然,它假设您可以更改IPC机制。如果你不能,也许你可以制作一个“桥接过程”,一方面与你坚持使用的IPC接口,另一方面使用select()able IPC与你的串行代码进行通信。

答案 2 :(得分:2)

您必须缓存足够的邮件,以确定邮件是否为完整邮件,或者您是否拥有完整的有效邮件。

如果它无效或者不在可接受的时间范围内,那么你就抛弃它。否则,你保留并处理它。

这通常称为实现设备协议的解析器。

答案 3 :(得分:0)

这是所需的算法(阻塞):

while(! complete_packet(p) &&  time_taken < timeout)
{
   p += reading_device.read(); //only blocks for t << 1sec. 

   time_taken.update();   
}
//now you have a complete packet or a timeout. 

如果您愿意,可以散布回调,或者在处理循环中注入相关部分。