1. Serial port API
In the Linux system, the unified interface for operating devices is: open/ioctl/read/write.
For UART, many functions are encapsulated on top of ioctl, which are mainly used to set line procedures.
So for UART, the programming routine is:
- open
- Set line procedures, such as baud rate, data bits, stop bits, check bits, RAW mode, return as soon as there is data
- How to set the line procedure for read/write
? The parameters of the line procedure are represented by the structure termios, you can refer to the Linux serial port—struct termios structure
typedef unsigned char cc_t;
typedef unsigned int speed_t;
typedef unsgined int tcflag_t;
#define NCCS 19
struct termios {
tcflag_t c_iflag; /* input mode flags */
tcflag_t c_oflag; /* output mode flags */
tcflag_t c_cflag; /* control mode flags */
tcflag_t c_lflag; /* local mode flags */
cc_t c_line; /* line discipline */
cc_t c_cc[NCCS]; /* control characters */
};
These functions have some conventions in their names:
- tc: terminal control
- cf: control flag
Function name | effect |
---|---|
tcgetattr | get terminal attributes, get the attributes of the terminal |
tcsetattr | set terminal attributes, modify terminal parameters |
tcflush | Clear the terminal's unfinished input/output requests and data |
cfsetispeed | sets the input baud rate, set the input baud rate |
cfsetospeed | sets the output baud rate, set the output baud rate |
cfsetspeed | Simultaneously set the input and output baud rate |
There are not many functions, the main thing is to set the parameters in termios. These parameters are very complicated. You can refer to the Linux serial port—struct termios structure .
Two, programming
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <stdlib.h>
int set_opt(int fd, int nSpeed, int nBits, char nEvent, int nStop)
{
struct termios newtio, oldtio;
if(tcgetattr(fd, &oldtio) != 0) {
perror("SetupSerial 1");
return -1;
}
bzero(&newtio, sizeof(newtio));
newtio.c_cflag |= CLOCAL|CREAD;
newtio.c_cflag &= ~CSIZE;
newtio.c_lflag &= ~(ICANON|ECHO|ECHOE|ISIG);
newtio.c_oflag &= ~OPOST;
switch(nBits) {
case 7:
newtio.c_cflag |= CS7;
break;
case 8:
newtio.c_cflag |= CS8;
break;
}
switch(nEvent) {
case 0:
newtio.c_cflag |= PARENB;
newtio.c_cflag |= PARODD;
newtio.c_iflag |= (INPCK | ISTRIP);
break;
case 'E':
newtio.c_iflag |= (INPCK|ISTRIP);
newtio.c_cflag |= PARENB;
newtio.c_cflag &= ~PARODD;
break;
case 'N':
newtio.c_cflag &= ~PARENB;
break;
}
switch(nSpeed) {
case 2400:
cfsetispeed(&newtio, B2400);
cfsetospeed(&newtio, B2400);
break;
case 4800:
cfsetispeed(&newtio, B4800);
cfsetospeed(&newtio, B4800);
break;
case 9600:
cfsetispeed(&newtio, B9600);
cfsetospeed(&newtio, B9600);
break;
case 115200:
cfsetispeed(&newtio, B115200);
cfsetospeed(&newtio, B115200);
break;
default:
cfsetispeed(&newtio, B9600);
cfsetospeed(&newtio, B9600);
break;
}
if(nStop == 1)
newtio.c_cflag &= ~CSTOPB;
else if(nStop == 2)
newtio.c_cflag |= CSTOPB;
newtio.c_cc[VMIN] = 1;
newtio.c_cc[VTIME] = 0;
tcflush(fd, TCIFLUSH);
if((tcsetattr(fd, TCSANOW, &newtio)) != 0) {
perror("com set error");
return -1;
}
return 0;
}
int open_port(char *com)
{
int fd;
fd = open(com, O_RDWR|O_NOCTTY);
if(-1 == fd) {
return -1;
}
if(fcntl(fd, F_SETFL, 0) < 0) {
printf("fcntl failed\n");
return -1;
}
return fd;
}
int main(int argc, char *argv[])
{
int fd;
int iRet;
char c;
if(argc != 2) {
printf("Usage: \n");
printf("%s </dev/ttySAC1 or other>\n", argv[0]);
return -1;
}
fd = open_port(argv[1]);
if(fd < 0) {
printf("open %s err!\n", argv[1]);
return -1;
}
iRet = set_opt(fd, 115200, 8, 'N', 1);
if(iRet) {
printf("set port err!\n");
return -1;
}
printf("Enter a char: ");
while(1) {
scanf("%c", &c);
iRet = write(fd, &c, 1);
iRet = read(fd, &c, 1);
if(iRet == 1) {
printf("get: %02x %c\n", c, c);
} else {
printf("can not get data\n");
}
}
return 0;
}
3. Computer experiment
Short the RX and TX of the serial port
root@npi:~/test# ./a.out /dev/ttymxc2
Enter a cahr: a
get: 61 a
get: 0a
get: 0a
get: 0a
a
get: 61 a
get: 0a