#include <stdio.h> /*标准输入输出定义*/
#include <stdlib.h> /*标准函数库定义*/
#include <unistd.h> /*Unix标准函数定义*/
#include <sys/types.h> /**/
#include <sys/stat.h> /**/
#include <fcntl.h> /*文件控制定义*/
#include <termios.h> /*PPSIX终端控制定义*/
#include <errno.h> /*错误号定义*/
static char *serial_name[]={"ttySAC0","/dev/ttySAC1","/dev/ttySAC2","/dev/ttySAC3"};
int main(void)
{
int n, len, fd_max,i;
fd_set readfds;/* 先申明一个 fd_set 集合来保存我们要检测的 socket句柄 */
char buffer[256];
static struct termios oldtio,newtio;
printf("0:ttySAC0,1:ttySAC1,2:ttySAC2,3:ttySAC3\n");
printf("please input the open serial:");
scanf("%d",&i);
//Open函数中除普通参数外,另有两个参数O_NOCTTY和O_NDELAY。
//O_NOCTTY: 通知linix系统,这个程序不会成为这个端口的控制终端。
// O_NDELAY: 通知linux系统不关心DCD信号线所处的状态(端口的另一端是否激活或者停止)然后,恢复串口的状态为阻塞状态,用于等待串口数据的读入。
int fd = open(serial_name[i],O_RDWR | O_NOCTTY | O_NDELAY);//270
if(fd<0)
{
perror("Cannot Open Serial Port !\n");
}
tcgetattr(fd,&oldtio);//保存原先串口配置使用tcgetattr(fd,&oldtio)函数
tcgetattr(fd,&newtio);
//设置波特率,使用函数cfsetispeed、 cfsetospeed
cfsetispeed(&newtio,B9600);
cfsetospeed(&newtio,B9600);
//newtio.c_lflag &= ~(ICANON | ECHO);
//ISIG:当输入INTR、QUIT、SUSP或DSUSP时,产生相应的信号
//ECHOE:如果ICANON同时设置,ERASE将删除输入的字符,WERASE将删除输入的单词
//ECHO:显示输入字符
//ICANON:使用标准输入模式
newtio.c_lflag&= ~(ICANON | ECHO | ECHOE | ISIG);
/*
设置奇偶校验位,使用c_cflag和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;
无奇偶校验
newtio.c_cflag &= ~PARENB;
*/
newtio.c_cflag &= ~PARENB;
/*
设置停止位,通过激活c_cflag中的CSTOPB实现。若停止位为1,则清除CSTOPB,若停止位为2,则激活CSTOPB。
if( nStop == 1 )
newtio.c_cflag &= ~CSTOPB;
else if ( nStop == 2 )
newtio.c_cflag |= CSTOPB;
*/
newtio.c_cflag &= ~CSTOPB;
//设置数据位,需使用掩码设置。
newtio.c_cflag &= ~CSIZE;
newtio.c_cflag |= CS8;
//处理后输出
newtio.c_oflag &= ~OPOST;
//激活选项有CLOCAL和CREAD,用于本地连接和接收使能
newtio.c_cflag |= (CLOCAL | CREAD);
newtio.c_iflag = 0;
/*
设置最少字符和等待时间,对于接收字符和等待时间没有特别要求时,可设为0。
VTIME:非规范模式读取时的超时时间
VMIN:非规范模式读取时的最小字符数
*/
newtio.c_cc[VTIME] = 1;
newtio.c_cc[VMIN] = 10;
//tcsetattr的参数opt使我们可以指定在什么时候新的终端属性才起作用。opt可以指定为下列常数中的一个:
//TCSANOW 更改立即发生。
//TCSADRAIN 发送了所有输出后更改才发生。若更改输出参数则应使用此选择项。
//TCSAFLUSH 发送了所有输出后更改才发生。更进一步,在更改发生时未读的所有输入数据都被删除(刷清)
if(tcsetattr(fd,TCSAFLUSH,&newtio)<0)
{
printf("tcsetattr fail !\n");
exit(1);
}
FD_ZERO(&readfds);//用来清除描述词组set的全部位
FD_SET(fd, &readfds);//用来设置描述词组set中相关fd的位
fd_max = fd + 1;
/* Do the select */
while(1)
{
//select系统调用是用来让我们的程序监视多个文件句柄(file descriptor)的状态变化的。程序会停在select这里等待,
//直到被监视的文件句柄有某一个或多个发生了状态改变
/*第2、3、4三个参数是一样的类型: fd_set *,即我们在程序里要申明几个fd_set类型的变量,比如rdfds, wtfds, exfds,
然后把这个变量的地址&rdfds, &wtfds, &exfds 传递给select函数。这三个参数都是一个句柄的集合,第一个rdfds是用来
保存这样的句柄的:当句柄的状态变成可读的时系统就会告诉select函数返回,同理第二个wtfds是指有句柄状态变成可写的
时系统就会告诉select函数返回,同理第三个参数exfds是特殊情况,即句柄上有特殊情况发生时系统会告诉select函数返回。
*/
n = select(fd_max,&readfds,NULL,NULL,NULL);
memset(buffer, 0, sizeof(buffer));
if (n<=0)/* 这说明select函数出错 */
printf("select failed");
else
{
if (FD_ISSET(fd, &readfds))/*先判断一下fd这个被监视的句柄是否真的变成可读的了 */
{
len=read(fd, buffer, 256);
buffer[len] = '\0';
fprintf(stderr, "Readed %d data:%s\n",len, buffer);
write(fd,"test code send abc",20);
}
}
}
}
评论0