一、在struct termios结构体中,对串口进行基本配置(如波特率设置,校验位和停止位设置 等)。
(一):
struct termios //串口的设置主要是设置struct termios结构体的各成员
{
tcflag_t c_iflag; //input mode flags 输入模式标志。
tcflag_t c_oflag; //output mode flags 输出模式标志
tcflag_t c_cflag; //control mode flags 控制模式标志
tcflag_t c_lflag; //local mode flags 本地模式标志。
cc_t c_line; //line discipline 线路规程(速率)。
cc_t c_cc[NCCS]; //control characters 控制字符数组
};
1、c_cflag代表控制模式
CLOCAL含义为忽略所有调制解调器的状态行,这个目的是为了保证程序不会占用串口。CREAD代表启用字符接收器,目的是是的能够从串口中读取输入的数据。
CS5/6/7/8表示发送或接收字符时使用5/6/7/8比特。
CSTOPB表示每个字符使用两位停止位。
HUPCL表示关闭时挂断调制解调器。
PARENB:启用奇偶校验码的生成和检测功能。
PARODD只使用奇校验而不使用偶校验。
2、c_iflag代表输入模式。
BRKINT:当在输入行中检测到一个到一个终止状态时,产生一个中断。
TGNBRK:忽略输入行中的终止状态。
TCRNL:将接受到的回车符转换为新行符。
TGNCR:忽略接受到的新行符。
INLCR:将接受到的新行符转换为回车符。
IGNPAR:忽略奇偶校检错误的字符。
INPCK:对接收到的字符执行奇偶校检。
PARMRK:对奇偶校检错误作出标记。
ISTRIP:将所有接收的字符裁减为7比特。
IXOFF:对输入启用软件流控。
IXON:对输出启用软件流控。
3、c_cc特殊的控制字符。
标准模式和非标准模式下,c_cc数组的下标有不同的值:
(1)标准模式:
VEOF:EOF字符
VEOL:EOF字符
VERASE:ERASE字符
VINTR:INTR字符
VKILL:KILL字符
VQUIT:QUIT字符
VSTART:START字符
VSTOP:STOP字符
(2)非标准模式:
VINTR:INTR字符
VMIN:MIN值
VQUIT:QUIT字符
VSUSP:SUSP字符
VTIME:TIME值
VSTART:START字符
VSTOP:STOP字符
(二):其中,通过对c_cflag赋值,可以设置波特率、字符大小、数据位、停止位、奇偶校验位和硬件流控等。
程序例如:
struct termios options; // 串口配置结构体
tcgetattr(fd,&options); //获取当前设置
bzero(&options,sizeof(options));
options.c_cflag |= B115200 | CLOCAL | CREAD; // 设置波特率,本地连接,接收使能
options.c_cflag &= ~CSIZE; //屏蔽数据位
options.c_cflag |= CS8; // 数据位为 8 ,CS7 for 7
options.c_cflag &= ~CSTOPB; // 一位停止位, 两位停止为 |= CSTOPB
options.c_cflag &= ~PARENB; // 无校验
//options.c_cflag |= PARENB; //有校验
//options.c_cflag &= ~PARODD // 偶校验
//options.c_cflag |= PARODD // 奇校验
options.c_cc[VTIME] = 0; // 等待时间,单位百毫秒
//************************************************************************************
没满足条件或读缓冲区中剩下的数据会在0百毫秒后读出。另外特别注意的是当设置VTIME后,如果read第三个参数小于VMIN ,将会将VMIN 修改为read的第三个参数,即使用read(fd,&buf,m);,以下设置变为:options.c_cc[VMIN] = m;
************************************************************************************//
options.c_cc[VMIN] = 0; // 最小字节数
//************************************************************************************
(1)VMIN = 0,当缓冲区字节数 >= 0 时进行读操作,实际上这时读串口操作并未被阻塞,因为条件始终被满足。
(2)VMIN = 1,当缓冲区字节数 >= 1 时进行读操作,当没有数据时读串口操作被阻塞。
(3)VMIN = 4,当缓冲区字节数 >= 4 时进行读操作,否则读串口操作被阻塞。每次读出的最大字节数由read函数中第三个参数决定。直到缓冲区剩下的数据< read 第三个参数 并且< 4 (如果这时read第三参数为 1 则进行4次读操作直至读完缓冲区,如read第三参数为2,连续进行读操作,直至缓冲区空或还剩一个字符)。
(4)没有设置VTIME,剩下的字符没有确定的期限,直到下次满足读条件的时候才被读出。
***********************************************************************************//
tcflush(fd, TCIOFLUSH);
// TCIFLUSH刷清输入队列。
//TCOFLUSH刷清输出队列。
//TCIOFLUSH刷清输入、输出队列。
tcsetattr(fd, TCSANOW, &options);
// TCSANOW立即生效;
//TCSADRAIN:Wait until everything has been transmitted;
//TCSAFLUSH:Flush input and output buffers and make the change
上述中,在设置波特率时需要在数字前加上'B'。程序例:
cfsetispeed(&newtio,B115200);
cfsetospeed(&newtio,B115200);
二、对串口进行操作。(串口是一个终端设备)。
(一)操作命令如下:
打开串口:fd = open( "/dev/ttyS0", O_RDWR|O_NOCTTY|O_NDELAY);
O_RDWR 读写方式打开;
O_NOCTTY 不允许进程管理串口;通知linix系统,这个程序不会成为这个端口的控 制终端。
O_NDELAY 非阻塞(默认为阻塞,打开后也可以使用fcntl()重新设置)。通知Linux 系统不关心DCD信号线所处的状态(端口的另一端是否激活或者停止)。
写入串口:n = write(fd, "linux", 5);
n实际写入字节数;
读取串口:res = read(fd,buf,len);
res 读取的字节数;
设置串口:fcntl(fd, F_SETFL, FNDELAY); //非阻塞
fcntl(fd, F_SETFL, 0); // 阻塞
关闭串口:close(fd);
(二)总体上:
1、在创建的函数open_port()中要实现的函数:
程序例如:
(1)open("/dev/ttys0",O_RDWR | O_NOCTTY | O_NDELAY);/*打开串口0*/
(2)fcntl(fd,F_SETFL,0)/*恢复串口为阻塞状态*/
(3)isatty(STDIN_FILENO) /*测试是否为中断设备 非0即是中断设备*/
2、配置串口参数函数set_opt()中要实现的函数:
(1)保存原先有串口配置
tcgetattr(fd,&oldtio);
(2)先将新串口配置清0
bzore(&newtio,sizeof(newito));
(3)激活选项CLOCAL和CREAD 用于本地连接和接收使用;
newtio.c_cflag |=CLOCAL | CREAD;
(4)并设置数据位大小 ,需使用掩码设置
newtio.c_cflag &= ~CSIZE;
newtio.c_cflag |=CS8;
(5)设置奇偶校验
奇校验:
newtio.c_cflag |= PARENB;
newtio.c_cflag |= PARODD;
newtio.c_iflag |= (INPCK | ISTRIP);
偶校验:
newtio.c_iflag |= (INPCK | ISTRIP);
newtio.c_cflag |= PAREND;
newtio.c_cflag &= ~PARODD;
无奇偶校验:
newtio.c_cflag &= ~PARENB;
(6) 设置停止位,通过激活c_cflag中的CSTOPB实现。若停止位为1,则清除CSTOPB,若停止位为2,则激活CSTOPB。
newtio.c_cflag &= ~CSTOPB; /*停止位为1*/
newtio.c_cflag |= CSTOPB;/*停止位为0*/
(7)设置波特率:
cfsetispeed(&newtio,B115200);
cfsetospeed(&newtio,B115200);
(8)设置等待时间和最小接受字符。对于接收字符和等待时间没有特别的要求时,可设为0:
newtio.c_cc[VTIME] = 0;
newtio.c_cc[VMIN] = 0;
(9)处理为接收字符(处理要写入的引用对象)。tcflush函数刷清(抛弃)输入缓存(终端驱动程序已接收到,但用户程序尚未读)或输出缓存(用户程序已经写,但尚未发送).
tcflush(fd,TCIFLUSH);
// TCIFLUSH 刷清输入队列。即刷新收到的数据但是不读
// TCOFLUSH 刷清输出队列。即刷新写入的数据但是不传送
// TCIOFLUSH 刷清输入、输出队列。即同时刷新收到的数据但是不读,并且刷新写入的数据但是不传送。
(10)激活新配置:
tcsetattr(fd,TCSANOW,&newtio);
3、读写串口
write(fd,buff,8);
read(fd,buff,8);
(三)另外:
1、获取文件的flags,即open函数的第二个参数:
flags = fcntl(fd,F_GETFL,0);
2、设置文件的flags:
fcntl(fd,F_SETFL,flags);
3、增加文件的某个flags,比如文件是阻塞的,想设置成非阻塞:
flags = fcntl(fd,F_GETFL,0);
flags |= O_NONBLOCK;
fcntl(fd,F_SETFL,flags);
4、取消文件的某个flags,比如文件是非阻塞的,想设置成为阻塞:
flags = fcntl(fd,F_GETFL,0);
flags &= ~O_NONBLOCK;
fcntl(fd,F_SETFL,flags);