首页 » PHP教程 » php串口壅塞技巧_Linux串口编程详解壅塞模式非壅塞模式select函数

php串口壅塞技巧_Linux串口编程详解壅塞模式非壅塞模式select函数

duote123 2024-12-05 0

扫一扫用手机浏览

文章目录 [+]

#include<fcntl.h>int open(const char pathname,int flags); int open(const char pathname,int flags,mode_t mode);

嵌入式进阶教程分门别类整理好了,看的时候十分方便,由于内容较多,这里就截取一部分图吧。

须要的朋友私信【内核】即可领取。

php串口壅塞技巧_Linux串口编程详解壅塞模式非壅塞模式select函数

内核学习地址:Linux内核源码/内存调优/文件系统/进程管理/设备驱动/网络协议栈-学习视频教程-腾讯教室

php串口壅塞技巧_Linux串口编程详解壅塞模式非壅塞模式select函数
(图片来自网络侵删)

参数flags:一些文件模式选择,有如下几个参数可以设置:

O_RDONLY 只读模式O_WRONLY 只写模式O_RDWR 读写模式

上面三个参数在设置的时候必须选择个中一个!
下面的参数是可选的:

O_APPEND 每次操作都写入文件的末端O_CREAT 如果指定文件不存在,则创建这个文件O_EXCL 如果要创建的文件已存在,则返回 -1,并且修正 errno 的值O_TRUNC 如果文件存在,并且以只写/读写的办法打开,则清空文件全部内容O_NOCTTY 如果路径名指向终端设备,不要把这个设备用作掌握终端O_NONBLOCK 如果路径名指向 FIFO/块文件/字符文件,则把文件的打开和后继 I/O设置为非壅塞模式O_NDELAY 表示用于设置非壅塞办法。
同时关照Linux系统,这个程序不关心DCD旗子暗记线所处的状态(端口的另一端是否激活或者停滞)。
如果用户没有指定这个标志,则进程将会一贯处在就寝状态,直到DCD旗子暗记线被激活。

下面三个常量同样是选用的,他们用于同步输入输出:

O_DSYNC 等待物理 I/O 结束后再 write。
在不影响读取新写入数据的条件下,不等待文件属性更新O_RSYNC read等待所有写入同一区域的写操作完成后再进行O_SYNC 等待物理 I/O 结束后再 write,包括更新文件属性的 I/O

对付串口的打开操作,必须利用O_NOCTTY参数,它表示打开的是一个终端设备,程序不会成为该端口的掌握终端。
如果不该用此标志,任务的一个输入(比如键盘终止旗子暗记等)都会影响进程。

open函数第三个参数mode为可选参数,表示打开文件权限

fcntl 函数

功能描述:根据文件描述词来操作文件的特性,返回-1代表出错

#include<unistd.h>#include<fcntl.h>int fcntl(int fd,int cmd);int fcntl(int fd,int cmd,long arg);int fcntl(int fd,int cmd,struct flock lock);

fcntl()函数紧张有5种功能:

复制一个现有的描述符(cmd=F_DUPFD/F_DUPFD_CLOEXEC)得到/设置文件描述符标记(cmd=F_GETFD/F_SETFD)得到/设置文件状态标记(cmd=F_GETFL/F_SETFL) #常用得到/设置异步I/O所有权(cmd=F_GETOWN/F_SETOWN)得到/设置记录锁(cmd=F_GETLK/F_SETLK/F_SETLKW) #常用

F_SETFL :设置文件状态标志。
个中O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_EXCL, O_NOCTTY 和 O_TRUNC不受影响,

能变动的标志有 O_APPEND,O_ASYNC, O_DIRECT, O_NOATIME 和 O_NONBLOCK。
此函数功能强大,在此不做详细阐述!

串口参数初始化

串口参数由构造体termio设置:

struct termio{ unsigned short c_iflag; / 输入模式标志 / unsigned short c_oflag; / 输出模式标志 / unsigned short c_cflag; / 掌握模式标志/ unsigned short c_lflag; / local mode flags / unsigned char c_line; / line discipline / unsigned char c_cc[NCC]; / control characters /};

这里列出常见配置:

int set_port_attr(int fd,int baudrate, int databit, const char stopbit, char parity, int vtime,int vmin ){ struct termios opt; tcgetattr(fd, &opt); //获取初始设置 set_baudrate(&opt, baudrate); set_data_bit(&opt, databit); set_parity(&opt, parity); set_stopbit(&opt, stopbit); opt.c_cflag &= ~CRTSCTS; // 不该用硬件流掌握 opt.c_cflag |= CLOCAL | CREAD; //CLOCAL--忽略 modem 掌握线,本地连线, 不具数据机掌握功能, CREAD--使能吸收标志 / IXON--启用输出的 XON/XOFF 流掌握 IXOFF--启用输入的 XON/XOFF 流掌握 IXANY--许可任何字符来重新开始输出 IGNCR--忽略输入中的回车 / opt.c_iflag &= ~(IXON | IXOFF | IXANY); opt.c_oflag &= ~OPOST; //启用输出处理 / ICANON--启用标准模式 (canonical mode)。
许可利用分外字符 EOF, EOL, EOL2, ERASE, KILL, LNEXT, REPRINT, STATUS, 和 WERASE,以及按行的缓冲。
ECHO--回显输入字符 ECHOE--如果同时设置了 ICANON,字符 ERASE 擦除前一个输入字符,WERASE 擦除前一个词 ISIG--当接管到字符 INTR, QUIT, SUSP, 或 DSUSP 时,产生相应的旗子暗记 / opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); opt.c_cc[VMIN] = vmin; //设置非规范模式下的超时时长和最小字符数:壅塞模式起浸染 opt.c_cc[VTIME] = vtime; //VTIME与VMIN合营利用,是指限定的传输或等待的最永劫光 单位:0.1S tcflush (fd, TCIFLUSH); / TCIFLUSH-- update the options and do it NOW / return (tcsetattr (fd, TCSANOW, &opt)); / TCSANOW--改变立即发生 /} static void set_baudrate(struct termios opt, unsigned int baudrate){ cfsetispeed(opt, baudrate); cfsetospeed(opt, baudrate);} static void set_stopbit(struct termios opt, const char stopbit){ if (0 == strcmp (stopbit, "1")) { opt->c_cflag &= ~CSTOPB; / 1位停滞位t / }else if (0 == strcmp (stopbit, "1.5")) { opt->c_cflag &= ~CSTOPB; / 1.5位停滞位 / }else if (0 == strcmp (stopbit, "2")) { opt->c_cflag |= CSTOPB; / 2 位停滞位 / }else { opt->c_cflag &= ~CSTOPB; / 1 位停滞位 / }} static void set_data_bit(struct termios opt, unsigned int databit){ opt->c_cflag &= ~CSIZE; switch (databit) { case 8: opt->c_cflag |= CS8; break; case 7: opt->c_cflag |= CS7; break; case 6: opt->c_cflag |= CS6; break; case 5: opt->c_cflag |= CS5; break; default: opt->c_cflag |= CS8; break; }} static void set_parity(struct termios opt, char parity){ switch (parity) { case 'N': / 无校验 / case 'n': opt->c_cflag &= ~PARENB; break; case 'E': / 偶校验 / case 'e': opt->c_cflag |= PARENB; opt->c_cflag &= ~PARODD; break; case 'O': / 奇校验 / case 'o': opt->c_cflag |= PARENB; opt->c_cflag |= ~PARODD; break; case 'S': case 's': opt->c_cflag &= ~PARENB; /打消校验位 disable pairty checking Space校验 / opt->c_cflag &= ~CSTOPB; opt->c_iflag |= INPCK; break; default: / 其它选择为无校验 / opt->c_cflag &= ~PARENB; break; }}
壅塞式读写配置

打开时利用:fd = open(USAR1, O_RDWR | O_NOCTTY );//壅塞式读写 打开后利用fcntl函数修正:fcntl(fd, F_SETFL, 0); //设为壅塞

壅塞式读写可设置以下两参数:

opt.c_cc[VMIN] = vmin; //设置非规范模式下的超时时长和最小字符数:壅塞模式起浸染opt.c_cc[VTIME] = vtime; //VTIME与VMIN合营利用,是指限定的传输或等待的最永劫光若 VMIN = 0 ,VTIME = 0 ,函数read未读到任何参数也立即返回,相称于非壅塞模式;若 VMIN = 0, VTIME > 0 ,函数read读取到数据立即返回,若无数据则等待VTIME韶光返回;若 VMIN > 0, VTIME = 0 ,函数read()只有在读取到VMIN个字节的数据或者收到一个旗子暗记的时候才返回;若 VMIN > 0, VTIME > 0 ,从read读取第一个字节的数据时开始计时,并会在读取到VMIN个字节或者VTIME韶光后返回。
非壅塞式读写配置

打开时利用

open(USAR1, O_RDWR | O_NOCTTY | O_NDELAY );//非壅塞式读写open(USAR1, O_RDWR | O_NOCTTY | O_NONBLOCK);//非壅塞式读写open(USAR1, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);//非壅塞式读写

打开后利用fcntl修正设置

fcntl(socket_descriptor, F_SETFL, flags | O_NONBLOCK); //设为非壅塞

O_NONBLOCK和O_NDELAY都是设置为非壅塞模式,但是它们有些差别,O_NDELAY会使I/O函式立时返回0,但是又衍生出一个问题,由于读取到档案结尾时所回传的也是0,这样无法得知是哪中情形;而O_NONBLOCK它在读取不到数据时会回传-1,并且设置errno为EAGAIN。

select函数读写

int select(int nfds, fd_set rdfds, fd_set wtfds, fd_set exfds, struct timeval timeout)ndfs:select监视的文件句柄,一样平常设为要监视的文件中的最大文件号加一;rdfds:select监视的可读文件句柄凑集,当rdfds映象的文件句柄状态变成可读时系统见告select函数返回。
这个凑集中有一个文件可读,select就会返回一个大于0的值,表示有文件可读,如果没有可读的文件,则根据timeout参数再判断是否超时,若超出timeout的韶光,select返回0,若发生缺点返回负值,可以传入NULL值,表示不关心任何文件的读变革;wtfds: select监视的可写文件句柄凑集,当wtfds映象的文件句柄状态变成可写时系统见告select函数返回,如果这个凑集中有一个文件可写,select就会返回一个大于0的值,表示有文件可写,如果没有可写的文件,则根据timeout参数再判断是否超时,若超出timeout的韶光,select返回0,若发生缺点返回负值,可以传入NULL值,表示不关心任何文件的写变革;exfds:select监视的非常文件句柄凑集,当exfds映象的文件句柄上有分外情形发生时系统会见告select函数返回;timeout:select的超时结束韶光,设为0则为壅塞模式,设为大于0的值时若所监视的句柄无状态变革则等待timeout韶光后返回0;

配置函数:

FD_ZERO(fd_set fdset):清空fdset与所有文件句柄的联系。
FD_SET(int fd, fd_set fdset):建立文件句柄fd与fdset的联系。
FD_CLR(int fd, fd_set fdset):打消文件句柄fd与fdset的联系。
FD_ISSET(int fd, fdset fdset):检讨fdset联系的文件句柄fd是否可读写,>0表示可读写。

select函数非常强大,它能同时监测多个工具,只要在注册的工具集中有一个或多个工具被激活就会有反应,以是利用select函数能在一个线程中处理多个等待式操作,这里以多串口壅塞读取为例:

#include <string.h>#include <stdio.h>#include <assert.h>#include <sys/time.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <termios.h> #define USAR1 "/dev/ttyS1"#define USAR2 "/dev/ttyS2"#define USAR3 "/dev/ttyS3"#define USAR4 "/dev/ttyS4"char buf[255] = {0}; int set_port_attr (int fd,int baudrate, int databit, const char stopbit, char parity, int vtime,int vmin );static void set_baudrate (struct termios opt, unsigned int baudrate);static void set_data_bit (struct termios opt, unsigned int databit);static void set_stopbit (struct termios opt, const char stopbit);static void set_parity (struct termios opt, char parity); void main(){ int fd1,fd2,fd3,fd4; int ret; int rxlen = 0; fd_set rfds; struct timeval tv; int retval; fd1 = open(USAR1, O_RDWR | O_NOCTTY );//壅塞式读写 非壅塞| O_NDELAY | O_NONBLOCK if (fd1 < 0) { perror("open uart1 error\n"); } fd2 = open(USAR2, O_RDWR | O_NOCTTY );//壅塞式读写 非壅塞| O_NDELAY | O_NONBLOCK if (fd2 < 0) { perror("open uart2 error\n"); } fd3 = open(USAR3, O_RDWR | O_NOCTTY );//壅塞式读写 非壅塞| O_NDELAY | O_NONBLOCK if (fd3 < 0) { perror("open uart3 error\n"); } fd4 = open(USAR4, O_RDWR | O_NOCTTY );//壅塞式读写 非壅塞| O_NDELAY | O_NONBLOCK if (fd4 < 0) { perror("open uart4 error\n"); } ret = set_port_attr(fd1, B115200, 8, "1", 'N',1,255 ); / 115200 8n1 / if(ret < 0) { printf("set uart1 arrt faile \n"); exit(-1); } ret = set_port_attr(fd2, B115200, 8, "1", 'N',1,255 ); / 115200 8n1 / if(ret < 0) { printf("set uart2 arrt faile \n"); exit(-1); } ret = set_port_attr(fd3, B115200, 8, "1", 'N',1,255 ); / 115200 8n1 / if(ret < 0) { printf("set uart3 arrt faile \n"); exit(-1); } ret = set_port_attr(fd4, B115200, 8, "1", 'N',1,255 ); / 115200 8n1 / if(ret < 0) { printf("set uart4 arrt faile \n"); exit(-1); } while(1) { FD_ZERO(&rfds); FD_SET(fd1, &rfds); FD_SET(fd2, &rfds); FD_SET(fd3, &rfds); FD_SET(fd4, &rfds); // tv.tv_sec = 1; //in block mode is not used // tv.tv_usec = 0; ret = select(fd4 + 1, &rfds, NULL, NULL, NULL); //block mode if(ret > 0) { if(FD_ISSET(fd1,&rfds)) { rxlen = read(fd1, buf, 255); if(rxlen > 0) { printf("len = %d\n\r",rxlen); printf("rx:%s\n\r",buf); write(fd1, buf, rxlen); } } if(FD_ISSET(fd2,&rfds)) { rxlen = read(fd2, buf, 255); if(rxlen > 0) { printf("len = %d\n\r",rxlen); printf("rx:%s\n\r",buf); write(fd2, buf, rxlen); } } if(FD_ISSET(fd3,&rfds)) { rxlen = read(fd3, buf, 255); if(rxlen > 0) { printf("len = %d\n\r",rxlen); printf("rx:%s\n\r",buf); write(fd3, buf, rxlen); } } if(FD_ISSET(fd4,&rfds)) { rxlen = read(fd4, buf, 255); if(rxlen > 0) { printf("len = %d\n\r",rxlen); printf("rx:%s\n\r",buf); write(fd4, buf, rxlen); } } } }}

此段程序为同时监控4路串口吸收状态,将吸收的内容直接原路返回,串口采取的是壅塞读取模式,select函数也采取壅塞式读取模式。

原文地址:https://blog.csdn.net/m0_38096844/article/details/90716182?spm=1001.2014.3001.5502

标签:

相关文章