2017-01-25 56 views
0

我試圖從BeagleBone Black上的串行端口(/dev/ttyS4)讀取,但我認爲(?)這應該適用於所有Linux設備。Linux串行讀取塊minicom

目前,我可以設置minicom的波特率爲9600和8N1的數據從串口讀取正確。但是,如果我直接嘗試cat /dev/ttyS4,則在我的終端中不會顯示任何內容。我的代碼也這樣做,並返回一個Resource temporarily unavailable錯誤,我懷疑是cat命令發生了什麼。

如果我跑stty -F /dev/ttyS4,我得到下面的輸出(其中,據我所知道的,是我的minicom設置一致):

speed 9600 baud; line = 0; 
intr = <undef>; quit = <undef>; erase = <undef>; kill = <undef>; eof = <undef>; start = <undef>; stop = <undef>; susp = <undef>; rprnt = <undef>; werase = <undef>; lnext = <undef>; flush = <undef>; 
-brkint -imaxbel 
-opost -onclr 
-isig -iexten -echo -echoe -echok -echoctl -echoke 

一個有趣的注意的是,當我有minicom開放,如果我開始執行程序,minicom將停止打印任何內容,即使停止執行程序,也會保持這種狀態。我需要再次打開串行設置(Ctrl-A,P),並關閉minicom以恢復工作(似乎沒有任何更改)。

我的代碼如下:

int main() { 
    std::cout << "Starting..." << std::endl; 

    std::cout << "Connecting..." << std::endl; 
    int tty4 = open("/dev/ttyS4", O_RDWR | O_NOCTTY | O_NDELAY); 
    if (tty4 < 0) { 
     std::cout << "Error opening serial terminal." << std::endl; 
    } 

    std::cout << "Configuring..." << std::endl; 
    struct termios oldtio, newtio; 
    tcgetattr(tty4, &oldtio); // save current serial port settings 
    bzero(&newtio, sizeof(newtio)); // clear struct for new settings 

    newtio.c_cflag = B9600 | CS8 | CREAD | CLOCAL; 
    newtio.c_iflag = IGNPAR | ICRNL; 
    newtio.c_oflag = 0; 
    newtio.c_lflag = ICANON; 

    tcflush(tty4, TCIFLUSH); 
    tcsetattr(tty4, TCSANOW, &newtio); 

    std::cout << "Reading..." << std::endl; 
    while (true) { 
     uint8_t byte; 
     int status = read(tty4, &byte, 1); 
     if (status > 0) { 
      std::cout << (char)byte; 
     } else if (status == -1) { 
      std::cout << "\tERROR: " << strerror(errno) << std::endl; 
     } 
    } 

    tcsetattr(tty4, TCSANOW, &oldtio); 
    close(tty4); 
} 

編輯:我已經按照Adafruit的的教程使用python與BeagleBone得到串口正常工作(在python)。此時我確定我是做錯了事;問題是什麼。我更願意使用C++而不是Python,因此能夠很好地工作。

+0

我看到幾個可能的問題,但是你的問題是什麼? – sawdust

+0

我該如何修改我的C++程序才能成功從串口讀取數據? –

回答

1

程序以非阻塞模式打開串行終端。

int tty4 = open("/dev/ttyS4", O_RDWR | O_NOCTTY | O_NDELAY); 

非阻塞I/O,尤其是讀操作,需要一個額外的程序,進行特殊處理。 由於您忽略提及此模式,並且您的程序無法正確處理此模式,因此可能會將其視爲一個錯誤。

請刪除從的open()調用O_NDELAY選項,或插入fcntl(tty4, F_SETFL, 0)語句恢復成阻塞模式。


我的代碼也這樣做,並返回一個錯誤Resource temporarily unavailable

這是一個EAGAIN錯誤,這是一個非阻塞閱讀()一致。
手冊頁描述當「文件描述符...已被標記爲非阻塞(O_NONBLOCK)並且讀取將阻塞」時將發生此錯誤。
read()系統調用「會阻塞」,因爲沒有數據來滿足讀取請求。

如果你堅持使用非阻塞模式,那麼你的程序必須能夠處理這種情況,這不是一個錯誤,而是一個臨時/瞬態狀態。
但阻塞模式是多任務系統中典型程序的更簡單和首選的操作模式。
您的程序應按前面所述進行修改。


串行終端的初始化有許多問題。


tcgetattr(tty4, &oldtio); // save current serial port settings 

tcgetattr返回值()tcsetattr()系統調用從不進行錯誤檢查。


bzero(&newtio, sizeof(newtio)); // clear struct for new settings 

與空termios結構開始幾乎總是一個壞主意。它似乎可以在某些系統上工作,但它不是可移植的代碼。
初始化termios結構的正確方法是使用tcgetattr()中的值。
Setting Terminal Modes Properly
由於它已經被調用,所有你需要的是複製結構的newtio = oldtio


newtio.c_cflag = B9600 | CS8 | CREAD | CLOCAL; 
    newtio.c_iflag = IGNPAR | ICRNL; 
    newtio.c_oflag = 0; 
    newtio.c_lflag = ICANON; 

而不是常量的分配,改變這些標誌的適當的方法是啓用或禁用個別屬性。
以下應該足夠規範模式:

newtio.c_cflag |= CLOCAL | CREAD; 
    newtio.c_cflag &= ~CSIZE; 
    newtio.c_cflag |= CS8;   /* 8-bit characters */ 
    newtio.c_cflag &= ~PARENB;  /* no parity bit */ 
    newtio.c_cflag &= ~CSTOPB;  /* only need 1 stop bit */ 
    newtio.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */ 

    newtio.c_lflag |= ICANON | ISIG; /* canonical input */ 
    newtio.c_lflag &= ~(ECHO | ECHOE | ECHONL | IEXTEN); 

    newtio.c_iflag &= ~INPCK; 
    newtio.c_iflag |= ICRNL; 
    newtio.c_iflag &= ~(INLCR | IGNCR | IUCLC | IMAXBEL); 
    newtio.c_iflag &= ~(IXON | IXOFF | IXANY); /* no SW flowcontrol */ 

    newtio.c_oflag &= ~OPOST; 

以下是用於設置波特率的優選方法:如果任何顯着屬性未指定

cfsetospeed(&newtio, B9600); 
    cfsetispeed(&newtio, B9600); 

,現有的設置是用過的。
這可能導致不穩定的程序行爲,例如有時會起作用,有時卻不起作用。


一個有趣的注意的是,當我有小型機開放,如果我開始我的計劃,小型機將停止打印任何東西,並且保持下去,即使我停止我的計劃。我需要再次打開串行設置(Ctrl-A,P),並關閉它以便minicom恢復工作(看起來沒有任何變化)。

串行終端不適用於在多個進程之間共享。
一些termios屬性必須在串行設備驅動程序中實現,該驅動程序沒有共享端口的概念。最近的termios屬性對設備有效。
當您在minicom已經啓動後執行程序時,您正在破壞minicom預期執行的termios屬性。
您正在使用其菜單將termios屬性恢復爲minicom的要求。

+0

非常感謝!這是我第一次嘗試這種東西,我覺得我有點不知所措(並且承認有點衝動,導致了一些非常糟糕的代碼)。你的回答非常有用:) –