Solution to LINUX serial port programming
Articles on Serial Port Programming in Linux are everywhere on the Internet, but most of them are from one article, and they all write some basic operations, such as controlling the Serial Port Pin status such as the RTS/CTS, the receipt and sending of binary data are not well described. I encountered some problems during use and wrote them out. I hope they will help you and avoid detours!
The operating system I use is redhat9, and the GCC version is 3.2.2.
In fact, in Linux, the serial port settings are mainly implemented through the termios struct, but this struct does not provide an interface for controlling the Serial Port Pin status such as RTS or CTS, you can use the ioctl system call to obtain/control.
Obtain:
IOCTL (FD, tiocmget, & controlbits );
If (controlbits & tiocm_cts)
Printf ("with signal/N ");
Else
Printf ("No signal/N ");
Settings:
IOCTL (FD, tiocmget, & ctrlbits );
If (FLAG)
Ctrlbits | = tiocm_rts;
Else
Ctrlbits & = ~ Tiocm_rts;
IOCTL (FD, tiocmset, & ctrlbits );
In fact, after tiocm_rts is effective, it sets the serial port's RTS as a signal, but when the serial port is low, there is a signal. When it is high, there is no signal, and the status obtained with tiocmget is the opposite, that is to say, tiocmget/tiocmset only obtains/controls whether the corresponding pins of the serial port have signals, and does not reflect the real level of the current serial port.
In many popular versions of LINUX serial programming on the internet, c_iflag (termios member variable) is not effectively set, so there is no problem in transmitting ASCII codes, however, 0x0d, 0x11, and 0x13 are lost when binary data is transmitted. Needless to say, these must be special characters and are used for special control. Disable the icrnl and ixon options.
C_iflag & = ~ (Icrnl | ixon );
0x0d carriage return character cr
0x11 ^ Q vstart character
0x13 ^ s vstop character
Icrnl converts the input Cr to Nl
Ixon enables start/stop output control flow to take effect
In Chapter 18th of the second edition of advanced programming for Unix environment, you can see that when you set terminal I/O to the original mode (Serial Communication is the original mode of terminal I/O), The INPUT attribute is set
Term. c_iflag & = ~ (Brkint | icrnl | inpck | istrip | ixon );
Many Attributes are blocked. No wonder it is said that if the serial communication c_iflag and c_oflag are both set to 0!
Below are some important serial port attributes of my settings
Term. c_cflag | = clocal | cread;
Term. c_lflag & = ~ (Icanon | echo | echoe | isig );
Term. c_oflag & = ~ Opost;
Term. c_iflag & = ~ (Brkint | icrnl | inpck | istrip | ixon );
Static void request_send (void)
{
IOCTL (FD, tiocmget, & status );
Status & = ~ Tiocm_rts; // high level of the RTS pin
IOCTL (FD, tiocmset, & status );
}
Static void clear_send (void)
{
IOCTL (FD, tiocmget, & status );
Status | = tiocm_rts; // low level of the RTS pin
IOCTL (FD, tiocmset, & status );
}
Int main (INT argc, char * argv [])
{
Int FD;
Struct termios OPT;
Int Len;
Char cmd;
// Data to be sent
Char sbuf [128] = {"Hello, this is a serial_port test! /N/0 "};
// Use the open function to open the serial port and obtain the file descriptor of the serial port device file
If (FD = open ("/dev/ttyama1", o_rdwr | o_noctty) =-1)
{
Perror ("cannot open the serial port ");
Return 1;
}
Tcgetattr (FD, & OPT );
Cfsetispeed (& OPT, b115200); // specify the input baud rate, 9600bps
Cfsetospeed (& OPT, b115200); // specify the output baud rate, 9600bps
Opt. c_cflag & = ~ Csize;
// Change the data bit to 8bit
Opt. c_cflag | = cs8;
Opt. c_cflag | = cbaud;
// No verification
Opt. c_cflag & = ~ Parenb;
Opt. c_cflag | = ixon | ixoff | ixany; // Software Data Flow Control
// Opt. c_cflag | = crtscts; // hardware Data Stream Control
// Opt. c_cflag & = ~ Crtscts; // No data flow control is used
Tcsetattr (FD, tcsanow, & OPT );
Int status;
IOCTL (FD, tiocmget, & status );
Printf ("status = % 04x/N", status );
// Status & = ~ Tiocm_rts; // high level of the RTS pin
Status | = tiocm_rts; // low level of the RTS pin
Printf ("status = % 04x/N", status );
IOCTL (FD, tiocmset, & status );
IOCTL (FD, tiocmget, & status );
Printf ("status = % 04x/N", status );
While (1)
{
Printf ("sellect: w | r | Q/N ");
Cmd = getchar ();
Switch (CMD)
{
Case 'W ':
Printf ("test write/N ");
// Definition of the number of bytes in the sending Buffer
{
Len = write (FD, sbuf, strlen (sbuf ));
If (LEN =-1)
Printf ("wirte sbuf error./N ");
Else
Printf ("wirte: % s", sbuf );
Break;
Case 'r ':
Printf ("test read/N ");
Len = read (FD, sbuf, sizeof (sbuf ));
If (LEN =-1)
Printf ("read sbuf error./N ");
Else
Printf ("read: % s", sbuf );
Break;
Case 'q ':
Close (FD );
Return 0;
Case '/N ':
Break;
Default:
Printf ("Worry cmd! /N ");
Break;
}
}
Close (FD );
Return 0;
}