Explanation of Serial Communication under Linux (Part I) Explanation of Opening Serial Port and Initialization of Serial Port

Keywords: Linux

Linux Lower serial communication mainly includes the following steps

Flow chart of serial communication

I will introduce these steps one by one.

1. Open the serial port

Code (serial port is ttyUSB0)

  1. //Open Serial Port  
  2. int open_port(void)  
  3. {  
  4.     int fd;  
  5.           
  6.     fd=open("/dev/ttyUSB0",O_RDWR | O_NOCTTY | O_NONBLOCK);//O_NONBLOCK is set to non-blocking mode and will not block when read. Read will be placed in the while loop when read. The next section will explain blocking and non-blocking in detail.  
  7. //  printf("fd=%d\n",fd);  
  8.       
  9.     if(fd==-1)  
  10.     {  
  11.         perror("Can't Open SerialPort");  
  12.     }  
  13.       
  14.     return fd;  
  15. }  
When opening the serial port, you can add more content, such as judging whether the serial port is blocked, testing whether it is a terminal device, etc. These are necessary. Therefore, more complete and robust code flow is shown below than the basic code of opening the serial port above.


Open a more complete flow chart of serial port

Code:

  1. /** 
  2.  * open port 
  3.  * @param  fd 
  4.  * @param  comport Serial slogans you want to open 
  5.  * @return  Return - 1 failed to open 
  6.  */  
  7. int open_port(int fd,int comport)   
  8. {   
  9.     char *dev[]={"/dev/ttyUSB0","/dev/ttyS1","/dev/ttyS2"};  
  10.   
  11.     if (comport==1)//Serial port 1  
  12.     {  
  13.         fd = open( "/dev/ttyUSB0", O_RDWR|O_NOCTTY|O_NDELAY);   
  14.         if (-1 == fd)  
  15.         {   
  16.             perror("Can't Open Serial Port");   
  17.             return(-1);   
  18.         }   
  19.      }   
  20.      else if(comport==2)//Serial port 2  
  21.      {       
  22.         fd = open( "/dev/ttyS1", O_RDWR|O_NOCTTY|O_NDELAY); //No < span style="font-family: Arial, Helvetica, sans-serif;" > O_NONBLOCK non-blocking mode or non-blocking mode can be set. The two modes are specified in the next blog.</span>  
  23.   
  24.         if (-1 == fd)  
  25.         {   
  26.             perror("Can't Open Serial Port");   
  27.             return(-1);   
  28.         }   
  29.      }   
  30.      else if (comport==3)//Serial Port 3  
  31.      {   
  32.         fd = open( "/dev/ttyS2", O_RDWR|O_NOCTTY|O_NDELAY);   
  33.         if (-1 == fd)  
  34.         {   
  35.             perror("Can't Open Serial Port");   
  36.             return(-1);   
  37.         }   
  38.      }   
  39.      /*Restoring Serial Port to Blocking State*/   
  40.      if(fcntl(fd, F_SETFL, 0)<0)   
  41.             printf("fcntl failed!\n");   
  42.      else   
  43.         printf("fcntl=%d\n",fcntl(fd, F_SETFL,0));   
  44.      /*Test whether it is a terminal device*/   
  45.      if(isatty(STDIN_FILENO)==0)   
  46.         printf("standard input is not a terminal device\n");   
  47.      else   
  48.         printf("isatty success!\n");   
  49.      printf("fd-open=%d\n",fd);   
  50.      return fd;   
  51. }  

Key Function Interpretation:

open

Function Description: For opening or creating a file, the file descriptor is returned if successful, otherwise - 1 is returned. The file descriptor returned by open must be the smallest unused descriptor.

  1. #include<fcntl.h>  
  2. int open(const char *pathname, int oflag, ... );  
Parametric interpretation:

pathname: file path name, serial port in linux It's seen as a document.

oflag: Some file mode choices can be set with the following parameters

  • O_RDONLY Read-Only Mode
  • O_WRONLY Write-Only Mode
  • O_RDWR Read-Write Mode
The above three parameters must be selected when setting!!! The following is optional

  • O_APPEND Writes to the end of the file each time it writes
  • O_CREAT Creates the specified file if it does not exist
  • O_EXCL returns - 1 if the file to be created already exists, and modifies the value of errno
  • O_TRUNC empties the entire contents of a file if it exists and opens in write-only/read-write mode
  • O_NOCTTY If the path name points to the terminal device, do not use the device as a control terminal.
  • O_NONBLOCK If the path name points to FIFO/block file/character file, set the opening and subsequent I/O of the file to non-blocking mode. mode)

The following three constants are also selected for synchronous input and output

  • O_DSYNC waits for physical I/O to finish before writing. Without affecting the reading of newly written data, it does not wait for the update of file attributes.
  • O_RSYNC Read waits for all writes written to the same area to complete before proceeding
  • O_SYNC waits for physical I/O to finish before writing, including updating I/O of file attributes
For the opening operation of serial port, O_NOCTTY parameter must be used, which means that a terminal device is opened, and the program will not become the control terminal of the port. If this flag is not used, an input to a task (such as a keyboard termination signal, etc.) will affect the process.

O_NDELAY indicates that it does not care about the state of the DCD signal (whether the other end of the port is activated or stopped).

fcntl

Function Description: According to the characteristics of the file descriptor to operate the file, return - 1 represents an error.

  1. #include<unistd.h>  
  2. #include<fcntl.h>  
  3. int fcntl(int fd,int cmd);  
  4. int fcntl(int fd,int cmd,long arg);  
  5. int fcntl(int fd,int cmd,struct flock *lock);  
Description of parameters:

  • fd: File Descriptor
  • cmd: Command parameters
The fcntl function has five functions:
1. Copy an existing descriptor (cmd=F_DUPFD).
2. Obtain/set file descriptor tags (cmd=F_GETFD or F_SETFD).
3. Obtain/set the file status tag (cmd=F_GETFL or F_SETFL).
4. Obtain/set asynchronous I/O ownership (cmd=F_GETOWN or F_SETOWN).
5. Get/set record locks (cmd = F_GETLK, F_SETLK or F_SETLKW).
See Specific Use http://www.cnblogs.com/lonelycatcher/archive/2011/12/22/2297349.html
isatty
Function function, implementation only uses a terminal-specific function tcgetattr (if the success star, it does not change anything), and take its return value. If 1 is returned for the terminal device, otherwise 0 is returned. For details see http://blog.csdn.net/wangjingyu00711/article/details/41693155

2. Initialization of Serial Port

Serial port initialization needs to do the following work:
  1. set baud rate
  2. Setting up data flow control
  3. Set the format of the frame (i.e. number of data bits, stop bits, check bits)
Serial port initialization
Code:
  1. int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)   
  2. {   
  3.      struct termios newtio,oldtio;   
  4. /*Save and test the existing serial port parameter settings, where there will be relevant error information if the serial number and other errors occur.*/   
  5.      if  ( tcgetattr( fd,&oldtio)  !=  0) {    
  6.       perror("SetupSerial 1");  
  7.     printf("tcgetattr( fd,&oldtio) -> %d\n",tcgetattr( fd,&oldtio));   
  8.       return -1;   
  9.      }   
  10.      bzero( &newtio, sizeof( newtio ) );   
  11. /*Step 1: Set the character size*/   
  12.      newtio.c_cflag  |=  CLOCAL | CREAD;    
  13.      newtio.c_cflag &= ~CSIZE;    
  14. /*Setting stop bit*/   
  15.      switch( nBits )   
  16.      {   
  17.      case 7:   
  18.       newtio.c_cflag |= CS7;   
  19.       break;   
  20.      case 8:   
  21.       newtio.c_cflag |= CS8;   
  22.       break;   
  23.      }   
  24. /*Setting parity bits*/   
  25.      switch( nEvent )   
  26.      {   
  27.      case 'o':  
  28.      case 'O'//Odd number  
  29.       newtio.c_cflag |= PARENB;   
  30.       newtio.c_cflag |= PARODD;   
  31.       newtio.c_iflag |= (INPCK | ISTRIP);   
  32.       break;   
  33.      case 'e':  
  34.      case 'E'//Even number  
  35.       newtio.c_iflag |= (INPCK | ISTRIP);   
  36.       newtio.c_cflag |= PARENB;   
  37.       newtio.c_cflag &= ~PARODD;   
  38.       break;  
  39.      case 'n':  
  40.      case 'N':  //No parity check bits  
  41.       newtio.c_cflag &= ~PARENB;   
  42.       break;  
  43.      default:  
  44.       break;  
  45.      }   
  46.      /*set baud rate*/   
  47. switch( nSpeed )   
  48.      {   
  49.      case 2400:   
  50.       cfsetispeed(&newtio, B2400);   
  51.       cfsetospeed(&newtio, B2400);   
  52.       break;   
  53.      case 4800:   
  54.       cfsetispeed(&newtio, B4800);   
  55.       cfsetospeed(&newtio, B4800);   
  56.       break;   
  57.      case 9600:   
  58.       cfsetispeed(&newtio, B9600);   
  59.       cfsetospeed(&newtio, B9600);   
  60.       break;   
  61.      case 115200:   
  62.       cfsetispeed(&newtio, B115200);   
  63.       cfsetospeed(&newtio, B115200);   
  64.       break;   
  65.      case 460800:   
  66.       cfsetispeed(&newtio, B460800);   
  67.       cfsetospeed(&newtio, B460800);   
  68.       break;   
  69.      default:   
  70.       cfsetispeed(&newtio, B9600);   
  71.       cfsetospeed(&newtio, B9600);   
  72.      break;   
  73.      }   
  74. /*Setting stop bit*/   
  75.      if( nStop == 1 )   
  76.       newtio.c_cflag &=  ~CSTOPB;   
  77.      else if ( nStop == 2 )   
  78.       newtio.c_cflag |=  CSTOPB;   
  79. /*Set waiting time and minimum receive character*/   
  80.      newtio.c_cc[VTIME]  = 0;   
  81.      newtio.c_cc[VMIN] = 0;   
  82. /*Handling Unreceived Characters*/   
  83.      tcflush(fd,TCIFLUSH);   
  84. /*Activate new configuration*/   
  85. if((tcsetattr(fd,TCSANOW,&newtio))!=0)   
  86.      {   
  87.       perror("com set error");   
  88.       return -1;   
  89.      }   
  90.      printf("set done!\n");   
  91.      return 0;   
  92. }   
Before explaining this piece of code, we need to study the data structure of termios. Typical definitions of the smallest termios structure are as follows:
  1. struct termios  
  2. {  
  3.            tcflag_t c_iflag;  
  4.            tcflag_t c_oflag;  
  5.            tcflag_t c_cflag;  
  6.            tcflag_t c_lflag;  
  7.            cc_t           c_cc[NCCS];  
  8. };  
The above five structural member names represent:
  • c_iflag: Input mode
  • c_oflag: Output mode
  • c_cflag: Control mode
  • c_lflag: Local mode
  • c_cc[NCCS]: Special Control Mode
See blog for parameters of five modes http://blog.csdn.net/querdaizhi/article/details/7436722
Tcgetattr can initialize a termios structure corresponding to a terminal. The prototype of tcgetattr function is as follows:
  1. #include<termios.h>    
  2. int tcgetattr(int fd, struct termios *termios_p);   
This function call writes the value of the low-cost front-end interface variable to the structure pointed by the termios_p parameter. If these values are later modified, they can be reconfigured by calling the function tcsetattr.
The prototype of tcsetattr function is as follows:
  1. #include<termios.h>    
  2. int tcsetattr(int fd , int actions , const struct termios *termios_h);    
There are three ways to modify the parameters actions, which are as follows:
  1. TCSANOW: Modify the value immediately
  2. TCSADRAIN: Modify the value after the current output is complete
  3. TCSAFLUSH: After the current output is complete, the value is modified, but any currently available input that has not been returned from the read call is discarded.
In our code, we set it to NOW to modify the value immediately.
The function prototype of tcflush is as follows:
  1. int tcflush(int fd, int queue_selector);  
When queue_selector controls the operation of tcflush, the value can be one of the following parameters: TCIFLUSH clearly receives the data and does not read it out; TCOFLUSH clearly writes the data and does not send it to the terminal; TCIOFLUSH clears all I/O data being sent.
Looking at our code, we modify the character size code to
  1. newtio.c_cflag  |=  CLOCAL | CREAD;    
  2. newtio.c_cflag &= ~CSIZE;    
c_cflag represents control mode
  • CLOCAL means ignoring the status lines of all modems. This is to ensure that the program does not occupy the serial port.
  • CREAD stands for enabling character receivers to read and read input data from serial ports.
  • CS5/6/7/8 denotes the use of 5/6/7/8 bits for sending or receiving characters.
  • CSTOPB means that each character uses two stop bits.
  • HUPCL means to suspend the modem when it is turned off.
  • PARENB: Enables parity code generation and detection.
  • PARODD: Use odd checks instead of even checks.
c_iflag stands for input mode

  • BRKINT: An interrupt occurs when a termination state is detected in the input line.
  • TGNBRK: Ignores the termination state in the input line.
  • TCRNL: Converts the accepted carriage return character to a new line character.
  • TGNCR: Ignore new lines accepted.
  • INLCR: Converts the new line character received to a carriage return character.
  • IGNPAR: Characters that ignore parity checking errors.
  • INPCK: Perform parity checks on received characters.
  • PARMRK: Mark parity checking errors.
  • ISTRIP: Reduce all received characters to 7 bits.
  • IXOFF: Enable software flow control for input.
  • IXON: Enable software flow control for output.
c_cc Special Control Character

In standard mode and non-standard mode, the subscripts of c_cc arrays have different values:

Standard mode:

  • VEOF:EOF character
  • VEOL:EOF Character
  • VERASE:ERASE character
  • VINTR:INTR character
  • VKILL:KILL character
  • VQUIT:QUIT character
  • VSTART:START character
  • VSTOP:STOP character

Non-standard mode:

  • VINTR:INTR character
  • VMIN:MIN value
  • VQUIT:QUIT character
  • VSUSP:SUSP character
  • VTIME:TIME value
  • VSTART:START character
  • VSTOP:STOP character

cfsetispeed and cfsetospeed are used to set the baud rate of input and output. The function model is as follows:

  1. int cfsetispeed(struct termios *termptr, speed_t speed);  
  2. int cfsetospeed(struct termios *termptr, speed_t speed);  
Description of parameters:

  • struct termios *termptr: pointer to termios structure
  • speed_t speed: baud rate to be set
  • Return value: Return 0 successfully or - 1 otherwise

In this way, all the initialization operations are completed.

Posted by frijole on Fri, 21 Jun 2019 14:32:16 -0700