原创 关于linux的串口中断问题★★★★★

2011-6-14 21:23 2803 10 10 分类: MCU/ 嵌入式
 
请问一下linux的串口中断是怎么实现的
 
driver/char/serial.c  
   
  在   static   int   startup(struct   async_struct   *   info)   函数中设置  
  一般为以下三个函数中的一个  
  rs_interrupt_multi    
  rs_interrupt    
  rs_interrupt_single
 
======================================================
 
看了很多关于串口编程的例子,大都是先初始化,设置波特率等,然后就用一个while(1)一直读串口,想请高手指点一下,能否用中断机制,而不要一直查询呢,谢谢
----------------------
在while中使用select,这样应该可以的。
-----------------------
需要用到:1、select   2、singal
----------------------
可以这样  
  1)新建立一个线程使用select来监听串口,发现数据发送出一个信号  
  2)打开的时候使用O_ASYNC标志,处理SIGIO信号  
   
  SIGIO不是异步IO,只是IO的信号机制,异步IO是AIO的方式
------------------------
============================================================
 
各位大侠,小弟先急需写一个类似DOS下面的串口中断接收发送数据的程序,由于第一次用Linux,不清楚怎么用,看了看,好像应该是对设备的信号量的操作,大家给点代码看看,谢谢
 
具体的是这样,主程序是一个死循环(在计算数据),这个时候,需要响应串口传过来的数据进行计算,需中断响应,这个程序怎么写?我用了termios这个结构,很奇怪的是,可以接收(用信号,听说这个类似DOS的INT),但是不能够发送,不知道哪里出错了,相串口发送数据是(write(fd,buff,100))这个函数吗?  
  有其他的函数吗?我在DOS下面用的outportb这个,直接对地址发送(outportb(0x3f8,buff,1))Linux下面的outb这个函数是否一样,给小弟一个解答!!写谢谢!!
---------------------------
给个简单例子:  
  void   sService()  
  {  
          struct   timeval   WaitTime;  
          int   ret,MaxFd;  
          int   nread,nwrite,i,j;  
  fd_set   readfs;          
   
          WaitTime.tv_sec   =   0;  
  WaitTime.tv_usec   =   20000;  
  FD_ZERO(&readfs);  
  FD_SET(fd[0],&readfs);  
  FD_SET(fd[1],&readfs);  
          FD_SET(fd[2],&readfs);  
          FD_SET(fd[3],&readfs);  
          FD_SET(fd[4],&readfs);  
          FD_SET(fd[5],&readfs);  
          FD_SET(fd[6],&readfs);  
          FD_SET(fd[7],&readfs);  
          MaxFd   =   MAX(8,fd)+1;  
           
          ret   =   select(MaxFd,   &readfs,   NULL,   NULL,   &WaitTime);  
          if   (ret>0)  
          {  
                  for   (i=0;i<8;i++)  
                  {  
                          if   (FD_ISSET(fd,   &readfs))  
                          {  
                              //接收串口数据                            
                          }  
                  }  
          }  
  }  
   
   
  int   main(int   argc,char   *argv[])  
  {  
        signal(SIGIO,sService);  
        while(1)  
  {  
  //业务处理  
  }  
  }
-----------------------------------------
你不能在你的程序中直接调用端口读写函数,必须利用驱动程序去读写。对串口和对文件操作差不多。就是多了设置串口这一步。  
  open(...)  
  tcsetattr(...)  
  read(...)/write(...)  
  close(...)  
   
  So   EZ!
------------------------------------
#ifdef   HAVE_CONFIG_H  
  #include   <config.h>  
  #endif  
   
   
  #include   <fcntl.h>  
  #include   <stdio.h>  
  #include   <stdlib.h>  
  #include   <string.h>  
  #include   <sys/stat.h>  
  #include   <sys/time.h>  
  #include   <sys/types.h>  
  #include   <unistd.h>  
   
  #ifdef   HAS_GETOPT_H  
  #include   <getopt.h>  
  #endif  
  extern   char*   optarg;  
   
  #include   <liberror/liberror.h>  
  #include   <libtty/libtty.h>  
   
  #define   USAGE_MSG   \  
        "modemtalk   ("   ##   VERSION   ##   ")\n"\  
        "usage:\n"   \  
        "             modemtalk   [-h]   [-m   dev]\n"   \  
        "\n"   \  
        "where   options   include:\n"   \  
        "           -h                       print   out   this   message\n"   \  
        "           -m   dev               use   modem   device   dev\n"   \  
        "           -v                       displays   version   information\n"\  
        "\n"  
  #define   VERSION_MSG   \  
        "modemtalk   version   "   ##   VERSION   ##   "\n"  
         
  static   char*   opt_string   =   "hm:v";  
   
  static   void   usage()  
  {  
        fprintf(   stdout,   USAGE_MSG   );  
  }  
   
  static   void   version()  
  {  
        fprintf(   stdout,   VERSION_MSG   );  
  }  
   
  void   main(   int   argc,   char*   argv[]   )  
  {  
        int   fdesc;  
        int   bytes;  
        int   i;  
        int   dest;  
        int   nfsd;  
        int   c;  
        fd_set   io;  
        char   buf[512];  
        char*   device;  
         
        /*   get   device   name   from   environment   */  
        device   =   getenv(   "MODEM"   );  
         
        /*   parse   command   line   arguments   */  
        while(   1   )  
        {  
              c   =   getopt(   argc,   argv,   opt_string   );  
              if(   c   ==   -1   )  
                    break;  
              switch(   c   )  
              {  
                    case   'h'   :  
                          usage();  
                          exit(   0   );  
                    case   'm'   :  
                          device   =   strdup(   optarg   );  
                          break;  
                    case   'v'   :  
                          version();  
                          exit(   0   );  
                    default:  
                          exit(   1   );  
                          break;  
              }  
        }  
   
        /*   open   terminal   (modem)   device   */  
        fdesc   =   open(   device,   O_RDWR   );  
        if(   fdesc   ==   -1   )  
        {  
              FAIL(   "open"   );  
              exit(   1   );  
        }  
        ttySetRaw(   STDIN_FILENO   );  
   
   
        /*  
          *   enter   loop.   Data   reseived   from   stdin   is   copied   to   fdesc.  
          *   data   read   from   fdesc   is   written   to   stdout  
          */  
        while(   1   )  
        {  
              FD_ZERO(   &io   );  
              FD_SET(   fdesc,   &io   );  
              FD_SET(   STDIN_FILENO,   &io   );  
   
              nfsd   =   select(   FD_SETSIZE,   &io,   NULL,   NULL,   NULL   );  
              if(   nfsd   <   0   )  
              {  
                    FAIL(   "select"   );  
                    exit(   1   );              
              }  
   
              if(   nfsd   >   0   )  
                    for(   i   =   0;   i   <   FD_SETSIZE;   i++   )  
                          if(   FD_ISSET(   i,   &io   )   )  
                          {  
                                if(   i   ==   STDIN_FILENO   )  
                                      dest   =   fdesc;  
                                else  
                                      dest   =   STDOUT_FILENO;   /*   stdout   */  
   
                                /*   read   from   device   */  
                                bytes   =   read(   i,   buf,   sizeof(   buf   )   );  
                                if(   bytes   <   0   )  
                                {  
                                      FAIL(   "read"   );  
                                      exit(   1   );  
                                }  
                                /*   eof   */  
                                if(   bytes   ==   0   )  
                                      exit(   0   );  
   
                                bytes   =   write(   dest,   buf,   bytes   );  
                                if(   bytes   <   0   )  
                                {  
                                      FAIL(   "write"   );  
                                      exit(   1   );  
                                }  
                                if(   bytes   ==   0   )  
                                      exit(   0   );   /*   eof   */  
                          }  
        }  
  }
-------------------------------------------
http://www-900.ibm.com/developerWorks/cn/linux/l-serials/index.shtml  
     
    Linux下串口编程入门  
---------------------------------------------
你在Linux下是不能使用中断来写程序的,除非你写Linux驱动来实现。这和DOS不一样,因为Linux是运行在保护模式下的。
-------------------------------------
你的UART芯片是什么?你的卡是ISA的还是PCI的?如果是现成的卡,那你利用Linux自带的drivers\char\serial.c修改一下就可以了,这个文件支持大多数目前流行的UART。
------------------------------------
好好看看Linux的串口书籍。
-----------------------------------
===============================================================
 
我正在编一个串口程序,是用TTY吧?但我找的所有LINUX串口程序都是这样做的  
  while(1)  
  {  
  while((nread   =   read(fd,buff,512))>0)  
  {  
  printf("\n%s",buff);  
  }  
  }  
  怎么样才能实现在LINUX下的串口中断接收呀,是不是TTY不支持呀
-------------------------------------
如果你想在应用程序中实现中断接收的话,可以模仿一个,就是用多线程加信号的方式,开辟一个新的线程轮询串口,收到数据后就向主线程发信号,对于主线程来说,相当于是中断接收了
-------------------------------------
====================================================================
 
需要在linux下用中断方式来写一个串口的程序,现在没有思路,网上有人说用select,signal,tasklet函数的,但是我没看懂,希望有做过的给一下例程,多谢!
----------------------------
Linux下用中断方式 ?

内核态才有中断, 用户态,只有软中断 即 信号。
你想要什么样子的?
----------------------------
就是能够当串口数据来临时自动通知串口读取数据,类似于中断,以前在windows下面做串口时用的是单独开辟一个线程来监测信号量,不知道在Linux下面怎么实现
----------------------------
linux 下跟windows 下差不多,  最好也是开一个线程来处理。
-----------------------------
http://www.ibm.com/developerworks/cn/linux/l-serials/index.html

建议你看看这篇文章。
-----------------------------
最好是单处开1个进程,线程会阻塞其他同进程的线程!
 
==================================================================
 
我是新来的linux菜鸟,以后还请大家多多帮助.在这里谢谢了.
  我现在要在linux下进行串口通信,程序用C编写,然后移植到ARM中,现在我很困惑关于串口的读写问题,我看了大多数程序只能在while循环里反复的读写串口,这样太浪费资源,我没有时间处理接收过来的数据了,还有就是使用select() 定时查询也很麻烦,关键是我不知道外部数据什么时候进来,请问有没有其他中断的方法,好比C51中有数据进入RI自动置位,进入串口中断程序.
  可能问题比较幼稚,还请各位大侠帮帮忙,我在网上查了好长时间也没有查到,谁有这方面例程请给我一个,谢谢!.      
-----------------------------
select调用,属于事件、超时触发!意思是:在设定的时间内,如果串口有数据,则不用等到超时,系统就会唤醒程序处理;如果到了设定的时间还没有数据,系统也会唤醒程序处理超时情况!select()的响应时间粒度在2.4上是10ms!在2.6上,比这个时间更短(应为可抢占的因素) 
 
=================================================================
 
我在linux系统下写的串口程序,需要实时的读取串口来的数据,但串口来的数据又是不定时的,想用中断的方式响应,看了一些资料,总觉的还所有些不妥。

首先,select函数,他需要一直在while中检测读文件描述符是否有变化,但串口来了数据会改变文件描述符吗?(即使我的串口一直处在open状态中)另外,即使能检测到文件描述符有了变化,那程序也都一直在while中,CPU将不能再做其他的事情。
其次,signal函数,串口来了数据,系统会自动广播SIGIO信号吗?即使能捕捉的这个信号,程序进入中断服务子程序中执行,那下一个串口数据又如何响应,难道在中断子程序的结尾再调用 signal函数吗?那CPU又将陷入这个等待串口数据的程序中,而不能做其他的事情了,而且SIGIO信号怎么能保证就是串口来的呢?
最后,tasklet,这个中断机制如何实现,他应该是在串口硬中断服务程序中定义中断的下班部分的入口,但这个硬中断服务程序又在什么地方?需要修改内核吗?

上只是我个人的理解,如有不正确的,请过来人指教。我现在希望串口数据能像以前用单片机一样,真正实现中断响应,只有当串口来数据时,CPU或者内核才会去执行串口读相关动作,串口没有数据时,CPU或者内核是完全不会理会串口的,不知哪位高人可以指点一下,如何来实现?
-------------------------------------
可以起一个线程,用select函数,其实这个函数很好用,你看看书,unix系统编程、unix网络编程上都有详细介绍。
-------------------------------------
首先,select函数,他需要一直在while中检测读文件描述符是否有变化,但串口来了数据会改变文件描述符吗?(即使我的串口一直处在open状态中)另外,即使能检测到文件描述符有了变化,那程序也都一直在while中,CPU将不能再做其他的事情。

答:select 的函数不需要每个cpu的时间片都去查询文件描述符是否发生过变化,

while(1)
{

  sleep(200);
  select();//这样就不会造成cpu的一直占用了。
 
}
http://www.faqs.org/docs/Linux-HOWTO/Serial-Programming-HOWTO.html
---------------------------------------
linux 下的标准串口,在核心的驱动程序中是通过中断方式处理的。
你如果做的是应用层的程序,那么可以采用 select 方式监测“读文件描述符”。
select 也并非你说的那样一直 while 等待方式,它是在中断中接收到对端发来
的数据后唤醒并通知应用程序:串口接收到数据 ...

如果你要像单片机方式,那么就需要实现一个自己的串口驱动运行在核心 ...
--------------------------------------

文章评论0条评论)

登录后参与讨论
我要评论
0
10
关闭 站长推荐上一条 /2 下一条