Sample to read serial port data in C++ using interrupt

This code example demonstrates how to read serial port data in C++ using an interrupt-driven approach. It sets up the serial port configuration, including control flags, input flags, local flags, and output flags. The program uses a signal handler to handle the SIGIO signal and sets up the file descriptor for the serial port to generate the signal. It reads data from the serial port when the data_ready flag is set and prints the data to the console and writes it to an output file. The program also includes a function to check for keyboard input without blocking. It is important to adapt and test the code for your specific application and environment, considering hardware and software compatibility and potential concurrency issues.
此代码示例演示了如何在C++中使用中断驱动方法读取串口数据。它设置了串口配置,包括控制标志、输入标志、本地标志和输出标志。程序使用信号处理器来处理SIGIO信号,并设置串口的文件描述符以生成该信号。当data_ready标志被设置时,它从串口读取数据,并将数据打印到控制台并写入输出文件。程序还包括一个检查键盘输入而不阻塞的功能。根据您的具体应用和环境适应并测试代码是很重要的,考虑到硬件和软件的兼容性以及潜在的并发问题。

Serial Port Configuration (8N1)

1. Control Flags (c_cflag)

  • tty.c_cflag |= (CLOCAL | CREAD);
    • CLOCAL: Ignore modem control lines. This is important for ports that are not connected to modems.
    • CREAD: Enable the receiver, so the port will read incoming data.
  • tty.c_cflag &= ~CSIZE;
    • Clears the current character size mask (CSIZE). This allows setting a new character size.
  • tty.c_cflag |= CS8;
    • CS8: Sets the character size to 8 bits.
  • tty.c_cflag &= ~PARENB;
    • PARENB: Disables parity generation and detection. This is part of configuring for "no parity."
  • tty.c_cflag &= ~CSTOPB;
    • CSTOPB: Clears this flag, configuring for one stop bit. If set, it would configure for two stop bits.
  • tty.c_cflag &= ~CRTSCTS;
    • CRTSCTS: Disables hardware flow control (RTS/CTS).

1. 控制标志 (c_cflag)

  • tty.c_cflag |= (CLOCAL | CREAD);
    • CLOCAL: 忽略调制解调器控制线。对于没有连接到调制解调器的端口来说,这一点很重要。
    • CREAD: 启用接收器,这样端口就会读取传入的数据。
  • tty.c_cflag &= ~CSIZE;
    • 清除当前字符大小掩码(CSIZE)。这允许设置新的字符大小。
  • tty.c_cflag |= CS8;
    • CS8: 将字符大小设置为8位。
  • tty.c_cflag &= ~PARENB;
    • PARENB: 禁用奇偶校验的生成和检测。这是配置为“无奇偶校验”时的一部分。
  • tty.c_cflag &= ~CSTOPB;
    • CSTOPB: 清除此标志,配置为一个停止位。如果设置,则会配置为两个停止位。
  • tty.c_cflag &= ~CRTSCTS;
    • CRTSCTS: 禁用硬件流控制(RTS/CTS)。

2. Input Flags (c_iflag)

  • tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
    • Disables various input processing features, such as:
      • Ignore break conditions.
      • Disable break interrupts.
      • No marking for parity errors.
      • Do not strip the eighth bit (useful for character sizes other than 8 bits).
      • Do not translate carriage return to newline, and vice versa.
      • Disable software flow control (XON/XOFF).

2. 输入标志 (c_iflag)

  • tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
    • 禁用各种输入处理功能,例如:
      • 忽略中断条件。
      • 禁用中断信号。
      • 不标记奇偶校验错误。
      • 不剥离第八位(对于非8位的字符大小很有用)。
      • 不将回车转换为换行符,反之亦然。
      • 禁用软件流控制(XON/XOFF)。

3. Local Flags (c_lflag)

  • tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
    • Turns off echoing of input characters, canonical mode (line-oriented input processing), signal generation (INTR, QUIT, SUSP, DSUSP), and any implementation-defined input processing.

3. 本地标志 (c_lflag)

  • tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
    • 关闭输入字符的回显、规范模式(基于行的输入处理)、信号生成(INTR, QUIT, SUSP, DSUSP)以及任何实现定义的输入处理。

4. Output Flags (c_oflag)

  • tty.c_oflag &= ~OPOST;
    • Disables output processing.

4. 输出标志 (c_oflag)

  • tty.c_oflag &= ~OPOST;
    • 禁用输出处理。

5. Control Characters (c_cc[VMIN] and c_cc[VTIME])

  • tty.c_cc[VMIN] = 1; tty.c_cc[VTIME] = 1;
    • VMIN (Minimum number of characters to read): Set to 1, meaning the read() call will return after at least one character is received.
    • VTIME (Time to wait for data): Set to 1 (in tenths of a second). This introduces a small timeout after the first character is received, after which read() will return if no additional character has arrived.

5. 控制字符(c_cc[VMIN]c_cc[VTIME]

  • tty.c_cc[VMIN] = 1; tty.c_cc[VTIME] = 1;
    • VMIN(读取的最小字符数):设置为1,意味着一旦至少收到一个字符,read() 调用就会返回。
    • VTIME(等待数据的时间):设置为1(以十分之一秒为单位)。这引入了一个在接收到第一个字符后的短暂超时,之后如果没有额外字符到达,read() 将返回。

Notes on the Code:

  • Signal Handler: The signal_handler function sets the data_ready flag when a SIGIO signal is received, indicating that data is available to read.
  • Serial Port Configuration: The serial port is configured with specific settings such as baud rate and mode flags.
  • Signal Setup: The sigaction function is used to set up the signal handler for SIGIO, and fcntl is used to associate the signal with the file descriptor for the serial port.
  • Data Reading: The program enters a loop, checking if data_ready is set (indicating that data is available) and then reads from the serial port.
  • Keyboard Input: The kbhit function checks for keyboard input without blocking, allowing the program to exit when 'q' or 'Q' is pressed.
  • Data Output: Read data is printed to the console and also written to an output file.

代码注释:

  • 信号处理器:当收到SIGIO信号时,signal_handler函数设置data_ready标志,表明有数据可读。
  • 串口配置:串口使用特定设置进行配置,例如波特率和模式标志。
  • 信号设置:使用sigaction函数来设置SIGIO的信号处理器,使用fcntl将信号与串口的文件描述符关联。
  • 数据读取:程序进入循环,检查data_ready是否被设置(表明数据可用),然后从串口读取数据。
  • 键盘输入kbhit函数检查键盘输入而不阻塞,允许在按下'q'或'Q'时程序退出。
  • 数据输出:读取的数据打印到控制台,并写入输出文件。

Additional Considerations:

  • Ensure that your environment and the serial device support the signal-driven I/O method.
  • Thoroughly test the program for any potential issues, especially those related to signal handling and concurrency.
  • This approach might require adjustments or additional error handling based on your specific hardware and software environment.

补充考虑事项:

  • 确保您的环境和串行设备支持信号驱动的I/O方法。
  • 彻底测试程序,特别是对于与信号处理和并发相关的潜在问题。
  • 根据您特定的硬件和软件环境,这种方法可能需要调整或额外的错误处理。
Loading...