Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學
您现在的位置: Windows教程網 >> Windows教程 >  >> Linux 系統教學 >> 關於 Linux

Linux 序列埠 (Serial Port) 程式設計完整指南:termios 結構體配置、波特率、資料位、停止位、奇偶校驗、流控

編輯:關於 Linux

Linux 序列埠程式設計核心在於配置 struct termios,透過 tcgetattr/tcsetattr 系統呼叫設定波特率、資料位、停止位、校驗、流控等參數。本文提供完整配置流程、旗標對照表、常用函式封裝與錯誤處理模式。

序列埠裝置檔案

  • /dev/ttyS0、/dev/ttyS1 ... (原生 UART,ISA/PCI)。
  • /dev/ttyUSB0、/dev/ttyUSB1 ... (USB 轉序列埠)。
  • /dev/ttyACM0 ... (USB CDC ACM,如 Arduino)。

開啟裝置

int fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
if (fd < 0) { perror("open"); exit(1); }
// 設為阻塞模式 (預設)
fcntl(fd, F_SETFL, 0);

termios 結構體旗標速查

成員常用旗標說明
c_cflag (控制模式)CBAUD (波特率)、CSIZE (資料位)、CSTOPB (停止位)、PARENB (啟用校驗)、PARODD (奇校驗)、HUPCL (關閉時掛斷)、CLOCAL (忽略載波)、CREAD (啟用接收)、CRTSCTS (硬體流控 RTS/CTS)核心通訊參數
c_iflag (輸入模式)IGNBRK、BRKINT、IGNPAR、PARMRK、INPCK (啟用輸入校驗)、ISTRIP (去除第 8 位)、IXON/IXOFF/IXANY (軟體流控 XON/XOFF)輸入處理
c_oflag (輸出模式)OPOST (啟用輸出處理)、ONLCR (NL→CR-NL)通常清零 (raw output)
c_lflag (本地模式)ICANON (規範模式)、ECHO、ECHOE、ISIG (信號字元)序列埠通常關閉 (raw mode)
c_cc[NCCS] (控制字元)VMIN (最少讀取字元)、VTIME (讀取逾時 0.1s 單位)非規範模式讀取行為

標準配置流程 (Raw Mode, 8N1, 115200, 無流控)

struct termios oldtio, newtio;

/* 1. 保存原配置 */
if (tcgetattr(fd, &oldtio) != 0) { perror("tcgetattr"); exit(1); }

/* 2. 清零新配置 */
memset(&newtio, 0, sizeof(newtio));

/* 3. 啟用接收與本地連線 */
newtio.c_cflag |= CLOCAL | CREAD;

/* 4. 設定波特率 (輸入/輸出同速) */
cfsetispeed(&newtio, B115200);
cfsetospeed(&newtio, B115200);

/* 5. 設定資料位 8 位 */
newtio.c_cflag &= ~CSIZE;   // 清除資料位遮罩
newtio.c_cflag |= CS8;

/* 6. 設定無奇偶校驗 (8N1) */
newtio.c_cflag &= ~PARENB;  // 關閉校驗
newtio.c_iflag &= ~INPCK;   // 關閉輸入校驗

/* 7. 設定停止位 1 位 */
newtio.c_cflag &= ~CSTOPB;

/* 8. 關閉硬體流控 */
newtio.c_cflag &= ~CRTSCTS;

/* 9. 關閉軟體流控 */
newtio.c_iflag &= ~(IXON | IXOFF | IXANY);

/* 10. 原始模式 (關閉規範、回顯、信號) */
newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

/* 11. 原始輸出 */
newtio.c_oflag &= ~OPOST;

/* 12. 讀取行為: 非阻塞輪詢 (VMIN=0, VTIME=0) 或阻塞等待 (VMIN=1, VTIME=0) */
newtio.c_cc[VMIN] = 0;
newtio.c_cc[VTIME] = 0;   // 0.1s * 0 = 0, 非阻塞回傳

/* 13. 清空輸入緩衝區並套用 */
tcflush(fd, TCIFLUSH);
if (tcsetattr(fd, TCSANOW, &newtio) != 0) { perror("tcsetattr"); exit(1); }

常用輔助函式封裝

int serial_set_baud(int fd, speed_t baud) {
    struct termios t;
    if (tcgetattr(fd, &t)) return -1;
    cfsetispeed(&t, baud);
    cfsetospeed(&t, baud);
    return tcsetattr(fd, TCSANOW, &t);
}

int serial_set_parity(int fd, int parity) { // 0=N, 1=O, 2=E
    struct termios t;
    if (tcgetattr(fd, &t)) return -1;
    t.c_cflag &= ~(PARENB | PARODD);
    t.c_iflag &= ~INPCK;
    if (parity == 1) { t.c_cflag |= PARENB | PARODD; t.c_iflag |= INPCK; }
    else if (parity == 2) { t.c_cflag |= PARENB; t.c_iflag |= INPCK; }
    return tcsetattr(fd, TCSANOW, &t);
}

ssize_t serial_read(int fd, void *buf, size_t count, int timeout_ms) {
    struct termios t;
    tcgetattr(fd, &t);
    t.c_cc[VMIN] = 0;
    t.c_cc[VTIME] = timeout_ms / 100;  // 0.1s 單位
    tcsetattr(fd, TCSANOW, &t);
    return read(fd, buf, count);
}

讀寫操作

// 寫入
write(fd, "AT\r\n", 4);

// 讀取 (阻塞直到有資料或逾時)
char buf[256];
int n = read(fd, buf, sizeof(buf)-1);
if (n > 0) { buf[n] = '\0'; printf("收到: %s", buf); }

關閉與還原

tcsetattr(fd, TCSANOW, &oldtio);  // 還原原配置
close(fd);

常見問題

收到亂碼
波特率不匹配、資料位/停止位/校驗不一致、線路干擾。
read() 立即回傳 0
VMIN=0, VTIME=0 非阻塞模式;改 VMIN=1, VTIME=0 阻塞等待。
權限被拒
將使用者加入 dialout 群組:usermod -aG dialout $USER,重新登入。
USB 序列埠斷線重連裝置名稱改變
用 /dev/serial/by-id/usb-... 符號連結 (固定唯一 ID)。

掌握 termios 旗標與標準配置流程,即可在 Linux 上穩健開發序列埠通訊應用 (Modbus RTU、GPS、傳感器、PLC 等)。

Copyright © Windows教程網 All Rights Reserved