C语言 在linux中设置串口中断

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15119412/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 05:29:20  来源:igfitidea点击:

setting serial port interruption in linux

cubuntuserial-portinterruptinterruption

提问by gus

I am trying to set the interruption for a serial port in ubuntu (in program written in C), but it does not work. I have checked that the serial communication works correctly without the interruption, so I may be setting something wrong. The code is the following:

我正在尝试为 ubuntu 中的串行端口设置中断(用 C 编写的程序),但它不起作用。我已经检查过串行通信是否正常工作而没有中断,所以我可能设置错误。代码如下:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <fcntl.h>
    #include <sys/signal.h>
    #include <errno.h>
    #include <termios.h>

    void signal_handler_IO (int status);   /* definition of signal handler */

    int n;
    int fd;
    int connected;
    struct termios termAttr;
    struct sigaction saio;

    int main(int argc, char *argv[])
    {
         fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);
         if (fd == -1)
         {
            perror("open_port: Unable to open /dev/ttyO1\n");
            exit(1);
         }

         saio.sa_handler = signal_handler_IO;
         saio.sa_flags = 0;
         saio.sa_restorer = NULL; 
         sigaction(SIGIO,&saio,NULL);

         fcntl(fd, F_SETFL, FNDELAY);
         fcntl(fd, F_SETOWN, getpid());

         tcgetattr(fd,&termAttr);
         baudRate = B115200; 
         cfsetispeed(&termAttr,B115200);
         cfsetospeed(&termAttr,B115200);
         termAttr.c_cflag &= ~PARENB;
         termAttr.c_cflag &= ~CSTOPB;
         termAttr.c_cflag &= ~CSIZE;
         termAttr.c_cflag |= CS8;
         termAttr.c_cflag |= (CLOCAL | CREAD);
         termAttr.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
         termAttr.c_iflag &= ~(IXON | IXOFF | IXANY);
         termAttr.c_oflag &= ~OPOST;
         tcsetattr(fd,TCSANOW,&termAttr);
         printf("UART1 configured....\n");

         connected = 1;
         while(connected == 1){
               // some code
         }

         close(fd);
         exit(0);             
    }

    void signal_handler_IO (int status)
    {
         printf("received data from UART.\n");
    }

So anytime time another device send a message through the configured port, the message "received data from UART." is never displayed.

因此,每当另一个设备通过配置的端口发送消息时,该消息“从 UART 接收数据”。从不显示。

Any suggestion to solve this problem? Also, how does the system relate the interruption with the serial port?, I have read about signal.h but I have not found an answer for that. I got the interruption idea from this page: http://www.faqs.org/docs/Linux-HOWTO/Serial-Programming-HOWTO.html

有什么建议可以解决这个问题吗?另外,系统如何将中断与串行端口联系起来?,我已经阅读了有关 signal.h 的内容,但我还没有找到答案。我从这个页面得到了中断的想法:http: //www.faqs.org/docs/Linux-HOWTO/Serial-Programming-HOWTO.html

Thanks in advance for any help. Thanks in advance.

在此先感谢您的帮助。提前致谢。

采纳答案by Chris Dodd

The problem is that you're disabling signals from the file descriptor by clearing the FASYNCflag with F_SETFL. You need to set that if you want to get signals:

问题是您通过清除FASYNC标志来禁用来自文件描述符的信号F_SETFL。如果你想获得信号,你需要设置它:

fcntl(fd, F_SETFL, FNDELAY|FASYNC);

Also, you might want to use the POSIX names for these flags (O_NDELAYand O_ASYNC) rather than the BSD names for more portability, though either will work on Linux.

此外,您可能希望对这些标志(O_NDELAYO_ASYNC)使用 POSIX 名称而不是 BSD 名称以获得更多的可移植性,尽管两者都适用于 Linux。

回答by user2178077

I have found that a piece of code is missing for the original code to work as expected. The code below is working on Linux compiled with gcc. The added line of code is the one marked with /**<<<<<<------This line made it work.**/
One line was also commented out : //baudRate = B115200;.

我发现缺少一段代码才能使原始代码按预期工作。下面的代码在用 gcc 编译的 Linux 上工作。添加的代码/**<<<<<<------This line made it work.**/
行是标记为One line 的那一行也被注释掉了 : //baudRate = B115200;

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <sys/signal.h>
#include <errno.h>
#include <termios.h>

void signal_handler_IO (int status);   /* definition of signal handler */

int n;
int fd;
int connected;
struct termios termAttr;
struct sigaction saio;

int main(int argc, char *argv[])
{
     fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);
     if (fd == -1)
     {
        perror("open_port: Unable to open /dev/ttyO1\n");
        exit(1);
     }

     saio.sa_handler = signal_handler_IO;
     saio.sa_flags = 0;
     saio.sa_restorer = NULL; 
     sigaction(SIGIO,&saio,NULL);

     fcntl(fd, F_SETFL, FNDELAY);
     fcntl(fd, F_SETOWN, getpid());
     fcntl(fd, F_SETFL,  O_ASYNC ); /**<<<<<<------This line made it work.**/

     tcgetattr(fd,&termAttr);
     //baudRate = B115200;          /* Not needed */
     cfsetispeed(&termAttr,B115200);
     cfsetospeed(&termAttr,B115200);
     termAttr.c_cflag &= ~PARENB;
     termAttr.c_cflag &= ~CSTOPB;
     termAttr.c_cflag &= ~CSIZE;
     termAttr.c_cflag |= CS8;
     termAttr.c_cflag |= (CLOCAL | CREAD);
     termAttr.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
     termAttr.c_iflag &= ~(IXON | IXOFF | IXANY);
     termAttr.c_oflag &= ~OPOST;
     tcsetattr(fd,TCSANOW,&termAttr);
     printf("UART1 configured....\n");

     connected = 1;
     while(connected == 1){
           // some code
     }

     close(fd);
     exit(0);             
}

void signal_handler_IO (int status)
{
     printf("received data from UART.\n");
}

The output from the program was:

程序的输出是:

./a.out 
UART1 configured....
received data from UART.
received data from UART.
received data from UART.
^C

I hope that works for you too.

我希望这对你也有用。

回答by Barath Ravikumar

Any suggestion to solve this problem? Also, how does the system relate the interruption with the serial port?

有什么建议可以解决这个问题吗?另外,系统如何将中断与串口相关联?

The serial port interrupt is written inside the device part of the serial driver in linux kernel. The interrupt is handled by the driver itself , so you can have not control over it.

串口中断写在linux内核中串口驱动的设备部分。中断由驱动程序本身处理,因此您无法控制它。

What the above program is doing is , notifying you through a signal , when a receive interrupt of the serial part device is triggered.

上述程序所做的是,当串行部分设备的接收中断被触发时,通过信号通知您。

The above signal handling is not related to interrupts , it is more of even handling. First you register , your program , to get a signal when an io interrupt occours , the signal handler in your program will then display the printf message.

以上信号处理与中断无关,更多的是偶数处理。首先,您注册您的程序,以便在发生 io 中断时获取信号,然后程序中的信号处理程序将显示 printf 消息。

I think the signal handling in your program , is not implemented properly Just correct the signal parts of your program

我认为您程序中的信号处理没有正确实现只需更正程序的信号部分

sigset_t mskvar_1                   //Variable of signal bitfieldtype
struct sigaction sigio_action       //Structure which describes signal handler
void sio_handler(void);             //Signal handler function

int main()
{
  sigfillset(&mskvar_1);                    //set all mask bits of maskbit variable
  sigprocmask(SIG_SETMASK,&mskvar_1,NULL);  //write the mask info present in mskvar_1 to the pd
  sigdelset(&mskvar_1,SIGIO);               //Unmask SIGIO , to register for IO Interrupt Events

  sigio_action.sa_handler = sio_handler;    //Configure Signal Handler
  sigio_action.sa_flags  = 0;
  sigfillset(&sigio_action.sa_mask);
  sigaction(SIGIO,&sigio_action,NULL);      //Install Signal handler

  // Serial port initializtion here
  // Set Serial port parameters , Baud Rate and flags


while(1);
return 0;
}


void sio_handler()
{
  printf("\nSIGIO RECEIVED , I/O interrupt signalled?\n");
  return;
}