1. 程式人生 > >linux下如何控制RTS?為了控制RS485傳送正常,但無法接收到端傳送過來的資料

linux下如何控制RTS?為了控制RS485傳送正常,但無法接收到端傳送過來的資料

Linux 下串列埠程式設計的文章網上是滿天飛,但大都是出自一篇文章,而且寫的都是些基本的操作,像控制 RTS/CTS 等串列埠引腳狀態,接收發送二進位制資料等,都沒有很好的說明,我在使用中遇到了些問題,寫出來,希望能對大家有所幫助,少走彎路,呵呵!

       我使用的作業系統是 Redhat9 , gcc 版本是 3.2.2
       其實在 linux 下對串列埠的設定主要是通過 termios 這個結構體實現的,但是這個結構體卻沒有提供控制 RTS 或獲得 CTS 等串列埠引腳狀態的介面,可以通過 ioctl 系統呼叫來獲得 / 控制。
獲得:
ioctl(fd, TIOCMGET, &controlbits);

if   (controlbits & TIOCM_CTS)
      printf(“ 有訊號 \n”);
else
      printf(“ 無訊號 \n”);
設定:
       ioctl(fd, TIOCMGET, &ctrlbits) ;
       if (flag)
           ctrlbits |= TIOCM_RTS;
       else
           ctrlbits &= ~TIOCM_RTS;
      ioctl(fd, TIOCMSET, &ctrlbits);

其實 TIOCM_RTS 有效後是把串列埠的 RTS 設定為有訊號,但串列埠的電平為低時是有訊號,為高時為無訊號,和用 TIOCMGET 獲得的狀態正好相反,也就是說 TIOCMGET/TIOCMSET 只是獲得 / 控制串列埠的相應引腳是否有訊號,並不反應當前串列埠的真實電平高低。

網上許多流行的 linux 串列埠程式設計的版本中都沒對 c_iflag ( termios 成員變數 )這個變數進行有效的設定,這樣傳送 ASCII 碼時沒什麼問題,但傳送二進位制資料時遇到 0x0d,0x11 和 0x13 卻會被丟掉。不用說也知道,這幾個肯定是特殊字元,被用作特殊控制了。關掉 ICRNL 和 IXON 選項即可解決。

       c_iflag &= ~(ICRNL | IXON);

0x0d 回車符 CR
0x11 ^Q VSTART 字元
0x13 ^S VSTOP 字元
ICRNL 將輸入的 CR 轉換為 NL  
IXON 使起動 / 停止輸出控制流起作用  

在《 UNIX 環境高階程式設計 第二版》第 18 章第 11 小節看到把終端 I/O 設定為原始模式(串列埠通訊就是終端 I/O 的原始模式)時輸入屬性設定為

term.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
遮蔽了許多屬性,怪不得有人說如果是使用串列埠通訊 c_iflag 和 c_oflag 都設定為 0 就行了!
以下是我的設定的一些重要的串列埠屬性
term.c_cflag |= CLOCAL | CREAD;
       term.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
       term.c_oflag &= ~OPOST;
term.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);