epoll 获取串口数据 亲测可用

串口助手发送八个字节,linux接收并打印。必须发送8个字节(这是bug。当然也可以在程序里改成必须发送9个字节)
#include     <stdio.h>  
#include     <stdlib.h>   
#include     <unistd.h>    
#include     <sys/types.h>  
#include     <sys/stat.h>  
#include     <fcntl.h>   
#include     <termios.h>  
#include     <errno.h>  
#include     <string.h>  
#include     <pthread.h>
#include     <sys/epoll.h>

#define MAXEVENTS 64
int fd; 
int efd;

void pthread_uartrecv(void)
{
  int n,i,nread,s;

  char buff[20];
  struct epoll_event event;
  struct epoll_event* events;
  events=calloc(MAXEVENTS,sizeof event);  
  efd=epoll_create(5);//epoll support number is 5 
  event.data.fd=fd;
  event.events=EPOLLIN|EPOLLET; //et mod,put in data
  s=epoll_ctl(efd,EPOLL_CTL_ADD,fd,&event);  
  
  while(1)
  {
	int len=0;
	bzero(buff,8);
	while(1)
	{
	    n=epoll_wait(efd,events,MAXEVENTS,-1);// -1 :wait until it happen
	    for(i=0;i<n;i++)
	    {
		if((events[i].events & EPOLLERR)||(events[i].events & EPOLLHUP)||(!(events[i].events & EPOLLIN)))
		{
			fprintf(stderr,"epoll error\n");  
		        close(events[i].data.fd);  
		        continue;  
		} 
		else 
		{
			nread = read(events[i].data.fd,buff+len,8);
			tcdrain(fd); 
			tcflush(fd,TCIOFLUSH); 
			len=len+nread;
			printf("nread=%d,len=%d\n",nread,len);
		}
	    }
	    if(len>=8)
		break;
	}
	printf("%s\n",buff); 
  }
}
    
int main()  
{  
    int flags;
    struct termios opt;   
    //fd = open("/dev/ttyUSB0", O_RDWR|O_NOCTTY|O_NDELAY); 
    fd = open("/dev/ttyUSB0", O_RDWR|O_NOCTTY|O_NONBLOCK); 
    //fcntl(fd, F_SETFL, 0); 
    //flags=fcntl(fd, F_GETFL, 0); 
    //flags|=O_NONBLOCK;
    //fcntl(fd, F_SETFL, flags); 

    tcgetattr(fd, &opt);        
    cfsetispeed(&opt, B9600);  
    cfsetospeed(&opt, B9600);  
    if(tcsetattr(fd, TCSANOW, &opt) != 0 )  
    {       
       perror("tcsetattr error1");  
       return -1;  
    }  
    opt.c_cflag &= ~CSIZE;    
    opt.c_cflag |= CS8;     
    opt.c_cflag &= ~CSTOPB;   
    opt.c_cflag &= ~PARENB;   
    opt.c_iflag &= ~INPCK;//opt.c_cflag &= ~INPCK;the last this is fetal set  
    opt.c_cflag |= (CLOCAL | CREAD);  
    opt.c_cflag &= ~CRTSCTS;
    opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);  
    opt.c_oflag &= ~OPOST;  
    opt.c_oflag &= ~(ONLCR | OCRNL);    //添加的  
    opt.c_iflag &= ~(ICRNL | INLCR);  
    opt.c_iflag &= ~(IXON | IXOFF | IXANY);    //添加的   
    opt.c_cc[VTIME] = 8;  
    opt.c_cc[VMIN] = 10;  
      
    tcflush(fd, TCIOFLUSH);  
   
    printf("configure complete\n");  
     
    if(tcsetattr(fd, TCSANOW, &opt) != 0)  
    {  
        perror("serial error");  
        return -1;  
    }   
    
    pthread_t id;
    pthread_create(&id,NULL,(void*)pthread_uartrecv,NULL);
  
    while(1)  
    {    
        sleep(2);
	printf("this is main function\n");
    }  
}
为了改善上述bug
 void pthread_uartrecv(void)
{
  int n,i,nread,s;
  char buff[20];
  struct epoll_event event;
  struct epoll_event* events;
  events=calloc(MAXEVENTS,sizeof event);  
  efd=epoll_create(5);//epoll support number is 5 
  event.data.fd=fd;
  event.events=EPOLLIN|EPOLLET; //et mod,put in data
  s=epoll_ctl(efd,EPOLL_CTL_ADD,fd,&event);  
  
  while(1)
  {
	int len=0;
	bzero(buff,20);
	while(1)
	{
	    //printf("here epoll_wait\n");
	    n=epoll_wait(efd,events,MAXEVENTS,20);// -1 :wait until it happen
	    for(i=0;i<n;i++)
	    {
		nread = read(events[i].data.fd,buff+len,20);
		if(nread>0)
		{
		    tcdrain(fd); 
		    tcflush(fd,TCIOFLUSH); 
		    len=len+nread;
		    printf("nread=%d,len=%d\n",nread,len);
		}
	    }
	    if(n==0)
	    {
		break;
	    }
	}
	if(len>0)
	    printf("%s\n",buff); 
  }
}

或者 封装成函数

#include     <stdio.h>  
#include     <stdlib.h>   
#include     <unistd.h>    
#include     <sys/types.h>  
#include     <sys/stat.h>  
#include     <fcntl.h>   
#include     <termios.h>  
#include     <errno.h>  
#include     <string.h>  
#include     <pthread.h>
#include     <sys/epoll.h>

#define MAXEVENTS 64
int fd; 
int efd;

//
int epoll_read(char *buff,int datalen)
{
    
    int n,i,nread,len;
    struct epoll_event event;
    struct epoll_event* events;
    events=calloc(MAXEVENTS,sizeof event);  
    efd=epoll_create(5);//epoll support number is 5 
    event.data.fd=fd;
    event.events=EPOLLIN|EPOLLET; //et mod,put in data
    epoll_ctl(efd,EPOLL_CTL_ADD,fd,&event);  
    len=0;
    while(1)
    {
	n=epoll_wait(efd,events,MAXEVENTS,20);// -1 :wait until it happen
	for(i=0;i<n;i++)
	{
	    nread = read(events[i].data.fd,buff+len,datalen);
	    if(nread>0)
	    {
		tcdrain(fd); 
		tcflush(fd,TCIOFLUSH); 
		len=len+nread;
		printf("nread=%d,len=%d\n",nread,len);
	    }
	}
	if(n==0)
	{
	    break;
	}
    }
    free(events);
    close(efd); //please close efd after used epoll 这是易错点,否则会导致后面无法接收串口数据
    return len;
}
void pthread_uartrecv(void)
{
  

  char buff[20];
  while(1)
  {
	int len=0;
	bzero(buff,20);
	len=epoll_read(buff,20);
	if(len>0)
	    printf("len=%d,buff=%s\n",len,buff); 
  }
}
    
int main()  
{  
    int flags;
    struct termios opt;   
    //fd = open("/dev/ttyUSB0", O_RDWR|O_NOCTTY|O_NDELAY); 
    fd = open("/dev/ttyUSB0", O_RDWR|O_NOCTTY|O_NONBLOCK); 
    //fcntl(fd, F_SETFL, 0); 
    //flags=fcntl(fd, F_GETFL, 0); 
    //flags|=O_NONBLOCK;
    //fcntl(fd, F_SETFL, flags); 

    tcgetattr(fd, &opt);        
    cfsetispeed(&opt, B9600);  
    cfsetospeed(&opt, B9600);  
    if(tcsetattr(fd, TCSANOW, &opt) != 0 )  
    {       
       perror("tcsetattr error1");  
       return -1;  
    }  
    opt.c_cflag &= ~CSIZE;    
    opt.c_cflag |= CS8;     
    opt.c_cflag &= ~CSTOPB;   
    opt.c_cflag &= ~PARENB;   
    opt.c_iflag &= ~INPCK;//opt.c_cflag &= ~INPCK;the last this is fetal set  
    opt.c_cflag |= (CLOCAL | CREAD);  
    opt.c_cflag &= ~CRTSCTS;
    opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);  
    opt.c_oflag &= ~OPOST;  
    opt.c_oflag &= ~(ONLCR | OCRNL);    //添加的  
    opt.c_iflag &= ~(ICRNL | INLCR);  
    opt.c_iflag &= ~(IXON | IXOFF | IXANY);    //添加的   
    opt.c_cc[VTIME] = 8;  
    opt.c_cc[VMIN] = 10;  
      
    tcflush(fd, TCIOFLUSH);  
   
    printf("configure complete\n");  
     
    if(tcsetattr(fd, TCSANOW, &opt) != 0)  
    {  
        perror("serial error");  
        return -1;  
    }   
    
    pthread_t id;
    pthread_create(&id,NULL,(void*)pthread_uartrecv,NULL);
  
    while(1)  
    {    
        sleep(2);
	printf("this is main function\n");
    }  
}



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
类似于在网络编程中使用epoll来监听文件描述符的变化一样,在串口编程中也可以使用epoll来实现监听串口是否有数据可读。但是在读取串口数据时可能会出现卡死的问题,这是因为read函数默认是阻塞的,如果没有数据可读,会一直等待,导致程序卡死。 为了解决这个问题,可以将串口设置为非阻塞模式,这样当没有数据可读时,read函数会立即返回,并返回-1并设置errno为EAGAIN或EWOULDBLOCK。在使用epoll监听串口时,当检测到串口数据可读时,再使用非阻塞模式的read函数读取数据,如果返回值为-1且errno为EAGAIN或EWOULDBLOCK,则说明当前没有数据可读,程序可以继续执行其他操作。 下面是一个使用epoll监听串口并读取数据的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <termios.h> #include <sys/epoll.h> #define BUF_SIZE 1024 #define MAX_EVENTS 10 int main(int argc, char *argv[]) { int fd; struct termios tty; struct epoll_event ev, events[MAX_EVENTS]; char buf[BUF_SIZE]; int n, i, nfds, epollfd; // 打开串口 fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NONBLOCK); if (fd == -1) { perror("open"); exit(EXIT_FAILURE); } // 设置串口属性 memset(&tty, 0, sizeof(tty)); tty.c_cflag = B9600 | CS8 | CLOCAL | CREAD; tty.c_iflag = IGNPAR; tty.c_oflag = 0; tty.c_lflag = 0; tcsetattr(fd, TCSANOW, &tty); // 创建epoll实例 epollfd = epoll_create1(0); if (epollfd == -1) { perror("epoll_create1"); exit(EXIT_FAILURE); } // 添加串口描述符到epoll实例中 ev.events = EPOLLIN; ev.data.fd = fd; if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) { perror("epoll_ctl"); exit(EXIT_FAILURE); } while (1) { // 等待文件描述符变化 nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1); if (nfds == -1) { perror("epoll_wait"); exit(EXIT_FAILURE); } // 处理所有可读事件 for (i = 0; i < nfds; i++) { if (events[i].events & EPOLLIN) { // 读取串口数据 n = read(fd, buf, BUF_SIZE); if (n == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // 当前没有数据可读,继续执行其他操作 continue; } else { perror("read"); exit(EXIT_FAILURE); } } else if (n == 0) { // 串口已关闭 printf("Serial port closed.\n"); exit(EXIT_SUCCESS); } else { // 处理读取到的数据 buf[n] = '\0'; printf("Received data: %s", buf); } } else if (events[i].events & (EPOLLHUP | EPOLLERR)) { // 串口出错或被关闭 printf("Serial port error or closed.\n"); exit(EXIT_FAILURE); } } } // 关闭串口 close(fd); return 0; } ``` 在上面的示例代码中,我们使用了非阻塞模式的read函数来读取串口数据,并在epoll事件循环中处理所有可读事件。当没有数据可读时,程序会立即返回并继续执行其他操作,避免了read函数阻塞程序的问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值