詳解linux下的串口通訊開發[轉載]
串列口是電腦一種常用的介面,具有連接線少,通訊簡單,得到廣泛的使用。常用的串口是RS-232-C介面(又稱EIA RS-232-C)它是在1970年由美國電子工業協會(EIA)聯合貝爾系統、數據機廠家及電腦終端生產廠家共同制定的用於串列通訊的標準。串口通訊指的是電腦依次以位(bit)為單位來傳送資料,串列通訊使用的範圍很廣,在嵌入式系統開發過程中串口通訊也經常用到通訊方式之一。
Linux對所有裝置的訪問是通過裝置檔案來進行的,串口也是這樣,為了訪問串口,只需開啟其裝置檔案即可操作串口裝置。在linux系統下面,每一個串口裝置都有裝置檔案與其關聯,裝置檔案位於系統的/dev目錄下面。如linux下的/ttyS0,/ttyS1分別表示的是串口1和串口2。下面來詳細介紹linux下是如何使用串口的:
1. 串口操作需要用到的標頭檔
#include <stdio.h> /*標準輸入輸出定義*/
#include <stdlib.h> /*標準函數庫定義*/
#include <unistd.h> /*Unix 標準函數定義*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> /*檔案控制定義*/
#include <termios.h> /*POSIX 終端控制定義*/
#include <errno.h> /*錯誤號碼定義*/
#include <string.h> /*字串功能函數*/
2. 串口通訊傳輸速率設定
傳輸速率的設定定義在<asm/termbits.h>,其包含在標頭檔<termios.h>裡。
常用的傳輸速率常數如下:
B0-------à0 B1800-------à1800
B50-----à50 B2400------à2400
B75-----à75 B4800------à4800
B110----à110 B9600------à9600
B134----à134.5 B19200-----à19200
B200----à200 B38400------à38400
B300----à300 B57600------à57600
B600----à600 B76800------à76800
B1200---à1200 B115200-----à115200
假定程式中想要設定通訊的傳輸速率,使用cfsetispeed( )和cfsetospeed( )函數來操作,擷取傳輸速率資訊是通過cfgetispeed()和cfgetospeed()函數來完成的。比如可以這樣來指定串口通訊的傳輸速率:
#include <stdio.h> //標頭檔定義
........
........
.......
struct termios opt; /*定義指向termios 結構類型的指標opt*/
/***************以下設定通訊傳輸速率****************/
cfsetispeed(&opt,B9600 ); /*指定輸入傳輸速率,9600bps*/
cfsetospeed(&opt,B9600);/*指定輸出傳輸速率,9600bps*/
/************************************************/
.........
..........
一般來說,輸入、輸出的傳輸速率應該是一致的。
3. 串口屬性配置
在程式中,很容易配置串口的屬性,這些屬性定義在結構體struct termios中。為在程式中使用該結構體,需要包含檔案<termbits.h>,該標頭檔定義了結構體struct termios。該結構體定義如下:
#define NCCS 19
struct termios {
tcflag_t c_iflag; /* 輸入參數 */
tcflag_t c_oflag; /* 輸出參數 */
tcflag_t c_cflag; /* 控制參數*/
tcflag_t c_ispeed; /* 輸入傳輸速率 */
tcflag_t c_ospeed; /* 輸出傳輸速率 */
cc_t c_line; /* 線控制 */
cc_t c_cc[NCCS]; /* 控制字元*/
};
其中成員c_line在POSIX(Portable Operating System Interface for UNIX)系統中不使用。對於支援POSIX終端介面的系統中,對於連接埠屬性的設定和擷取要用到兩個重要的函數是:
(1).int tcsetattr(int fd,int opt_DE,*ptr)
該函數用來設定終端控制屬性,其參數說明如下:
l fd:待操作的檔案描述符
l opt_DE:選項值,有三個選項以供選擇:
TCSANOW: 不等資料轉送完畢就立即改變屬性
TCSADRAIN:等待所有資料轉送結束才改變屬性
TCSAFLUSH:清空輸入輸出緩衝區才改變屬性
l *ptr:指向termios結構的指標
函數傳回值:成功返回0,失敗返回-1。
(2).int tcgetattr(int fd,*ptr)
該函數用來擷取終端控制屬性,它把串口的預設設定賦給了termios資料資料結構,其參數說明如下:
l fd:待操作的檔案描述符
l *ptr:指向termios結構的指標
函數傳回值:成功返回0,失敗返回-1。
4. 開啟串口
在前面已經提到linux下的串口訪問是以裝置檔案形式進行的,所以開啟串口也即是開啟檔案的操作。函數原型可以如下所示:
int open(“DE_name”,int open_Status)
參數說明:
(1).DE_name:要開啟的裝置檔案名稱
比如要開啟串口1,即為/dev/ttyS0。
(2).open_Status:檔案開啟檔案,可採用下面的檔案開啟模式:
l O_RDONLY:以唯讀方式開啟檔案
l O_WRONLY:以唯寫方式開啟檔案
l O_RDWR:以讀寫方式開啟檔案
l O_APPEND:寫入資料時添加到檔案末尾
l O_CREATE:如果檔案不存在則產生該檔案,使用該標誌需要設定存取權限位mode_t
l O_EXCL:指定該標誌,並且指定了O_CREATE標誌,如果開啟的檔案存在則會產生一個錯誤
l O_TRUNC:如果檔案存在並且成功以寫或者唯寫方式開啟,則清除檔案所有內容,使得檔案長度變為0
l O_NOCTTY:如果開啟的是一個終端裝置,這個程式不會成為對應這個連接埠的控制終端,如果沒有該標誌,任何一個輸入,例如鍵盤中止訊號等,都將影響進程。
l O_NONBLOCK:該標誌與早期使用的O_NDELAY標誌作用差不多。程式不關心DCD訊號線的狀態,如果指定該標誌,進程將一直在休眠狀態,直到DCD訊號線為0。
函數傳回值:
成功返迴文件描述符,如果失敗返回-1
例如假定以可讀寫方式開啟/dev/ttyS0裝置,就可以這樣操作:
#include<stdio.h> //標頭檔包含
......
......
int fd; /* 檔案描述符 */
fd = open("/dev/ttyS0", O_RDWR | 0_NOCTTY); /*以讀寫方式開啟裝置*/
if(fd == -1)
perror("Can not open Serial_Port 1/n!");/*開啟失敗時的錯誤提示*/
........
........
5. 串口讀操作(接收端)
用open函數開啟裝置檔案,函數返回一個檔案描述符(file descriptors,fd),通過檔案描述符來訪問檔案。讀串口操作是通過read函數來完成的。函數原型如下:
int read(int fd, *buffer,length);
參數說明:
(1).int fd:檔案描述符
(2).*buffer:資料緩衝區
(3).length:要讀取的位元組數
函數傳回值:
讀操作成功讀取返回讀取的位元組數,失敗則返回-1。
6. 串口寫操作(發送端)
寫串口操作是通過write函數來完成的。函數原型如下:
write(int fd, *buffer,length);
參數說明:
(1).fd:檔案描述符
(2).*buffer:儲存寫入資料的資料緩衝區
(3).length:寫入緩衝去的資料位元組數
函數傳回值:
成功返回寫入資料的位元組數,該值通常等於length,如果寫入失敗返回-1。
例如:向終端裝置發送初始化命令
#include<stdio.h> //標頭檔包含
......
......
int n
sbuf[]={Hello,this is a Serial_Port test!/n };//待發送資料
int len_send="sizeof"(sbuf);//發送緩衝區位元組數定義
n = write(fd,sbuf,len_send); //寫緩衝區
if(n == -1)
{
printf("Wirte sbuf error./n");
}
......
......
7. 關閉串口
對裝置檔案的操作與對普通檔案的操作一樣,開啟操作之後還需要關閉,關閉串口用函數close( )來操作,函數原型為:
int close(int fd);
參數說明:
fd:檔案描述符
函數傳回值:
成功返回0,失敗返回-1。
在後面的文章我會提供一個串列通訊的測試程式,供大家參考!