POSIX操作系统串行编程指南.docx
- 文档编号:22906395
- 上传时间:2023-04-29
- 格式:DOCX
- 页数:48
- 大小:52.51KB
POSIX操作系统串行编程指南.docx
《POSIX操作系统串行编程指南.docx》由会员分享,可在线阅读,更多相关《POSIX操作系统串行编程指南.docx(48页珍藏版)》请在冰豆网上搜索。
POSIX操作系统串行编程指南
POSIX操作系统串行编程指南
5thEdition,3rdRevision
Copyright1994-2003byMichaelR.Sweet
允许拷贝,分发或在GNU自由文档许可(Version1.2或任何更新的由自由软件基金会发布的版本)的条件下的修改,不可有任何章节的变化,额外的开头和结尾文字。
一份许可包含在附录C,GNU自由文档许可.
目录
介绍
∙许可
∙组织
第一章,串行通讯基础
∙什么是串行通讯?
∙什么是RS-232?
o信号定义
∙异步通讯
o什么是全双工和半双工?
o流控制
o什么是中断?
∙同步通讯
∙访问串口
o串口文件
o打开一个串口
o写数据到端口
o从端口读取数据
o关闭串口
第二章,设置串口
∙POSIX终端接口
o控制项
o本地项
o输入项
o输出项
o控制字符
第三章,MODEM通讯
∙什么是MODEM?
∙与一MODEM设备通讯
o标准MODEM指令
o见MODEM通讯问题
第四章,高级串口编程
∙串口IOCTLs
o获得控信号
o设置串口控制信号
o获得可用的字节数目
∙从一串口选择输入
oSELECT系统呼叫
o使用SELECT系统呼叫
o使SELECT与X内置库联用
附录A,引脚
∙RS-232引脚
∙RS-422引脚
∙RS-574(IBMPC/AT)引脚
∙SGI引脚
附录B,ASCII控制码
∙控制码
附录C,GNU自由文档许可
附录D,修改历史
∙版本5,第3次修订
介绍
POSIX操作系统串行编程指南将教会你如何成功、有效和可移植地在你的UNIX?
工作站或PC上编程。
每章提供的编程样例使用POSIX(UNIX可移植标准)终端控制函数,少量修改就可以运行于IRIX®,HP-UX,SunOS®,Solaris®,DigitalUNIX®,Linux®,和许多其它的UNIX操作系统。
你将发现在不同操作系统之间的最大差别是串口设备和锁定文件的名字。
许可
在GNU自由文档许可(版本1.2或更新的,由自由软件基金发布的版本)的条件下,允许复制、分发或修改这个文档;不能改变章节,不能有开头和结尾的附加文本。
在附录C,GNU自由文档许可中有一份许可复制,作为参考。
组织
这篇指南由以下章节和附录组成:
∙第一章,串行编程基础
∙第二章,配置串口
∙第三章,与MODEM通讯
∙第四章,高级串口编程
∙附录A,RS-232引脚
∙附录B,ASCII控制码
∙附录C,GNU自由文档许可
∙附录D,修改历史
第一章,串行通讯基础
本章简单介绍串口通信,RS-232及其它在计算机上使用的标准。
并介绍如何用C程序来访问串口的内容。
什么是串行通讯?
计算机一次传输一或多位的信息(数据)。
串行是指一次传输一位数据。
串行通讯包括了大多数的网络设备、键盘、麦克风,调制解调器和终端。
当进行串行通讯时,你传送或接受的每个字(例如:
字节或字符)是以每次一位传输的。
每位或者为on或者off。
有时你也能听到以mark表示on状态和space表示off状态。
串行数据的速度常表示为比特每秒("bps")或波特率("波特")。
这只是用于表示每秒能够传送的1和0的数量。
追溯到计算机时代的早期,300波特被认为是很快的速度,但今天的计算机能够控制RS-232速度高达430,800波特!
当波特率超过1,000,你通常将看到速度被表示为千波特,或kbps(例如9.6k,19.2k等等)。
对于超过1,000,000的速度表示为兆波特,或者Mbps(例如1.5Mbps)。
当提及串行设备或端口的时候,他们被表明数据通讯设备("DCE")或者数据终端设备("DTE")。
这之间的差别很简单每对信号,例如传送和接受,都需要交换。
当连接两个DTE或两个DCE接口到一起的时候,需要使用一个串行null-MODEM缆线或适配卡来交换信号对。
什么是RS-232?
RS-232一标准的串行通讯电气接口,由ElectronicIndustriesAssociation("EIA")定义。
RS-232实际分为三部分(A,B和C),每部分都定义了不同的on与off间的电压等级。
最为常用的是RS-232C,它定义mark(on)一位电压在-3V到-12V之间和space(off)一位在电压+3V到+12V之间。
RS-232C定义这些信号可以传输达25英尺(8米)有效。
只要波特率足够低,你通常能够传送更长的距离。
除了输入和输出数据的引线,还有提供时间,状态和握手信号的引线:
表1-RS-232引脚定义
Pin
描述
Pin
描述
Pin
描述
Pin
描述
Pin
描述
1
EarthGround
6
DSR-DataSetReady
11
未定义
16
SecondaryRXD
21
SignalQualityDetect
2
TXD-TransmittedData
7
GND-LogicGround
12
SecondaryDCD
17
ReceiverClock
22
RingDetect
3
RXD-ReceivedData
8
DCD-DataCarrierDetect
13
SecondaryCTS
18
未定义
23
DataRateSelect
4
RTS-RequestToSend
9
Reserved
14
SecondaryTXD
19
SecondaryRTS
24
TransmitClock
5
CTS-ClearToSend
10
Reserved
15
TransmitClock
20
DTR-DataTerminalReady
25
未定义
其它两个你可能也看到过的串行接口标准是RS-422和RS-574。
RS-422使用低电压和微分信号,允许线缆长度到1000英尺(300米)。
RS-574定义了9-pinPC串行接口和电压。
信号定义
RS-232标准定义了18种不同的串行通讯信号。
当然,在UNIX环境下只有6种。
GND-LogicGround逻辑地
学术上而言,逻辑地不是个信号,但没有它,其它信号都不能工作。
简而言之,逻辑地作为参考电压,从而使电子器件知道某个电压是正或负。
TXD-TransmittedData传送数据
TXD信号传送数据从你的工作站到计算机或在另一端的设备(例如MODEM)。
一个mark电压被解释为1,与此同时一space电压被解释为0。
RXD-ReceivedData接受数据
RXD信号传送数据从计算机或另一端的设备到你的工作站。
类似TXD,mark和space电压相应地被解释为1和0。
DCD-DataCarrierDetect载波侦听
DCD信号接受你的串行电缆另一头的计算机或其它设备信号。
一个space电压表示计算机或设备当前连接着或在线。
DCD并不总可用或存在。
DTR-DataTerminalReady数据终端准备好
DTR信号由你的工作站产生,告诉另一端的计算机或设备你准备好了(一个space电压)或者没有(一个mark电压)。
当你在工作站上打开串行接口时,DTR总是自动有效。
CTS-ClearToSend允许发送
CTS信号接受自串行缆线另一端。
一个space电压表明可以从你的工作站发送更多的串行数据。
CTS通常被用作控制从你的工作站发往另一端的串行数据。
RTS-RequestToSend要求发送
RTS信号被你的工作站设置为space电压表明有更多的数据等待传送。
类似CTS,RTS帮助控制你的工作站和另一端的计算机或设备间的数据流。
多数工作站始终保持这个信号为space电压。
异步通讯
为使计算机理解进入它的串行数据,它需要一些途径决定那里是字符的开始和结束。
本指南仅讨论异步串行数据。
在异步模式下,串行数据线保持在mark
(1)状态,直到有字符传送。
一位起始start位,字符内容的每一位,一位可选的校验位,以及一位或一位半的终止位。
起始位始终是一个space(0),从而告诉计算机新的串行数据到来。
数据能够在任何时候传送或接受,所以称做异步。
图1--异步数据通讯
可选的校验是一个简单数据位的加和,表明了数据位包含偶数或奇数个1。
如果是偶校验,当在字符中的1是偶数个数时,校验位为0。
如果是奇校验,当字符中的1是奇数个时,校验位为0。
你可能也听说过space校验,mark校验,和无校验。
Space校验意味着校验位始终为0,而mark校验意味着校验位始终为1。
无校验意味校验不存在或不传输。
余下的被称为停止位。
这可以是1,1.5,或2位停止位在字符之间,始终是1。
停止位原先是用来给计算机时间处理前面的字符的,但现在只是用来同步计算机和接收字符。
异步数据格式通常表示为"8N1","7E1",诸如此类。
它们相应地表示"8位数据,无校验,1位停止"和"7位数据,偶校验,1位停止"。
什么是全双工与半双工?
全双工表明计算机能够同时接受和发送数据-有两个分离的数据通道(一个输入,一个输出)。
半双工表明计算机不能同时接受和发送数据。
通常这意味着只有一个数据通道用来通讯。
这并不意味着一些RS-232信号没有使用。
而通常是表明通讯链路使用了不同于RS-232的标准,而它们不支持全双工操作。
流控制
通常在两个串口间传送数据时,需要控制数据流。
这可能是由于通讯连接媒介、一个串行接口、或某些存储介质的限制。
两种方法通常用于异步数据。
第一个方法叫作"软件"流控制,使用特殊字符开始(XONorDC1,021octal)或停止(XOFForDC3,023octal)数据流。
这些字符由AmericanStandardCodeforInformationInterchange("ASCII")定义。
虽然这些代码在传送文本信息时十分有用,但没有特殊的编程手段,在传输其它类型信息的时候就不能使用了。
第二个方法叫做"硬件"流控制,使用RS-232CTS和RTS信号代替特殊字符。
当准备好接受更多的数据后,接受方设置CTS为space电压;而设置为mark电压,表示没有准备好。
同样的,准备好发送更多数据后,发送方将RTS设置为space电压。
因为硬件流控制使用独立的信号,所以同样情况下,它要比需要传送更多位信息的软件流控制快许多。
CTS/RTS流控制并不被所有的硬件或操作系统支持。
什么是中断?
N正常的一个接受或发送数据信号保持在mark电压知道一个新的字符被传送。
如果信号掉到space电压一段较长时间,通常是1/4到1/2秒,就说出现了个中断。
中断有时是用于重置通讯线或改变通讯硬件的模式,例如MODEM.第三章,MODEM通讯更为详细地讨论了这些。
同步通讯
不同于异步数据,同步数据表现为连续数据流。
为在线读取数据,计算机必须提供或接受一比特同步时钟,从而使接受和发送同步。
即便是同步情况下,计算机仍然必须标明数据的开始。
最通常的做法是使用数据包协议,例如串行DataLinkControl("SDLC")或High-SpeedDataLinkControl("HDLC")。
每个协议都定义了表示数据包开始和结束的一定比特序列。
且都定义了没有数据时的比特序列。
这些比特序列使得计算机能够看到数据包的起始。
因为同步协议不使用每字符的同步位,它们通常提供比异步通讯至少高25%的效率,适合于在两个以上的串行接口环境下,远距离网络操作与配置。
尽管同步通讯的速度优势,多数RS-232硬件仍不支持,主要是由于额外的硬件和软件需求。
访问串行端口
象所有的设备一样,UNIX提供设备文件以访问端口。
要访问一个串行端口,你只要简单地打开相应的设备文件。
串行端口文件
每个串行端口在UNIX系统上有一个或多个设备文件(文件在/dev目录下)相关联:
表2-串行端口设备文件
系统
端口1
端口2
IRIX®
/dev/ttyf1
/dev/ttyf2
HP-UX
/dev/tty1p0
/dev/tty2p0
Solaris®/SunOS®
/dev/ttya
/dev/ttyb
Linux®
/dev/ttyS0
/dev/ttyS1
DigitalUNIX®
/dev/tty01
/dev/tty02
打开串行端口
由于串行端口是一个文件,open
(2)函数正是用来访问它的。
存在的阻碍是UNIX下设备文件经常不允许普通用户访问。
工作的范围包括改变有疑问的文件访问许可,以超级用户(root)运行你的程序,或使你的程序设置userid,从而它能以设备文件的拥有者运行(由于显著的安全性问题,不建议用...)
现在我们假设文件能够被所有的用户访问。
列表1表示了在运行Linux的PC上打开串行端口一的例子。
列表1-打开一个串行端口。
#include
#include
#include
#include
#include
#include
/*
*'open_port()'-OpenSerialport1.
*
*Returnsthefiledescriptoronsuccessor-1onerror.
*/
int
open_port(void)
{
intfd;/*Filedescriptorfortheport*/
fd=open("/dev/ttyS0",O_RDWR|O_NOCTTY|O_NDELAY);
if(fd==-1)
{
/*
*Couldnotopentheport.
*/
perror("open_port:
Unabletoopen/dev/ttyS0-");
}
else
fcntl(fd,F_SETFL,0);
return(fd);
}
其它系统可能需要不同的设备文件名,然而代码是一样的。
Open选项
你将注意到我们打开设备文件时,除了读写模式外,还使用了两个其它的标志:
fd=open("/dev/ttyS0",O_RDWR|O_NOCTTY|O_NDELAY);
O_NOCTTY标志告诉UNIX,该程序不想成为那个端口的"控制终端"。
如果你不指明这个,任何输入(例如键盘中断信号,诸如此类)都会影响你的进程。
象getty(1M/8)之类的程序在启动登录进程时,设置这一特性,但通常用户的程序不想有这种行为。
O_NDELAY标志告诉UNIX,该程序不关心DCD信号的输入状态-即无论另一端端口是否启用和运行。
如果你不指明这个标志,你的进程将休眠,直到DCD信号线是space电压。
写数据到端口
写数据到端口是简单的--只需要使用write
(2)系统呼叫去传送数据:
n=write(fd,"ATZ\r",4);
if(n<0)
fputs("write()of4bytesfailed!
\n",stderr);
write函数返回发送的字节号--或1如果发现了任何错误。
通常唯一的错误你可能运行进入是EIO,即当MODEM或数据链路丢失CarrierDetect(DCD)线。
该条件允许你保持直到端口关闭。
从端口读数据端口
从端口读取数据有一点小骗术。
当你以行数据模式操作端口,每个read
(2)系统调用都会返回,而不论多少字符实际存在于串行输入缓冲中。
如果没有字符存在,调用将阻塞(等待)直到有字符进入,或超时,或错误出现。
read方法能够用以下方法获得立即的返回:
fcntl(fd,F_SETFL,FNDELAY);
当端口没有接受到字符时,FNDELAY项使得read函数返回0。
要实现标准的(阻塞)行为,调用fcntl()而不带FNDELAY项:
fcntl(fd,F_SETFL,0);
这同样可以在带O_NDELAY项打开串行端口后使用。
关闭串行端口
要关闭串行端口,只要使用close系统调用:
close(fd);
关闭串行端口通常同时将DTR信号设置为低,这将使多数MODEM挂机。
第二章,设置串行端口
本章讨论如何通过POSIXtermios接口,在C语言中设置端口。
POSIX终端接口
多数系统支持通过POSIX终端(串行)接口来改变,例如波特率,字符尺寸,等参数。
你需要做的第一件事情是引入文件
两个最重要的POSIX函数函数是tcgetattr(3)和tcsetattr(3)。
这些获得和设定相关的终端特性,你要提供一个termios结构的指针包含所有可用的串行设置项:
表3-Termios结构成员
成员
描述
c_cflag
控制项
c_lflag
线路项
c_iflag
输入项
c_oflag
输出项
c_cc
控制字符
c_ispeed
输入波特(新接口)
c_ospeed
输出波特(新接口)
控制项
c_cflag成员控制波特率、数据位、校验、停止位和硬件流控制。
所有支持的设置都有常数对应。
表4-c_cflag成员对应的常数
常数
描述
CBAUD
波特率掩码
B0
0波特(dropDTR)
B50
50波特
B75
75波特
B110
110波特
B134
134.5波特
B150
150波特
B200
200波特
B300
300波特
B600
600波特
B1200
1200波特
B1800
1800波特
B2400
2400波特
B4800
4800波特
B9600
9600波特
B19200
19200波特
B38400
38400波特
B57600
57,600波特
B76800
76,800波特
B115200
115,200波特
EXTA
外部速率时钟
EXTB
外部速率时钟
CSIZE
位数据位掩码
CS5
5位数据位
CS6
6位数据位
CS7
7位数据位
CS8
8位数据位
CSTOPB
2位停止位(不指明是1位)
CREAD
接收有效
PARENB
校验位有效
PARODD
使用奇校验代替偶校验
HUPCL
最后关闭后,挂起(降低DTR)
CLOCAL
本地线-不改变端口的"拥有者"
LOBLK
阻塞方式工作控制输出
CNEW_RTSCTS
CRTSCTS
采用硬件流控制(在所有的平台上都不支持)
c_cflag成员包含两个选项必须总是有效,CLOCAL和CREAD。
这些将保证你的程序不会成为端口的所有者,从而妨碍控制工作和挂起信号,并使串行接口驱动将读取进入的数据。
波特率常数(CBAUD,B9600,等等。
)是用来老式接口,那些缺少c_ispeed和c_ospeed成员的。
参考下一章关于用于波特率设定的POSIX函数。
决不直接初始化c_cflag(或其它)成员;你应该总是用AND,OR和NOT比特操作来设定或清除成员中的比特位。
不同的操作系统版本(甚至是补丁)能也确实使用不同方式处理比特位,所以使用比特操作符,能够使你避免在使用一个新的串行设备要用的比特位时遭到残败。
设置波特率
波特率存储于不同的位置依赖于具体系统。
旧版本接口存储波特率在c_cflag成员中,使用一个表4中的波特率常数,而新的实现提供了c_ispeed和c_ospeed成员来包含波特率数值。
cfsetospeed(3)和cfsetispeed(3)函数用于提供波特率设置到termios结构中,而不论其下的操作系统系统接口如何。
典型地你使用列表2来设置波特率。
列表2-设置波特率
structtermiosoptions;
/*
*Getthecurrentoptionsfortheport...
*/
tcgetattr(fd,&options);
/*
*Setthe波特ratesto19200...
*/
cfsetispeed(&options,B19200);
cfsetospeed(&options,B19200);
/*
*Enablethereceiverandsetlocalmode...
*/
options.c_cflag|=(CLOCAL|CREAD);
/*
*Setthenewoptionsfortheport...
*/
tcsetattr(fd,TCSANOW,&options);
tcgetattr(3)函数用当前的串行端口设置来填充你的termios结构。
在我们设置了波特率、本地模式和串行数据接收,我们使用tcsetattr(3)选定新的设置。
TCSANOW常数表明所有的改变立即生效而不等待发送或接受的数据结束。
还有其它的参数常数用来等待输出和输入结束或刷新输入输出缓冲。
多数系统不支持端口有不同的输入与输出速率,所以确定设置为相同的值以获得最大的可移植性。
表5-tcsetattr常数
常数
描述
TCSANOW
立即改变,不等待数据结束
TCSADRAIN
等待直到所有的都传完
TCSAFLUSH
刷新输入输出缓冲,然后改变
设置字符尺寸
不同于波特率,没有简便的函数用于设定字符尺寸。
取而代之的是你需要做一点比特掩码的操作来实现。
字符的大小是以位方式设定:
options.c_cflag&=~CSIZE;/*Maskthecharactersizebits*/
option
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- POSIX 操作系统 串行 编程 指南