Linux下的串口編程(二)

Linxu下的串口編程(二)linux

 

---------------------------------------------------------ios

Author             :tiger-john
WebSite            :blog.csdn.net/tigerjb
編程

Email               jibo.tiger@gmail.com函數

Update-Time   : 2011214日星期一測試

 

Tiger聲明:本人鄙視直接複製本人文章而不加出處的我的或團體,spa

但不排斥別人轉載tiger-john的文章,只是請您註明出處並和本人.net

聯繫或留言給我3Q指針

---------------------------------------------------------orm

 

 

前面已經提到過Linux下皆爲文件,這固然也包括咱們今天的主角àUART0串口。所以對他的一切操做都和文件的操做同樣(涉及到了open,read,write,close等文件的基本操做)。對象

一.Linux下的串口編程又那幾部分組成

 

 

1.    打開串口

2.    串口初始化

3.    讀串口或寫串口

4.    關閉串口

二.串口的打開

既然串口在linux中被看做了文件,那麼在對文件進行操做前先要對其進行打開操做

1.Linxu中,串口設備是經過串口終端設備文件來訪問的,即經過訪問/dev/ttyS0,/dev/ttyS1,/dev/ttyS2這些設備文件實現對串口的訪問。

2.調用open()函數來代開串口設備,對於串口的打開操做,必須使用O_NOCTTY參數。

l  O_NOCTTY:表示打開的是一個終端設備,程序不會成爲該端口的控制終端。若是不使用此標誌,任務一個輸入(eg:鍵盤停止信號等)都將影響進程。

l  O_NDELAY:表示不關心DCD信號線所處的狀態(端口的另外一端是否激活或者中止)。

3.打開串口模塊有那及部分組成

1>調用open()函數打開串口,獲取串口設備文件描述符

2>獲取串口狀態,判斷是否阻塞

3>測試打開的文件描述符是否爲終端設備

 

 

 

 

 

 

4程序:

/*****************************************************************

* 名稱:                    UART0_Open

* 功能:                    打開串口並返回串口設備文件描述

* 入口參數:            fd    :文件描述符     port :串口號(ttyS0,ttyS1,ttyS2)

* 出口參數:            正確返回爲1,錯誤返回爲

*****************************************************************/

int UART0_Open(int fd,char* port)

{

 

      fd = open( port, O_RDWR|O_NOCTTY|O_NDELAY);

      if (FALSE == fd)

             {

                    perror("Can''t Open Serial Port");

                    return(FASLE);

             }

  //判斷串口的狀態是否爲阻塞狀態                            

  if(fcntl(fd, F_SETFL, 0) < 0)

      {

             printf("fcntl failed!/n");

           return(FALSE);

      }     

  else

  {

       printf("fcntl=%d/n",fcntl(fd, F_SETFL,0));

  }

  //測試是否爲終端設備    

  if(0 == isatty(STDIN_FILENO))

      {

             printf("standard input is not a terminal device/n");

        return(FALSE);

      }

  else

      {

           printf("isatty success!/n");

      }       

  printf("fd->open=%d/n",fd);

  return fd;

}

 

 

 

三.串口的初始化

 

1.    linux中的串口初始化和前面的串口初始化同樣。須要設置串口波特率,數據流控制,幀的格式(即數據位個數,中止位,校驗位,數據流控制)

2.    串口初始化模塊有那幾部分組成:

1>.設置波特率

2>設置數據流控制

2>設置幀的格式(即數據位個數,中止位,校驗位)

John哥說明:

1>設置串口參數時要用到termios結構體,所以先要經過函數

tcgettattr(fd,&options)得到串口指向termios結構的指針。

2>經過cfsetispeed函數和cfsetospeed函數用來設置串口的輸入/輸出波特率。通常狀況下,輸入和輸出波特率相等的。

3>設置數據位能夠經過修改termios機構體中c_flag來實現。其中CS5,CS6,CS7,CS8對應數據位的5678。在設置數據位時,必需要用CSIZE作位屏蔽。

4>數據流控制是使用何種方法來標誌數據傳輸的開始和結束。

5>在設置完波特率,數據流控制,數據位,校驗位,中止位,中止位後,還要設置最小等待時間和最小接收字符。

6>在完成配置後要經過tcsetattr()函數來激活配置。

3.程序:

 

/*******************************************************************

* 名稱:                UART0_Set

* 功能:                設置串口數據位,中止位和效驗位

* 入口參數:        fd         串口文件描述符

*                              speed      串口速度

*                              flow_ctrl  數據流控制

*                           databits   數據位   取值爲 7 或者8

*                           stopbits   中止位   取值爲 1 或者2

*                           parity     效驗類型 取值爲N,E,O,,S

*出口參數:              正確返回爲1,錯誤返回爲

*******************************************************************/

int UART0_Set(int fd,int speed,int flow_ctrl,int databits,int stopbits,int parity)

{

   

      int   i;

         int   status;

         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 };

         

    struct termios options;

   

    /*tcgetattr(fd,&options)獲得與fd指向對象的相關參數,並將它們保存於options,該函數,還能夠測試配置是否正確,該串口是否可用等。若調用成功,函數返回值爲,若調用失敗,函數返回值爲1.

    */

    if  ( tcgetattr( fd,&options)  !=  0)

       {

          perror("SetupSerial 1");    

          return(FALSE); 

       }

  

    //設置串口輸入波特率和輸出波特率

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

                {

              if  (speed == name_arr[i])

              {       

                          cfsetispeed(&Options, speed_arr[i]); 

                          cfsetospeed(&Options, speed_arr[i]);  

              }

       }     

   

    //修改控制模式,保證程序不會佔用串口

    options.c_cflag |= CLOCAL;

    //修改控制模式,使得可以從串口中讀取輸入數據

    options.c_cflag |= CREAD;

  

    //設置數據流控制

    switch(flow_ctrl)

    {

      

       case 0 ://不使用流控制

              options.c_cflag &= ~CRTSCTS;

              break;   

      

       case 1 ://使用硬件流控制

              options.c_cflag |= CRTSCTS;

              break;

       case 2 ://使用軟件流控制

              options.c_cflag |= IXON | IXOFF | IXANY;

              break;

    }

    //設置數據位

    options.c_cflag &= ~CSIZE; //屏蔽其餘標誌位

    switch (databits)

    {  

       case 5    :

                     options.c_cflag |= CS5;

                     break;

       case 6    :

                     options.c_cflag |= CS6;

                     break;

       case 7    :    

                 options.c_cflag |= CS7;

                 break;

       case 8:    

                 options.c_cflag |= CS8;

                 break;  

       default:   

                 fprintf(stderr,"Unsupported data size/n");

                 return (FALSE); 

    }

    //設置校驗位

    switch (parity)

    {  

       case ''n'':

       case ''N'': //無奇偶校驗位。

                 options.c_cflag &= ~PARENB; 

                 options.c_iflag &= ~INPCK;    

                 break; 

       case ''o'':  

       case ''O''://設置爲奇校驗    

                 options.c_cflag |= (PARODD | PARENB); 

                 options.c_iflag |= INPCK;             

                 break; 

       case ''e'': 

       case ''E''://設置爲偶校驗  

                 options.c_cflag |= PARENB;       

                 options.c_cflag &= ~PARODD;       

                 options.c_iflag |= INPCK;       

                 break;

       case ''s'':

       case ''S'': //設置爲空格 

                 options.c_cflag &= ~PARENB;

                 options.c_cflag &= ~CSTOPB;

                 break; 

        default:  

                 fprintf(stderr,"Unsupported parity/n");   

                 return (FALSE); 

    } 

    // 設置中止位 

    switch (stopbits)

    {  

       case 1:   

                 options.c_cflag &= ~CSTOPB; 

                 break; 

       case 2:   

                 options.c_cflag |= CSTOPB; 

                         break;

       default:   

                       fprintf(stderr,"Unsupported stop bits/n"); 

                       return (FALSE);

    }

   

    //修改輸出模式,原始數據輸出

    options.c_oflag &= ~OPOST;

   

    //設置等待時間和最小接收字符

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

    options.c_cc[VMIN] = 1; /* 讀取字符的最少個數爲1 */

   

    //若是發生數據溢出,接收數據,可是再也不讀取

    tcflush(fd,TCIFLUSH);

   

    //激活配置 (將修改後的termios數據設置到串口中)

    if (tcsetattr(fd,TCSANOW,&options) != 0)  

    {

               perror("com set error!/n");  

       return (FALSE); 

    }

    return (TRUE); 

}

/*******************************************************************

* 名稱:                  UART0_Init()

* 功能:                串口初始化

* 入口參數:        fd           文件描述符   

*               speed     串口速度

*                              flow_ctrl   數據流控制

*               databits    數據位   取值爲 7 或者8

*                           stopbits   中止位   取值爲 1 或者2

*                           parity     效驗類型 取值爲N,E,O,,S                    

* 出口參數:        正確返回爲1,錯誤返回爲

*******************************************************************/

int UART0_Init(int fd, int speed,int flow_ctrlint databits,int stopbits,int parity)

{

    int err;

    //設置串口數據幀格式

    if (UART0_Set(fd,115200,0,8,1,''N'') == FALSE)

    {                                                     

        return FALSE;

    }

    else

    {

               return  TRUE;

        }

}

 

 

 

 

注:

若是不是開發終端之類的,只是串口傳輸數據,而不須要串口來處理,那麼使用原始模式(Raw Mode)方式來通信,設置方式以下:

 

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

options.c_oflag  &= ~OPOST;   /*Output*/

 

 

 

四.    串口的讀寫函數:

1.     讀寫串口是經過使用read函數和write函數來實現的。

2.     程序

 

/*******************************************************************

* 名稱:                  UART0_Recv

* 功能:                接收串口數據

* 入口參數:        fd                  :文件描述符    

*                              rcv_buf     :接收串口中數據存入rcv_buf緩衝區中

*                              data_len    :一幀數據的長度

* 出口參數:        正確返回爲1,錯誤返回爲

*******************************************************************/

int UART0_Recv(int fd, char *rcv_buf,int data_len)

{

    int len,fs_sel;

    fd_set fs_read;

   

    struct timeval time;

   

    FD_ZERO(&fs_read);

    FD_SET(fd,&fs_read);

   

    time.tv_sec = 10;

    time.tv_usec = 0;

   

    //使用select實現串口的多路通訊

    fs_sel = select(fd+1,&fs_read,NULL,NULL,&time);

    if(fs_sel)

       {

              len = read(fd,data,data_len);

              return len;

       }

    else

       {

              return FALSE;

       }     

}

/*******************************************************************

* 名稱:                UART0_Send

* 功能:                發送數據

* 入口參數:        fd                  :文件描述符    

*                              send_buf    :存放串口發送數據

*                              data_len    :一幀數據的個數

* 出口參數:        正確返回爲1,錯誤返回爲

*******************************************************************/

int UART0_Send(int fd, char *send_buf,int data_len)

{

    int len = 0;

   

    len = write(fd,send_buf,data_len);

    if (len == data_len )

       {

              return len;

       }     

    else   

        {

               

                tcflush(fd,TCOFLUSH);

                return FALSE;

        }

    }

 

五.    關閉串口

在完成對串口設備的操做後,要調用close函數關閉該文件描述符。

程序:

 

/******************************************************

* 名稱:                UART0_Close

* 功能:                關閉串口並返回串口設備文件描述

* 入口參數:        fd    :文件描述符   

* 出口參數:        void

*******************************************************************/

 

void UART0_Close(int fd)

{

    close(fd);

}

一.    一個完整程序

/************************Copyright(c)*******************************

**                       西安郵電學院

**                       graduate school

**                                     XNMS項目組

**                       WebSite :blog.csdn.net/tigerjb

**------------------------------------------FileInfo-------------------------------------------------------

** File name:                 main.c

** Last modified Date:  2011-01-31

** Last Version:              1.0

** Descriptions:            

**------------------------------------------------------------------------------------------------------

** Created by:               冀博

** Created date:            2011-01-31

** Version:                            1.0

** Descriptions:             The original version

**------------------------------------------------------------------------------------------------------

** Modified by:

** Modified date:

** Version:

** Descriptions:

*******************************************************************/

 

 

//串口相關的頭文件

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

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

#include<unistd.h>     /*Unix 標準函數定義*/

#include<sys/types.h> 

#include<sys/stat.h>   

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

#include<termios.h>    /*PPSIX 終端控制定義*/

#include<errno.h>      /*錯誤號定義*/

#include<string.h>

 

 

//宏定義

#define FALSE  -1

#define TRUE  

 

struct termios

{  

    unsigned short  c_iflag;           //輸入模式標誌   

    unsigned short  c_oflag;        //輸出模式標誌    

    unsigned short  c_cflag;        //控制模式標誌

    unsigned short  c_lflag;        //本地模式標誌

    unsigned char   c_line;        //line discipline   

    unsigned char   c_cc[NCC];     // control characters

};

 

/*******************************************************************

* 名稱:                  UART0_Open

* 功能:                打開串口並返回串口設備文件描述

* 入口參數:        fd    :文件描述符     port :串口號(ttyS0,ttyS1,ttyS2)

* 出口參數:        正確返回爲1,錯誤返回爲

*******************************************************************/

int UART0_Open(int fd,char* port)

{

   

         fd = open( port, O_RDWR|O_NOCTTY|O_NDELAY);

         if (FALSE == fd)

                {

                       perror("Can''t Open Serial Port");

                       return(FASLE);

                }

     //判斷串口的狀態是否爲阻塞狀態                                

     if(fcntl(fd, F_SETFL, 0) < 0)

                {

                       printf("fcntl failed!/n");

                     return(FALSE);

                }     

         else

                {

                  printf("fcntl=%d/n",fcntl(fd, F_SETFL,0));

                }

      //測試是否爲終端設備    

      if(0 == isatty(STDIN_FILENO))

                {

                       printf("standard input is not a terminal device/n");

                  return(FALSE);

                }

  else

                {

                     printf("isatty success!/n");

                }              

  printf("fd->open=%d/n",fd);

  return fd;

}

/*******************************************************************

* 名稱:                UART0_Close

* 功能:                關閉串口並返回串口設備文件描述

* 入口參數:        fd    :文件描述符     port :串口號(ttyS0,ttyS1,ttyS2)

* 出口參數:        void

*******************************************************************/

 

void UART0_Close(int fd)

{

    close(fd);

}

 

/*******************************************************************

* 名稱:                UART0_Set

* 功能:                設置串口數據位,中止位和效驗位

* 入口參數:        fd        串口文件描述符

*                              speed     串口速度

*                              flow_ctrl   數據流控制

*                           databits   數據位   取值爲 7 或者8

*                           stopbits   中止位   取值爲 1 或者2

*                           parity     效驗類型 取值爲N,E,O,,S

*出口參數:          正確返回爲1,錯誤返回爲

*******************************************************************/

int UART0_Set(int fd,int speed,int flow_ctrl,int databits,int stopbits,int parity)

{

   

      int   i;

         int   status;

         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, };

         

    struct termios options;

   

    /*tcgetattr(fd,&options)獲得與fd指向對象的相關參數,並將它們保存於options,該函數還能夠測試配置是否正確,該串口是否可用等。若調用成功,函數返回值爲,若調用失敗,函數返回值爲1.

    */

    if  ( tcgetattr( fd,&options)  !=  0)

       {

          perror("SetupSerial 1");    

          return(FALSE); 

       }

  

    //設置串口輸入波特率和輸出波特率

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

                {

                     if  (speed == name_arr[i])

                            {             

                                 cfsetispeed(&Options, speed_arr[i]); 

                                 cfsetospeed(&Options, speed_arr[i]);  

                            }

              }     

   

    //修改控制模式,保證程序不會佔用串口

    options.c_cflag |= CLOCAL;

    //修改控制模式,使得可以從串口中讀取輸入數據

    options.c_cflag |= CREAD;

  

    //設置數據流控制

    switch(flow_ctrl)

    {

      

       case 0 ://不使用流控制

              options.c_cflag &= ~CRTSCTS;

              break;   

      

       case 1 ://使用硬件流控制

              options.c_cflag |= CRTSCTS;

              break;

       case 2 ://使用軟件流控制

              options.c_cflag |= IXON | IXOFF | IXANY;

              break;

    }

    //設置數據位

    //屏蔽其餘標誌位

    options.c_cflag &= ~CSIZE;

    switch (databits)

    {  

       case 5    :

                     options.c_cflag |= CS5;

                     break;

       case 6    :

                     options.c_cflag |= CS6;

                     break;

       case 7    :    

                 options.c_cflag |= CS7;

                 break;

       case 8:    

                 options.c_cflag |= CS8;

                 break;  

       default:   

                 fprintf(stderr,"Unsupported data size/n");

                 return (FALSE); 

    }

    //設置校驗位

    switch (parity)

    {  

       case ''n'':

       case ''N'': //無奇偶校驗位。

                 options.c_cflag &= ~PARENB; 

                 options.c_iflag &= ~INPCK;    

                 break; 

       case ''o'':  

       case ''O''://設置爲奇校驗    

                 options.c_cflag |= (PARODD | PARENB); 

                 options.c_iflag |= INPCK;             

                 break; 

       case ''e'': 

       case ''E''://設置爲偶校驗  

                 options.c_cflag |= PARENB;       

                 options.c_cflag &= ~PARODD;       

                 options.c_iflag |= INPCK;      

                 break;

       case ''s'':

       case ''S'': //設置爲空格 

                 options.c_cflag &= ~PARENB;

                 options.c_cflag &= ~CSTOPB;

                 break; 

        default:  

                 fprintf(stderr,"Unsupported parity/n");    

                 return (FALSE); 

    } 

    // 設置中止位 

    switch (stopbits)

    {  

       case 1:   

                 options.c_cflag &= ~CSTOPB; 

                 break; 

       case 2:   

                 options.c_cflag |= CSTOPB; 

                         break;

       default:   

                       fprintf(stderr,"Unsupported stop bits/n"); 

                       return (FALSE);

    }

   

  //修改輸出模式,原始數據輸出

  options.c_oflag &= ~OPOST;

   

    //設置等待時間和最小接收字符

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

    options.c_cc[VMIN] = 1; /* 讀取字符的最少個數爲1 */

   

    //若是發生數據溢出,接收數據,可是再也不讀取

    tcflush(fd,TCIFLUSH);

   

    //激活配置 (將修改後的termios數據設置到串口中)

    if (tcsetattr(fd,TCSANOW,&options) != 0)  

           {

               perror("com set error!/n");  

              return (FALSE); 

           }

    return (TRUE); 

}

/*******************************************************************

* 名稱:                UART0_Init()

* 功能:                串口初始化

* 入口參數:        fd       :  文件描述符   

*               speed  :  串口速度

*                              flow_ctrl  數據流控制

*               databits   數據位   取值爲 7 或者8

*                           stopbits   中止位   取值爲 1 或者2

*                           parity     效驗類型 取值爲N,E,O,,S

*                      

* 出口參數:        正確返回爲1,錯誤返回爲

*******************************************************************/

int UART0_Init(int fd, int speed,int flow_ctrlint databits,int stopbits,int parity)

{

    int err;

    //設置串口數據幀格式

    if (UART0_Set(fd,115200,0,8,1,''N'') == FALSE)

       {                                                         

        return FALSE;

       }

    else

       {

               return  TRUE;

        }

}

 

/*******************************************************************

* 名稱:                  UART0_Recv

* 功能:                接收串口數據

* 入口參數:        fd                  :文件描述符    

*                              rcv_buf     :接收串口中數據存入rcv_buf緩衝區中

*                              data_len    :一幀數據的長度

* 出口參數:        正確返回爲1,錯誤返回爲

*******************************************************************/

int UART0_Recv(int fd, char *rcv_buf,int data_len)

{

    int len,fs_sel;

    fd_set fs_read;

   

    struct timeval time;

   

    FD_ZERO(&fs_read);

    FD_SET(fd,&fs_read);

   

    time.tv_sec = 10;

    time.tv_usec = 0;

   

    //使用select實現串口的多路通訊

    fs_sel = select(fd+1,&fs_read,NULL,NULL,&time);

    if(fs_sel)

       {

              len = read(fd,data,data_len);

              return len;

       }

    else

       {

              return FALSE;

       }     

}

/********************************************************************

名稱:                  UART0_Send

* 功能:                發送數據

* 入口參數:        fd                  :文件描述符    

*                              send_buf    :存放串口發送數據

*                              data_len    :一幀數據的個數

* 出口參數:        正確返回爲1,錯誤返回爲

*******************************************************************/

int UART0_Send(int fd, char *send_buf,int data_len)

{

    int len = 0;

   

    len = write(fd,send_buf,data_len);

    if (len == data_len )

              {

                     return len;

              }     

    else   

        {

               

                tcflush(fd,TCOFLUSH);

                return FALSE;

        }

   

}

 

 

int main(int argc, char **argv)

{

    int fd;                            //文件描述符

    int err;                           //返回調用函數的狀態

    int len;                        

    int i;

    char rcv_buf[100];       

    char send_buf[20]="tiger john";

    if(argc != 3)

       {

              printf("Usage: %s /dev/ttySn 0(send data)/1 (receive data) /n",argv[0]);

              return FALSE;

       }

    fd = UART0_Open(fd,argv[1]); //打開串口,返回文件描述符

    do{

                  err = UART0_Init(fd,115200,0,8,1,''N'');

                  printf("Set Port Error/n");

       }while(FASLE == err || FASLE == fd);

   

    if(0 == strcmp(argv[2],"0"))

           {

                  for(i = 0;i < 10;i++)

                         {

                                len = URAT0_Send(fd,send_buf,10);

                                if(len > 0)

                                       printf(" %d send data successful/n",i);

                                else

                                       printf("send data failed!/n");

                          

                                sleep(2);

                         }

                  UART0_Close(fd);             

           }

    else

           {

                                      

           while (1) //循環讀取數據

                  {  

                     len = read(fd, rcv_buf,9);

                     if(len > 0)

                            {

                                   printf("receive data is %s/n",recv_buf);

                            }

                     else

                            {

                                   printf("cannot receive data/n");

                            }

                     sleep(2);

              }            

       UART0_Close(fd); 

           }

}

  

/*********************************************************************                            End Of File                          **

*******************************************************************/

相關文章
相關標籤/搜索