2013-02-27 23 views
7

Sto cercando di impostare l'interruzione per una porta seriale in ubuntu (nel programma scritto in C), ma non funziona. Ho controllato che la comunicazione seriale funzioni correttamente senza l'interruzione, quindi potrei impostare qualcosa di sbagliato. Il codice è il seguente:impostazione interruzione porta seriale in linux

#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"); 
    } 

Così il tempo in qualsiasi momento un altro dispositivo invia un messaggio tramite la porta configurata, il messaggio "ha ricevuto i dati da UART." non viene mai visualizzato.

Qualche suggerimento per risolvere questo problema? Inoltre, come si collega il sistema all'interruzione con la porta seriale? Ho letto su signal.h ma non ho trovato una risposta per questo. Ho ricevuto l'idea di interruzione da questa pagina: http://www.faqs.org/docs/Linux-HOWTO/Serial-Programming-HOWTO.html

Grazie in anticipo per qualsiasi aiuto. Grazie in anticipo.

+0

1) Non installarei il gestore di segnale prima che l'inizializzazione di ttyS sia completata.2) Non dovresti chiamare printf() da un gestore di segnale; printf() è non rientranti. – wildplasser

+0

Grazie per aver risposto, ma seguendo i tuoi commenti la "interruzione" continua a non funzionare. Altre idee? – gus

risposta

4

Il problema è che si stanno disabilitando i segnali dal descrittore di file deselezionando il flag FASYNC con F_SETFL. È necessario impostare che se si vuole ottenere segnali:

fcntl(fd, F_SETFL, FNDELAY|FASYNC); 

Inoltre, si potrebbe desiderare di utilizzare i nomi POSIX per queste bandiere (O_NDELAY e O_ASYNC) piuttosto che i nomi BSD per più portabilità, anche se sia funzionerà su Linux.

1

Qualche suggerimento per risolvere questo problema? Inoltre, in che modo il sistema mette in relazione l'interruzione con la porta seriale?

L'interrupt della porta seriale è scritto all'interno della parte periferica del driver seriale nel kernel di Linux. L'interrupt è gestito dal driver stesso, quindi non è possibile controllarlo.

Ciò che il programma di cui sopra sta facendo, è la notifica attraverso un segnale, quando viene attivato un interrupt di ricezione del dispositivo della parte seriale.

La gestione del segnale sopra descritta non è correlata agli interrupt, è più uniforme. Prima di registrare, il tuo programma, per ottenere un segnale quando si verifica un interrupt io, il gestore di segnale nel tuo programma visualizzerà quindi il messaggio printf.

Credo che la gestione del segnale nel programma, non è implementata correttamente Basta correggere le parti del segnale del programma

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

Grazie per la risposta, ma il segnale ("interruzione") continua a non funzionare, e ho già controllato che il programma riceva/trasmetta i dati attraverso la porta correttamente. Hai un altro approccio per risolvere questo problema? – gus

6

ho trovato che un pezzo di codice mancante per il codice originale di lavorare come previsto. Il codice qui sotto funziona su Linux compilato con gcc. La riga di codice aggiunta è quella contrassegnata con /**<<<<<<------This line made it work.**/
Una riga è stata anche commentata: //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"); 
} 

L'output del programma è stato:

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

spero che funziona per voi troppo.

+0

Grazie mille per la risposta, ha senso ora. – gus