Linux下的串口通信
發(fā)布時(shí)間:2022-01-07 11:19:10
點(diǎn)擊上方藍(lán)字關(guān)注我們
串行接口簡(jiǎn)稱串口,也稱串行通信接口或串行通訊接口(通常指COM口,在設(shè)備管理器中可以查看到),是采用串行通信方式的擴(kuò)展接口。串行接口(SerialInterface)是指數(shù)據(jù)一位一位地順序傳送。其特點(diǎn)是通信線路簡(jiǎn)單,只要一對(duì)傳輸線就可以實(shí)現(xiàn)雙向通信(可以直接利用電話線作為傳輸線),從而大大降低了成本,特別適用于遠(yuǎn)距離通信,但傳送速度較慢,可以用于交換機(jī)、電腦主板接口等。
在Linux系統(tǒng)中,一切接文件,因此串口設(shè)備是通過(guò)串口終端設(shè)備文件來(lái)訪問(wèn)的,也就是通過(guò)訪問(wèn)/dev/ttyS0、/dev/ttyS1、/dev/ttyS2、/dev/ttyS3這些設(shè)備文件實(shí)現(xiàn)對(duì)串口的訪問(wèn)。對(duì)串口進(jìn)行讀寫(xiě)要經(jīng)過(guò)下面幾個(gè)步驟。
與打開(kāi)文件類(lèi)似,打開(kāi)串口同樣使用open函數(shù)。注意對(duì)于串口的打開(kāi)操作,必須使用O_NOCTTY參數(shù)。該參數(shù)表示:如果打開(kāi)的是一個(gè)終端設(shè)備,程序不會(huì)成為對(duì)應(yīng)這個(gè)端口的控制終端。如果沒(méi)有使用該標(biāo)志,任何一個(gè)輸入(例如,鍵盤(pán)中止信號(hào)等)都將影響進(jìn)程。具體代碼如下:
#include
#include
#include
int main(void)
{
…
int fd;
//使用open函數(shù)打開(kāi)串口,獲得串口設(shè)備文件的文件描述符
if((fd=open("/dev/ttyS0",O_RDWR|O_NOCTTY))==-1)
{
perror("Cannot open theserial port");
return 1;
}
…
}
……
串口通信參數(shù)指的是波特率、數(shù)據(jù)位、奇偶校驗(yàn)位和停止位。對(duì)串口實(shí)現(xiàn)控制的時(shí)候同樣要用到termio結(jié)構(gòu)體。
1.波特率設(shè)置
獲得端口波特率信息是通過(guò)cfgetispeed函數(shù)和cfgetospeed函數(shù)來(lái)實(shí)現(xiàn)的。cfgetispeed函數(shù)用于獲得結(jié)構(gòu)體termios_p中的輸入波特率信息,而cfgetospeed函數(shù)用于獲得結(jié)構(gòu)體termios_p中的輸出波特率信息。這兩個(gè)函數(shù)的具體信息如表1所示。
頭文件 | #include #include | ||
函數(shù)形式 | speed_t cfgetispeed(const struct termios *termios_p); speed_t cfgetospeed(const struct termios *termios_p); | ||
返回值 | 成功 | 失敗 | 是否設(shè)置errno |
返回termios_p結(jié)構(gòu)中的輸入/輸出端口的波特率 | ?1 | 是 |
表1 cfgetispeed函數(shù)和cfgetospeed函數(shù)
cfsetispeed函數(shù)和cfsetospeed函數(shù)用于設(shè)置端口的輸入/輸出波特率。一般情況下,輸入和輸出波特率是相等的。cfsetispeed函數(shù)和cfsetospeed函數(shù)的函數(shù)聲明信息如表2所示。
頭文件 | |||
函數(shù)形式 | int cfsetispeed(struct termios *termios_p, speed_t speed); int cfsetospeed(struct termios *termios_p, speed_t speed); | ||
返回值 | 成功 | 失敗 | 是否設(shè)置errno |
返回termios_p結(jié)構(gòu)中的輸入/輸出端口的波特率 | ?1 | 是 |
表2 cfsetispeed函數(shù)和cfsetospeed函數(shù)
cfsetispeed函數(shù)和cfsetospeed函數(shù)會(huì)修改結(jié)構(gòu)體termios_p中的波特率信息,其中參數(shù)speed可以使用表3中所列出的宏。
宏 定 義 | 波特率(單位:bit/s) | 宏 定 義 | 波特率(單位:bit/s) |
B0 | 0 | B1800 | 1800 |
B50 | 50 | B2400 | 2400 |
B75 | 75 | B4800 | 4800 |
B110 | 110 | B9600 | 9600 |
B134 | 134 | B19200 | 19200 |
B150 | 150 | B38400 | 38400 |
B200 | 200 | B57600 | 57600 |
B300 | 300 | B115200 | 115200 |
B600 | 600 | B230400 | 230400 |
B1200 | 1200 |
表3 speed參數(shù)常用波特率信息
使用cfsetispeed函數(shù)和cfsetospeed函數(shù)進(jìn)行串口波特率設(shè)置具體代碼如下所示:
#include
#include
#include < termios.h >
……
struct termios opt; /*定義指向termios結(jié)構(gòu)類(lèi)型的指針opt*/
……
//獲得串口指向termios結(jié)構(gòu)的指針
tcgetattr(fd, &Opt);
cfsetispeed(&opt,B9600); /*指定輸入波特率,9600bps*/
cfsetospeed(&opt,B9600);/*指定輸出波特率,9600bps*/
//將修改后的termios數(shù)據(jù)設(shè)置到串口中
tcsetattr(fd,TCANOW,&Opt);
……
2.?dāng)?shù)據(jù)位
數(shù)據(jù)位指的是每字節(jié)中實(shí)際數(shù)據(jù)所占的比特?cái)?shù)。要修改數(shù)據(jù)位可以通過(guò)修改termios結(jié)構(gòu)體中c_cflag成員來(lái)實(shí)現(xiàn)。CS5、CS6、CS7和CS8分別表示數(shù)據(jù)位為5、6、7和8。值得注意的是,在設(shè)置數(shù)據(jù)位時(shí),必須先使用CSIZE做位屏蔽。具體設(shè)置代碼如下:
#include
#include
#include< termios.h >
……
structtermios opt; /*定義指向termios結(jié)構(gòu)類(lèi)型的指針opt*/
.......
//獲得串口指向termios結(jié)構(gòu)的指針
tcgetattr(fd,&Opt);
…
//屏蔽其他標(biāo)志
Opt.c_cflag&=~CSIZE;
//將數(shù)據(jù)位修改為8bit
Opt.c_cflag|=CS8;
…
//將修改后的termios數(shù)據(jù)設(shè)置到串口中
tcsetattr(fd,TCANOW,&Opt);
……
3.奇偶校驗(yàn)位
奇偶校驗(yàn)可以選擇偶校驗(yàn)、奇校驗(yàn)、空格等方式,也可以不使用校驗(yàn)。如果要設(shè)置為偶校驗(yàn)的話,首先要將termios結(jié)構(gòu)體中c_cflag設(shè)置PARENB標(biāo)志,并清除PARODD標(biāo)志。如果要設(shè)置奇校驗(yàn),要同時(shí)設(shè)置termios結(jié)構(gòu)體中c_cflag設(shè)置PARENB標(biāo)志和PARODD標(biāo)志。如果不想使用任何校驗(yàn)的話,清除termios結(jié)構(gòu)體中c_cflag的PARENB位。表4所示為設(shè)置奇偶校驗(yàn)的具體方法。
設(shè) 置 | 具 體 代 碼 |
無(wú)校驗(yàn) | opt.c_cflag &= ~PARENB; |
奇校驗(yàn) | opt.c_cflag |= (PARODD | PARENB); |
偶校驗(yàn) | opt.c_cflag &= ~ PARENB; opt.c_cflag &= ~PARODD; |
空格 | opt.c_cflag &= ~PARENB; opt.c_cflag &= ~CSTOPB; |
表4 設(shè)置奇偶校驗(yàn)位
下面給出將串口通信的奇偶校驗(yàn)設(shè)置為偶校驗(yàn)的例子,具體代碼如下:
#include
#include
#include < termios.h >
……
struct termios opt; /*定義指向termios結(jié)構(gòu)類(lèi)型的指針opt*/
……
//獲得串口指向termios結(jié)構(gòu)的指針
tcgetattr(fd, &Opt);
…
opt.c_cflag &= ~ PARENB;
opt.c_cflag &= ~PARODD;
…
//將修改后的termios數(shù)據(jù)設(shè)置到串口中
tcsetattr(fd,TCANOW,&Opt);
……
4.?dāng)?shù)據(jù)流控制
數(shù)據(jù)流控制指是使用何種方法來(lái)標(biāo)志數(shù)據(jù)傳輸?shù)拈_(kāi)始和結(jié)束??梢赃x擇不使用數(shù)據(jù)流控制、使用硬件進(jìn)行流控制和使用軟件進(jìn)行流控制。數(shù)據(jù)流控制設(shè)置如表5所示。
設(shè) 置 | 具 體 代 碼 |
不使用數(shù)據(jù)流控制 | opt.c_cflag &= ~CRTSCTS |
硬件 | opt.c_cflag |= CRTSCTS |
軟件 | opt.c_cflag | = IXON|IXOFF|IXANY |
由于使用硬件流控制需要相應(yīng)連接的電纜,常用的流控制方法還是使用軟件進(jìn)行流控制。下面給出了設(shè)置不使用數(shù)據(jù)流控制的相關(guān)代碼:
#include
#include
#include < termios.h >
……
struct termios opt; /*定義指向termios結(jié)構(gòu)類(lèi)型的指針opt*/
……
//獲得串口指向termios結(jié)構(gòu)的指針
tcgetattr(fd, &opt);
…
opt.c_cflag &= ~CRTSCTS…
//將修改后的termios數(shù)據(jù)設(shè)置到串口中
tcsetattr(fd,TCANOW,&Opt);
……
讀寫(xiě)串口是通過(guò)使用read函數(shù)和write函數(shù)實(shí)現(xiàn)的。在Linux系統(tǒng)中,對(duì)設(shè)備的讀寫(xiě)類(lèi)似于對(duì)文件的讀寫(xiě)。下面給出對(duì)串口的寫(xiě)操作的代碼:
……
int len;
//待發(fā)送數(shù)據(jù)
char sbuf[]={Hello,thisis a Serial_Port test!/n};
int send_len=sizeof(sbuf);
//發(fā)送緩沖區(qū)字節(jié)數(shù)定義
len= write(fd,sbuf,send_len);//
if(n == -1)
printf("Wirte sbuferror./n");
……
在完成對(duì)設(shè)備文件讀寫(xiě)操作后,需要調(diào)用close函數(shù)關(guān)閉該文件描述符。
以上就是關(guān)于Linux下串口文件的相關(guān)知識(shí),你學(xué)會(huì)了嗎?