2013-02-27 14 views
7

Próbuję ustawić przerwanie dla portu szeregowego w Ubuntu (w programie napisanym w C), ale to nie działa. Sprawdziłem, czy komunikacja szeregowa działa poprawnie, bez przerwy, więc mogę ustawić coś złego. Kod jest następujący:ustawienie przerwania portu szeregowego w Linuksie

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

Więc czas każdej chwili inne urządzenie wysłać wiadomość poprzez skonfigurowanego portu komunikat „otrzymane dane z UART.” nigdy nie jest wyświetlane.

Wszelkie sugestie dotyczące rozwiązania tego problemu? Ponadto, w jaki sposób system odnosi się do przerwania z portem szeregowym ?, Czytałem o signal.h, ale nie znalazłem odpowiedzi na to. Pomysł na przerwę został przesłany z tej strony: http://www.faqs.org/docs/Linux-HOWTO/Serial-Programming-HOWTO.html

Z góry dziękuję za pomoc. Z góry dzięki.

+0

1) Nie zainstalowałbym procedury obsługi sygnału przed zakończeniem inicjalizacji ttyS.2) Nie powinieneś wywoływać printf() z obsługi sygnału; printf() jest nierecentrantem. – wildplasser

+0

Dzięki za odpowiedź, ale po twoich komentarzach "przerwa" nadal nie działa. Więcej pomysłów? – gus

Odpowiedz

4

Problem polega na tym, że wyłączasz sygnały z deskryptora pliku, czyszcząc flagę FASYNC za pomocą F_SETFL. Trzeba ustawić, że jeśli chce się sygnały:

fcntl(fd, F_SETFL, FNDELAY|FASYNC); 

Również możesz używać nazw POSIX dla tych flag (O_NDELAY i O_ASYNC), a nie nazwami BSD dla większej przenośności, albo chociaż będzie działać w systemie Linux.

1

Wszelkie sugestie dotyczące rozwiązania tego problemu? Ponadto, w jaki sposób system odnosi się do przerwania z portem szeregowym?

Przerwanie portu szeregowego jest zapisane wewnątrz części sterownika szeregowego w jądrze Linux. Przerwanie jest obsługiwane przez samego sterownika, więc nie masz nad nim kontroli.

To, co robi powyższy program, powiadamia użytkownika za pomocą sygnału, gdy zostanie przerwane przerwanie odbioru urządzenia z częściami seryjnymi.

Powyższe przetwarzanie sygnału nie jest związane z przerywaniem, jest to bardziej równomierne manipulowanie. Najpierw zarejestrujesz swój program, aby uzyskać sygnał, gdy pojawi się przerwie io io, program obsługi sygnału w twoim programie wyświetli komunikat printf.

myślę przenoszenia sygnału w programie, nie jest realizowany właściwie Wystarczy skorygowania części sygnałowe programie

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

Dzięki za odpowiedź, ale sygnał ("przerwanie") nadal nie działa, a ja już sprawdziłem, czy program poprawnie odbiera/przesyła dane przez port. Czy masz inne podejście do rozwiązania tego problemu? – gus

6

I odkryli, że fragment kodu brakuje na oryginalny kod do pracy spodziewany. Poniższy kod działa na Linuksie skompilowanym przy użyciu gcc. Dodana linia kodu to linia oznaczona /**<<<<<<------This line made it work.**/
Jedna linia została również skomentowana: //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"); 
} 

Wyjście z programu było:

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

Mam nadzieję, że pracuje dla Ciebie.

+0

Wielkie dzięki za odpowiedź, teraz ma to sens. – gus