Linux c下串口使用相關函數


Linux c下串口使用相關函數

① 串口使用相關頭文件

#include<stdio.h>         /*標准輸入輸出的定義*/

#include<stdlib.h>        /*標准函數庫定義*/

#include<unistd.h>       /*UNIX標准函數定義*/

#include<sys/types.h>  /*基本系統數據類型*/

#include<sys/stat.h>      /*文件狀態*/

#include<fcntl.h>         /*文件控制定義*/

#inlcude<error.h>          /*錯誤號定義*/

#include<assert.h>

#define FALSE -1

#define TRUE 0

int speed_arr[] = { B38400, B19200, B9600, B4800, B2400,B1200, B300,B38400, B19200, B9600, B4800, B2400,B1200, B300, };

int name_arr[] ={38400, 19200, 9600, 4800, 2400, 1200, 300, 38400,19200, 9600, 4800, 2400, 1200, 300, };

② 打開串口設備函數

static int fd;

int OpenDev(int fd, const char *pathname)

{

       assert(pathname);          //檢測串口路徑pathname是否存在

  fd=open(pathname,O_RDWR);//|O_NOCTTY|O_[c1] NONBLOCK

       if(-1==fd)

  {

         perror(“Can’t Open Serial Port”);

         return -1;

  }

  else

         return fd;

}

/*

[c1]O_RDWR:以讀寫的方式打開;

O_NOCTTY:如果p a t h n a m e指的是終端設備,則不將此設備分配作為此進程的控制終端。

O_NONBLOCK: 如果p a t h n a m e指的是一個F I F O、一個塊特殊文件或一個字符特殊文件,則此選擇項為此文件的本次打開操作和后續的I / O操作設置非阻塞方式。

*/

 

③ 設置串口參數(串口波特率、數據流控制、幀的格式(即數據位的個數,停止位,校驗位[c1] ))

int SerialPort_Config(int fd,int baude,int c_flow,int bits,char parity,int stop)

{

       struct termios options;

       /*獲得當前設備模式,與終端相關的參數,fd=0標准輸入*/

       if(tcgetattr(fd,&options)<0)

       {

              perror(“tcgetarrt error”);

              return-1;

  }

 

void set_speed(int fd,int speed)

{

       int i;

       int status;

       for(i=0;i<sizeof(speed_attr)/sizeof(int);i++)

       {

              if(speed==name_attr[i])

    {

         tcflush(fd,TCIOFLUSH);//設置當前flush

         cfsetispeed(&options,speed_attr[i]);

         cfsetospeed(&options,speed_attr[i]);

    }

  }

}

}

/*

[c1]串口的設置主要是設置 struct termios 結構體的各成員值。

struct termio

{

  unsigned short c_iflag; /* 輸入模式標志 */

  unsigned short c_oflag; /* 輸出模式標志 */

  unsigned short c_cflag; /* 控制模式標志*/

  unsigned short c_lflag; /* local mode flags */

  unsigned char c_line; /* line discipline */

  unsigned char c_cc[NCC]; /* control characters */

};

 */

 串口屬性設置

1. 屬性描述

串口屬於終端設備,其接口屬性用termios結構描述,如程序清單13.9所示。

程序清單13.9termios結構

struct termios {

tcflag_t  c_cflag/* 控制標志*/

tcflag_t  c_iflag;/* 輸入標志*/

tcflag_t  c_oflag;/* 輸出標志*/

tcflag_t  c_lflag;/* 本地標志*/

tcflag_t  c_cc[NCCS];/* 控制字符*/

};

粗略而言,控制標志影響到RS-232串行線(如:忽略調制解調器的狀態線、每個字符需要一個或兩個停止位等),輸入標志由終端設備驅動程序用來控制字符的輸入(如:剝除輸入字節的第8位,允許輸入奇偶校驗等),輸出控制則控制驅動程序輸出(如:執行輸出處理、將換行符映射為CR/LF),本地標志影響驅動程序和用戶之間的接口(如:本地回顯的開和關等),c_cc數組則包含了所有可以更改的特殊字符。

1)控制標志

c_cflag成員控制着波特率、數據位、奇偶校驗、停止位以及流控制,表13.4列出了c_cflag可用的部分選項。

標志

說明

標志

說明

CBAUD

波特率位屏蔽

CSIZE

數據位屏蔽

B0

0/秒(掛起)

CS5

5位數據位

B110

100/

CS6

6位數據位

B134

134/

CS7

7位數據位

B1200

1200/

CS8

8位數據位

13.4c_cflag部分可用選項

B2400

2400/

CSTOPB

2位停止位,否則為1

B4800

4800/

CREAD

啟動接收

B9600

9600/

PARENB

進行奇偶校驗

B19200

19200/

PARODD

奇校驗,否則為偶校驗

B57600

57600/

HUPCL

最后關閉時斷開

B115200

115200/

CLOCAL

忽略調制調解器狀態行

B460800

460800/

                                                                                                                                       

    c_cflag成員的CREADCLOCAL選項通常是要啟用的,這兩個選項使驅動程序啟動接收字符裝置,同時忽略串口信號線的狀態。

2)輸入標志

c_iflag成員負責控制串口輸入數據的處理,表13.5所示是c_iflag的部分可用標志。

13.5c_iflag標志

.標志

說明

INPCK

打開輸入奇偶校驗

IGNPAR

忽略奇偶錯字符

PARMRK

標記奇偶錯

ISTRIP

剝除字符第8

IXON

啟用/停止輸出控制流起作用

IXOFF

啟用/停止輸入控制流起作用

IGNBRK

忽略BREAK條件

INLCR

將輸入的NL轉換為CR

IGNCR

忽略CR

ICRNL

將輸入的CR轉換為NL

設置輸入校驗

c_cflag成員的PARENB(奇偶校驗)選項啟用時c_iflag的也應啟用奇偶校驗選項。操作方法是啟用INPCKISTRIP選項:

options.c_iflag |= (INPCK | ISTRIP);

注意:IGNPAR選項在一些場合的應用帶有一定的危險性,它指示串口驅動程序忽略奇偶校驗錯誤,也就是說,IGNPAR使奇偶校驗出錯的字符也通過輸入。這在測試通信鏈路的質量時也許有用,但在通常的數據通信應用中不應使用。

設置軟件流控制

使用軟件流控制是啟用IXONIXOFFIXANY選項:

options.c_iflag |= (IXON | IXOFF | IXANY);

相反,要禁用軟件流控制是禁止上面的選項:

options.c_iflag &= ~(IXON | IXOFF | IXANY);

 

3)輸出標志

c_oflag成員管理輸出過濾,如表13.6所示是c_oflag成員的部分選項標志。

13.6c_oflag標志

標志

說明

BSDLY

退格延遲屏蔽

CMSPAR

標志或空奇偶性

CRDLY

CR延遲屏蔽

FFDLY

換頁延遲屏蔽

OCRNL

將輸出的CR轉換為NL

OFDEL

填充符為DEL,否則為NULL

OFILL

對於延遲使用填充符

OLCUC

將輸出的小寫字符轉換為大寫字符

ONLCR

NL轉換為CR-NL

ONLRET

NL執行CR功能

ONOCR

0列不輸出CR

OPOST

執行輸出處理

OXTABS

將制表符擴充為空格

 

啟用輸出處理

啟用輸出處理需要在c_oflag成員中啟用OPOST選項,其操作方法如下:

options.c_oflag |= OPOST;

使用原始輸出

使用原始輸出,就是禁用輸出處理,使數據能不經過處理、過濾地完整地輸出到串口接口。當OPOST被禁止,c_oflag其它選項也被忽略,其操作方法如下:

options.c_oflag &= ~OPOST;

 

4)本地標志

本地標志c_lflag控制着串口驅動程序如何管理輸入的字符,如表13.7所示是c_lflag的部分可用標志。

13.7c_lflag標志

標志

說明

ISIG

啟用終端產生的信號

ICANON

啟用規范輸入

XCASE

規范大/小寫表示

ECHO

進行回送

ECHOE

可見擦除字符

ECHOK

回送kill

ECHONL

回送NL

NOFLSH

在中斷或退出鍵后禁用刷清

IEXTEN

啟用擴充的輸入字符處理

ECHOCTL

回送控制字符為^(char)

ECHOPRT

硬拷貝的可見擦除方式

ECHOKE

Kill的可見擦除

PENDIN

重新打印未決輸入

TOSTOP

對於后台輸出發送SIGTTOU

 

選擇規范模式

規范模式是行處理的。調用read讀取串口數據時,每次返回一行數據。當選擇規范模式時,需要啟用ICANONECHOECHOE選項:

options.c_lflag |= (ICANON | ECHO | ECHOE);

當串口設備作為用戶終端時,通常要把串口設備配置成規范模式。

選擇原始模式

在原始模式下,串口輸入數據是不經過處理的,在串口接口接收的數據被完整保留。要使串口設備工作在原始模式,需要關閉ICANONECHOECHOEISIG選項,其操作方法如下:

options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

 

4)控制字符組

c_cc數組的長度是NCCS,一般介於15-20之間。c_cc數組的每個成員的下標都用一個宏表示,表13.8列出了c_cc的部分下標標志名及其對應說明。

13.8c_cc標志

VINTR

中斷

VQUIT

退出

VERASE

擦除

VEOF

行結束

VEOL

行結束

VMIN

需讀取的最小字節數

VTIME

VMIN配合使用,是指限定的傳輸或等待的最長時間

 

在規范模式下,調用read讀取串口數據時,通常是返回一行數據。而在原始模式下,串口輸入數據是不分行的。在原始模式下,返回讀取數據的數量需要考慮兩個變量:MINTIMEMINTIMEc_cc數組中的下標名為VMINVTIME

MIN是指一次read調用期望返回的最小字節數。TIMEMIN組合使用,其具體含義分以下四種情形:

1)當MIN > 0TIME > 0

TIME為接收到第一個字節后允許的數據傳輸或等待的最長分秒數(1分秒= 0.1秒)。定時器在收到第一個字節后啟動,在計時器超時之前,若已收到MIN個字節,則read返回MIN個字節,否則,在計時器超時后返回實際接收到的字節。

注意:因為只有在接收到第一個字節時才啟動,所以至少可以返回1個字節。這種情形中,在接到第一個字節之前,調用者阻塞。如果在調用read時數據已經可用,則如同在read后數據立即被接到一樣。

2)當MIN > 0TIME = 0

MIN個字節完整接收后,read才返回,這可能會造成read無限期地阻塞。

3)當MIN = 0, TIME > 0

TIME為允許等待的最大時間,計時器在調用read時立即啟動,在串口接到1字節數據或者計時器超時后即返回,如果是計時器超時,則返回0

4)當MIN = 0TIME = 0

如果有數據可用,則read最多返回所要求的字節數,如果無數據可用,則read立即返回0

 

2. 屬性設置

使用函數tcgetattrtcsetattr可以獲取和設置串口termios結構屬性,如程序清單13.10所示。

程序清單13.10設置和獲取termios結構屬性

#include <termios.h>/* 使用終端接口函數需要使用此頭文件*/

int tcgetattr(int fd, struct termios *termptr);

int tcsetattr(int fd, int opt, const struct termios *termptr);

其中:fd為串口設備文件描述符,termptr參數在tcgetattr函數中是用於存放串口設置的termios結構體,opt是整形變量,使用方法如下:

1TCSANOW:更改立即發生;

2TCSADRAIN:發送了所有輸出后更改才發生,若更改輸出參數則應用此選項;

3TCSAFLUSH:發送了所有輸出后更改才發生,更進一步,在更改發生時未讀的所有輸入數據被刪除(Flush)。

在串口驅動程序里,有輸入緩沖區和輸出緩沖區。在改變串口屬性時,緩沖區中的數據可能還存在,這時需要考慮到更改后的屬性什么時候起作用。tcsetattr的參數opt可以指定在什么時候新的串口屬性才起作用。

上述兩函數執行時,若成功則返回0,若出錯則返回-1

掌握了如何獲取和設置串口的屬性結構后,下面將介紹串口主要屬性的修改,即修改termios結構體的成員。

termios結構體的各個成員的各個選項中除需要用屏蔽標志的選項外(如波特率選項、數據位選項等),都是按位表示的,對這些選項的設置或清除可以直接用^&邏輯運算來完成。

需要用屏蔽標志的選項的話則需要先用&運算清除原設置,再用^運算設置新選項。例如,為了設置字符長度,需先用字符長度屏蔽標志CSIZE將表示字符長度的位清0,然后再將對應位設置為CS5CS6CS7CS8

1)設置波特率

串口的輸入和輸出波特率可分別用cfsetispeed()cfsetospeed()函數來設置,如程序清單13.11所示。

程序清單13.11設置串口輸入/輸出波特率函數

#include <termios.h>

int cfsetispeed(struct termios *termptr, speed_t speed);

int cfsetospeed(struct termios *termptr, speed_t speed);

這兩個函數若執行成功返回0,若出錯則返回-1

使用這兩個函數時,應當理解輸入、輸出波特率是存在串口設備termios結構中的。在調用任一cfset函數之前,先要用tcgetattr獲得設備的termios結構。與此類似,在調用任一cfset函數后,波特率都被設置到termios結構中。為使這種更改影響到設備,應當調用tcsetattr函數。操作方法如程序清單13.12所示。

程序清單13.12設置波特率示例

if (tcgetattr(fd, &opt)< 0) {

return ERROR;

}

cfsetispeed(&opt, B9600);

cfsetospeed(&opt, B9600);

if (tcsetattr(fd,   TCSANOW,   &opt)<0) {

return   ERROR;

}

(2)設置數據位

設置數據位不需要專用的函數,只需要在設置數據位之前用數據位屏蔽標志(CSIZE)把對應數據位清零,然后再設置新的數據位即可,如下所示:

options.c_cflag &= ~CSIZE;/* 先把數據位清零*/

options.c_cflag |= CS8;/* 把數據位設置為8*/

3)設置奇偶校驗

正如設置數據位一樣,設置奇偶校驗是在直接在cflag成員上設置。下面是各種類型的校驗設置方法。

 

1)無奇偶校驗(8N1):

options.c_cflag &= ~PARENB;

options.c_cflag &= ~CSTOPB;

options.c_cflag &= ~CSIZE;

options.c_cflag |= CS8;

27位數據位奇偶校驗(7E1):

options.c_cflag |= PARENB;

options.c_cflag &= ~PARODD;

options.c_cflag &= ~CSTOPB;

options.c_cflag &= ~CSIZE;

options.c_cflag |= CS7;

3)奇校驗(7O1):

options.c_cflag|= PARENB;

options.c_cflag |= PARODD;

options.c_cflag &= ~CSTOPB;

options.c_cflag &= ~CSIZE;

options.c_cflag |= CS7;

 

串口設置示例:

static int UART2_Init(void)

{

    struct termios opt; //屬性描述

    fdUart2 = open(DEV_UART2, O_RDWR | O_NOCTTY);            

    if(fdUart2 < 0)

    {

        perror(DEV_UART2);

        return -1;

    }

    tcgetattr(fdUart2, &opt);     //獲取串口屬性結構體對象

    cfsetispeed(&opt, B38400);     //設置輸入波特率

    cfsetospeed(&opt, B38400);     //設置輸出波特率

 

    /* raw mode */   //偶校驗

    opt.c_lflag   &=   ~(ECHO | ICANON | IEXTEN |ISIG); //設置本地標志:不進行回送,關閉規范輸入,關閉擴充輸入字符處理,關閉終端產生的信號

    opt.c_iflag   &=  ~(IXON | ISTRIP);       // 關閉輸出流控制, 不剝除第8

    opt.c_iflag   |= (ICRNL | BRKINT | INPCK);// 將輸入的CR轉換為NL,使得輸入和輸出隊列被刷新,打開奇偶校驗

    opt.c_oflag   &=   ~(OPOST);              // 設置輸出標志:不執行輸出處理

    opt.c_cflag   &=   ~(PARODD | CSIZE);     // 關閉輸入輸出是奇校驗,使用屏蔽位

    opt.c_cflag   |=   (CS8 | CLOCAL | CREAD | PARENB);//8位數據位,保證程序不會占用串口,能夠從串口讀取輸入數據,允許輸出產生奇偶信息以及輸入的奇偶校驗

    /*'DATA_LEN' bytes can be read by serial*/

 

    opt.c_cc[VMIN]   =   DATA_LEN;   //讀取字符的最少個數                                  

    opt.c_cc[VTIME]  =   1;        //讀取一個字符等待1*1/10s

   

    tcflush(fdUart2,TCIOFLUSH);  //清空所有正在發生的IO數據

   

    if (tcsetattr(fdUart2, TCSANOW, &opt) < 0) //激活配置(將修改后的termios數據設置到串口)

    {

        return   -1;

    }

    return fdUart2;

}

1. 屬性描述

串口屬於終端設備,其接口屬性用termios結構描述,如程序清單13.9所示。

程序清單13.9termios結構

struct termios {

tcflag_t  c_cflag/* 控制標志*/

tcflag_t  c_iflag;/* 輸入標志*/

tcflag_t  c_oflag;/* 輸出標志*/

tcflag_t  c_lflag;/* 本地標志*/

tcflag_t  c_cc[NCCS];/* 控制字符*/

};

粗略而言,控制標志影響到RS-232串行線(如:忽略調制解調器的狀態線、每個字符需要一個或兩個停止位等),輸入標志由終端設備驅動程序用來控制字符的輸入(如:剝除輸入字節的第8位,允許輸入奇偶校驗等),輸出控制則控制驅動程序輸出(如:執行輸出處理、將換行符映射為CR/LF),本地標志影響驅動程序和用戶之間的接口(如:本地回顯的開和關等),c_cc數組則包含了所有可以更改的特殊字符。

1)控制標志

c_cflag成員控制着波特率、數據位、奇偶校驗、停止位以及流控制,表13.4列出了c_cflag可用的部分選項。

標志

說明

標志

說明

CBAUD

波特率位屏蔽

CSIZE

數據位屏蔽

B0

0/秒(掛起)

CS5

5位數據位

B110

100/

CS6

6位數據位

B134

134/

CS7

7位數據位

B1200

1200/

CS8

8位數據位

13.4c_cflag部分可用選項

B2400

2400/

CSTOPB

2位停止位,否則為1

B4800

4800/

CREAD

啟動接收

B9600

9600/

PARENB

進行奇偶校驗

B19200

19200/

PARODD

奇校驗,否則為偶校驗

B57600

57600/

HUPCL

最后關閉時斷開

B115200

115200/

CLOCAL

忽略調制調解器狀態行

B460800

460800/

                                                                                                                                       

    c_cflag成員的CREADCLOCAL選項通常是要啟用的,這兩個選項使驅動程序啟動接收字符裝置,同時忽略串口信號線的狀態。

2)輸入標志

c_iflag成員負責控制串口輸入數據的處理,表13.5所示是c_iflag的部分可用標志。

13.5c_iflag標志

.標志

說明

INPCK

打開輸入奇偶校驗

IGNPAR

忽略奇偶錯字符

PARMRK

標記奇偶錯

ISTRIP

剝除字符第8

IXON

啟用/停止輸出控制流起作用

IXOFF

啟用/停止輸入控制流起作用

IGNBRK

忽略BREAK條件

INLCR

將輸入的NL轉換為CR

IGNCR

忽略CR

ICRNL

將輸入的CR轉換為NL

設置輸入校驗

c_cflag成員的PARENB(奇偶校驗)選項啟用時c_iflag的也應啟用奇偶校驗選項。操作方法是啟用INPCKISTRIP選項:

options.c_iflag |= (INPCK | ISTRIP);

注意:IGNPAR選項在一些場合的應用帶有一定的危險性,它指示串口驅動程序忽略奇偶校驗錯誤,也就是說,IGNPAR使奇偶校驗出錯的字符也通過輸入。這在測試通信鏈路的質量時也許有用,但在通常的數據通信應用中不應使用。

設置軟件流控制

使用軟件流控制是啟用IXONIXOFFIXANY選項:

options.c_iflag |= (IXON | IXOFF | IXANY);

相反,要禁用軟件流控制是禁止上面的選項:

options.c_iflag &= ~(IXON | IXOFF | IXANY);

 

3)輸出標志

c_oflag成員管理輸出過濾,如表13.6所示是c_oflag成員的部分選項標志。

13.6c_oflag標志

標志

說明

BSDLY

退格延遲屏蔽

CMSPAR

標志或空奇偶性

CRDLY

CR延遲屏蔽

FFDLY

換頁延遲屏蔽

OCRNL

將輸出的CR轉換為NL

OFDEL

填充符為DEL,否則為NULL

OFILL

對於延遲使用填充符

OLCUC

將輸出的小寫字符轉換為大寫字符

ONLCR

NL轉換為CR-NL

ONLRET

NL執行CR功能

ONOCR

0列不輸出CR

OPOST

執行輸出處理

OXTABS

將制表符擴充為空格

 

啟用輸出處理

啟用輸出處理需要在c_oflag成員中啟用OPOST選項,其操作方法如下:

options.c_oflag |= OPOST;

使用原始輸出

使用原始輸出,就是禁用輸出處理,使數據能不經過處理、過濾地完整地輸出到串口接口。當OPOST被禁止,c_oflag其它選項也被忽略,其操作方法如下:

options.c_oflag &= ~OPOST;

 

4)本地標志

本地標志c_lflag控制着串口驅動程序如何管理輸入的字符,如表13.7所示是c_lflag的部分可用標志。

13.7c_lflag標志

標志

說明

ISIG

啟用終端產生的信號

ICANON

啟用規范輸入

XCASE

規范大/小寫表示

ECHO

進行回送

ECHOE

可見擦除字符

ECHOK

回送kill

ECHONL

回送NL

NOFLSH

在中斷或退出鍵后禁用刷清

IEXTEN

啟用擴充的輸入字符處理

ECHOCTL

回送控制字符為^(char)

ECHOPRT

硬拷貝的可見擦除方式

ECHOKE

Kill的可見擦除

PENDIN

重新打印未決輸入

TOSTOP

對於后台輸出發送SIGTTOU

 

選擇規范模式

規范模式是行處理的。調用read讀取串口數據時,每次返回一行數據。當選擇規范模式時,需要啟用ICANONECHOECHOE選項:

options.c_lflag |= (ICANON | ECHO | ECHOE);

當串口設備作為用戶終端時,通常要把串口設備配置成規范模式。

選擇原始模式

在原始模式下,串口輸入數據是不經過處理的,在串口接口接收的數據被完整保留。要使串口設備工作在原始模式,需要關閉ICANONECHOECHOEISIG選項,其操作方法如下:

options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

 

4)控制字符組

c_cc數組的長度是NCCS,一般介於15-20之間。c_cc數組的每個成員的下標都用一個宏表示,表13.8列出了c_cc的部分下標標志名及其對應說明。

13.8c_cc標志

VINTR

中斷

VQUIT

退出

VERASE

擦除

VEOF

行結束

VEOL

行結束

VMIN

需讀取的最小字節數

VTIME

VMIN配合使用,是指限定的傳輸或等待的最長時間

 

在規范模式下,調用read讀取串口數據時,通常是返回一行數據。而在原始模式下,串口輸入數據是不分行的。在原始模式下,返回讀取數據的數量需要考慮兩個變量:MINTIMEMINTIMEc_cc數組中的下標名為VMINVTIME

MIN是指一次read調用期望返回的最小字節數。TIMEMIN組合使用,其具體含義分以下四種情形:

1)當MIN > 0TIME > 0

TIME為接收到第一個字節后允許的數據傳輸或等待的最長分秒數(1分秒= 0.1秒)。定時器在收到第一個字節后啟動,在計時器超時之前,若已收到MIN個字節,則read返回MIN個字節,否則,在計時器超時后返回實際接收到的字節。

注意:因為只有在接收到第一個字節時才啟動,所以至少可以返回1個字節。這種情形中,在接到第一個字節之前,調用者阻塞。如果在調用read時數據已經可用,則如同在read后數據立即被接到一樣。

2)當MIN > 0TIME = 0

MIN個字節完整接收后,read才返回,這可能會造成read無限期地阻塞。

3)當MIN = 0, TIME > 0

TIME為允許等待的最大時間,計時器在調用read時立即啟動,在串口接到1字節數據或者計時器超時后即返回,如果是計時器超時,則返回0

4)當MIN = 0TIME = 0

如果有數據可用,則read最多返回所要求的字節數,如果無數據可用,則read立即返回0

 

2. 屬性設置

使用函數tcgetattrtcsetattr可以獲取和設置串口termios結構屬性,如程序清單13.10所示。

程序清單13.10設置和獲取termios結構屬性

#include <termios.h>/* 使用終端接口函數需要使用此頭文件*/

int tcgetattr(int fd, struct termios *termptr);

int tcsetattr(int fd, int opt, const struct termios *termptr);

其中:fd為串口設備文件描述符,termptr參數在tcgetattr函數中是用於存放串口設置的termios結構體,opt是整形變量,使用方法如下:

1TCSANOW:更改立即發生;

2TCSADRAIN:發送了所有輸出后更改才發生,若更改輸出參數則應用此選項;

3TCSAFLUSH:發送了所有輸出后更改才發生,更進一步,在更改發生時未讀的所有輸入數據被刪除(Flush)。

在串口驅動程序里,有輸入緩沖區和輸出緩沖區。在改變串口屬性時,緩沖區中的數據可能還存在,這時需要考慮到更改后的屬性什么時候起作用。tcsetattr的參數opt可以指定在什么時候新的串口屬性才起作用。

上述兩函數執行時,若成功則返回0,若出錯則返回-1

掌握了如何獲取和設置串口的屬性結構后,下面將介紹串口主要屬性的修改,即修改termios結構體的成員。

termios結構體的各個成員的各個選項中除需要用屏蔽標志的選項外(如波特率選項、數據位選項等),都是按位表示的,對這些選項的設置或清除可以直接用^&邏輯運算來完成。

需要用屏蔽標志的選項的話則需要先用&運算清除原設置,再用^運算設置新選項。例如,為了設置字符長度,需先用字符長度屏蔽標志CSIZE將表示字符長度的位清0,然后再將對應位設置為CS5CS6CS7CS8

1)設置波特率

串口的輸入和輸出波特率可分別用cfsetispeed()cfsetospeed()函數來設置,如程序清單13.11所示。

程序清單13.11設置串口輸入/輸出波特率函數

#include <termios.h>

int cfsetispeed(struct termios *termptr, speed_t speed);

int cfsetospeed(struct termios *termptr, speed_t speed);

這兩個函數若執行成功返回0,若出錯則返回-1

使用這兩個函數時,應當理解輸入、輸出波特率是存在串口設備termios結構中的。在調用任一cfset函數之前,先要用tcgetattr獲得設備的termios結構。與此類似,在調用任一cfset函數后,波特率都被設置到termios結構中。為使這種更改影響到設備,應當調用tcsetattr函數。操作方法如程序清單13.12所示。

程序清單13.12設置波特率示例

if (tcgetattr(fd, &opt)< 0) {

return ERROR;

}

cfsetispeed(&opt, B9600);

cfsetospeed(&opt, B9600);

if (tcsetattr(fd,   TCSANOW,   &opt)<0) {

return   ERROR;

}

(2)設置數據位

設置數據位不需要專用的函數,只需要在設置數據位之前用數據位屏蔽標志(CSIZE)把對應數據位清零,然后再設置新的數據位即可,如下所示:

options.c_cflag &= ~CSIZE;/* 先把數據位清零*/

options.c_cflag |= CS8;/* 把數據位設置為8*/

3)設置奇偶校驗

正如設置數據位一樣,設置奇偶校驗是在直接在cflag成員上設置。下面是各種類型的校驗設置方法。

 

1)無奇偶校驗(8N1):

options.c_cflag &= ~PARENB;

options.c_cflag &= ~CSTOPB;

options.c_cflag &= ~CSIZE;

options.c_cflag |= CS8;

27位數據位奇偶校驗(7E1):

options.c_cflag |= PARENB;

options.c_cflag &= ~PARODD;

options.c_cflag &= ~CSTOPB;

options.c_cflag &= ~CSIZE;

options.c_cflag |= CS7;

3)奇校驗(7O1):

options.c_cflag|= PARENB;

options.c_cflag |= PARODD;

options.c_cflag &= ~CSTOPB;

options.c_cflag &= ~CSIZE;

options.c_cflag |= CS7;

 

串口設置示例:

static int UART2_Init(void)

{

    struct termios opt; //屬性描述

    fdUart2 = open(DEV_UART2, O_RDWR | O_NOCTTY);            

    if(fdUart2 < 0)

    {

        perror(DEV_UART2);

        return -1;

    }

    tcgetattr(fdUart2, &opt);     //獲取串口屬性結構體對象

    cfsetispeed(&opt, B38400);     //設置輸入波特率

    cfsetospeed(&opt, B38400);     //設置輸出波特率

 

    /* raw mode */   //偶校驗

    opt.c_lflag   &=   ~(ECHO | ICANON | IEXTEN |ISIG); //設置本地標志:不進行回送,關閉規范輸入,關閉擴充輸入字符處理,關閉終端產生的信號

    opt.c_iflag   &=  ~(IXON | ISTRIP);       // 關閉輸出流控制, 不剝除第8

    opt.c_iflag   |= (ICRNL | BRKINT | INPCK);// 將輸入的CR轉換為NL,使得輸入和輸出隊列被刷新,打開奇偶校驗

    opt.c_oflag   &=   ~(OPOST);              // 設置輸出標志:不執行輸出處理

    opt.c_cflag   &=   ~(PARODD | CSIZE);     // 關閉輸入輸出是奇校驗,使用屏蔽位

    opt.c_cflag   |=   (CS8 | CLOCAL | CREAD | PARENB);//8位數據位,保證程序不會占用串口,能夠從串口讀取輸入數據,允許輸出產生奇偶信息以及輸入的奇偶校驗

    /*'DATA_LEN' bytes can be read by serial*/

 

    opt.c_cc[VMIN]   =   DATA_LEN;   //讀取字符的最少個數                                  

    opt.c_cc[VTIME]  =   1;        //讀取一個字符等待1*1/10s

   

    tcflush(fdUart2,TCIOFLUSH);  //清空所有正在發生的IO數據

   

    if (tcsetattr(fdUart2, TCSANOW, &opt) < 0) //激活配置(將修改后的termios數據設置到串口)

    {

        return   -1;

    }

    return fdUart2;

}

轉自:https://blog.csdn.net/qq_39101111/article/details/78975688


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM