我想使用串口与其他设备txdev进行通信,问题是txdev异步发送数据而且我不想阻止read
功能,好的是txdev正在发送固定大小的数据,但我不知道如何使用这个技巧。
我正在做的是以下内容:
fd = open(DEVICE_NAME, O_RDWR | O_NOCTTY);
bzero(&termios_p, sizeof(termios_p));
termios_p.c_cflag = CS8|CSTOPB|CLOCAL|CREAD;
termios_p.c_iflag = IGNPAR;
termios_p.c_oflag = 0;
termios_p.c_lflag = ~ICANON;
termios_p.c_cc[VMIN]=DATA_LENGTH;
termios_p.c_cc[VTIME]=10;
cfsetispeed(&termios_p, BAUDRATE);
cfsetospeed(&termios_p, BAUDRATE);
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&termios_p);
来自this post i undrestand这导致读取被阻止VTIME = 0也被阻止。
任何人都可以帮我找出解决方案我认为我必须使用中断处理程序而不是read
你同意吗?
第二个问题:由于发送方无法与接收方同步,因此存在一个中断处理程序,将接收到的数据存储在指定的缓冲区中(我认为这是Canonical模式的情况,但不是非规范模式)或者只有在达到read
功能时才会这样做,如果我错了请纠正我
像往常一样非常感谢。
答案 0 :(得分:4)
我想使用串口与另一台设备txdev通讯,问题是txdev是异步发送数据而我不希望读取功能被阻塞,
您似乎误解了Linux应用程序应该如何读取和写入串行端口。所有数据都在程序和UART之间进行缓冲。您的程序不必随时准备好读取数据。操作系统(特别是UART设备驱动程序和包含线路规则的tty子系统)可以实现这一点,并缓冲程序的数据。
RS-232定义为异步通信链路。字符/字节可以随时传输。消息包将在任何时间点到达,因此应用程序必须等待组成消息包的字节。这是使用阻塞读取的情况。
接收串行数据的典型问题是如何对接收到的数据进行词法扫描以识别完整的消息包。文本消息(规范模式)只是使用ASCII行控制字符来分隔消息/行。即使是固定长度的数据包也需要验证(以确保消息实际上在正确的字节上开始)。请参阅this example of scanning fixed-length packets。
我认为我必须使用中断处理程序而不是读取你同意吗?
不,UART设备驱动程序已经在为其中断(或使用DMA)提供服务,以捕获从串行链路接收的每个字节。
由于发送方无法与接收方同步,因此存在一个中断处理程序,用于将接收到的数据存储在指定的缓冲区中(我认为这是Canonical模式但不是非规范模式的情况)或者这是仅在达到读取功能时才完成,
接收端的串口不需要"同步"使用字节级别的发送串行端口。 RS-232是一个异步通信链路:发送器可以/将在任何时间发送字符/字节,另一端必须准备接收它(除非有硬件或软件流量控制到位)在设备驱动程序级别(而不是应用程序)。
操作系统始终缓冲此接收的数据。应用程序的 read()系统调用仅仅是从系统缓冲区到用户缓冲区的复制操作。此复制操作适用于规范和非规范模式。
"同步"通常是协议在消息或数据包级别解决的问题。主从是用于定义串行链路协议的通用配置。主端向从端发送查询消息。从站必须始终准备好接收查询。从属方可以使用事务请求或数据捕获或其他任何方式进行响应,或者使用NAK消息来指示它对主服务器没有任何内容。此请求 - 响应对话框旨在控制或调整两个单元之间的数据流(和处理负载)。
附录
我正在计划做的事实上是无限循环中的阻塞读取(VTIME = 0 VMIN = DATA_LENGTH)
据推测,您将始终在发送设备之前启动您的程序,以便第一个传输的DATA_LENGTH将与程序的第一次读取对齐。
这可能在理想或受监控的情况下大部分时间都有效 但是对于工业24/7应用,丢失消息帧对齐的可能性是真实的(例如,在传输的中间重新启动发送设备),因此没有用于验证和重新获得消息帧对齐的有效装置的方案是不适当的。
IOW串口的原始 read()可能不会在缓冲区中返回对齐的消息(即buf [0]可能不包含消息的第一个字节)。
具有非零VTIME的小得多的VMIN是典型的termios配置,其基于在每条消息之后串行链路空闲(短时间间隔)的前提。
但是代码应该是健壮的,以便在读取时处理任何/所有消息片段。因此,可能需要多个 read()来重建整个消息。