Настройка прерывания последовательного порта в linux
Я пытаюсь установить прерывание для последовательного порта в 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
Заранее благодарю за любую помощь. Заранее спасибо.
3 ответа
Проблема в том, что вы отключаете сигналы из файлового дескриптора путем очистки FASYNC
флаг с F_SETFL
, Вам нужно установить это, если вы хотите получать сигналы:
fcntl(fd, F_SETFL, FNDELAY|FASYNC);
Кроме того, вы можете использовать имена POSIX для этих флагов (O_NDELAY
а также O_ASYNC
), а не имена BSD для большей переносимости, хотя любой из них будет работать на Linux.
Я обнаружил, что фрагмент кода отсутствует для исходного кода, чтобы работать, как ожидалось. Код ниже работает на Linux, скомпилированном с помощью gcc. Добавленная строка кода отмечена знаком /**<<<<<<------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
Я надеюсь, что это работает для вас тоже.
Любое предложение, чтобы решить эту проблему? Кроме того, как система соотносит прерывание с последовательным портом?
Прерывание последовательного порта записывается внутри части устройства последовательного драйвера в ядре 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;
}