Linux串口编程详解(转)
串口本身,标准和硬件 †
串口是计算机上的串行通讯的物理接口。计算机历史上,串口曾经被广泛用于连接计算机和终端设备和各种外部设备。虽然以太网接口和USB接口也是以一个串行流进行数据传送的,但是串口连接通常特指那些与RS-232标准兼容的硬件或者调制解调器的接口。虽然现在在很多个人计算机上,原来用以连接外部设备的串口已经广泛的被USB和Firewire替代;而原来用以连接网络的串口则被以太网替代,还有用以连接终端的串口设备则已经被MDA或者VGA取而代之。但是,一方面因为串口本身造价便宜技术成熟,另一方面因为串口的控制台功能RS-232标准高度标准化并且非常普及,所以直到现在它仍然被广泛应用到各种设备上。 某些计算机使用一个叫做UART的集成电路来作为串口设备。这个集成电路可以进行字符和异步串行通讯序列之间的转换,并且可以自动地处理数据的时序。而某些低端设备则会让CPU直接通过输出针来传送数据,这种技术叫做bit-banging。 因为“串口”,RS-232和UARTs基本上总是在同一个语境中出现,所以这些名词通常会被搞混。下面逐一解释以下一些重要的名词和术语。
什么是串行通信 †
什么是RS-232 †
针脚 | 描述 | 针脚 | 描述 | 针脚 | 描述 | 针脚 | 描述 | 针脚 | 描述 |
1 | Earth Ground | 6 | DSR - Data Set Ready | 11 | Unassigned | 16 | Secondary RXD | 21 | Signal Quality Detect |
2 | TXD - Transmitted Data | 7 | GND - Logic Ground | 12 | Secondary DCD | 17 | Receiver Clock | 22 | Ring Detect |
3 | RXD - Received Data | 8 | DCD - Data Carrier Detecter | 13 | Secondary CTS | 18 | Unassigned | 23 | Data Rate Select |
4 | RTS - Request To Send | 9 | Reserved | 14 | Secondary TXD | 19 | Secondary RTS | 24 | Transmit Clock |
5 | CTS - Clear To Send | 10 | Reserved | 15 | Transmit Clock | 20 | DTR - Data Terminal Ready | 25 | Unassigned |
DB-9
针脚 | 名称 | 全名 | 方向(主机 外设) |
3 | TD | Transmit Data | -> |
2 | RD | Receive Data | <- |
7 | RTS | Request To Send | -> |
8 | CTS | Clear To Send | <- |
6 | DSR | Data Set Ready | <- |
4 | DTR | Data Terminal Ready | -> |
1 | CD | Data Carrier Detect | <- |
9 | RI | Ring Indicator | <- |
5 | - | Signal Ground |
另外两个比较常见的串行接口的标准式RS-422和RS-574。RS-422使用更低的电压和差分信号,这样可以将传输距离扩张到300m。而RS-574定义了通常可以见到的用在电脑上的9针连接器和电压。
信号定义 †
RS-232标准定义了18个不同的串行通信的信号。而这些之中,仅仅有如下6个可以在UNIX环境中使用。
- GND - Logic Ground
从技术角度讲,GND不能算是信号。但是没有它其他信号都不能用了。基本上,logic ground有点像一个参考电压,通过它来判断哪个电压表示正哪个电压表示负。
- TXD - Transmitted Data
TXD信号负载着从你的电脑或者设备到另一端(比如调制解调器)的数据。Mark范围的电压被解析成1,而space范围电压被解析成0。
- RXD - Received Data
RXD于TXD正好相反。它负载着从另一端的电脑或者设备上传到你的工作站的数据。Mark和space的解析方法于TXD一致。
- DCD - Data Carrier Detect
DCD信号通常来自串口连结线的另一端。这条信号线上的space电压表示另一端的电脑或者设备现在已经连接。但是,DCD信号线却不是总可以得到的,有些设备上有这条信号线,而有的则没有。
- DTR - Data Terminal Ready
DTR信号是你的工作站产生的,用以告诉另一端的电脑或者设备你已经是否已经准备好了。Space电压表示准备好了,而mark电压表示没有准备好。当你在工作站上打开串行接口时,DTR通常自动被设置位有效。
- CTS - Clear To Send
CTS则通常来自连结线的另一端。Space电压表示你可以从工作站送出更多的数据。CTS通常用来协调你的工作站和另一端之间的串行数据流。
- RTS - Request To Send
如果RTS信号被设置成space电压,这表示你准备好了一些数据需要传送。和CTS一样,RTS也被用来协调工作站和另一端的电脑或者设备之间的数据流。有些工作站上会一直将这个信号设置位space。
异步通讯 †
计算机为了弄懂传给它的串行数据,它需要确定每个字符开始和结束的位置。这通常是用异步串行数据来完成的。
#ref(): File not found: "async.gif" at page "Linux串口编程详解"
什么是全双工和半双工 †
全双工(Full duplex)是说计算机可以同时接受和发送数据——也就是它有两个分开的数据传输通道(一个传入,一个传出)。
什么是流控制 †
两个串行接口之间的传输数据流通常需要协调一致才行。这可能是由于用以通信的某个串行接口或者某些存储介质的中间串行通信链路的限制造成的。对于异步数据这里有两个方法做到这一点。
什么是BREAK †
通常,直到有数据传输时,接收和传输信号会保持在mark电压。如果一个信号掉到space电压并且持续了很长时间,一般来说是1/4到1/2秒,那么就说有一个break条件存在了。
BREAK经常被用来重置一条数据线或者用来改变像调制解调器这样的设备的通讯模式。
同步通讯 †
这些协议每个都定义了一个确定的比特序列来表示数据包的开始和结束。当然,它们也定义了一个用来表示没有数据传输的比特序列。这些比特序列可以帮助计算机识别数据包的开端。
用户看到的串口和用户空间的串口编程 †
和其他设备一样,Linux也是通过设备文件来提供访问串口的功能。当需要访问串口的时候,你只需要open相应的文件。
串口的设备文件 †
Linux系统上一般有一个或者多个串口,而这些串口设备文件名字比较奇怪,如比下面这样
操作系统 | 串口1 | 串口2 | USB/RS-232转换器 |
Windows | COM1 | COM2 | - |
Linux | /dev/ttyS0 | /dev/ttyS1 | /dev/ttyUSB0 |
打开串口 †
OK.假如你已经准备好了让串口设备文件可以被所有用户访问,你可以在Linux系统中实验一下下面这个程序,它可以打开计算机的串口1。
#include <stdio.h> #include <string.h> #include <unistd.h> #include <fcntl.h> /* File control definitions */ #include <errno.h> #include <termios.h> /* POSIX terminal control definitions *//** 'open_port()' - Open serial port 1* Returns the file descriptor on success or -1 on error.*/int open_port(void) {int fd; /* File descriptor for the port */fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);if (fd == -1){/** Could not open the port.*/perror("open_port: Unable to open /dev/ttyS0 -");}else{fcntl(fd, F_SETFL, 0);return (fd);} }
打开文件的选项 †
打开串口连接的时候,程序在open函数中除了Read+Write模式以外还指定了两个选项;
fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
O_NDELAY标志则是告诉UNIX,这个程序并不关心DCD信号线的状态——也就是不关心端口另一端是否已经连接。如果不指定这个标志的话,除非DCD信号线上有space电压否则这个程序会一直睡眠。
给端口上写数据 †
给端口上写入数据也很简单,使用write(2)系统调用就可以发送数据了:
n = write(fd, "ATZ\r", 4); if (n < 0)fputs("write() of 4 bytes failed!\n", stderr);
从端口上读取数据 †
fcntl(fd, F_SETFL, FNDELAY);
标志FNDELAY可以保证read(2)函数在端口上读不到字符的时候返回0。需要回到正常(阻塞)模式的时候,需要再次在不带FNDELAY标志的情况下调用fcntl(2)函数:
fcntl(fd, F_SETFL, 0);
当然,如果你最初就是以O_NDELAY标志打开串口的,你也可在之后使用这个方法改变读取的行为方式。
关闭串口 †
close(fd);
关闭串口会将DTR信号线设置成low,这会导致很多调制解调器挂起。
配置串口 †
POSIX终端接口 †
成员 | 描述 |
c_cflag | 控制选项 |
c_lflag | 行选项 |
c_iflag | 输入选项 |
c_oflag | 输出选项 |
c_cc | 控制字符 |
c_ispeed | 输入波特率(NEW) |
c_ospeed | 输出波特率(NEW) |
控制选项 †
通过termios结构体的c_cflag成员可以控制波特率,数据的比特数,parity,停止位和硬件流控制。下面这张表列出了所有可以使用的常数。
常量 | 描述 |
CBAUD | Bit mask for baud rate |
B0 | 0 baud (drop DTR) |
B50 | 50 baud |
B75 | 75 baud |
B110 | 110 baud |
B134 | 134.5 baud |
B150 | 150 baud |
B200 | 200 baud |
B300 | 300 baud |
B600 | 600 baud |
B1200 | 1200 baud |
B1800 | 1800 baud |
B2400 | 2400 baud |
B4800 | 4800 baud |
B9600 | 9600 baud |
B19200 | 19200 baud |
B38400 | 38400 baud |
B57600 | 57,600 baud |
B76800 | 76,800 baud |
B115200 | 115,200 baud |
EXTA | External rate clock |
EXTB | External rate clock |
CSIZE | Bit mask for data bits |
CS5 | 5 data bits |
CS6 | 6 data bits |
CS7 | 7 data bits |
CS8 | 8 data bits |
CSTOPB | 2 stop bits (1 otherwise) |
CREAD | Enable receiver |
PARENB | Enable parity bit |
PARODD | Use odd parity instead of even |
HUPCL | Hangup (drop DTR) on last close |
CLOCAL | Local line - do not change "owner" of port |
LOBLK | Block job control output |
CNEW_RTSCTS/CRTSCTS | Enable hardware flow control (not supported on all platforms) |
在传统的POSIX编程中,当连接一个本地的(不通过调制解调器)或者远程的终端(通过调制解调器)时,这里有两个选项应当一直打开,一个是CLOCAL,另一个是CREAD。这两个选项可以保证你的程序不会变成端口的所有者,而端口所有者必须去处理发散性作业控制和挂断信号,同时还保证了串行接口驱动会读取过来的数据字节。
波特率常数(CBAUD,B9600等等)通常指用到那些不支持c_ispeed和c_ospeed成员的旧的接口上。后面文章将会提到如何使用其他POSIX函数来设置波特率。
千万不要直接用使用数字来初始化c_cflag(当然还有其他标志),最好的方法是使用位运算的与或非组合来设置或者清除这个标志。不同的操作系统版本会使用不同的位模式,使用常数定义和位运算组合来避免重复工作从而提高程序的可移植性。
设置波特率 †
不同的操作系统会将波特率存储在不同的位置。旧的编程接口将波特率存储在上表所示的c_cflag成员中,而新的接口实装则提供了c_ispeed和c_ospeed成员来保存实际波特率的值。
程序中可是使用cfsetospeed(3)和cfsetispeed(3)函数在termios结构体中设置波特率而不用去管底层操作系统接口。下面的代码是个非常典型的设置波特率的例子。
struct termios options;/** Get the current options for the port...*/ tcgetattr(fd, &options);
/** Set the baud rates to 19200...*/ cfsetispeed(&options, B19200); cfsetospeed(&options, B19200);/** Enable the receiver and set local mode...*/ options.c_cflag |= (CLOCAL | CREAD);/** Set the new options for the port...*/ tcsetattr(fd, TCSANOW, &options);
常量 | 描述 |
TCSANOW | Make changes now without waiting for data to complete |
TCSADRAIN | Wait until everything has been transmitted |
TCSAFLUSH | Flush input and output buffers and make the change |
不同的系统上可能支持不同的输入输出速度,所以,通过串口连接两台机器或者设备的时候,应该将波特率设置成两者中较小的那个,即MIN(speed1, speed2)。
设置字符大小 †
设置字符大小的时候,这里却没有像设置波特率那么方便的函数。所以,程序中需要一些位掩码运算来把事情搞定。字符大小以比特为单位指定:
options.c_flag &= ~CSIZE; /* Mask the character size bits */ options.c_flag |= CS8; /* Select 8 data bits */
设置奇偶校验 †
与设置字符大小的方式差不多,这里仍然需要组合一些位掩码来将奇偶校验设为有效和奇偶校验的类型。UNIX串口驱动可以生成even,odd和no parity位码。设置space奇偶校验需要耍点小手段。
options.c_cflag &= ~PARENB options.c_cflag &= ~CSTOPB options.c_cflag &= ~CSIZE; options.c_cflag |= CS8;
options.c_cflag |= PARENB options.c_cflag &= ~PARODD options.c_cflag &= ~CSTOPB options.c_cflag &= ~CSIZE; options.c_cflag |= CS7;
options.c_cflag |= PARENB options.c_cflag |= PARODD options.c_cflag &= ~CSTOPB options.c_cflag &= ~CSIZE; options.c_cflag |= CS7;
options.c_cflag &= ~PARENB options.c_cflag &= ~CSTOPB options.c_cflag &= ~CSIZE; options.c_cflag |= CS8;
设置硬件流控制 †
options.c_cflag |= CNEW_RTSCTS; /* Also called CRTSCTS
options.c_cflag &= ~CNEW_RTSCTS;
本地设置 †
本地模式成员变量c_lflag可以控制串口驱动怎样控制输入字符。通常,你可能需要通过c_lflag成员来设置经典输入和原始输入模式。
ISIG | Enable SIGINTR, SIGSUSP, SIGDSUSP, and SIGQUIT signals |
ICANON | Enable canonical input (else raw) |
XCASE | Map uppercase \lowercase (obsolete) |
ECHO | Enable echoing of input characters |
ECHOE | Echo erase character as BS-SP-BS |
ECHOK | Echo NL after kill character |
ECHONL | Echo NL |
NOFLSH | Disable flushing of input buffers after interrupt or quit characters |
IEXTEN | Enable extended functions |
ECHOCTL | Echo control characters as ^char and delete as ~? |
ECHOPRT | Echo erased character as character erased |
ECHOKE | BS-SP-BS entire line on line kill |
FLUSHO | Output being flushed |
PENDIN | Retype pending input at next read or input char |
TOSTOP | Send SIGTTOU for background output |
选择经典输入 †
经典输入是以面向行设计的。在经典输入模式中输入字符会被放入一个缓冲之中,这样可以以与用户交互的方式编辑缓冲的内容,直到收到CR(carriage return)或者LF(line feed)字符。
选择使用经典输入模式的时候,你通常需要选择ICANON,ECHO和ECHOE选项:
options.c_lflag |= (ICANON | ECHO | ECHOE);
选择原始输入 †
原始输入根本不会被处理。输入字符只是被原封不动的接收。一般情况中,如果要使用原始输入模式,程序中需要去掉ICANON,ECHO,ECHOE和ISIG选项:
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
输入选项 †
可以通过输入模式成员c_iflag来控制从端口上收到的字符的输入过程。与c_cflag一样,c_iflag的最终值是想要使用的所有状态的位运算OR的组合。
常量 | 描述 |
INPCK | Enable parity check |
IGNPAR | Ignore parity errors |
PARMRK | Mark parity errors |
ISTRIP | Strip parity bits |
IXON | Enable software flow control (outgoing) |
IXOFF | Enable software flow control (incoming) |
IXANY | Allow any character to start flow again |
IGNBRK | Ignore break condition |
BRKINT | Send a SIGINT when a break condition is detected |
INLCR | Map NL to CR |
IGNCR | Ignore CR |
ICRNL | Map CR to NL |
IUCLC | Map uppercase to lowercase |
IMAXBEL | Echo BEL on input line too long |
设置输入奇偶校验选项 †
options.c_iflag |= (INPCK | ISTRIP);
IGNPAR是一个比较危险选项,即便有错误发生时,它也会告诉串口驱动直接忽略奇偶校验错误给数据放行。这个选项在测试链接的通讯质量时比较有用而通常不会被用在实际程序中。
设置软件流控制 †
软件流控制可以通过IXON,IXOFF和IXANY常量设置成有效:
options.c_iflag |= (IXON | IXOFF | IXANY);
options.c_iflag &= ~(IXON | IXOFF | IXANY);
XON(start data)和XOFF(stop data)字符却是在c_cc数组中定义的,下面会详细描述这个数组。
输出选项 †
成员变量c_oflag之中包括了输出过滤选项。和输入模式相似,程序可以选择使用经过加工的或者原始的数据输出。
常量 | 描述 |
OPOST | Postprocess output (not set = raw output) |
OLCUC | Map lowercase to uppercase |
ONLCR | Map NL to CR-NL |
OCRNL | Map CR to NL |
NOCR | No CR output at column 0 |
ONLRET | NL performs CR function |
OFILL | Use fill characters for delay |
OFDEL | Fill character is DEL |
NLDLY | Mask for delay time needed between lines |
NL0 | No delay for NLs |
NL1 | Delay further output after newline for 100 milliseconds |
CRDLY | Mask for delay time needed to return carriage to left column |
CR0 | No delay for CRs |
CR1 | Delay after CRs depending on current column position |
CR2 | Delay 100 milliseconds after sending CRs |
CR3 | Delay 150 milliseconds after sending CRs |
TABDLY | Mask for delay time needed after TABs |
TAB0 | No delay for TABs |
TAB1 | Delay after TABs depending on current column position |
TAB2 | Delay 100 milliseconds after sending TABs |
TAB3 | Expand TAB characters to spaces |
BSDLY | Mask for delay time needed after BSs |
BS0 | No delay for BSs |
BS1 | Delay 50 milliseconds after sending BSs |
VTDLY | Mask for delay time needed after VTs |
VT0 | No delay for VTs |
VT1 | Delay 2 seconds after sending VTs |
FFDLY | Mask for delay time needed after FFs |
FF0 | No delay for FFs |
FF1 | Delay 2 seconds after sending FFs |
选择加工过的输出 †
通过在c_oflag成员变量中设置OPOST选项的方法程序可以选择加工过的输入。
options.c_oflag |= OPOST;
在所有选项当中,你可能只需要使用ONLCR选项来将行分隔符映射到CR-LF组合对上。其他选项主要是历史遗留,仅仅与行打印机和终端跟不上串行数据的年代有关。
选择原始输出 †
原始输出方式可以通过在c_oflag中重置OPOST选项来选择:
options.c_oflag &= ~OPOST;
如果OPOST选项被设置成无效的话,其他c_oflag中的选项都会失效。
控制字符 †
字符数组c_cc里面包括了控制字符的定义和超时参数。这个数组的每个元素都是以常量定义的。
常量 | 描述 | 键 |
VINTR | Interrupt | CTRL-C |
VQUIT | Quit | CTRL-Z |
VERASE | Erase | Backspace (BS) |
VKILL | Kill-line | CTRL-U |
VEOF | End-of-file | CTRL-D |
VEOL | End-of-line | Carriage return (CR) |
VEOL2 | Second end-of-line | Line feed (LF) |
VMIN | Minimum number of characters to read | - |
VSTART | Start flow | CTRL-Q (XON) |
VSTOP | Stop flow | CTRL-S (XOFF) |
VTIME | Time to wait for data (tenths of seconds) | - |
设置软件流控制字符 †
设置读取超时 †
VMIN可以指定读取的最小字符数。如果它被设置为0,那么VTIME值则会指定每个字符读取的等待时间。
VTIME可以以十分之一秒为单位指定等待字符输入的时间。如果VTIME设置为0(默认情况),除非open(2)或者fcntl(2)函数设置了NDELAY选项,否则read(2)将会永久得阻塞(等待)。
调制解调器通讯 †
说到串口通讯就不得不提一下通过调剂解调器通讯的方式。这里给出的程序例子都适用于支持“事实上的”标准AT命令集的调制解调器。
什么是调制解调器 †
今天可以见到的调制解调器可以通过电话线每秒传输53000比特——5.3Kbps——的数据。还有就是,大多数调制解调器都使用数据压缩技术,这样就可以将某些类型数据的传输比特率提高到100kbps。
与调制解调器通讯 †
于调制解调器通讯的第一步就是要以原始输入模式打开和配置串口。
int fd; struct termios options;
/* open the port */ fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY); fcntl(fd, F_SETFL, 0);/* get the current options */ tcgetattr(fd, &options);/* set raw input, 1 second timeout */ options.c_cflag |= (CLOCAL | CREAD); options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); options.c_oflag &= ~OPOST; options.c_cc[VMIN] = 0; options.c_cc[VTIME] = 10;/* set the options */ tcsetattr(fd, TCSANOW, &options);
int /* O - 0 = MODEM ok, -1 = MODEM bad */ init_modem(int fd) /* I - Serial port file */ {char buffer[255]; /* Input buffer */char *bufptr; /* Current char in buffer */int nbytes; /* Number of bytes read */int tries; /* Number of tries so far */ for (tries = 0; tries < 3; tries ++){/* send an AT command followed by a CR */ if (write(fd, "AT\r", 3) < 3) continue;/* read characters into our string buffer until we get a CR or NL */bufptr = buffer;while ((nbytes = read(fd, bufptr, buffer + sizeof(buffer) - bufptr - 1)) > 0){bufptr += nbytes;if (bufptr[-1] == '\n' | bufptr[-1] == '\r')break;}/* nul terminate the string and see if we got an OK response */*bufptr = '\0';if (strncmp(buffer, "OK", 2) == 0)return (0);}return (-1); }
标准调制解调器命令 †
通过ATD命令可以拨打一个指定号码。除过号码和分隔符(-)以外,你还可以指定以音频("T")或者脉冲("P")方式拨号,暂停一秒(",")和等待拨号音("W"):
ATDT 555-1212 ATDT 18008008008W1234,1,1234 ATD T555-1212WP1234
NO DIALTONE BUSY NO CARRIER CONNECT CONNECT baud
通过ATH命令可以让调制解调器挂断。因为,调制解调器如果在“命令”模式的话,你可能就不能打普通电话了。
如果DTR信号线掉了的话,大部分调制解调器也会挂断。你可以将波特率设置成0并且持续至少1秒来做到这一点。再次让DTR掉落同样也可以把调制解调器重新拉回命令模式。
调制解调器成功挂断以后,它会回复一个"NO CARRIER"回来。如果调制解调器仍然保持连接,它则会发送"CONNECT"或者"CONNECT baud"这样的消息。
通过ATZ命令可以重置调制解调器。重置之后它会回复字符串"OK"。
首先,也是最重要的一点,千万不要使用回声输入(input echoing)。回声输入会导致调制解调器和计算机之间产生反馈循环。
其次,当发送调制解调器命令时,命令必须以回车(CR)而不是换行(NL)结束。C语言中回车的字符常量是"\r"。
最后,处理调制解调器通讯的时候,要一定保证你使用了调制解调器支持的波特率。虽然大多数调制解调器都支持自动探测波特率,但你也会注意到某些(通常是19.2kbps或者比较老的调制解调器)有局限性。
高级串口编程 †
所谓高级串口编程其实说的就是使用更直接的底层的ioctl(2)和select(2)系统调用来操作串口。
串口的ioctl †
前文中曾经提到使用tcgetattr和tcsetattr函数来配置串口。UNIX环境下,这些函数都是使用ioctl(2)系统调用来实现的。
int ioctl(int fd, int request, ...);
显然,fd参数对于串口编程来说就是串口设备文件的文件描述符咯。而request参数是在<termios.h>头文件中定义的常量,而且一般不会超出下表所列的范围。
REQUEST | 描述 | POSIX函数 |
TCGETS | Gets the current serial port settings. | tcgetattr |
TCSETS | Sets the serial port settings immediately. | tcsetattr(fd, TCSANOW, &options) |
TCSETSF | Sets the serial port settings after flushing the input and output buffers. | tcsetattr(fd, TCSAFLUSH, &options) |
TCSETSW | Sets the serial port settings after allowing the input and output buffers to drain/empty. | tcsetattr(fd, TCSADRAIN, &options) |
TCSBRK | Sends a break for the given time. | tcsendbreak, tcdrain |
TCXONC | Controls software flow control. | tcflow |
TCFLSH | Flushes the input and/or output queue. | tcflush |
TIOCMGET | Returns the state of the "MODEM" bits. | None |
TIOCMSET | Sets the state of the "MODEM" bits. | None |
FIONREAD | Returns the number of bytes in the input buffer. | None |
取得控制信号 †
TIOCMGET ioctl可以取得当前调制解调器的状态位。这个状态位囊括了除去RXD和TXD信号线的所有RS-232信号,这些都在下表中列出。
常量 | 描述 |
TIOCM_LE | DSR (data set ready/line enable) |
TIOCM_DTR | DTR (data terminal ready) |
TIOCM_RTS | RTS (request to send) |
TIOCM_ST | Secondary TXD (transmit) |
TIOCM_SR | Secondary RXD (receive) |
TIOCM_CTS | CTS (clear to send) |
TIOCM_CAR | DCD (data carrier detect) |
TIOCM_CD | Synonym for TIOCM_CAR |
TIOCM_RNG | RNG (ring) |
TIOCM_RI | Synonym for TIOCM_RNG |
TIOCM_DSR | DSR (data set ready) |
例如下面这个程序片段,你可以通过给ioctl带一个用来保存状态位的整形变量的指针来取得状态位。
#include <unistd.h> #include <termios.h>int fd; int status;ioctl(fd, TIOCMGET, &status);
设置控制信号 †
TIOCMSET ioctl可以设置上面定义的调制解调器状态位。下面的例子展示如何使用它来将DTR信号线设成掉线状态。
#include <unistd.h> #include <termios.h>int fd; int status;ioctl(fd, TIOCMGET, &status); status &= ~TIOCM_DTR; ioctl(fd, TIOCMSET, &status);
可能被设置的状态位取决于操作系统,驱动和正在使用的模式。关于更详细的信息应该去看以下你所使用的操作系统的文档。
英文原文 †
转载于:https://www.cnblogs.com/jimmy1989/p/3545749.html
Linux串口编程详解(转)相关推荐
- Linux串口编程详解
Linux串口编程详解(阻塞模式.非阻塞模式.select函数) 之前一直觉得串口编程很简单,这两天仔细研究后发现串口里的各种参数还挺复杂,稍不注意就容易出错,这里总结一下网上的各种文章及自己的理解与 ...
- Linux网络编程---详解TCP
Linux网络编程---详解TCP的三次握手和四次挥手_shanghx_123的博客-CSDN博客_tcp的协议数据单元被称为 TCP协议详解(TCP报文.三次握手.四次挥手.TIME_WAIT状态. ...
- linux进程文件描述符 vnode,Linux C编程详解:进程原理分析、文件描述符和文件记录表、文件句柄和文件原理...
一.引言 文件操作是Linux C编程中其中的一项核心技术,实际上也相当重要,这里并不是说狭义上的那种文件操作,它也非常有助于理解和学习Linux系统.为什么这样说呢?因为在Unix/Linux的世界 ...
- qt linux 串口eventdriven,详解 Qt 串口通信程序全程图文 (1)
Qt 串口通信程序全程图文 是本文介绍的内容,在Qt中并没有特定的串口控制类,现在大部分人使用的是第三方写的qextserialport类,我们这里也是使用的该类.我们可以去 http://sourc ...
- 6410 实现 linux 串口驱动详解
为了实现串口通信,需要在嵌入式linux下编写相应的驱动程序.在嵌入式系统中,串口被看做终端设备tty.终端设备是unix体系中一个非常重要的对象,内容非常复杂,它是整个unix人机交互的基础,其地位 ...
- linux串口对调,Linux串口调试详解
测试平台 宿主机平台:Ubuntu 16.04.6 目标机:iMX6ULL 目标机内核:Linux 4.1.15 目标机添加串口设备 一般嵌入式主板的默认镜像可能只配置了调试串口,并用于 consol ...
- linux下使用串口调试设备,Linux串口调试详解
测试平台 宿主机平台:Ubuntu 16.04.6 目标机:iMX6ULL 目标机内核:Linux 4.1.15 目标机添加串口设备 一般嵌入式主板的默认镜像可能只配置了调试串口,并用于 consol ...
- Linux 网络编程详解二(socket创建流程、多进程版)
netstat -na | grep "8080" --查看TCP/IP协议连接状态 //socket编程提高版--服务器 #include <stdio.h> #in ...
- Linux 网络编程详解一(IP套接字结构体、网络字节序,地址转换函数)
IPv4套接字地址结构 struct sockaddr_in {uint8_t sinlen;(4个字节)sa_family_t sin_family;(4个字节)in_port_t sin_port ...
- linux can设备,Linux CAN编程详解
最近写了个自认为不错的基于linux socket can程序,主要功能: 程序具备全部CAN功能,包括CAN标准帧/扩展帧接收与发送.CAN总线错误判断.环回等功能 适用基于LINUX SOCKET ...
最新文章
- python转cython_Cython安装与使用入门
- ROS知识【12】:用户的功能包覆盖系统功能包
- Dubbo服务发布调用
- 再见 Typora,这款 Markdown 编辑器开源又免费!
- 数据特征分析-相关性分析
- (八)Hibernate的一对多关联关系
- PyQt5将ui文件编译为py文件的方法
- ssms 缺少索引信息_疯象网:都说二十世纪信息值钱,其实二十一世纪的信息更值钱...
- RDD之一:总体介绍
- 通达OA 指纹考勤机接口 源代码
- 阜阳智慧城市建设居全国地市级城市第11位
- TOMCAT安装指南
- 双引号后面要加句号吗_引号里应不应该用句号,双引号后的句号在前还是在后?...
- 【三】rabbitmq消费者ACK机制message acknowledgment
- python笔记三之面向对象(继承,封装,多态)
- js 除了自己获取其他所有兄弟节点
- 响应式网页设计的20个误区
- cmd命令生成webservice_根据wsdl文件生成WebService客户端代码
- DFSGSDGHSDGSEDFG
- 聊天机器人简介与体验网址
热门文章
- android流式布局实现sku,[Kotlin协程] 回调地狱的一种解决思路
- Orthanc+OHIF DICOM Viewer最佳Dicom解析、在线浏览实践指南(解决方案)
- python接口自动化测试二十六:使用pymysql模块链接数据库
- centos 6.9修改系统默认字符集
- js数字格式化千分位格式
- webpack打包vue项目IE报错,“对象不支持“use”属性或方法”
- 省选专练SCOI2015小凸想跑步
- Struts2.0中ActionInvocation使用
- 从远程库克隆(转载)
- 2012/7/25Extjs学习随笔