您是否考虑过使用串行设备而不是使用并行端口?由于您有 TTL 信号,您可能需要一个电平转换器将 TTL 转换为 RS232 +/- 12V 电平。使用串行设备后,您可以使用标准串行ioctl()
调用来检测控制信号状态的变化。
具体来说,您可以使用TIOCMIWAIT
连接的串行设备上的 ioctl 来等待 DCD 线路的变化,您将连接到您的时钟源。
您的用户空间应用程序将在TIOCMIWAIT
ioctl 系统调用中等待,直到时钟线上的状态发生变化,此时您的应用程序将变为可运行并从 ioctl 返回。您可能需要注意确保处理在串行控制信号的上升沿和下降沿都发生状态变化中断的情况。在某些 UART 硬件(例如 TL16C554A UART)上,您可能只会收到单向信号转换的中断。例如,对于 TL16C554A,它TIOCMIWAIT
只会在任何 Ring Indicate 信号变化的上升沿下降。
以这种方式使用串行 ioctl 还具有优势,即您可以使用支持TIOCMIWAIT
(例如 PL2303)的 USB 串行加密狗,并且仍然保持用户级软件兼容性,尽管以 USB 导致的延迟增加为代价。
如果您需要比通过用户空间实现的延迟更低的延迟,您最好编写一个可以处理时序和采样的内核驱动程序模块,但除非绝对需要,否则我不建议使用此路线。开发用户空间代码更容易。
下面是一些使用TIOCMIWAIT
ioctl 的不完整示例 C 代码片段。
int serial_fd = open(cmdline.device_name, O_RDWR | O_NONBLOCK | O_NOCTTY);
static const unsigned int ri_flag = TIOCM_RNG;
/* Set up serial port here using tcsetattr. Set CRTSCTS | CLOCAL to ensure status interrupts
* are generated.
*/
while (1) {
/* Wait for positive RI transition. TIOCMIWAIT takes a mask
* as argument, only returning when the appropriate signal has changed.
*/
if (ioctl(serial_fd, TIOCMIWAIT, ri_flag)) {
fprintf(stderr, "ioctl() failed waiting for RI edge [%s]\n", strerror(errno));
break;
}
/* Do sensor sampling here. You could use TIOCMGET to first verify that
* the clock line is in the expected state, eg high, before continuing.
*/
}