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 串口編程完整指南:術語、API、配置流程與設備節點差異

編輯:Linux 教學

Linux 串口通信是嵌入式開發、工業控制、儀表設備對接的基礎技能。本文提供完整的用戶態串口應用程序框架,涵蓋打開設備、配置屬性(波特率、校驗、數據位、停止位)、讀寫操作、非阻塞/阻塞模式切換,並深度解析 ttyS* 與 ttySAC* 設備節點的內核版本差異。

一、 核心數據結構 termios

struct termios {
    tcflag_t c_iflag;   // 輸入模式標志
    tcflag_t c_oflag;   // 輸出模式標志
    tcflag_t c_cflag;   // 控制模式標志(波特率、數據位、校驗、停止位)
    tcflag_t c_lflag;   // 本地模式標志
    cc_t     c_cc[NCCS]; // 控制字符數組(VMIN, VTIME 等)
};

二、 完整應用程序框架

#include 
#include 
#include 
#include 
#include 
#include 
#include 

// 打開串口:返回文件描述符,失敗返回 -1
int open_port(const char *device) {
    int fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY);
    if (fd < 0) {
        perror("open_port");
        return -1;
    }
    // 恢復阻塞模式(去除 O_NDELAY)
    if (fcntl(fd, F_SETFL, 0) < 0)
        perror("fcntl F_SETFL");
    return fd;
}

// 配置串口參數
int set_opt(int fd, int speed, int databits, char parity, int stopbits) {
    struct termios newtio, oldtio;
    if (tcgetattr(fd, &oldtio) != 0) { perror("tcgetattr"); return -1; }
    bzero(&newtio, sizeof(newtio));

    // 1. 啟用接收、忽略調製解調器控制線
    newtio.c_cflag |= CLOCAL | CREAD;
    newtio.c_cflag &= ~CSIZE;

    // 2. 數據位
    switch (databits) {
        case 7: newtio.c_cflag |= CS7; break;
        case 8: newtio.c_cflag |= CS8; break;
        default: return -1;
    }

    // 3. 校驗位
    switch (parity) {
        case 'O': case 'o':  // 奇校驗
            newtio.c_cflag |= PARENB | PARODD;
            newtio.c_iflag |= INPCK | ISTRIP;
            break;
        case 'E': case 'e':  // 偶校驗
            newtio.c_cflag |= PARENB;
            newtio.c_cflag &= ~PARODD;
            newtio.c_iflag |= INPCK | ISTRIP;
            break;
        case 'N': case 'n':  // 無校驗
            newtio.c_cflag &= ~PARENB;
            break;
        default: return -1;
    }

    // 4. 波特率
    speed_t sp;
    switch (speed) {
        case 2400: sp = B2400; break;
        case 4800: sp = B4800; break;
        case 9600: sp = B9600; break;
        case 19200: sp = B19200; break;
        case 38400: sp = B38400; break;
        case 57600: sp = B57600; break;
        case 115200: sp = B115200; break;
        case 460800: sp = B460800; break;
        default: sp = B9600;
    }
    cfsetispeed(&newtio, sp);
    cfsetospeed(&newtio, sp);

    // 5. 停止位
    if (stopbits == 1)
        newtio.c_cflag &= ~CSTOPB;
    else if (stopbits == 2)
        newtio.c_cflag |= CSTOPB;
    else
        return -1;

    // 6. 非規範模式,無最小字符/超時限制(即時讀取)
    newtio.c_cc[VTIME] = 0;
    newtio.c_cc[VMIN]  = 0;

    // 7. 刷新輸入隊列,立即生效
    tcflush(fd, TCIFLUSH);
    if (tcsetattr(fd, TCSANOW, &newtio) != 0) {
        perror("tcsetattr");
        return -1;
    }
    printf("Serial port configured: %d %d%c%d\n", speed, databits, parity, stopbits);
    return 0;
}

// 主程序示例
int main() {
    const char *dev = "/dev/ttySAC0";  // 根據平台調整
    int fd = open_port(dev);
    if (fd < 0) return 1;

    if (set_opt(fd, 115200, 8, 'N', 1) < 0) {
        close(fd);
        return 1;
    }

    char *msg = "Hello\n";
    for (int i = 0; i < 20; i++) {
        int n = write(fd, msg, strlen(msg));
        printf("Write %d bytes: %d\n", (int)strlen(msg), n);
        sleep(1);
    }
    close(fd);
    return 0;
}

三、 關鍵配置參數速查表

常見 VMIN/VTIME 組合

  • VMIN=0, VTIME=0:非阻塞輪詢,立即返回。
  • VMIN>0, VTIME=0:阻塞直到讀到 VMIN 字符。
  • VMIN=0, VTIME>0:超時讀取,最多等待 VTIME*0.1s。
  • VMIN>0, VTIME>0:讀到第一個字符後,最多等待 VTIME 獲取剩餘字符。

四、 設備節點之謎:ttyS* vs ttySAC*

實測現象:S3C2410 開發板上 /dev/ttyS0 打開失敗,/dev/ttySAC0 成功。

根因:內核版本與驅動模型變更

宏屬於含義
CLOCALc_cflag忽略調製解調器狀態,直接連接
CREADc_cflag啟用接收器
CS7/CS8c_cflag7/8 數據位
PARENBc_cflag啟用奇偶校驗
PARODDc_cflag奇校驗(未設置則偶校驗)
INPCKc_iflag啟用輸入奇偶檢查
ISTRIPc_iflag剝離第 8 位
CSTOPBc_cflag2 停止位(未設置則 1 位)
VMINc_cc最小讀取字符數
VTIMEc_cc讀取超時(十分之一秒)

Samsung SoC 串口控制器在 2.6 內核中遷移至新 uart 子系統,驅動 samsung.c 註冊 struct uart_driver 時指定 dev_name = "ttySAC",因此節點名為 ttySAC*。舊版 ttyS* 由 8250 驅動佔用,S3C 系列不再使用。

驗證方法

# 查看內核註冊的串口驅動
cat /proc/tty/drivers
# 輸出示例:
/dev/ttySAC    /dev/ttySAC    204  64-79  serial   # Samsung UART
/dev/ttyS      /dev/ttyS      4    64-67  serial   # 8250/16550

五、 進階主題

  • 硬件流控:啟用 CRTSCTS(c_cflag),需硬件支持 RTS/CTS 線。
  • RS485 方向控制:使用 ioctl(fd, TIOCSRS485, &rs485conf) 配置發送使能極性、延遲。
  • 異步通知:fcntl(fd, F_SETFL, FASYNC) + fcntl(fd, F_SETOWN, getpid()) + 信號處理函數 SIGIO。
  • 設備樹配置:status="okay"、current-speed、clock-frequency、pinctrl 綁定。
Copyright © Windows教程網 All Rights Reserved
內核版本驅動文件設備節點命名註冊接口
2.4drivers/char/serial.cttyS0, ttyS1...register_serial()
2.6+drivers/serial/samsung.cttySAC0, ttySAC1...uart_register_driver() + platform_device