Linux RS-232 程式設計
Linux RS-232 程式設計
6-1 終端機介面
終端機介面又稱為TTY介面,用來讓Linux系統透過RS-232串列埠連接數據機,通過電話線路與遠端的電腦系統相連接。終端機介面有二種模式:正規(canonical)模式和非正規(non-canonical)模式。
模式 | 說明 |
正規模式 | 又稱為cooked模式。在這種模式中,終端設備會處理特殊字元,且會以一次一列的方式將輸入傳給應用程式。例如Linux的shell指令。 |
非正規模式 | 又稱為raw模式。在這種模式中,終端設備不會處理特殊字元,且會以一次一個字元的方式將輸入傳給應用程式。例如在Linux使用vim編輯程式。 |
串列埠檔案
在Linux中針對所有的周邊裝置都提供了[裝置檔案]供使用者存取。若要存取TTY串列埠只要開啟相關的[裝置檔案]即可。
在Linux中,每一個TTY串列埠都會對應到一個或多個[裝置檔案],[裝置檔案]放在[/dev]目錄中。相關的裝置檔案如下:
裝置檔案 | 說明 |
/dev/ttyS0 | 串列埠的COM1 |
/dev/typS1 | 串列埠的COM2 |
開啟通訊埠
在Linux中將串列埠視為一個檔案,可以使用open()函數來開啟串列埠。底下的程式用來開啟PC的COM1串列通訊埠。
#include |
其中
O_NOCTTY:告訴Linux這個程式不想控制TTY介面,如果不設定這個旗標,有些輸入(例如鍵盤的abort)信號可能影響程式。
O_NOCTTY:告訴Linux這個程式不想控制TTY介面,如果不設定這個旗標,有些輸入(例如鍵盤的abort)信號可能影響程式。
O_NDELAY:告訴Linux這個程式不介意RS-232的DCD信號的狀態。如果不設定這個旗標,程式會處於speep狀態,直到RS-232有DCD信號進來。
6-2 Termios結構
在Linux中設定串列埠的參數,例如鮑率、字元長度等,可以透過POSIX標準終端介面,此介面稱為Termios,並定義於系統的標頭檔中。termios的結構如下:
struct termios{
tcflag_t c_iflag; //輸入模式
tcflag_t c_oflag; //輸出模式
tcflag_t c_cflag; //控制模式
tcflag_t c_lflag; //局部模式
cc_t c_cc[NCCS]; //特殊控制字元
輸入模式 c_iflag
IGNBRK | Ignore BREAK condition on input. |
BRKINT | If IGNBRK is set, a BREAK is ignored. If it is not set but BRKINT is set, then a BREAK causes the input and output queues to be flushed, and if the terminal is the controlling terminal of a foreground process group, it will cause a SIGINT to be sent to this foreground process group. When neither IGNBRK nor BRKINT are set, a BREAK reads as a NUL character, except when PARMRK is set, in which case it reads as the sequence \377 \0 \0. |
IGNPAR | Ignore framing errors and parity errors. 忽略frame和同位錯誤 |
PARMRK | If IGNPAR is not set, prefix a character with a parity error or framing error with \377 \0. If neither IGNPAR nor PARMRK is set, read a character with a parity error or framing error as \0. |
INPCK | Enable input parity checking. 執行同位位元檢查 |
ISTRIP | Strip off eighth bit. 去除第8個位元 |
INLCR | Translate NL to CR on input. |
IGNCR | Ignore carriage return on input. |
ICRNL | Translate carriage return to newline on input (unless IGNCR is set). |
IUCLC | (not in POSIX) Map uppercase characters to lowercase on input. |
IXON | Enable XON/XOFF flow control on output. |
IXANY | (not in POSIX.1; XSI) Enable any character to restart output. |
IXOFF | Enable XON/XOFF flow control on input. |
IMAXBEL | (not in POSIX) Ring bell when input queue is full. Linux does not implement this bit, and acts as if it is always set. |
程式:
使用RS-232接收字元,執行同位位元檢查,c_iflag設定如下:
options.c_iflag |= (INPCK | ISTRIP);
串列埠忽略同位錯誤,接收傳入的字元
options.c_iflag |= IGNPAR;
輸出模式 c_oflag
c_oflag包含輸出過濾功能,負責控制輸出字元的處理方式。輸出字元在傳送到序列埠或螢幕之前是如何被程式處理。c_oflag的旗標如下:
OPOST | Enable implementation-defined output processing. |
OLCUC | (not in POSIX) Map lowercase characters to uppercase on output. |
ONLCR | (XSI) Map NL to CR-NL on output. |
OCRNL | Map CR to NL on output. |
ONOCR | Don't output CR at column 0. |
ONLRET | Don't output CR. |
OFILL | Send fill characters for a delay, rather than using a timed delay. |
OFDEL | (not in POSIX) Fill character is ASCII DEL (0177). If unset, fill character is ASCII NUL. |
NLDLY | Newline delay mask. Values are NL0 and NL1. |
CRDLY | Carriage return delay mask. Values are CR0, CR1, CR2, or CR3. |
TABDLY | Horizontal tab delay mask. Values are TAB0, TAB1, TAB2, TAB3 (or XTABS). A value of TAB3, that is, XTABS, expands tabs to spaces (with tab stops every eight columns). |
BSDLY | Backspace delay mask. Values are BS0 or BS1. (Has never been implemented.) |
VTDLY | Vertical tab delay mask. Values are VT0 or VT1. |
FFDLY | Form feed delay mask. Values are FF0 or FF1. |
程式
若要啟動輸出處理,必須加入OPOST選項,程式碼如下:
options.c_oflag |= OPOST;
將換列字元轉換成[CR][LF]
options.c_oflag |= OPOST | ONLCR;
若要啟動非正規模式,將OPOST選項設為disable,設定如下:
options.c_oflag &= ~OPOST;
控制模式 c_cflag
termios結構的c_cflag成員用來控制串列埠的鮑率、同位元、停止位元等。c_cflag的選項如下:
CBAUD | (not in POSIX) Baud speed mask (4+1 bits). |
CBAUDEX | (not in POSIX) Extra baud speed mask (1 bit), included in CBAUD. |
CSIZE | Character size mask. Values are CS5, CS6, CS7, or CS8. |
CSTOPB | Set two stop bits, rather than one. |
CREAD | Enable receiver. 允許串列埠讀取傳入的資料。 |
PARENB | Enable parity generation on output and parity checking for input. |
PARODD | Parity for input and output is odd. |
HUPCL | Lower modem control lines after last process closes the device (hang up). |
CLOCAL | Ignore modem control lines. 忽略數據機控制線的信號 |
LOBLK | (not in POSIX) Block output from a noncurrent shell layer. (For use by shl.) |
CIBAUD | (not in POSIX) Mask for input speeds. The values for the CIBAUD bits are the same as the values for the CBAUD bits, shifted left IBSHIFT bits. |
CRTSCTS | (not in POSIX) Enable RTS/CTS (hardware) flow control. |
程式
將鮑率設定為9600bps。
struct termios options;
options.c_cflag |= (B9600 | CLOCAL | CREAD);
設定傳輸的資料長度為8 bits:
options.c_cflag |= CS8;
設定(8N1)傳輸資料長度8位元、無同位元檢查、1停止位元:
options.c_cflag |= ~PARENB; //不允許同位元檢查
options.c_cflag |= ~CSTOPB; //不是2停止位元
options.c_cflag |= CS8; //8 bits
設定(7E1)傳輸資料長度7位元、偶同位元檢查、1停止位元:
options.c_cflag |= PARENB; //允許同位元檢查
options.c_cflag |= ~PARODD; //不是奇同位元檢查
options.c_cflag |= ~CSTOPB; //不是2停止位元
options.c_cflag |= CS7; //7 bits
設定(7O1)傳輸資料長度7位元、奇同位元檢查、1停止位元:
options.c_cflag |= PARENB; //允許同位元檢查
options.c_cflag |= PARODD; //不是奇同位元檢查
options.c_cflag |= ~CSTOPB; //不是2停止位元
options.c_cflag |= CS7; //7 bits
局部模式 c_lflag
c_lflag用來控制串列埠如何處理輸入字元。透過c_lflag設定串列埠為正規模式或非正規模式,c_lflag的旗標值如下:
ISIG | When any of the characters INTR, QUIT, SUSP, or DSUSP are received, generate the corresponding signal. |
ICANON | Enable canonical mode. This enables the special characters EOF, EOL, EOL2, ERASE, KILL, LNEXT, REPRINT, STATUS, and WERASE, and buffers by lines. |
XCASE | (not in POSIX; not supported under Linux) If ICANON is also set, terminal is uppercase only. Input is converted to lowercase, except for characters preceded by \. On output, uppercase characters are preceded by \ and lowercase characters are converted to uppercase. |
ECHO | Echo input characters. |
ECHOE | If ICANON is also set, the ERASE character erases the preceding input character, and WERASE erases the preceding word. |
ECHOK | If ICANON is also set, the KILL character erases the current line. |
ECHONL | If ICANON is also set, echo the NL character even if ECHO is not set. |
ECHOCTL | (not in POSIX) If ECHO is also set, ASCII control signals other than TAB, NL, START, and STOP are echoed as ^X, where X is the character with ASCII code 0x40 greater than the control signal. For example, character 0x08 (BS) is echoed as ^H. |
ECHOPRT | (not in POSIX) If ICANON and IECHO are also set, characters are printed as they are being erased. |
ECHOKE | (not in POSIX) If ICANON is also set, KILL is echoed by erasing each character on the line, as specified by ECHOE and ECHOPRT. |
DEFECHO | (not in POSIX) Echo only when a process is reading. |
FLUSHO | (not in POSIX; not supported under Linux) Output is being flushed. This flag is toggled by typing the DISCARD character. |
NOFLSH | Disable flushing the input and output queues when generating the SIGINT, SIGQUIT and SIGSUSP signals. |
TOSTOP | Send the SIGTTOU signal to the process group of a background process which tries to write to its controlling terminal. |
PENDIN | (not in POSIX; not supported under Linux) All characters in the input queue are reprinted when the next character is read. (bash handles typeahead this way.) |
IEXTEN | Enable implementation-defined input processing. This flag, as well as ICANON must be enabled for the special characters EOL2, LNEXT, REPRINT, WERASE to be interpreted, and for the IUCLC flag to be effective. |
程式
將串列埠設定為正規模式
options.c_lflag |= (ICANON | ECHO | ECHOE);
將串列埠設定為非正規模式
options.c_lflag |= ~(ICANON | ECHO | ECHOE | ISIG);
特殊控制字元 c_cc[NCCS]
c_cc 陣列成員用來定義支援的特殊控制字元,及一些timeout參數。
對正規模式,c_cc陣列的包括
NCCS | 特殊控制字元 |
VEOF | EOF字元 |
VEOL | EOL字元 |
VERASE | ERASE字元 |
VINTR | INTR字元 |
VKILL | KILL字元 |
VQUIT | QUIT字元 |
VSUSP | SUSP字元 |
VSTART | START字元 |
VSTOP | STOP字元 |
對非正規模式,c_cc陣列的包括
NCCS | 特殊控制字元 |
VINTR | KINTR字元 |
VMIN | MIN字元 |
VQUIT | QUIT字元 |
VSUSP | START字元 |
VTIME | TIME字元 |
VSTART | START字元 |
VSTOP | STOP字元 |
特殊控制字元:
VINTR | (003, ETX, Ctrl-C, or also 0177, DEL, rubout) Interrupt character. Send a SIGINT signal. Recognized when ISIG is set, and then not passed as input. |
VQUIT | (034, FS, Ctrl-\) Quit character. Send SIGQUIT signal. Recognized when ISIG is set, and then not passed as input. |
VERASE | (0177, DEL, rubout, or 010, BS, Ctrl-H, or also #) Erase character. This erases the previous not-yet-erased character, but does not erase past EOF or beginning-of-line. Recognized when ICANON is set, and then not passed as input. |
VKILL | (025, NAK, Ctrl-U, or Ctrl-X, or also @) Kill character. This erases the input since the last EOF or beginning-of-line. Recognized when ICANON is set, and then not passed as input. |
VEOF | (004, EOT, Ctrl-D) End-of-file character. More precisely: this character causes the pending tty buffer to be sent to the waiting user program without waiting for end-of-line. If it is the first character of the line, the read() in the user program returns 0, which signifies end-of-file. Recognized when ICANON is set, and then not passed as input. |
VMIN | Minimum number of characters for non-canonical read. |
VEOL | (0, NUL) Additional end-of-line character. Recognized when ICANON is set. |
VTIME | Timeout in deciseconds for non-canonical read. |
VEOL2 | (not in POSIX; 0, NUL) Yet another end-of-line character. Recognized when ICANON is set. |
VSWTCH | (not in POSIX; not supported under Linux; 0, NUL) Switch character. (Used by shl only.) |
VSTART | (021, DC1, Ctrl-Q) Start character. Restarts output stopped by the Stop character. Recognized when IXON is set, and then not passed as input. |
VSTOP | (023, DC3, Ctrl-S) Stop character. Stop output until Start character typed. Recognized when IXON is set, and then not passed as input. |
VSUSP | (032, SUB, Ctrl-Z) Suspend character. Send SIGTSTP signal. Recognized when ISIG is set, and then not passed as input. |
VDSUSP | (not in POSIX; not supported under Linux; 031, EM, Ctrl-Y) Delayed suspend character: send SIGTSTP signal when the character is read by the user program. Recognized when IEXTEN and ISIG are set, and the system supports job control, and then not passed as input. |
VLNEXT | (not in POSIX; 026, SYN, Ctrl-V) Literal next. Quotes the next input character, depriving it of a possible special meaning. Recognized when IEXTEN is set, and then not passed as input. |
VWERASE | (not in POSIX; 027, ETB, Ctrl-W) Word erase. Recognized when ICANON and IEXTEN are set, and then not passed as input. |
VREPRINT | (not in POSIX; 022, DC2, Ctrl-R) Reprint unread characters. Recognized when ICANON and IEXTEN are set, and then not passed as input. |
VDISCARD | (not in POSIX; not supported under Linux; 017, SI, Ctrl-O) Toggle: start/stop discarding pending output. Recognized when IEXTEN is set, and then not passed as input. |
VSTATUS | (not in POSIX; not supported under Linux; status request: 024, DC4, Ctrl-T). |
非正規模式的特殊字元TIME和MIN對於輸入字元的處理非常重要,有下列4種組合:
組合 | 說明 |
MIN=0, TIME = 0 | 以read()函數讀取串列埠後立即返回,若讀取到字元則傳回字元,否則傳回0。 |
MIN=0, TIME > 0 | 以read()函數讀取串列埠後,會在TIME時間內等待第一個字元。若有字元傳入或時間到,立即返回。若讀取到字元則傳回字元,否則傳回0。 |
MIN > 0, TIME = 0 | 以read()函數讀取串列埠後會等待資料傳入,若有MIN個字元可讀取,傳回讀取的字元數。 |
MIN > 0, TIME > 0 | 以read()函數讀取串列埠後,會等待資料的傳入。若有MIN個字元可讀取時,傳回讀取到的字元數。若TIME的時間到,則read()傳回0。 |
程式
將串列埠設為非正規模式,讀取時間timeout設為1秒。
struct termios options;
options.c_cflag |= (CLOCAL | CREAD);
options.c_lflag |= ~(ICANON | ECHO | ECHOE | ISIG);
options.c_oflag |= ~OPOST;
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = 10;
6-3 終端機相關函數
tcgetattr()
用來取得目前的串列埠參數值。
格式:
#include
int tcgetattr(int fd, struct termios *fp);
說明:
tcgetattr()取得檔案描述子fd後,將其存入tp所指向的termios資料結構。
傳回值:
成功:0
失敗:-1
tcsetattr()
用來設定串列埠參數值。
格式:
#include
int tcsetattr(int fd, int action, const struct termios *tp);
說明:
tcsetattr()執行後使用fp指向的termios資料結構,重新設定檔案描述子fd,其中引數action可以是下列的值
action值 | 說明 |
TCSANOW | 立即將值改變 |
TCSADRAIN | 當目前輸出完成時,將值改變 |
TCSAFLUSH | 當目前輸出完成時,將值改變;並捨棄目前所有的輸入。 |
cfgetispeed()
傳回串列埠的輸入速率:
格式:
#include
int cfgetispeed(struct termios *tp);
其中tp為被處理的termios結構。
cgsetispeed()
設定串列埠的輸入速度。
格式:
#include
int cfsetispeed(struct termios *tp, speed_t speed);
其中tp為被處理的termios結構,speed為鮑率,可以是以下的一個值。
speed值 | speed值 |
B0 | B1800 |
B50 | B2400 |
B75 | B4800 |
B110 | B9600 |
B134 | B19200 |
B150 | B38400 |
B200 | B57600 |
B300 | B115200 |
B600 | B230400 |
cfgetospeed()
傳回串列埠的輸出速度。
格式:
#include
int cfgetospeed(struct *tp);
其中tp為被處理的termios結構。
cfsetospeed()
設定串列埠的輸出速度。
格式:
#include
int cfsetospeed(struct termios *tp, speed_t speed)
其中tp為被處理的termios結構,speed為鮑率。
tcdrain()
等待所有輸出寫到串列埠後,才返回呼叫的程式。
格式:
#include
tcdrain(int fd);
其中fd為被處理的串列埠。
tcflush()
清除所有佇列在串列埠的輸入和輸出。
格式:
#include
int tcflush(int fd, int queue);
其中fd為被處理的串列埠,引數queue為下列值。
queue值 | 說明 |
TCIFLUSH | 清除輸入 |
TCOFLUSH | 清除輸出 |
TCIOFLUSH | 清除輸入和輸出 |
tcflow()
啟動或停止串列埠的資料傳送或接收。
格式:
#include
int tcflow(int fd, int action);
其中fd為被處理的串列埠,引數action為下列值。
action值 | 說明 |
TCOON | 啟動輸出 |
TCOOFF | 停止輸出 |
TCION | 啟動輸入 |
TCIOFF | 停止輸入 |
6-4 程式:RS-232通訊
目的:
以正規模式撰寫RS-232通訊程式
要求:
透過COM1和COM2,藉由RS-232通訊來傳送資料。COM1為傳送端,COM2為接收端。RS-232的通訊格式為38400,n,8,1。
接收端程式
讀取COM2傳入的資料,並將其顯示在螢幕,當收到@字元表示傳送結束。
/* rs232_recv.c */
#include printf("Close...\n"); close(fd); tcsetattr(fd, TCSANOW, &oldtio); return 0; } |
傳送端程式
將資料從COM1傳送出去,每當使用者按下enter鍵,就傳送出去。
/* rs232_send.c */ #include |
6-5 程式:刷卡機應用
刷卡機套件
1. 讀取單軌ISO7811/2規格的磁卡,並將號碼顯示在LCD上。
2.有讀取錯誤的文字和聲音警告功能。
3.讀取到的資料可傳送到8051。
4.可與PC溝通,支援COM1和COM2。
目的:
以Linux C設計一個可以讀取讀卡機資料的程式。
使用非正規模式來設計Linux RS-232通序程式。
要求:
讀卡機與PC的COM1連接,通訊規格為9600,n,8,1。
程式:
/* rs232_card.c */ #include |
options.c_cflag |= PARODD;//不是奇同位元檢查
回覆刪除這行應該是//是奇同位元檢查
請問什麼要close(fd); 之後才設回oldtio,而不是之前?
回覆刪除麻煩解惑了