#include <stdio.h>
#include <stdlib.h>
#include <termio.h>
#include <unistd.h>
#include <fcntl.h>
#include <getopt.h>
#include <time.h>
#include <errno.h>
#include <string.h>

#define FALSE -1
#define TRUE 
 1
int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300, //
B38400, B19200, B9600, B4800, B2400, B1200, B300, };
int name_arr[] = {38400, 19200, 9600, 4800, 2400, 1200, 300,
38400, 19200, 9600, 4800, 2400, 1200, 300, };
void set_speed(int fd, int speed)
{
 
int i;
 
int status;
 
struct termios Opt;
 
tcgetattr(fd, &Opt);
 
for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++)
 
{
 
 if (speed == name_arr[i])
 
 {
 
  tcflush(fd, TCIOFLUSH);
 
  cfsetispeed(&Opt, speed_arr[i]); 
 
  cfsetospeed(&Opt, speed_arr[i]);
 
  status = tcsetattr(fd, TCSANOW, &Opt); 
 
  if (status != 0)
 
   perror("tcsetattr fd1");
 
  return;
 
 }
 
 tcflush(fd,TCIOFLUSH); //ͬÉÏ
 
}
}

int set_Parity(int fd,int databits,int stopbits,int parity)
{
 
struct termios options; //¶¨ÒåÒ»¸ö½á¹¹
 
if ( tcgetattr( fd,&options) != 0) //Ê×ÏȶÁȡϵͳĬÈÏÉèÖÃoptionsÖÐ,±ØÐë
 
{
 
 perror("SetupSerial 1");
 
 return(FALSE);
 
}
 
options.c_cflag &= ~CSIZE; //ÕâÊÇÉèÖÃc_cflagÑ¡Ïî²»°´Î»Êý¾ÝλÑÚÂë
 
switch (databits)
 
{
 
case 7:
 
 options.c_cflag |= CS7; //ÉèÖÃc_cflagÑ¡ÏîÊý¾ÝλΪ7λ
 
 break;
 
case 8:
 
 options.c_cflag |= CS8; //ÉèÖÃc_cflagÑ¡ÏîÊý¾ÝλΪ8λ
 
 break;
 
default:
 
 fprintf(stderr,"Unsupported data size\n"); //ÆäËûµÄ¶¼²»Ö§³Ö
 
 return (FALSE);
 
}
 
switch (parity) //ÉèÖÃÆæżУÑ飬c_cflagºÍc_iflagÓÐЧ
 
{
 
case 'n':
 
case 'N':
 
 options.c_cflag &= ~PARENB;
 
 options.c_iflag &= ~INPCK;
 
 break;
 
case 'o':
 
case 'O': options.c_cflag |= (PARODD | PARENB);
 
 options.c_iflag |= INPCK;
 
 break;
 
case 'e':
 
case 'E':
 
 options.c_cflag |= PARENB;
 
 options.c_cflag &= ~PARODD;
 
 options.c_iflag |= INPCK;
 
 break;
 
default:
 
 fprintf(stderr,"Unsupported parity\n");
 
 return (FALSE);
 
}
 

 
switch (stopbits)
 
{
 
case 1:
 
 options.c_cflag &= ~CSTOPB;
 
 break;
 
case 2:
 
 options.c_cflag |= CSTOPB;
 
 break;
 
default:
 
 fprintf(stderr,"Unsupported stop bits\n");
 
 return (FALSE);
 
}
 

 
if (parity != 'n')
 
 options.c_iflag |= INPCK;
 

 

 
options.c_cc[VTIME] = 150; // 15 seconds
 
options.c_cc[VMIN] = 0;
 

 
tcflush(fd,TCIFLUSH);
 
if (tcsetattr(fd,TCSANOW,&options) != 0)
 
{
 
 perror("SetupSerial 3");
 
 return (FALSE);
 
}
 
return (TRUE);
}

int OpenDev(char *Dev)
{
 
   int fd = open( Dev, O_RDWR ); //| O_NOCTTY | O_NDELAYÕâÖÖ·½Ê½¿´openº¯Êý
 
   if (-1 == fd)
 
   {
 
 perror("Can't Open Serial Port");
 
 return -1;
 
   }
 
   else
 
 return fd;
}

int main(int argc, char **argv)
{
 
   int fd;
 
   int nread;
 
   char buff[512];
 
   char *dev ="/dev/ttySAC1";
 
   fd = OpenDev(dev);
 
   if (fd>0)
 
   {
 
printf("Open Serial succeed\n");
 
set_speed(fd,19200);
 
   }
 
   else
 
   {
 
 printf("Can't Open Serial Port!\n");
 
 exit(0);
 
   }
 
   if (set_Parity(fd,8,1,'N')== FALSE)
 
   {
 
 printf("Set Parity Error\n");
 
 exit(1);
 
   }
 

 
   while(1)
 
   {
 
int i;
// 
char buff1[2]={0x5a,0x5a};
// 
write(fd,buff1,1);
 
while((nread = read(fd,buff,512))>0)
 
{
 
 printf("\nLen %d\n",nread);
 
 buff[nread+1]='\0';
 
 for(i=0;i<nread;i++)
 
  printf("0x%x",buff[i]);
 
 printf("\n");
 
}
 
   }
 
   //close(fd);
 
   //exit(0);
}

6.7.2 设置串口通信参数

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

1.波特率设置

 

……

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);
……

int tcgetattr(int fd, struct termios *termios_p);函数

tcgetattr函数用于获取与终端相关的参数。参数fd为终端的文件描述符,返回的结果保存在termios结构体中,该结构体一般包括如下的成员:
tcflag_t c_iflag;      
tcflag_t c_oflag;      
tcflag_t c_cflag;      
tcflag_t c_lflag;     
cc_t     c_cc[NCCS];
其具体意义如下。
c_iflag:输入模式标志,控制终端输入方式,具体参数如表1所示。
表1 c_iflag参数表
键    值
 
说    明
 
IGNBRK
 
忽略BREAK键输入
 
BRKINT
 
如果设置了IGNBRK,BREAK键输入将被忽略
 
IGNPAR
 
忽略奇偶校验错误
 
PARMRK
 
标识奇偶校验错误
 
INPCK
 
允许输入奇偶校验
 
ISTRIP
 
去除字符的第8个比特
 
INLCR
 
将输入的NL(换行)转换成CR(回车)
 
IGNCR
 
忽略输入的回车
 
ICRNL
 
将输入的回车转化成换行(如果IGNCR未设置的情况下)
 
IUCLC
 
将输入的大写字符转换成小写字符(非POSIX)
 
IXON
 
允许输入时对XON/XOFF流进行控制
 
IXANY
 
输入任何字符将重启停止的输出
 
IXOFF
 
允许输入时对XON/XOFF流进行控制
 
IMAXBEL
 
当输入队列满的时候开始响铃
 
c_oflag:输出模式标志,控制终端输出方式,具体参数如表2所示。
表2 c_oflag参数
键    值
 
说    明
 
OPOST
 
处理后输出
 
OLCUC
 
将输入的小写字符转换成大写字符(非POSIX)
 
ONLCR
 
将输入的NL(换行)转换成CR(回车)及NL(换行)
 
OCRNL
 
将输入的CR(回车)转换成NL(换行)
 
ONOCR
 
第一行不输出回车符
 
ONLRET
 
不输出回车符
 
OFILL
 
发送填充字符以延迟终端输出
 
OFDEL
 
以ASCII码的DEL作为填充字符,如果未设置该参数,填充字符为NUL
 
NLDLY
 
换行输出延时,可以取NL0(不延迟)或NL1(延迟0.1s)
 
CRDLY
 
回车延迟,取值范围为:CR0、CR1、CR2和 CR3
 
TABDLY
 
水平制表符输出延迟,取值范围为:TAB0、TAB1、TAB2和TAB3
 
BSDLY
 
空格输出延迟,可以取BS0或BS1
 
VTDLY
 
垂直制表符输出延迟,可以取VT0或VT1
 
FFDLY
 
换页延迟,可以取FF0或FF1
 
c_cflag:控制模式标志,指定终端硬件控制信息,具体参数如表3所示。
表3 c_cflag参数
键    值
 
说    明
 
CBAUD
 
波特率(4+1位)(非POSIX)
 
CBAUDEX
 
附加波特率(1位)(非POSIX)
 
CSIZE
 
字符长度,取值范围为CS5、CS6、CS7或CS8
 
CSTOPB
 
设置两个停止位
 
CREAD
 
使用接收器
 
PARENB
 
使用奇偶校验
 
PARODD
 
对输入使用奇偶校验,对输出使用偶校验
 
HUPCL
 
关闭设备时挂起
 
CLOCAL
 
忽略调制解调器线路状态
 
CRTSCTS
 
使用RTS/CTS流控制
 
c_lflag:本地模式标志,控制终端编辑功能,具体参数如表4所示。
表4 c_lflag参数
键    值
 
说    明
 
ISIG
 
当输入INTR、QUIT、SUSP或DSUSP时,产生相应的信号
 
ICANON
 
使用标准输入模式
 
XCASE
 
在ICANON和XCASE同时设置的情况下,终端只使用大写。
 
ECHO
 
显示输入字符
 
ECHOE
 
如果ICANON同时设置,ERASE将删除输入的字符
 
ECHOK
 
如果ICANON同时设置,KILL将删除当前行
 
ECHONL
 
如果ICANON同时设置,即使ECHO没有设置依然显示换行符
 
ECHOPRT
 
如果ECHO和ICANON同时设置,将删除打印出的字符(非POSIX)
 
TOSTOP
 
向后台输出发送SIGTTOU信号
 
c_cc[NCCS]:控制字符,用于保存终端驱动程序中的特殊字符,如输入结束符等。c_cc中定义了如表5所示的控制字符。
表5 c_cc支持的控制字符
 
说    明
 
 
说    明
 
VINTR
 
Interrupt字符
 
VEOL
 
附加的End-of-file字符
 
VQUIT
 
Quit字符
 
VTIME
 
非规范模式读取时的超时时间
 
VERASE
 
Erase字符
 
VSTOP
 
Stop字符
 
VKILL
 
Kill字符
 
VSTART
 
Start字符
 
VEOF
 
End-of-file字符
 
VSUSP
 
Suspend字符
 
VMIN
 
非规范模式读取时的最小字符数
 
tcsetattr函数用于设置终端的相关参数。参数fd为打开的终端文件描述符,参数optional_actions用于控制修改起作用的时间,而结构体termios_p中保存了要修改的参数。
optional_actions可以取如下的值:
TCSANOW:不等数据传输完毕就立即改变属性。
TCSADRAIN:等待所有数据传输结束才改变属性。
TCSAFLUSH:清空输入输出缓冲区才改变属性。
错误信息:
EBADF:非法的文件描述符。
EINTR:tcsetattr函数调用被信号中断。
EINVAL:参数optional_actions使用了非法值,或参数termios中使用了非法值。
ENCTTY:非终端的文件描述符。