Linux下SerialPort编程详解

标签:
serialport |
分类: linux |
0.2.1:RS-232信号定义
RS-232标准定义串口中18中不同的信号。在这些中仅有6个是在UNIX环境中可用。
GND - 逻辑地
逻辑地不是信号,办事没有它却没有办法操作信号。基本上,逻辑地是一个参考电压已让电子管知道那些事正的和负的。
TXD- 传输数据
TXD信号载波数据从你的工作站到另一端的计算机或者设备(如猫)。一个高电平表示1,一个空电平表示0.
RXD- 接收数据
RXD载波信号将电脑或设备传输到工作站。像TXD,高低电平分别表示1和0.
DCD-数据载波检测
DCD信号接收来自电脑或者其他串口电缆。一个低电平在信号线上表示设备和电脑正在连接。DCD通常没有用。
DTR- 数据终端准备
DTR信号是工作站产生兵告诉计算机或者另一端的设备你正在准备(空电平)或者没有准备(高电平)。DTR能够自动运行当你打开在工作站上的串口。
CTS- 清除发送
CTS信号从其他串口电缆接收数据。
空电平表示已经准备从工作站发送串口数据。CTS通常用来控制从工作站到终端的串行数据流。
RTS- 请求发送
TRS信号设置低电平被工作站用来表示更多的数据准备发送。
像CTS,RTS辅助控制从工作站到计算机和另一端的串口设备的数据流。大部分工作站始终设置这种信号为低电平。
0.3: 异步传输(Asynchronous Communications)
串行数据是1bit为单位发送的,那如何解析这些数据,哪里是某个character的头和尾。下面来看异步传输中如何解决这个问题。
在异步传输模式,在没有数据传输时,保持低电平。有数据传输时,会先产生一个高电平作为起始位(start
bit).后面跟数据bit. 然后是可选的校验位(Parity bit).
最后是一个或多个停止位(Stop bits).
http://s3/mw690/001Ld2gwgy6XtTcB45Qf2&690
MARK=1
起始位:Start
校验位,Parity Bit :单纯的相加,看合是奇数还是偶数。通常,校验位有以下几种选择:
A:Even Parity.偶校验。(0:表示数据位中有偶数个1)
B:Odd Parity. 奇校验。(0: 表示数据位中有奇数个1)
C:Space Parity:校验位总是0.
D: Mark Parity: 校验位总为1.
E: No Parity: 无校验位。
停止位,Stop Bits:在连个字符间可以为1,1.5,或者2停止bits并且他们的值为1(MARK).
0.4: 全双工,半双工:
全双工是指计算机能够同时接收和传输数据-有两个单独的数据信道(一进一出)。
半双工是指计算机不能同时接收和传输数据。通常这意味着只有单一的信道通信。RS232并不支持全双工。
0.5:同步传输:
同步通信表现为一个恒定的数据流。读取线上的数据,电脑必须提供或者接收一个同步时钟以至发送和接收同步。尽管同步通信的高速率优点,但是大多数RS-232硬件并不支持,因为还需要额外的硬件和软件。
0.6: Flow Control:
Flow Control(数据流控制)作用,数据在两个串口之间传输时,常常会出现丢失数据的现象,或者两台计算机的处理速度不同,如台式机与单片机之间的通讯,接收端数据缓冲区已满,则此时继续发送来的数据就会丢失。当接收端数据处理不过来时,就发出“不再接收”的信号,发送端就停止发送,直到收到“可以继续发送”的信号再发送数据。因此流控制可以控制数据传输的进程,防止数据的丢失。
A:硬件流控制
B:软件流控制
1. 设备的打开:
Linux系统下,字符设备和块设备都是文件形式存在。所以打开串口设备,也像打开文件一样。
设备名通常为: /dev/ttyS0-/dev/ttySn.
USB转RS232则为: /dev/ttyUSB0-/dev/ttyUSBn
fd = open( port, O_RDWR|O_NOCTTY|O_NDELAY);
if (fd == -1)
{
这个打开文件的方式很奇特,除了常用的O_RDWR,
还使用了
O_NDELAY的通常使用方式是:将文件以非阻塞模式打开,即在检测不到数据时立刻返回。但后面却立刻变回到阻塞模式。什么理由呢?
O_NDELAY实际上是告知系统,程序不在乎DCD(数据载波检测),即端口的另一端是否插入设备并up并不关心。如果不设置,程序会sleep直到DCD信号变为SPACE(0)
O_NOCTTY:
告知系统,程序不希望成为"controlling
terminal".
2. 设备的配置:
串口通讯中,隐藏最多细节,最容易出错的地方就是设备的配置。现在详细学习如下:
POSIX Terminal(Serial) Interface 支持用户修改参数。其中最重要的两个function是:
tcgetattr(3)和tcsetattr(3).用来得到和设置Terminal (Serial) Attriabute.
int tcgetattr(int fd, struct termios *termios_p);
int tcsetattr(int fd, int
optional_actions,
其中关键是:struct termios,它至少要包含以下项目:
Member | Description |
---|---|
c_cflag | Control options |
c_lflag | Line options |
c_iflag | Input options |
c_oflag | Output options |
c_cc | Control characters |
c_ispeed | Input baud (new interface) |
c_ospeed | Output baud (new interface) |
Control Modes,:
包含:baud rate, data
bit个数, parity, stop bits, Hardware
Constant | Description |
---|---|
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) |
这其中,CLOCAL
绝对不要直接初始化和修改c_cflag等设置。二是应该使用AND,OR,NOT操作去设置和clear bit去修改。因为不同OS的成员并不相同,所以使用位操作可以避免错误。
2.1. Baud rate(波特率)的设置:
CBAUD, B9600等常量是用在老接口之上的,那时候缺少c_ispeed和c_ospeed成员。当前设置baud rate可以使用POSIX function.
int cfsetispeed(struct termios *termios_p, speed_t speed);
int cfsetospeed(struct termios *termios_p, speed_t speed);
典型的设置波特率的代码如下:
struct termios options;
// Get the current options for the port...
tcgetattr(fd, &options);
cfsetispeed(&options, B19200);
cfsetospeed(&options, B19200);
options.c_cflag |= (CLOCAL | CREAD);
tcsetattr(fd, TCSANOW, &options);
2.2: 设置Character Size, Parity, Stop Bit。
与设置Baud rate不同,这支数据位,校验位,停止位没有方便的函数操作,只能按位操作。
数据位:
options.c_cflag &= ~CSIZE;
options.c_cflag |=
CS8;
校验位:
无校验
options.c_cflag &= ~PARENB;
Even校验(偶校验)、
options.c_cflag &= ~PARENB;
options.c_cflag &= ~PARODD;
ODD校验:
options.c_cflag &= ~PARENB;
options.c_cflag &= PARODD;
停止位:
1停止位:
options.c_cflag &= ~CSTOPB;
2停止位:
options.c_cflag &= CSTOPB;
2.3: 数据流控制:
硬件数据流:
某些版本的UNIX支持使用CTS和RTS信号线的硬件流控。
options.c_cflag |=
CNEW_RTSCTS;
停止硬件流控l:
options.c_cflag &=
~CNEW_RTSCTS;
软件数据流控制:
Enable XON,XOFF:
options.c_iflag |= (IXON | IXOFF | IXANY);
Disable:
options.c_iflag &= ~(IXON | IXOFF | IXANY);
2.4: Local Options:
Local modes c_lflag: 用来设置串口驱动管理如何输入字符。
2.5:Input Options:
设置如何处理从端口中读出的数据。
这里有几个项目要注意:INLCR, 和0x0D, 0x0A有关。
3. Read, Wirte。
4. 异常查找:
4.1:
在用write发送数据时没有键入回车,信息就发送不出去,这主要是因为我们在输入输出时是按照规范模式接收到回车或换行才发送,而更多情况下我们是不必键入回车或换行的。此时应转换到行方式输入,不经处理直接发送,设置如下:
Opt.c_lflag &= ~ (ICANON | ECHO | ECHOE | ISIG);
4.2:发送字符0X0d的时候,往往接收端得到的字符是0X0a,原因是因为在串口设置中c_iflag和c_oflag中存在从NL-CR和CR-NL的映射,即串口能把回车和换行当成同一个字符
// Disable 0x0D<-->0x0A
options.c_iflag &= ~(INLCR | ICRNL | IGNCR);
options.c_oflag &= ~(ONLCR | OCRNL);
资源文档:
http://digilander.libero.it/robang/rubrica/serial.htm#CONTENTS