【问题标题】:setting serial port interruption in linux在linux中设置串口中断
【发布时间】:2013-02-27 18:22:29
【问题描述】:

我正在尝试在 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");
    }

因此,只要其他设备通过配置的端口发送消息,消息“从 UART 接收数据”。从不显示。

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

提前感谢您的帮助。 提前致谢。

【问题讨论】:

  • 1) 在 ttyS 的初始化完成之前,我不会安装信号处理程序。 2) 您不应从信号处理程序调用 printf(); printf() 是不可重入的。
  • 感谢您的回答,但是在您的 cmets 之后,“中断”仍然不起作用。还有什么想法吗?

标签: c ubuntu serial-port interrupt interruption


【解决方案1】:

我发现原始代码缺少一段代码才能按预期工作。下面的代码在使用 gcc 编译的 Linux 上运行。添加的代码行是标有/**&lt;&lt;&lt;&lt;&lt;&lt;------This line made it work.**/
还注释掉了一行://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");
}

程序的输出是:

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

我希望这也对你有用。

【讨论】:

  • 非常感谢您的回答,现在说得通了。
  • 为什么你的输出显示了3次?
  • 有没有办法显示一次?
【解决方案2】:

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

fcntl(fd, F_SETFL, FNDELAY|FASYNC);

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

【讨论】:

    【解决方案3】:

    有解决这个问题的建议吗?还有,系统是怎么把中断和串口联系起来的?

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

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

    上述信号处理与中断无关,更多的是偶数处理。 首先你注册,你的程序,当一个io中断发生时得到一个信号,你程序中的信号处理程序会显示printf消息。

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

    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;
    }
    

    【讨论】:

    • 感谢您的回答,但是信号(“中断”)仍然不起作用,并且我已经检查了程序通过端口正确接收/传输数据。你有其他方法来解决这个问题吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多