Linux Serial Programming Tutorial (iii)--serial port programming detailed
Preface: This chapter will formally explain the serial port programming technology, uses a serial port to send and receive the data the procedure, comes step-by-step explanation.
Note: You can download my source code for reference. Open serial Port
As we all know, the device is in the form of a file in the Linux system, so we access the device in the manner of opening the file. It should be noted here that ordinary users generally can not access the device directly, need root permissions.
There are 3 ways to solve this problem: Run as root superuser. (commonly) Change the access rights of device files. Use setuid in the program to run the program as the serial device owner.
Code:
#include <stdio.h>
#include <fcntl.h>
#include <assert.h>
static int fd;
int uart_open (int fd,const char *pathname)
{
assert (pathname);
/* Open serial port *
/FD = open (pathname,o_rdwr| o_noctty| O_ndelay);
if (fd = = 1)
{
perror ("Open UART failed!");
return-1;
}
/* Clear serial port non-blocking sign/
if (Fcntl (fd,f_setfl,0) < 0)
{
fprintf (stderr, "Fcntl failed!\n");
return-1;
}
return FD;
}
Description: O_noctty: means that the device is open, the program will not become the control terminal of the port. If you do not use this flag, the CTRL + C stop signal over the keyboard will affect the process. O_ndelay: Indicates that you do not care about the state of the DCD signal line (whether the other end of the port is active or stopped). Close serial Port
Turning off the serial port operation is simple, but you need to be aware that you need to do some cleanup after the shutdown.
Code:
#include <unistd.h>
#include <assert.h>
static int fd;
int uart_close (int fd)
{
assert (FD);
Close (FD);
/* You can do some cleanup work here
/* return 0;
}
Configure serial Port
Serial port initialization needs to set serial port baud rate, data flow control, frame format (that is, the number of data bits, stop bit, check bit, Data flow control).
Code:
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <
assert.h> #include <termios.h> #include <string.h> static int ret;
static int fd;
int uart_set (int fd,int baude,int c_flow,int bits,char parity,int stop) {struct options;
/* Get Terminal properties */if (tcgetattr (fd,&options) < 0) {perror ("tcgetattr error");
return-1;
/* Set Input output baud rate, both remain consistent * * Switch (baude) {case 4800:cfsetispeed (&options,b4800);
Cfsetospeed (&options,b4800);
Break
Case 9600:cfsetispeed (&options,b9600);
Cfsetospeed (&options,b9600);
Break
Case 19200:cfsetispeed (&options,b19200);
Cfsetospeed (&options,b19200);
Break
Case 38400:cfsetispeed (&options,b38400);
Cfsetospeed (&options,b38400); Break;
default:fprintf (stderr, "Unkown baude!\n");
return-1;
/* Set control mode/* Options.c_cflag |= clocal;//Guarantee program does not occupy the serial port Options.c_cflag |= cread;//Guarantee Program can read data from the string/* Set Data flow control * *
Switch (c_flow) {case 0://does not flow control Options.c_cflag &= ~crtscts;
Break
Case 1://for hardware flow control options.c_cflag |= crtscts;
Break Case 2://for Software flow control Options.c_cflag |= ixon| Ixoff|
Ixany;
Break
default:fprintf (stderr, "Unkown c_flow!\n");
return-1; /* Set Data bit */switch (BITS) {case 5:options.c_cflag &= ~csize;//shield other flag bit op
Tions.c_cflag |= CS5;
Break
Case 6:options.c_cflag &= ~csize;//shielding other sign bit options.c_cflag |= CS6;
Break
Case 7:options.c_cflag &= ~csize;//shielding other sign bit options.c_cflag |= CS7;Break
Case 8:options.c_cflag &= ~csize;//shielding other sign bit options.c_cflag |= CS8;
Break
default:fprintf (stderr, "Unkown bits!\n");
return-1; /* Set parity bit */switch (parity) {/* No parity bit * * case ' n ': Case ' n ': OPTIONS.C_CFL
AG &= ~parenb;//parenb: Generating parity bit, performing parity Options.c_cflag &= ~INPCK;//INPCK: making parity function break;
/* Set to a space, that is, stop bit 2-bit * * case ' s ': The case ' s ': Options.c_cflag &= ~parenb;//parenb: Create parity bit, perform parity
Options.c_cflag &= ~CSTOPB;//CSTOPB: Use two bit stop bit break; /* Set odd check/Case ' O ': Case ' o ': Options.c_cflag |= parenb;//parenb: Generate parity bit, perform parity opti Ons.c_cflag |= parodd;//parodd: If the setting is odd check, otherwise parity Options.c_cflag |= INPCK;//INPCK: Make parity work OPTIONS.C
_cflag |= Istrip;//istrip: If set then the valid input number is stripped 7 bytes, otherwise all 8-bit break is preserved; /* SetParity/Case ' E ': Case ' e ': Options.c_cflag |= Parenb;//parenb: Generating parity bit, performing parity options . C_cflag &= ~parodd;//parodd: If set to odd check, or parity Options.c_cflag |= INPCK;//INPCK: Make parity work options
. C_cflag |= Istrip;//istrip: If set then the valid input number is stripped 7 bytes, otherwise all 8 bit break is preserved;
default:fprintf (stderr, "Unkown parity!\n");
return-1;
/* Set Stop bit */switch (stop) {case 1:options.c_cflag &= ~CSTOPB;//CSTOPB: Use two-bit stop bit
Break
Case 2:options.c_cflag |= CSTOPB;//CSTOPB: Use two bit stop bit break;
default:fprintf (stderr, "Unkown stop!\n");
return-1; /* Set the output mode to the original output/Options.c_oflag &= ~opost;//opost: If the setting is processed according to the defined output, otherwise all c_oflag fail/* Set local mode to original mode * * * optio Ns.c_lflag &= ~ (Icanon | ECHO | Echoe |
ISIG); /* *icanon: Allow canonical mode for input processing *echo: Allow local echo of input characters *echoe: Execute Backspace,space,backspa when receiving EpaseCe combination *isig: Allow signal/* Set wait time and minimum accept character/options.c_cc[vtime] = 0;//can be set in select options.c_cc[vmin] = 1;
Read at least one character/* If a data overflow occurs, only the data is accepted, but no read operation is performed * * Tcflush (Fd,tciflush);
/* Activation configuration */if (tcsetattr (fd,tcsanow,&options) < 0) {perror ("tcsetattr failed");
return-1;
return 0; }
Read and write serial port
Code:
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include < assert.h> #include <termios.h> #include <string.h> #include <sys/time.h> #include <sys/types.h
> #include <errno.h> static int ret;
static int fd;
* * Secure Read/write function * * ssize_t safe_write (int fd, const void *vptr, size_t n) {size_t nleft;
ssize_t Nwritten;
const char *ptr;
ptr = vptr;
Nleft = n; while (Nleft > 0) {if (Nwritten = write (FD, PTR, nleft)) <= 0) {if (Nwritten < 0&
&errno = = eintr) Nwritten = 0;
else return-1;
} nleft-= Nwritten;
PTR + = Nwritten;
return (n);
} ssize_t safe_read (int fd,void *vptr,size_t n) {size_t nleft;
ssize_t nread;
Char *ptr;
Ptr=vptr;
Nleft=n; while (Nleft > 0) {if (nread = Read (fd,ptr,nleft)) < 0) {if (errNo = = Eintr)/interrupted by signal nread = 0;
else return-1;
else if (nread = 0) break;
Nleft-= nread;
PTR + = nread;
return (N-nleft);
int uart_read (int fd,char *r_buf,size_t len) {ssize_t cnt = 0;
Fd_set RfDs;
struct Timeval time;
/* Add the file descriptor to the read descriptor set/Fd_zero (&RFDS);
Fd_set (Fd,&rfds);
/* Set Timeout to 15s*/time.tv_sec = 15;
time.tv_usec = 0;
/* Implementation of the serial port i/o*/ret = select (Fd+1,&rfds,null,null,&time);
Switch (ret) {case-1: fprintf (stderr, "select error!\n");
return-1;
Case 0:fprintf (stderr, "Time over!\n");
return-1;
default:cnt = Safe_read (Fd,r_buf,len);
if (cnt = = 1) {fprintf (stderr, "read error!\n");
return-1;
} return CNT; int uart_write (int fd,const Char *w_buf,size_t len) {ssize_t cnt = 0;
CNT = Safe_write (Fd,w_buf,len);
if (cnt = = 1) {fprintf (stderr, "Write error!\n");
return-1;
} return CNT; }
Full program
readers are requested to write the specific reading and writing commands.
/************************************************************************* > File name:uart_operation.c > A Uthor:answer > Mail:1045837697@qq.com > Created time:2015 year September 02 Wednesday 12:45 48 sec ************************* /#include <stdio.h> #include <stdlib.h> #include < fcntl.h> #include <unistd.h> #include <assert.h> #include <termios.h> #include <string.h> #
include<sys/time.h> #include <sys/types.h> #include <errno.h> static int ret;
static int fd;
* * Secure Read/write function * * ssize_t safe_write (int fd, const void *vptr, size_t n) {size_t nleft;
ssize_t Nwritten;
const char *ptr;
ptr = vptr;
Nleft = n; while (Nleft > 0) {if (Nwritten = write (FD, PTR, nleft)) <= 0) {if (Nwritten < 0&
&errno = = eintr) Nwritten = 0;
else return-1; } nleft-= NWRitten;
PTR + = Nwritten;
return (n);
} ssize_t safe_read (int fd,void *vptr,size_t n) {size_t nleft;
ssize_t nread;
Char *ptr;
Ptr=vptr;
Nleft=n;
while (Nleft > 0) {if (nread = Read (fd,ptr,nleft)) < 0) {if (errno = = eintr)/interrupted by signal
nread = 0;
else return-1;
else if (nread = 0) break;
Nleft-= nread;
PTR + = nread;
return (N-nleft);
int uart_open (int fd,const char *pathname) {assert (pathname); /* Open serial port */FD = open (pathname,o_rdwr| o_noctty|
O_ndelay);
if (fd = = 1) {perror ("Open UART failed!");
return-1;
/* Clear serial port non-blocking flag/if (FCNTL (fd,f_setfl,0) < 0) {fprintf (stderr, "Fcntl failed!\n");
return-1;
} return FD;
int uart_set (int fd,int baude,int c_flow,int bits,char parity,int stop) {struct options; /* ObtainedTake the terminal attribute/if (tcgetattr (fd,&options) < 0) {perror ("tcgetattr error");
return-1;
/* Set Input output baud rate, both remain consistent * * Switch (baude) {case 4800:cfsetispeed (&options,b4800);
Cfsetospeed (&options,b4800);
Break
Case 9600:cfsetispeed (&options,b9600);
Cfsetospeed (&options,b9600);
Break
Case 19200:cfsetispeed (&options,b19200);
Cfsetospeed (&options,b19200);
Break
Case 38400:cfsetispeed (&options,b38400);
Cfsetospeed (&options,b38400);
Break
default:fprintf (stderr, "Unkown baude!\n");
return-1;
/* Set control mode/* Options.c_cflag |= clocal;//Guarantee program does not occupy the serial port Options.c_cflag |= cread;//Guarantee Program can read data from the string/* Set Data flow control * *
Switch (c_flow) {case 0://does not flow control Options.c_cflag &= ~crtscts; Break
Case 1://for hardware flow control options.c_cflag |= crtscts;
Break Case 2://for Software flow control Options.c_cflag |= ixon| Ixoff|
Ixany;
Break
default:fprintf (stderr, "Unkown c_flow!\n");
return-1; /* Set Data bit */switch (BITS) {case 5:options.c_cflag &= ~csize;//shield other flag bit op
Tions.c_cflag |= CS5;
Break
Case 6:options.c_cflag &= ~csize;//shielding other sign bit options.c_cflag |= CS6;
Break
Case 7:options.c_cflag &= ~csize;//shielding other sign bit options.c_cflag |= CS7;
Break
Case 8:options.c_cflag &= ~csize;//shielding other sign bit options.c_cflag |= CS8;
Break
default:fprintf (stderr, "Unkown bits!\n");
return-1;
/* Set parity bit */switch (parity) {/* No parity bit * * case ' n ': Case ' n ': Options.c_cflag &= ~parenb;//parenb: Create parity bit, perform parity Options.c_cflag &= ~INPCK;//INPCK: Make parity
With a break;
/* Set to a space, that is, stop bit 2-bit * * case ' s ': The case ' s ': Options.c_cflag &= ~parenb;//parenb: Create parity bit, perform parity
Options.c_cflag &= ~CSTOPB;//CSTOPB: Use two bit stop bit break; /* Set odd check/Case ' O ': Case ' o ': Options.c_cflag |= parenb;//parenb: Generate parity bit, perform parity opti Ons.c_cflag |= parodd;//parodd: If the setting is odd check, otherwise parity Options.c_cflag |= INPCK;//INPCK: Make parity work OPTIONS.C
_cflag |= Istrip;//istrip: If set then the valid input number is stripped 7 bytes, otherwise all 8-bit break is preserved; /* Set parity/Case ' E ': Case ' e ': Options.c_cflag |= parenb;//parenb: Generate parity bit, perform parity opti Ons.c_cflag &= ~parodd;//parodd: If the setting is odd check, otherwise parity Options.c_cflag |= INPCK;//INPCK: Make parity work Opti Ons.c_cflag |= Istrip;//istrip: If set then the valid input number is stripped 7 bytes, otherwise all 8-bit break is preserved;
default:fprintf (stderr, "Unkown parity!\n");
return-1;
/* Set Stop bit */switch (stop) {case 1:options.c_cflag &= ~CSTOPB;//CSTOPB: Use two-bit stop bit
Break
Case 2:options.c_cflag |= CSTOPB;//CSTOPB: Use two bit stop bit break;
default:fprintf (stderr, "Unkown stop!\n");
return-1; /* Set the output mode to the original output/Options.c_oflag &= ~opost;//opost: If the setting is processed according to the defined output, otherwise all c_oflag fail/* Set local mode to original mode * * * optio Ns.c_lflag &= ~ (Icanon | ECHO | Echoe |
ISIG);
/* *icanon: Allow canonical mode for input processing *echo: Allow local echo of input characters *echoe: Execute backspace,space,backspace combination *isig when receiving epase: Allow signal * * Set wait time and minimum accept character/options.c_cc[vtime] = 0;//can set options.c_cc[vmin in select = 1;//read at least one character/* If data occurs
Overflow, only accept data, but do not read operation * * Tcflush (Fd,tciflush);
/* Activation configuration */if (tcsetattr (fd,tcsanow,&options) < 0) {perror ("tcsetattr failed");
return-1; return 0;
int uart_read (int fd,char *r_buf,size_t len) {ssize_t cnt = 0;
Fd_set RfDs;
struct Timeval time; /* Add the file descriptor to the Read Descriptor collection/* Fd_