Serial port programming for Linux applications

/Disclaimer: I only reprinted this article when I saw that it was very helpful to me, but there were grammatical errors in this complete program. Now let me correct it/

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

Email : jibo.tiger@gmail.com

Update time: Monday, February 14, 2011

Tiger statement: I despise individuals or groups that directly copy my articles without source,

However, we do not exclude others from reprinting tiger John's article, but please indicate the source and contact me

Contact or leave a message to me. 3Q

As mentioned earlier, all files under Linux are files, which of course also includes our protagonist today's long UART0 serial port. Therefore, all operations on him are the same as those on files (involving the basic operations of files such as open, read, write and close).

1, What are the components of serial port programming under Linux

  1. Open serial port

  2. Serial port initialization

  3. Read serial port or write serial port

  4. Close the serial port

2, Opening of serial port

Since the serial port is regarded as a file in linux, it is necessary to open the file before operating it.

1. In Linxu, the serial port device is accessed through the serial port terminal device files, that is, the serial port is accessed by accessing the device files / dev/ttyS0,/dev/ttyS1,/dev/ttyS2.

2. Call the open() function to open the serial port device instead. For the opening operation of the serial port, O must be used_ Noctty parameter.

l O_NOCTTY: indicates that a terminal device is opened, and the program will not become the control terminal of the port. If this flag is not used, one input of the task (eg: keyboard abort signal, etc.) will affect the process.

l O_NDELAY: indicates that you do not care about the state of the DCD signal line (whether the other end of the port is activated or stopped).

3. Open the serial port module and its components

1> Call the open() function to open the serial port and obtain the serial port device file descriptor

2> Get the serial port status and judge whether it is blocked

3> Test whether the open file descriptor is a terminal device

4 procedure:

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

  • Name: UART0_Open

  • Function: open the serial port and return the serial port device file description

  • Entry parameter: fd: file descriptor port: serial port number (ttyS0,ttyS1,ttyS2)

  • Exit parameters: the correct return is 1 and the error return is 0

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

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

         }

//Judge whether the status of the serial port is blocked

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

  {

         printf("fcntl failed!/n");

       return(FALSE);

  }     

else

{

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

}

//Test whether it is a terminal device

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;

}

3, Serial port initialization

  1. The serial port initialization in linux is the same as the previous serial port initialization. Serial port baud rate, data flow control and frame format (i.e. number of data bits, stop bit, check bit and data flow control) need to be set

  2. What are the components of the serial port initialization module:

1>. set baud rate

2> Set data flow control

2> Set the format of the frame (i.e. number of data bits, stop bits, check bits)

Description:

1> The termios structure is used when setting serial port parameters, so the function must be passed first

Tcgettattr (FD, & Options) obtains the pointer of the serial port to the termios structure.

2> The cfsetispeed function and cfsetospeed function are used to set the input / output baud rate of the serial port. Generally, the input and output baud rates are equal.

3> The data bit can be set by modifying C in termios mechanism_ Flag. CS5, CS6, CS7 and CS8 correspond to 5, 6, 7 and 8 of data bits. When setting data bits, CSIZE must be used as bit mask.

4> Data flow control is the method used to mark the beginning and end of data transmission.

5> After setting baud rate, data flow control, data bit, check bit, stop bit and stop bit, set the minimum waiting time and minimum received characters.

6> After completing the configuration, activate the configuration through the tcsetattr() function.

3. Procedure:

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

  • Name: UART0_Set

  • Function: set serial port data bit, stop bit and validity bit

  • Entry parameter: fd serial port file descriptor

  •                          speed      Serial port speed
    
  •                          flow_ctrl  Data flow control
    
  •                       databits   The data bit value is 7 or 8
    
  •                       stopbits   The stop bit value is 1 or 2
    
  •                       parity     The value of validation type is N,E,O,,S
    

*Exit parameters: the correct return is 1 and the error return is 0

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

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)Get the parameters related to the object pointed to by fd and save them in options. This function can also test whether the configuration is correct and whether the serial port is available. If the call succeeds, the return value of the function is 0. If the call fails, the return value of the function is 1

*/

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

   {

      perror("SetupSerial 1");    

      return(FALSE); 

   }



//Set the serial port input baud rate and output baud rate

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]);  

          }

   }     



//Modify the control mode to ensure that the program will not occupy the serial port

options.c_cflag |= CLOCAL;

//Modify the control mode so that the input data can be read from the serial port

options.c_cflag |= CREAD;



//Set data flow control

switch(flow_ctrl)

{

  

   case 0 ://Do not use flow control

          options.c_cflag &= ~CRTSCTS;

          break;   

  

   case 1 ://Using hardware flow control

          options.c_cflag |= CRTSCTS;

          break;

   case 2 ://Using software flow control

          options.c_cflag |= IXON | IXOFF | IXANY;

          break;

}

//set data bit

options.c_cflag &= ~CSIZE; //Shield other flag bits

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

}

//Set check bit

switch (parity)

{  

   case 'n':

   case 'N': //No parity bit.

             options.c_cflag &= ~PARENB; 

             options.c_iflag &= ~INPCK;    

             break; 

   case 'o':  

   case 'O'://Set to odd check    

             options.c_cflag |= (PARODD | PARENB); 

             options.c_iflag |= INPCK;             

             break; 

   case 'e': 

   case 'E'://Set to even check  

             options.c_cflag |= PARENB;       

             options.c_cflag &= ~PARODD;       

             options.c_iflag |= INPCK;       

             break;

   case 's':

   case 'S': //Set to space 

             options.c_cflag &= ~PARENB;

             options.c_cflag &= ~CSTOPB;

             break; 

    default:  

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

             return (FALSE); 

} 

// Set stop bit 

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

}



//Modify the output mode and output the original data

options.c_oflag &= ~OPOST;



//Set the waiting time and minimum received characters

options.c_cc[VTIME] = 1; /* Read a character and wait 1*(1/10)s */  

options.c_cc[VMIN] = 1; /* The minimum number of characters to read is 1 */



//If a data overflow occurs, the data is received but no longer read

tcflush(fd,TCIFLUSH);



//Activate the configuration (set the modified termios data to the serial port)

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

{

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

   return (FALSE); 

}

return (TRUE); 

}

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

  • Name: UART0_Init()

  • Function: serial port initialization

  • Entry parameter: fd file descriptor

  •           speed     Serial port speed
    
  •                          flow_ctrl   Data flow control
    
  •           databits    The data bit value is 7 or 8
    
  •                       stopbits   The stop bit value is 1 or 2
    
  •                       parity     The value of validation type is N,E,O,,S                    
    
  • Exit parameters: the correct return is 1 and the error return is 0

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

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

{

int err;

//Set serial port data frame format

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

{                                                     

    return FALSE;

}

else

{

           return  TRUE;

    }

}

Note:

If it is not the development terminal, but only the serial port transmits data without serial port processing, the raw mode is used for communication. The setting method is as follows:

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

options.c_oflag &= ~OPOST; /Output/

4, Read / write function of serial port:

  1. The read-write serial port is used read Function sum write Function.
    
  2. program
    

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

  • Name: UART0_Recv

  • Function: receive serial data

  • Entry parameter: fd: file descriptor

  •                          rcv_buf     :Data storage in receiving serial port rcv_buf In buffer
    
  •                          data_len    :Length of one frame of data
    
  • Exit parameters: the correct return is 1 and the error return is 0

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

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;



//Using select to realize multi-channel communication of serial port

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

if(fs_sel)

   {

          len = read(fd,data,data_len);

          return len;

   }

else

   {

          return FALSE;

   }     

}

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

  • Name: UART0_Send

  • Function: send data

  • Entry parameter: fd: file descriptor

  •                          send_buf    :Store data sent by serial port
    
  •                          data_len    :Number of data in one frame
    
  • Exit parameters: the correct return is 1 and the error return is 0

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

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;

    }

}

5, Close the serial port

After completing the operation on the serial port device, call the close function to close the file descriptor.

Procedure:

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

  • Name: UART0_Close

  • Function: close the serial port and return the serial port device file description

  • Entry parameter: fd: file descriptor

  • Exit parameter: void

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

void UART0_Close(int fd)

{

close(fd);

}

1, A complete program

/Copyright©*******
**Xi'an University of Posts and Telecommunications
** graduate school
**XNMS project team
** WebSite :blog.csdn.net/tigerjb
**------------------------------------------FileInfo-------------------------------------------------------
** File name: main.c
** Last modified Date: 2011-01-31
** Last Version: 1.0
** Descriptions:
**------------------------------------------------------------------------------------------------------
**Created by: Jibo
** Created date: 2011-01-31
** Version: 1.0
** Descriptions: The original version
**------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
** Version:
** Descriptions:
*******************************************************************/

//Serial port related header file
#include<stdio. h> / * standard I / O definitions*/
#include<stdlib. h> / * standard library definition*/
#include<unistd. h> / * UNIX standard function definition*/
#include<sys/types.h> 
#include<sys/stat.h>   
#include<fcntl. h> / * document control definition*/
#include<termios. h> / * ppsix terminal control definition*/
#include<errno. h> / * error number definition*/
#include<string.h>
 
 
//Macro definition
#define FALSE  -1
#define TRUE   0
 
/*******************************************************************
* Name: UART0_Open
* Function: open the serial port and return the serial port device file description
* Entry parameter: fd: file descriptor port: serial port number (ttyS0,ttyS1,ttyS2)
* Exit parameters: the correct return is 1 and the error return is 0
*******************************************************************/
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(FALSE);
                }
     //Restore the serial port to the blocking state                               
     if(fcntl(fd, F_SETFL, 0) < 0)
                {
                       printf("fcntl failed!\n");
                     return(FALSE);
                }     
         else
                {
                  printf("fcntl=%d\n",fcntl(fd, F_SETFL,0));
                }
      //Test whether it is a terminal device    
      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;
}
/*******************************************************************
* Name: UART0_Close
* Function: close the serial port and return the serial port device file description
* Entry parameter: fd: file descriptor port: serial port number (ttyS0,ttyS1,ttyS2)
* Exit parameter: void
*******************************************************************/
 
void UART0_Close(int fd)
{
    close(fd);
}
 
/*******************************************************************
* Name: UART0_Set
* Function: set serial port data bit, stop bit and validity bit
* Entry parameter: fd serial port file descriptor
*                              speed     Serial port speed
*                              flow_ctrl   Data flow control
*                           databits   The data bit value is 7 or 8
*                           stopbits   The stop bit value is 1 or 2
*                           parity     The value of validity type is n, e, O, S
*Exit parameters: the correct return is 1 and the error return is 0
*******************************************************************/
int UART0_Set(int fd,int speed,int flow_ctrl,int databits,int stopbits,int parity)
{
   
      int   i;
         int   status;
         int   speed_arr[] = { B115200, B19200, B9600, B4800, B2400, B1200, B300};
     int   name_arr[] = {115200,  19200,  9600,  4800,  2400,  1200,  300};
         
    struct termios options;
   
    /*tcgetattr(fd,&options)Get the parameters related to the object pointed to by fd and save them in options. This function can also test whether the configuration is correct, whether the serial port is available, etc. If the call succeeds, the return value of the function is 0. If the call fails, the return value of the function is 1
    */
    if  ( tcgetattr( fd,&options)  !=  0)
       {
          perror("SetupSerial 1");    
          return(FALSE); 
       }
  
    //Set the serial port input baud rate and output baud rate
    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]);  
                            }
              }     
   
    //Modify the control mode to ensure that the program will not occupy the serial port
    options.c_cflag |= CLOCAL;
    //Modify the control mode so that the input data can be read from the serial port
    options.c_cflag |= CREAD;
  
    //Set data flow control
    switch(flow_ctrl)
    {
      
       case 0 ://Do not use flow control
              options.c_cflag &= ~CRTSCTS;
              break;   
      
       case 1 ://Using hardware flow control
              options.c_cflag |= CRTSCTS;
              break;
       case 2 ://Using software flow control
              options.c_cflag |= IXON | IXOFF | IXANY;
              break;
    }
    //set data bit
    //Shield other flag bits
    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); 
    }
    //Set check bit
    switch (parity)
    {  
       case 'n':
       case 'N': //No parity bit.
                 options.c_cflag &= ~PARENB; 
                 options.c_iflag &= ~INPCK;    
                 break; 
       case 'o':  
       case 'O'://Set to odd check    
                 options.c_cflag |= (PARODD | PARENB); 
                 options.c_iflag |= INPCK;             
                 break; 
       case 'e': 
       case 'E'://Set to even check  
                 options.c_cflag |= PARENB;       
                 options.c_cflag &= ~PARODD;       
                 options.c_iflag |= INPCK;      
                 break;
       case 's':
       case 'S': //Set to space 
                 options.c_cflag &= ~PARENB;
                 options.c_cflag &= ~CSTOPB;
                 break; 
        default:  
                 fprintf(stderr,"Unsupported parity\n");    
                 return (FALSE); 
    } 
    // Set stop bit 
    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);
    }
   
  //Modify the output mode and output the original data
  options.c_oflag &= ~OPOST;
  
  options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);//I added it
//options.c_lflag &= ~(ISIG | ICANON);
   
    //Set the waiting time and minimum received characters
    options.c_cc[VTIME] = 1; /* Read a character and wait 1*(1/10)s */  
    options.c_cc[VMIN] = 1; /* The minimum number of characters to read is 1 */
   
    //If a data overflow occurs, the data is received but not read. The received data is refreshed but not read
    tcflush(fd,TCIFLUSH);
   
    //Activate the configuration (set the modified termios data to the serial port)
    if (tcsetattr(fd,TCSANOW,&options) != 0)  
           {
               perror("com set error!\n");  
              return (FALSE); 
           }
    return (TRUE); 
}
/*******************************************************************
* Name: UART0_Init()
* Function: serial port initialization
* Entry parameter: fd: file descriptor   
*               speed  :  Serial port speed
*                              flow_ctrl  Data flow control
*               databits   The data bit value is 7 or 8
*                           stopbits   The stop bit value is 1 or 2
*                           parity     The value of validity type is n, e, O, S
*                      
* Exit parameters: the correct return is 1 and the error return is 0
*******************************************************************/
int UART0_Init(int fd, int speed,int flow_ctrl,int databits,int stopbits,int parity)
{
    int err;
    //Set serial port data frame format
    if (UART0_Set(fd,19200,0,8,1,'N') == FALSE)
       {                                                         
        return FALSE;
       }
    else
       {
               return  TRUE;
        }
}
 
/*******************************************************************
* Name: UART0_Recv
* Function: receive serial data
* Entry parameter: fd: file descriptor    
*                              rcv_buf     :The data in the receiving serial port is stored in RCV_ In buf buffer
*                              data_len    :Length of one frame of data
* Exit parameters: the correct return is 1 and the error return is 0
*******************************************************************/
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;
   
    //Using select to realize multi-channel communication of serial port
    fs_sel = select(fd+1,&fs_read,NULL,NULL,&time);
    if(fs_sel)
       {
              len = read(fd,rcv_buf,data_len);
	      printf("I am right!(version1.2) len = %d fs_sel = %d\n",len,fs_sel);
              return len;
       }
    else
       {
	      printf("Sorry,I am wrong!");
              return FALSE;
       }     
}
/********************************************************************
* Name: UART0_Send
* Function: send data
* Entry parameter: fd: file descriptor    
*                              send_buf    :Store data sent by serial port
*                              data_len    :Number of data in one frame
* Exit parameters: the correct return is 1 and the error return is 0
*******************************************************************/
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;                            //File descriptor
    int err;                           //Returns the status of the calling function
    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]); //Open the serial port and return the file descriptor
    do{
                  err = UART0_Init(fd,19200,0,8,1,'N');
                  printf("Set Port Exactly!\n");
       }while(FALSE == err || FALSE == fd);
   
    if(0 == strcmp(argv[2],"0"))
           {
                  for(i = 0;i < 10;i++)
                         {
                                len = UART0_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) //Loop read data
                  {  
                     len = UART0_Recv(fd, rcv_buf,9);
                     if(len > 0)
                            {
			           rcv_buf[len] = '\0';
                                   printf("receive data is %s\n",rcv_buf);
			           printf("len = %d\n",len);
                            }
                     else
                            {
                                   printf("cannot receive data\n");
                            }
                     sleep(2);
              }            
       UART0_Close(fd); 
           }
}
  
/*********************************************************************                            End Of File                          **
*******************************************************************/

Keywords: Linux Operation & Maintenance Embedded system Single-Chip Microcomputer

Added by Pawn on Tue, 04 Jan 2022 08:50:40 +0200