UART/TTL/RS232学习总结

关于RS232与TTL间的转换

特别注意的是:UART是将计算机的并行信号转换成串行信号的硬件设备,不要简单理解为协议

关于Linux终端①

  Linux在为用户提供对终端设备简洁的读写接口之外,还提供了一组编程接口来对终端进行更精细的控制。下面是用户能够控制的主要功能:

行编辑: 是否允许使用退格键来编辑。

缓存:是立即读取字符,还是等待一段可配置的延迟之后再读取它们。

回显:允许控制字符的回显,例如读取密码时。

回车/换行(CR/LF):定义如何在输入/输出时映射回车/换行符,比如打印\n字符时应该如何处理。

线速:这种功能很少用于PC控制台,但对调制解调器或通过串行线连接的终端就很重要。

标准模式:所有的操作都基于行进行处理,在一个输入行完成前(通常是用户按下回车键之前),终端接口负责管理所有的键盘输入,包括退格键(Backspace)和删除键(Del),应用程序读不到用户的任何输入。这样做是有益的,因为允许用户来纠正输入中的错误直到满意为止。

termios结构

  可以分为以下几个模式:输入模式,输出模式,控制模式,本地模式,特殊控制字符模式。

函数接口原型:②

1
2
3
4
5
6
7
8
9
10
#include <termios.h>
struct termios{
tcflag_t c_iflag;
tcflag_t c_oflag;
tcflag_t c_cflag;
tcflag_t c_lflag;
tcflag_t c_cc[NCCS];
};
int tcgetattr(int fd,struct termios* termios_p);
int tcsetattr(int fd, int ations,const struct trmios* termios_p);

参数action控制修改方式,共有三种修改方式:

TCSANOW:立即对值进行修改。

TCSADRAIN:等当前的值输出完成后再对值进行修改。

TCSAFLUSH:等当前的值输出完成后再对值进行修改,但丢弃还未从read调用返回的当前可用的任何输入。

  特别注意,程序有责任将终端设置恢复到程序开始运行之前的状态,这一点是非常重要的。在kydevmonit的devicesManagerd中该如何做呢?

本地模式

  通过设置termios中的c_lflag成员的标志来对本地模式进行设置。可用于c_lflag成员的宏如下:

ECHO:启用输入字符的本地回显功能。

ECHONL:回显新行符。

ICANON:启用标准输入处理,否则就启用非标准模式。

ISIG:启用信号。

NOFLUSH:禁止清空队列。

TOSTOP:在试图进行写操作之前给后台进程发送一个信号。

ECHOE/ECHOK/IEXTEN:略

输入模式

  输入模式控制输入数据(终端驱动程序从串行口或键盘接收到的字符)在被传递给程序之前的处理方式。设置c_iflag。成员宏如下:

BRKINT:当在输入行中检测到一个终止状态(连接丢失)时,产生一个中断。

IGNBRK:忽略输入行中的终止状态。

ICRNL:将接收到的回车符转换为新行符。

INLCR:将接收到的新行符转换为回车符。

IGNCR:忽略接收到的回车符。

IGNPAP:忽略奇偶校验错误的字符。

INPCK:对接收到的字符进行奇偶校验。

ISTRIP:将所有接收到的字符裁剪为7bit。

IXOFF/IXON:关闭/打开软件流控。

输出模式

  输出模式控制输出字符的处理方式,即由程序发送出去的字符在传递到串行口或屏幕之前是如何处理的。设置c_oflag。成员宏如下:

OPOST:打开输出处理功能。如果没有设置该标志,则所有其他标志则被忽略。

OCRNL:将输出的回车符转换为新行符。

ONLCR:将输出到的新行符转换为回车符。

ONLRET:不输出回车符。

其他略

控制模式

  控制模式控制终端的硬件特性。你通过设置c_cflag成员的标志来对控制模式进行配置。成员宏如下:

CLOCAL:忽略所有调试解调器的状态行。

CREAD:启用字符接收器。

CS5:发送或接收时使用5bit。

CS6:发送或接收时使用6bit。

CS7:发送或接收时使用7bit。

CS8:发送或接收时使用8bit。

CSTOP:每个字符使用两个停止位而不是一个。

CSIZE:对数据的bit位使用掩码。注意,在设置CS数据位时要先屏蔽其他位。c_cflag &= ~CSIZE;

HUPCL:关闭时挂断调制解调器。

PARENB:启用就校验码的生成和检测功能。

PARODD:使用奇校验而不是偶检验。

1
2
3
c_flag &= ~PARENB; // 无校验
c_flag |=(PARODD | PARENB);//奇校验
c_falg &= ~PARENB;c_falg &= ~PARODD;//偶校验

特殊控制字符

这里只说明TIME与MIN值。用于是作为c_cc数组的index:

1
2
3
int TIME,MIN;
c_cc[VTIME] = TIME;
c_cc[VMIN] =MIN;

  TIME与MIN只能用于非标准模式(禁用ICANON标志),两者结合起来共同控制对输入的读取。

  两者的结合分为如下四种情况:

  MIN=0和TIME=0:在这种情况下,read调用总是立即返回,如果有等待处理的字符,它们就会被返回;如果没有字符等待处理,read调用返回0,并且不读取任何字符。

  MIN=0和TIME>1:这种情况下,只要有字符可以处理或者是经过TIME个0.1秒的时间间隔,read调用会返回。如果因为超时而未读到任何字符,read返回0,否则read返回读取的字符数目。

  MIN>0和TIME=0:这种情况下,read调用会一直等待,直到有MIN个字符可以读取时才返回,返回值是读取的字符数量,但文件尾时返回0。

  MIN>0和TIME>0:这种情况下,当read被调用时,它会等待接收一个字符。在接收到第一个字符及后续的每个字符后,一个字符间隔定时器被启动。当有MIN个字符可读或者两个字符的时间间隔超过TIME个0.1秒时,read调用返回。这个功能可用于区分是单独按下了Escape键还是按下了以Escape键开始的功能组合键。但要注意的是,网络通信或处理器的高负载使得类似这样的定时器失去作用。

  通过设置非标准模式与使用MIN和TIME值,程序可以逐个字符地处理输入

终端速度

  设置终端速度直接作用于termios结构,因此要设置新的终端速度,你必须使用tcgetattr获取当前配置,最后使用tcsetattr写回。只有写回后,终端速度才会改变。

1
2
3
4
speed_t cfgetispeed(const struct termios*);
speed_t cfgetospeed(const struct termios*);
int cfsetispeed(struct termios*,speed_t speed);
intccfsetospeed(struct termios*,speed_t speed);

speed的值可设置如下:

B0:挂起终端。

B9600:9600波特率。

B115200:115200波特率。

其他波特率包括B1200,B2400,B19200,B38400等。

其他函数

1
2
3
int tcdrain(int fd); //让调用程序一直等待,直到所有排队的输出都已发送完毕。
int tcflow(int fd, int flowtype);//用于暂停或重新开始输出。
int tcflush(int fd,int in_out_selector);//用于清空输入、输出或者两者都输出。

使用shell命令stty -F <DEVICE> -a可以查看某个设备当前的termios值。

虚拟控制台

  Linux提供一组终端设备来共享PC电脑的屏幕、键盘和鼠标。虚拟控制台通过字符设备文件/dev/ttyN来使用。

  使用命令who或者ps -e你可以查看目前登录进系统的用户,以及在这个虚拟控制台上运行的shell和执行的程序。

  Linux系统通常会在前6个虚拟台上运行一个getty进程,这样用户既可用同一个屏幕、键盘和鼠标在6个不同的虚拟控制台上登录。

伪终端

PTY与pts

参考资料

① Linux程序设计:第4版/(英)马修(Mattew,N.),(英)斯通斯(Stones,R.)著;陈健,宋健健译.——北京:人民邮电出版社,2010.6

② manpage for tcgetattr/tcsetattr