串口设置详解
本节主要讲解设置串口的主要方法。
如前所述,设置串口中最基本的包括波特率设置,校验位和停止位设置。串口的设置主
要是设置struct termios结构体的各成员值,如下所示:
include<termios.h>
struct termio
{ unsigned short c_iflag; /* 输入模式标志*/
unsigned short c_oflag; /* 输出模式标志*/
unsigned short c_cflag; /* 控制模式标志*/
unsigned short c_lflag; /*本地模式标志*/
unsigned char c_line; /* line discipline */
unsigned char c_cc[NCC]; /* control characters */
};
在这个结构中最为重要的是c_cflag,通过对它的赋值,用户可以设置波特率、字符大小、
数据位、停止位、奇偶校验位和硬件流控等。另外c_iflag c_cc 也是比较常用的标志。在
此主要对这3 个成员进行详细说明。
c_cflag 支持的常量名称如表6.10 所示。其中设置波特率为相应的波特率前加上‘B’,
由于数值较多,本表没有全部列出。
6.10 c_cflag支持的常量名称
CBAUD 波特率的位掩码
B0 0波特率(放弃DTR
《嵌入式Linux应用程序开发详解》——6章、文件IO编程
续表
B1800 1800波特率
B2400 2400波特率
B4800 4800波特率
B9600 9600波特率
B19200 19200波特率
B38400 38400波特率
B57600 57600波特率
B115200 115200波特率
EXTA 外部时钟率
EXTB 外部时钟率
CSIZE 数据位的位掩码
CS5 5个数据位
CS6 6个数据位
CS7 7个数据位
CS8 8个数据位
CSTOPB 2个停止位(不设则是1个停止位)
CREAD 接收使能
PARENB
PARODD
校验位使能
使用奇校验而不使用偶校验
HUPCL 最后关闭时挂线(放弃DTR
CLOCAL 本地连接(不改变端口所有者)
LOBLK 块作业控制输出
CNET_CTSRTS 硬件流控制使能
在这里,对于c_cflag成员不能直接对其初始化,而要将其通过“与”、“或”操作使用其
中的某些选项。
输入模式c_iflag 成员控制端口接收端的字符输入处理。c_iflag 支持的变量名称,如表
6.11 所示。
6.11 c_iflag支持的常量名称
INPCK 奇偶校验使能
IGNPAR 忽略奇偶校验错误
PARMRK 奇偶校验错误掩码
ISTRIP 除去奇偶校验位
续表
IXON 启动出口硬件流控
IXOFF 启动入口软件流控
IXANY 允许字符重新启动流控
IGNBRK 忽略中断情况
BRKINT 当发生中断时发送SIGINT信号
INLCR NL映射到CR
IGNCR 忽略CR
ICRNL CR映射到NL
IUCLC 将高位情况映射到低位情况
IMAXBEL 当输入太长时回复ECHO
c_cc 包含了超时参数和控制字符的定义。c_cc 所支持的常用变量名称,如表6.12
所示。
6.12 c_cc 支持的常量名称
VINTR 中断控制,对应键为CTRL+C
VQUIT 退出操作,对应键为CRTL+Z
VERASE 删除操作,对应键为BackspaceBS
VKILL 删除行,对应键为CTRL+U
VEOF 位于文件结尾,对应键为CTRL+D
VEOL 位于行尾,对应键为Carriage returnCR
VEOL2 位于第二行尾,对应键为Line feedLF
VMIN 指定了最少读取的字符数
VTIME 指定了读取每个字符的等待时间
下面就详细讲解设置串口属性的基本流程。
1.保存原先串口配置
首先,为了安全起见和以后调试程序方____________便,可以先保存原先串口的配置,在这里可以使
用函数tcgetattrfd&oldtio)。该函数得到与fd指向对象的相关参数,并将它们保存于oldtio
引用的termios结构中。该函数还可以测试配置是否正确、该串口是否可用等。若调用成功,
函数返回值为0,若调用失败,函数返回值为-1,其使用如下所示:
if ( tcgetattr( fd,&oldtio) != 0) {
perror("SetupSerial 1");
《嵌入式Linux应用程序开发详解》——6章、文件IO编程
return -1;
}
2.激活选项有CLOCALCREAD
CLOCALCREAD 分别用于本地连接和接受使能,因此,首先要通过位掩码的方式激
活这两个选项。
newtio.c_cflag |= CLOCAL | CREAD;
3.设置波特率
设置波特率有专门的函数,用户不能直接通过位掩码来操作。设置波特率的主要函数有:
cfsetispeedcfsetospeed。这两个函数的使用很简单,如下所示:
cfsetispeed(&newtio, B115200);
cfsetospeed(&newtio, B115200);
一般地,用户需将输入输出函数的波特率设置成一样的。这几个函数在成功时返回0
失败时返回-1
4.设置字符大小
与设置波特率不同,设置字符大小并没有现成可用的函数,需要用位掩码。一般首先去
除数据位中的位掩码,再重新按要求设置。如下所示:
options.c_cflag &= ~CSIZE;/* mask the character size bits */
options.c_cflag |= CS8;
5.设置奇偶校验位
设置奇偶校验位需要用到两个termio 中的成员:c_cflag c_iflag。首先要激活c_cflag
中的校验位使能标志PARENB 和是否要进行偶校验,同时还要激活c_iflag 中的奇偶校验使
能。如使能奇校验时,代码如下所示:
newtio.c_cflag |= PARENB;
newtio.c_cflag |= PARODD;
newtio.c_iflag |= (INPCK | ISTRIP);
而使能偶校验时代码为:
newtio.c_iflag |= (INPCK | ISTRIP);
newtio.c_cflag |= PARENB;
newtio.c_cflag &= ~PARODD;
6.设置停止位
设置停止位是通过激活c_cflag中的CSTOPB而实现的。若停止位为1,则清除CSTOPB
若停止位为0,则激活CSTOPB。下面是停止位是1时的代码:
newtio.c_cflag &= ~CSTOPB;
7.设置最少字符和等待时间
在对接收字符和等待时间没有特别要求的情况下,可以将其设置为0,如下所示:
newtio.c_cc[VTIME] = 0;
newtio.c_cc[VMIN] = 0;
8____________处理要写入的引用对象
由于串口在重新设置之后,在此之前要写入的引用对象要重新处理,这时就可调用函数
tcflushfdqueue_selector)来处理要写入引用的对象。对于尚未传输的数据,或者收到的
但是尚未读取的数据,其处理方法取决于queue_selector 的值。
这里,queue_selector 可能的取值有以下几种。
∙TCIFLUSH:刷新收到的数据但是不读。
∙TCOFLUSH:刷新写入的数据但是不传送。
∙TCIOFLUSH:同时刷新收到的数据但是不读,并且刷新写入的数据但是不传送。
如在本例中所采用的是第一种方法:
tcflush(fd,TCIFLUSH);
9.激活配置
在完成全部串口配置之后,要激活刚才的配置并使配置生效。这里用到的函数是tcsetattr
它的函数原型是:
tcsetattr(fd,OPTION,&newtio);
这里的newtio就是termios 类型的变量,OPTION 可能的取值有以下三种:
∙TCSANOW:改变的配置立即生效。
∙TCSADRAIN:改变的配置在所有写入fd的输出都结束后生效。
∙TCSAFLUSH:改变的配置在所有写入fd 引用对象的输出都被结束后生效,所有已
接受但未读入的输入都在改变发生前丢弃。
该函数若调用成功则返回0,若失败则返回-1
如下所示:
if((tcsetattr(fd,TCSANOW,&newtio))!=0)
{
perror("com set error");
《嵌入式Linux应用程序开发详解》——6章、文件IO编程
return -1;
}
下面给出了串口配置的完整的函数。通常,为了函数的通用性,通常将常用的选项都在
模拟串口使用printf函数
函数中列出,这样可以大大方便以后用户的调试使用。该设置函数如下所示:
int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)
{
struct termios newtio,oldtio;
/*保存测试现有串口参数设置,在这里如果串口号等出错,会有相关的出错信息*/
if ( tcgetattr( fd,&oldtio) != 0) {
perror("SetupSerial 1");
return -1;
}
bzero( &newtio, sizeof( newtio ) );
/*步骤一,设置字符大小*/
newtio.c_cflag |= CLOCAL | CREAD;
newtio.c_cflag &= ~CSIZE;
/*设置停止位*/
switch( nBits )
{
case 7:
newtio.c_cflag |= CS7;
break;
case 8:
newtio.c_cflag |= CS8;
break;
}
/*设置奇偶校验位*/
switch( nEvent )
{
case 'O': //奇数
newtio.c_cflag |= PARENB;
newtio.c_cflag |= PARODD;