Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1216671
  • 博文数量: 404
  • 博客积分: 10011
  • 博客等级: 上将
  • 技术积分: 5382
  • 用 户 组: 普通用户
  • 注册时间: 2008-09-03 16:29
文章存档

2010年(40)

2009年(140)

2008年(224)

我的朋友

分类: LINUX

2009-03-24 09:24:11

6.6  串口通信的基本概念

Linux系统通过串口终端设备文件来实现对串口设备的访问。串口是计算机上常见的接口,往往用于调试设备和连接一些对传输速度要求不高的设备。本节将介绍如何在Linux系统中编写C程序来访问串口,并进行读写操作。

6.6.1  串行通信与串口定义

串口的数据传输是以串行方式进行的。串口在数据通信中,一次只传输一个比特的数据。串行数据的传输速度用bps或波特率来描述。串行通信设备也被称为数据通信设备(DCE,Data Communication Equipment)或数据终端设备(DTE,Data Terminal Equipment)。

常用的串口是RS-232C接口(又称EIA RS-232C),是一个25脚的DB25连接器。RS-232C定义的传输长度为8m,具体的引脚定义如表6.8所示。

表6.8   RS-232C引脚定义

   

   

   

   

2

发送数据

TXD

DTEDCE

DTE发送数据

3

接收数据

RXD

DTEDCE

DTE接收数据

4

请求发送数据

RTS

DTEDCE

DTE请求DCE切换到发送方式

5

允许发送数据

CTS

DTEDCE

DCE通告DTE线路准备好,可以发送数据

6

数据设备准备好

DSR

DTEDCE

DCE准备好

7

接地

 

 

信号地

8

载波检测

DCD

DTEDCE

DCE接收到远程载波

20

数据终端准备好

DTR

DTEDCE

DTE准备好

22

振铃提示

RI

DTEDCE

DCE与线路接通,开始振铃

6.6.2  串口通信的基本参数

串口一般用于ASCII码字符的传输。最基本的串口通信只需3个引脚即可实现,分别是地线、接收和发送。其他引脚用于握手协议。由于串口通信属于异步通信,可以在进行通信时不使用握手协议。

为了正确实现串口间的通信,必须对串口的参数进行设置。图6.13所示为使用Windows中的超级终端进行串口通信时设置参数的界面。参数具体说明如下:

 

图6.13  串口通信参数设置

1.每秒位数
即波特率。该参数表示每秒传输的比特数。例如,对于发送端,2400波特率表示每秒发送2400bit;对于接收端而言,2400波特率意味着串口通信在数据线上的采样率为2400Hz。由于波特率和距离之间成反比,距离相隔很近的设备间才可以实现高波特率通信。

2.数据位
表示通信中实际数据位的参数。在计算机发送的数据包中,实际的数据往往不会是8位。在串口通信中,可以选择5、6、7或8位,如图6.14所示。设定数据位主要考虑所要传输的数据内容。如果要传输的是标准的ASCII码,由于ASCII码的范围是0~127,因此使用7位就可以了。如果要传输的是扩展ASCII码,其范围是0~255,必须使用8位。当然,7位或8位数据位中不仅仅是数据,还包括开始/停止位、数据位以及奇偶校验位等。

3.奇偶校验位
该位用于串口通信中的简单检错。奇偶校验位主要有:偶校验、奇校验、标记、空格的方式,也可以不使用校验,如图6.15所示。奇/偶校验是通过统计数据中高位或低位的个数来实现校验的。而标记、空格并不真正检测数据,只是通过简单的置位来实现对数据的检测。通过置位方式,可以判断出是否存在噪声干扰数据通信或数据传输,以及接收是否存在不同步的现象。

 

          图6.14  数据位设置                      

 

图6.15  奇偶校验位设置

4.停止位
停止位用于标志该数据包数据结束,可以取1位、1.5位或2位,如图6.16所示。停止位不仅仅用于数据包的传输结束标志,还提供了计算机之间校正同步时钟的机会。用于停止位的位数越多,不同时钟同步的容忍程度越大。但是由于停止位占用了数据空间,过多的停止位将导致数据传输速度的下降。

5.数据流控制
通过串口传输数据时,由于计算机之间处理速度或其他因素的影响,会造成丢失数据的现象。例如,台式机与单片机之间的通信,接收端数据缓冲区已满的情况下,继续收到数据,新发送来的数据就会由于无法处理造成丢失。数据流控制用于解决这个问题。通过控制发送数据的速度,确保数据不会出现丢失。

数据流控制可以分为软件流控制(Xon/Xoff)和硬件流控制,如图6.17所示,也可以选择不使用数据流控制。软件流控制使用特殊的字符作为启动或停止的标志。而硬件流控制通过使用硬件信号(CTR/RTS)来实现。使用硬件流控制时,在接收端准备好接收数据后,设定CTS为1,否则CTS为0。同样,如果发送端准备好要发送数据,则设定RTS为1;如果还未准备好,设置CTS为0。

 

图6.16  停止位设置                     

 

图6.17  数据流控制设置

6.7  在Linux下进行串口通信

在Linux系统中,串口设备是通过串口终端设备文件来访问的,也就是通过访问/dev/ttyS0、/dev/ttyS1、/dev/ttyS2、/dev/ttyS3这些设备文件实现对串口的访问。对串口进行读写要经过下面几个步骤。

6.7.1  打开串口

与打开文件类似,打开串口同样使用open函数。注意对于串口的打开操作,必须使用O_NOCTTY参数。该参数表示:如果打开的是一个终端设备,程序不会成为对应这个端口的控制终端。如果没有使用该标志,任何一个输入(例如,键盘中止信号等)都将影响进程。具体代码如下:

    

#include
#include
#include

int main(void){

int fd;

//使用open函数打开串口,获得串口设备文件的文件描述符
if((fd=open("/dev/ttyS0",O_RDWR| O_NOCTTY))==-1){
perror("Cannot open the serial port");
return 1;
}


}

6.7.2  设置串口通信参数

串口通信参数指的是波特率、数据位、奇偶校验位和停止位。对串口实现控制的时候同样要用到termio结构体。下面将结合具体的代码说明如何设置这些参数。

1.波特率设置
获得端口波特率信息是通过cfgetispeed函数和cfgetospeed函数来实现的。cfgetispeed函数用于获得结构体termios_p中的输入波特率信息,而cfgetospeed函数用于获得结构体termios_p中的输出波特率信息。这两个函数的具体信息如表6.9所示。

表6.9   cfgetispeed函数和cfgetospeed函数

头文件

函数形式

speed_t cfgetispeed(const struct termios *termios_p);

speed_t cfgetospeed(const struct termios *termios_p);

返回值

成功

失败

是否设置errno

返回termios_p结构中的输入/输出端口的波特率

−1

cfsetispeed函数和cfsetospeed函数用于设置端口的输入/输出波特率。一般情况下,输入和输出波特率是相等的。cfsetispeed函数和cfsetospeed函数的函数声明信息如表6.10所示。

表6.10   cfsetispeed函数和cfsetospeed函数

头文件

函数形式

int cfsetispeed(struct termios *termios_p, speed_t speed);

int cfsetospeed(struct termios *termios_p, speed_t speed);

返回值

成功

失败

是否设置errno

返回termios_p结构中的输入/输出端口的波特率

−1

cfsetispeed函数和cfsetospeed函数会修改结构体termios_p中的波特率信息,其中参数speed可以使用表6.11中所列出的宏。

表6.11   speed参数常用波特率信息 

   

波特率(单位:bit/s

   

波特率(单位:bit/s

B0

0

B1800

1800

B50

50

B2400

2400

B75

75

B4800

4800

B110

110

B9600

9600

B134

134

B19200

19200

B150

150

B38400

38400

B200

200

B57600

57600

B300

300

B115200

115200

B600

600

B230400

230400

B1200

1200

 

 

使用cfsetispeed函数和cfsetospeed函数进行串口波特率设置具体代码如下所示:

    #include     //头文件定义
#include
#include < termios.h >
……
struct termios opt;           /*定义指向termios 结构类型的指针opt*/
……
//获得串口指向termios结构的指针
tcgetattr(fd, &Opt);
cfsetispeed(&opt,B9600 ); /*指定输入波特率,9600bps*/
cfsetospeed(&opt,B9600);/*指定输出波特率,9600bps*/
//将修改后的termios数据设置到串口中
tcsetattr(fd,TCANOW,&Opt);
……

2.数据位
数据位指的是每字节中实际数据所占的比特数。要修改数据位可以通过修改termios结构体中c_cflag成员来实现。CS5、CS6、CS7和CS8分别表示数据位为5、6、7和8。值得注意的是,在设置数据位时,必须先使用CSIZE做位屏蔽。具体设置代码如下:

    

#include     //头文件定义
#include
#include < termios.h >
……
struct termios opt;           /*定义指向termios 结构类型的指针opt*/
.......
//获得串口指向termios结构的指针
tcgetattr(fd, &Opt);

//屏蔽其他标志
Opt.c_cflag&=~CSIZE;
//将数据位修改为8bit
Opt.c_cflag |=CS8;

//将修改后的termios数据设置到串口中
tcsetattr(fd,TCANOW,&Opt);
……

3.奇偶校验位
奇偶校验可以选择偶校验、奇校验、空格等方式,也可以不使用校验。如果要设置为偶校验的话,首先要将termios结构体中c_cflag设置PARENB标志,并清除PARODD标志。如果要设置奇校验,要同时设置termios结构体中c_cflag设置PARENB标志和PARODD标志。如果不想使用任何校验的话,清除termios结构体中c_cflag的PARENB位。表6.12所示为设置奇偶校验的具体方法。

表6.12   设置奇偶校验位

   

无校验

opt.c_cflag &= ~PARENB;

奇校验

opt.c_cflag |= (PARODD | PARENB);

偶校验

opt.c_cflag &= ~ PARENB;

opt.c_cflag &= ~PARODD;

空格

opt.c_cflag &= ~PARENB;

opt.c_cflag &= ~CSTOPB;

下面给出将串口通信的奇偶校验设置为偶校验的例子,具体代码如下:

    #include     //头文件定义
#include
#include < termios.h >
……
struct termios opt;           /*定义指向termios 结构类型的指针opt*/
……
//获得串口指向termios结构的指针
tcgetattr(fd, &Opt);

opt.c_cflag &= ~ PARENB;
opt.c_cflag &= ~PARODD;

//将修改后的termios数据设置到串口中
tcsetattr(fd,TCANOW,&Opt);
……

4.数据流控制
数据流控制指是使用何种方法来标志数据传输的开始和结束。可以选择不使用数据流控制、使用硬件进行流控制和使用软件进行流控制。数据流控制设置如表6.13所示。

表6.13  数据流控制设置

   

不使用数据流控制

opt.c_cflag &= ~CRTSCTS

硬件

opt.c_cflag   |=  CRTSCTS

软件

opt.c_cflag   | = IXON|IXOFF|IXANY

由于使用硬件流控制需要相应连接的电缆,常用的流控制方法还是使用软件进行流控制。下面给出了设置不使用数据流控制的相关代码:

    

#include     //头文件定义
#include
#include < termios.h >
……
struct termios opt;           /*定义指向termios 结构类型的指针opt*/
……
//获得串口指向termios结构的指针
tcgetattr(fd, &opt);

opt.c_cflag &= ~CRTSCTS…

//将修改后的termios数据设置到串口中
tcsetattr(fd,TCANOW,&Opt);
……

6.7.3  读写串口

读写串口是通过使用read函数和write函数实现的。在Linux系统中,对设备的读写类似于对文件的读写。下面给出对串口的写操作的代码:

    

……
int len;
//待发送数据
char sbuf[]={Hello,this is a Serial_Port test!\n };
int send_len=sizeof(sbuf);
//发送缓冲区字节数定义
len= write(fd,sbuf,send_len); //
if(n == -1)
printf("Wirte sbuf error.\n");
……

6.7.4  关闭串口

在完成对设备文件读写操作后,需要调用close函数关闭该文件描述符。

阅读(1153) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~