C:串口 select函数使用

接收缓存区:

/* 接收长度 */
int recv_len;
	
/* 接收缓存区 */
char  recv_buf[1024];

串口接收函数:

void Uart1::RecvSerial(int fd)
{
	fd_set fds; 
    struct timeval timeout={1,0}; //select等待1秒,1秒轮询,要非阻塞就置0
	int select_ret=-1;
	while(true)
		{
			FD_ZERO(&fds); //每次循环都要清空集合,否则不能检测描述符变化
			FD_SET(fd,&fds); //添加描述符
			select_ret = select(fd+1,&fds,NULL,NULL,&timeout);
			switch(select_ret)   //select使用
				{
				case -1:
					exit(-1);
					break; //select错误,退出程序
				case 0:
					break; //再次轮询
				default:
					if(FD_ISSET(fd,&fds)) //测试fd是否可读。即是否有串口数据
						{
							recv_len=read(fd, recv_buf, sizeof(recv_buf));
							recv_buf[recv_len] = '\0';
							printf("recv_buf : %s \n", recv_buf);	
						}
				}
		}
}

其中fd为打开串口的文件描述符。使用open函数打开串口,是否阻塞和select无关。

/* 以阻塞的方式打开 */
	int fd = open(dev_name_buf,  O_RDWR|O_NOCTTY);
/* 以非阻塞的方式打开 */	
	/* int fd = open(dev_name_buf,  O_RDWR); */

上述两种打开,在接收函数中都是可以正常使用的。open传入的阻塞参数只是对read函数起作用。

关于selecet函数:

函数原型:

int select(int nfds,fd_set * readfds,fd_set * writefds,fd_set * exceptfds,struct timeval * timeout);

参数nfds:select监视的文件句柄数。

视进程中打开的文件数而定,一般设为你要监视各文件中的最大文件号加一。

(注:nfds并非一定表示监视的文件句柄数。官方文档仅指出nfds is the highest-numbered file descriptor in any of the three sets, plus 1. (可在linux环境中通过man select命令查得))

参数readfds、writefds和exceptfds 称为描述词组,是用来回传该描述词的读,写或例外的状况。

readfds:select监视的可读文件句柄集合。

writefds: select监视的可写文件句柄集合。

exceptfds:select监视的异常文件句柄集合。

对该三种描述词组的操作有如下宏可供使用:

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, fd_set *fdset):检查fdset联系的文件句柄fd是否可读写,当>0表示可读写。

(关于fd_set及相关宏的定义见/usr/include/sys/types.h)

struct timeval是一个大家常用的结构,用来代表时间值,有两个成员,一个是秒数,另一个是毫秒数。

struct timeval
{
	time_t tv_sec;
	time_t tv_usec;
};

上述接收函数中,select函数中第三个参数传入NULL,表示不关心任何文件的写变化。

参考链接:
https://www.cnblogs.com/zhengAloha/p/8661762.html

https://blog.csdn.net/zimiao815/article/details/52806133


20190709补充:

Linux man中提供的函数:

       #include <stdio.h>
       #include <stdlib.h>
       #include <sys/time.h>
       #include <sys/types.h>
       #include <unistd.h>

       int
       main(void)
       {
           fd_set rfds;
           struct timeval tv;
           int retval;

           /* Watch stdin (fd 0) to see when it has input. */
           FD_ZERO(&rfds);
           FD_SET(0, &rfds);

           /* Wait up to five seconds. */
           tv.tv_sec = 5;
           tv.tv_usec = 0;

           retval = select(1, &rfds, NULL, NULL, &tv);
           /* Don't rely on the value of tv now! */

           if (retval == -1)
               perror("select()");
           else if (retval)
               printf("Data is available now.\n");
               /* FD_ISSET(0, &rfds) will be true. */
           else
               printf("No data within five seconds.\n");

           exit(EXIT_SUCCESS);
       }

使用select函数进行串口的读写时,需要将串口文件描述符(通常为整数)添加到select函数的监视对象集合中。在调用select函数之前,需要首先打开串口并设置其参数,例如波特率、数据位、停止位等。一般情况下,可以通过以下步骤设置串口: 1. 打开串口使用open函数打开串口文件,例如 /dev/ttyS0。 2. 设置串口参数:使用tcsetattr函数设置串口的参数,例如波特率、数据位、停止位等。 3. 将串口文件描述符添加到select函数的监视对象集合中。 4. 使用select函数进行读写操作:在监视对象集合中有数据可读或可写时,select函数会返回,此时可以使用read或write函数进行读写操作。 下面是一个简单的示例代码,演示如何使用select函数进行串口读写: ``` #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <termios.h> #include <sys/select.h> int main() { int fd; struct termios options; fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NONBLOCK); if (fd == -1) { perror("open"); exit(EXIT_FAILURE); } // 设置串口参数 tcgetattr(fd, &options); cfsetispeed(&options, B9600); cfsetospeed(&options, B9600); options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB; options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; tcsetattr(fd, TCSANOW, &options); // 将串口文件描述符添加到监视对象集合中 fd_set readfds, writefds; FD_ZERO(&readfds); FD_ZERO(&writefds); FD_SET(fd, &readfds); FD_SET(fd, &writefds); while (1) { // 使用select函数进行读写操作 select(fd + 1, &readfds, &writefds, NULL, NULL); if (FD_ISSET(fd, &readfds)) { char buf[1024]; int len = read(fd, buf, sizeof(buf)); if (len > 0) { // 处理读取到的数据 printf("Received %d bytes: %.*s\n", len, len, buf); } } if (FD_ISSET(fd, &writefds)) { char msg[] = "Hello, world!"; int len = write(fd, msg, sizeof(msg)); if (len > 0) { // 处理已发送的数据 printf("Sent %d bytes: %.*s\n", len, len, msg); } } } close(fd); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值