The specific Encapsulation Format is C code, so that it can be compiled and used in both C and C ++ environments for good portability. The header file of the Code is as follows:
// Filename: stty. h
# Ifndef _ stty_h __
# DEFINE _ stty_h __
# Include <stdio. h>
# Include <stdlib. h>
# Include <unistd. h>
# Include <sys/types. h>
# Include <sys/STAT. h>
# Include <fcntl. h>
# Include <termios. h>
# Include <errno. h>
# Include <pthread. h>
//
// Serial device information structure
Typedef struct tty_info_t
{
Int FD; // serial device ID
Pthread_mutex_t MT; // The thread synchronizes mutex objects.
Char name [24]; // serial device name, for example, "/dev/ttys0"
Struct termios NTM; // new serial port device options
Struct termios OTM; // old serial port device options
} Tty_info;
//
// Serial operation function
Tty_info * readytty (int id );
Int setttyspeed (tty_info * ptty, int speed );
Int setttyparity (tty_info * ptty, int databits, int parity, int stopbits );
Int cleantty (tty_info * ptty );
Int sendntty (tty_info * ptty, char * pbuf, int size );
Int recvntty (tty_info * ptty, char * pbuf, int size );
Int locktty (tty_info * ptty );
Int unlocktty (tty_info * ptty );
# Endif
From the function definition in the file, it is not difficult to see that the function usage process is as follows:
(1) Open the serial port device and call the setttyspeed () function ();
(2) set the baud rate of serial port read/write, and call the setttyspeed () function ();
(3) set the attributes of the serial port, including the stop bit, check bit, and data bit. Call the setttyparity () function ();
(4) write data to the serial port and call the sendntty function ();
(5) read data from the serial port and call the recvntty function ();
(6) After the operation is complete, call the cleantty () function to release the applied serial port information interface;
Among them, locktty () and unlocktty () are used in multithreading. Before and after reading and writing operations, You need to lock and release serial port resources.
The specific usage is demonstrated in the main () function in the original file of code implementation. The following is the source code file:
//////////////////////////////////////// ////////////////////////////////////////
// Stty. c
# Include <stdio. h>
# Include <sys/IOCTL. h>
# Include "stty. H"
//////////////////////////////////////// ///////////////////////////////////////
// Initialize the serial device and save the original settings
Tty_info * readytty (int id)
{
Tty_info * ptty;
Ptty = (tty_info *) malloc (sizeof (tty_info ));
If (ptty = NULL)
Return NULL;
Memset (ptty, 0, sizeof (tty_info ));
Pthread_mutex_init (& ptty-> Mt, null );
Sprintf (ptty-> name, "/dev/TTYs % d", ID );
//
// Open and set the serial port
Ptty-> FD = open (ptty-> name, o_rdwr | o_noctty | o_ndelay );
If (ptty-> FD <0)
{
Free (ptty );
Return NULL;
}
//
// Get and save the original settings
Tcgetattr (ptty-> FD, & ptty-> OTM );
Return ptty;
}
//////////////////////////////////////// ///////////////////////////////////////
// Clear serial device resources
Int cleantty (tty_info * ptty)
{
//
// Disable the enabled serial port device
If (ptty-> FD> 0)
{
Tcsetattr (ptty-> FD, tcsanow, & ptty-> OTM );
Close (ptty-> FD );
Ptty-> FD =-1;
Free (ptty );
Ptty = NULL;
}
Return 0;
}
//////////////////////////////////////// ///////////////////////////////////////
// Set the serial communication rate
// Ptty parameter type (tty_info *), the structure pointer of the initialized serial port device information
// Speed parameter type (INT), used to set the baud rate of the serial port
// Return value type (INT). If the function is successfully executed, the return value is zero. Otherwise, the return value is greater than zero.
//////////////////////////////////////// ///////////////////////////////////////
Int setttyspeed (tty_info * ptty, int speed)
{
Int I;
//
// Configure a new serial port. The data bit is 8 bits.
Bzero (& ptty-> NTM, sizeof (ptty-> NTM ));
Tcgetattr (ptty-> FD, & ptty-> NTM );
Ptty-> NTM. c_cflag = clocal | cread;
Switch (speed)
{
Case 300:
Ptty-> NTM. c_cflag | = b300;
Break;
Case 1200:
Ptty-> NTM. c_cflag | = b1200;
Break;
Case 2400:
Ptty-> NTM. c_cflag | = b2400;
Break;
Case 4800:
Ptty-> NTM. c_cflag | = b4800;
Break;
Case 9600:
Ptty-> NTM. c_cflag | = b9600;
Break;
Case 19200:
Ptty-> NTM. c_cflag | = b19200;
Break;
Case 38400:
Ptty-> NTM. c_cflag | = b38400;
Break;
Case 115200:
Ptty-> NTM. c_cflag | = b115200;
Break;
}
Ptty-> NTM. c_iflag = ignpar;
Ptty-> NTM. c_oflag = 0;
//
//
Tcflush (ptty-> FD, tciflush );
Tcsetattr (ptty-> FD, tcsanow, & ptty-> NTM );
//
//
Return 0;
}
//////////////////////////////////////// ///////////////////////////////////////
// Set the serial data bit, stop bit and verify bit
// Ptty parameter type (tty_info *), the structure pointer of the initialized serial port device information
// Databits parameter type (INT), data bit, value 7 or 8
// Stopbits parameter type (INT), stop bit, value: 1 or 2
// Parity parameter type (INT). Valid values: N, E, O, and s
// Return value type (INT). If the function is successfully executed, the return value is zero. Otherwise, the return value is greater than zero.
//////////////////////////////////////// ///////////////////////////////////////
Int setttyparity (tty_info * ptty, int databits, int parity, int stopbits)
{
//
// Obtain the serial port settings
If (tcgetattr (ptty-> FD, & ptty-> NTM )! = 0)
{
Printf ("setupserial [% s] \ n", ptty-> name );
Return 1;
}
Bzero (& ptty-> NTM, sizeof (ptty-> NTM ));
Ptty-> NTM. c_cflag = cs8 | clocal | cread;
Ptty-> NTM. c_iflag = ignpar;
Ptty-> NTM. c_oflag = 0;
//
// Set parameters of the serial port
Ptty-> NTM. c_cflag & = ~ Csize;
Switch (databits)
{// Set the number of data digits
Case 7:
Ptty-> NTM. c_cflag | = cs7;
Break;
Case 8:
Ptty-> NTM. c_cflag | = cs8;
Break;
Default:
Printf ("unsupported data size \ n ");
Return 5;
}
//
Switch (parity)
{// Set the number of parity digits
Case 'N ':
Case 'N ':
Ptty-> NTM. c_cflag & = ~ Parenb;
Ptty-> NTM. c_iflag & = ~ Inpck;
Break;
Case 'O ':
Case 'O ':
Ptty-> NTM. c_cflag | = (parodd | parenb );
Ptty-> NTM. c_iflag | = inpck;
Break;
Case 'E ':
Case 'E ':
Ptty-> NTM. c_cflag | = parenb;
Ptty-> NTM. c_cflag & = ~ Parodd;
Ptty-> NTM. c_iflag | = inpck;
Break;
Case's ':
Case's ':
Ptty-> NTM. c_cflag & = ~ Parenb;
Ptty-> NTM. c_cflag & = ~ Cstopb;
Break;
Default:
Printf ("unsupported parity \ n ");
Return 2;
}
//
// Set the stop bit
Switch (stopbits)
{
Case 1:
Ptty-> NTM. c_cflag & = ~ Cstopb;
Break;
Case 2:
Ptty-> NTM. c_cflag | = cstopb;
Break;
Default:
Printf ("unsupported Stop bits \ n ");
Return 3;
}
//
//
Ptty-> NTM. c_lflag = 0;
Ptty-> NTM. c_cc [vtime] = 0; // inter-character timer unused
Ptty-> NTM. c_cc [Vmin] = 1; // blocking read until 1 chars committed ed
Tcflush (ptty-> FD, tciflush );
If (tcsetattr (ptty-> FD, tcsanow, & ptty-> NTM )! = 0)
{
Printf ("setupserial \ n ");
Return 4;
}
Return 0;
}
Int recvntty (tty_info * ptty, char * pbuf, int size)
{
Int ret, left, bytes;
Left = size;
While (left> 0)
{
Ret = 0;
Bytes = 0;
Pthread_mutex_lock (& ptty-> MT );
IOCTL (ptty-> FD, fionread, & bytes );
If (Bytes> 0)
{
Ret = read (ptty-> FD, pbuf, left );
}
Pthread_mutex_unlock (& ptty-> MT );
If (Ret> 0)
{
Left-= ret;
Pbuf + = ret;
}
Usleep (100 );
}
Return size-left;
}
Int sendntty (tty_info * ptty, char * pbuf, int size)
{
Int ret, nleft;
Char * pTMP;
Ret = 0;
Nleft = size;
PTMP = pbuf;
While (nleft> 0)
{
Pthread_mutex_lock (& ptty-> MT );
Ret = write (ptty-> FD, pTMP, nleft );
Pthread_mutex_unlock (& ptty-> MT );
If (Ret> 0)
{
Nleft-= ret;
PTMP + = ret;
}
// Usleep (100 );
}
Return size-nleft;
}
Int locktty (tty_info * ptty)
{
If (ptty-> FD <0)
{
Return 1;
}
Return flock (ptty-> FD, lock_ex );
}
Int unlocktty (tty_info * ptty)
{
If (ptty-> FD <0)
{
Return 1;
}
Return flock (ptty-> FD, lock_un );
}
# Ifdef leaf_tty_test
//////////////////////////////////////// ///////////////////////////////////////
// Interface Test
Int main (INT argc, char ** argv)
{
Tty_info * ptty;
Int nbyte, idx;
Unsigned char CC [16];
Ptty = readytty (0 );
If (ptty = NULL)
{
Printf ("readytty (0) error \ n ");
Return 1;
}
//
//
Locktty (ptty );
If (setttyspeed (ptty, 9600)> 0)
{
Printf ("setttyspeed () error \ n ");
Return-1;
}
If (setttyparity (ptty, 8, 'n', 1)> 0)
{
Printf ("setttyparity () error \ n ");
Return-1;
}
//
Idx = 0;
While (1)
{
CC [0] = 0xfa;
Sendntty (ptty, & CC [0], 1 );
Nbyte = recvntty (ptty, CC, 1 );
Printf ("% d: X \ n", idx ++, CC [0]);
}
Cleantty (ptty );
}
# Endif
Serial Port is a protocol for communication between very common devices on computers. Commonly Used PCs contain RS232 serial ports with few connection lines and simple communication, which are widely used.
Linux accesses all devices through device files. The same is true for the serial port. To access the serial port, you only need to open the file of the device to operate the serial port device. In Linux, each serial device has a device file associated with it. The device file is located under the/dev directory of the system. For example, in Linux,/ttys0 and/ttys1 indicate Serial 1 and Serial 2 respectively.
In serial programming, it is important to set the serial port. The settings include the baud rate, data bit, stop bit, and parity bit, the default settings for the serial port of each machine may be different. If you do not set these settings, send data only according to the default settings, it is very likely that n many different ideas cannot be found.
1) set the baud rate
# Include <termios. h> # Include <unistd. h> Int cfsetispeed (struct termios * termios_p, speed_t speed ); Int cfsetospeed (struct termios * termios_p, speed_t speed ); |
2) Set Properties: parity bit, data bit, and stop bit. Set the termios struct in <termbits. h> as follows:
# Define NCCs 19 Struct termios { Tcflag_t c_iflag; Tcflag_t c_oflag; Tcflag_t c_cflag; Tcflag_t c_lflag; Cc_t c_line; Cc_t c_cc [NCCs]; }; |
The corresponding functions are available for obtaining and setting attributes:
Int tcgetattr (int fd, struct termios * termios_p ); Int tcsetattr (int fd, int optional_actions, struct termios * termios_p ); |
3) Enable, disable, and read/write the serial port. The serial port acts as a device file and can be operated directly using the file descriptor.
# Include <sys/types. h> # Include <sys/STAT. h> # Include <fcntl. h> Int open (const char * pathname, int flags ); # Include <unistd. h> Int close (int fd ); Ssize_t write (int fd, const void * Buf, size_t count ); Ssize_t read (int fd, void * Buf, size_t count ); |
The embedded Linux operating system uses the termios interface of POSIX to control serial port behavior. In Linux, serial ports and other devices are processed as files. The main implementation of the program module is as follows:
Int FD = open ("/dev/ttys1", o_rdwrio_noctty); // open the serial port
......
New_options.c_cflag & = ~ Parenb; // No parity
New_options.c_cflag & = ~ Csize; // do not hide the data bit
New_options.c_cflag & = ~ Cstop8; // No stop bit
New_options.c_cflag | = cs8; // 8-Bit Data bit
Cfsetispeed (& new_options, b4800); // set the baud rate to 4800bit/s.
Cfsetospeed (& new_options, b4800 );
Tcflush (FD, tcioflush );
Tcsetattr (FD, tcsanow, & new_options); // sets the new device mode.
After setting the serial port, you can use the read () and write () functions to perform operations on the serial port. It should be noted that the serial port is blocking by default. When no data arrives, it will be blocked and suspended, in this case, you can adjust and control it through multi-threaded programming, serial port timeout settings, or select round robin. The system uses multi-threaded programming to control serial port congestion. It uses the qthread class of QT, and can also directly use the multi-threaded functions of Linux.