Comment configurer correctement la communication série sur Linux
Je suis d'essayer de lire et écrire des données depuis et vers une carte FPGA. Le conseil lui-même est venu avec un pilote de créer un terminal appelé ttyUSB0 chaque fois que le conseil d'administration est branché. Sur le FPGA, asynchrone, le récepteur et l'émetteur ont été mises en œuvre, et ils semblent fonctionner.
Cependant, il semble y avoir un problème sur le C côté des choses. J'ai été en utilisant des vecteurs de test pour tester si le FPGA est de la transmission de la bonne information. J'ai remarqué quelques choses de choses:
- L'appareil, parfois ne s'ouvre pas correctement
- Le terminal attributs parfois ne parviennent pas à être récupéré ou défini.
- La lecture est parfois non-blocage et de ne pas récupérer la bonne valeur.
Ci-dessous comment j'ai configuré le terminal et le descripteur de fichier options. Beaucoup d'elle a été prise à partir d'ici: http://slackware.osuosl.org/slackware-3.3/docs/mini/Serial-Port-Programming
Vos commentaires ou vos conseils pour lesquelles le programme est peut-être défectueux serait grandement utile.
#include <stdio.h> //Standard input/output definitions
#include <string.h> //String function definitions
#include <unistd.h> //UNIX standard function definitions
#include <fcntl.h> //File control definitions
#include <errno.h> //Error number definitions
#include <termios.h> //POSIX terminal control definitions
int open_port(void){
int fd; //File descriptor for the port
fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY);
if (fd == -1){
fprintf(stderr, "open_port: Unable to open /dev/ttyUSB0 %s\n",strerror(errno));
exit(EXIT_FAILURE);
}
return (fd);
}
int main(void){
int fd = 0; //File descriptor
struct termios options; //Terminal options
fd = open_port(); //Open tty device for RD and WR
fcntl(fd, F_SETFL); //Configure port reading
tcgetattr(fd, &options); //Get the current options for the port
cfsetispeed(&options, B230400); //Set the baud rates to 230400
cfsetospeed(&options, B230400);
options.c_cflag |= (CLOCAL | CREAD); //Enable the receiver and set local mode
options.c_cflag &= ~PARENB; //No parity bit
options.c_cflag &= ~CSTOPB; //1 stop bit
options.c_cflag &= ~CSIZE; //Mask data size
options.c_cflag |= CS8; //Select 8 data bits
options.c_cflag &= ~CRTSCTS; //Disable hardware flow control
//Enable data to be processed as raw input
options.c_lflag &= ~(ICANON | ECHO | ISIG);
//Set the new attributes
tcsetattr(fd, TCSANOW, &options);
////////////////////////////////////
//Simple read and write code here//
////////////////////////////////////
//Close file descriptor & exit
close(fd)
return EXIT_SUCCESS
}
Mise à JOUR
J'ai modifié mon code en fonction de la première réponse. C'est ce que j'ai maintenant:
#include <errno.h> //Error number definitions
#include <stdint.h> //C99 fixed data types
#include <stdio.h> //Standard input/output definitions
#include <stdlib.h> //C standard library
#include <string.h> //String function definitions
#include <unistd.h> //UNIX standard function definitions
#include <fcntl.h> //File control definitions
#include <termios.h> //POSIX terminal control definitions
//Open usb-serial port for reading & writing
int open_port(void){
int fd; //File descriptor for the port
fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY);
if (fd == -1){
fprintf(stderr, "open_port: Unable to open /dev/ttyUSB0 %s\n",strerror(errno));
exit(EXIT_FAILURE);
}
return fd;
}
int main(void){
int fd = 0; //File descriptor
struct termios options; //Terminal options
int rc; //Return value
fd = open_port(); //Open tty device for RD and WR
//Get the current options for the port
if((rc = tcgetattr(fd, &options)) < 0){
fprintf(stderr, "failed to get attr: %d, %s\n", fd, strerror(errno));
exit(EXIT_FAILURE);
}
//Set the baud rates to 230400
cfsetispeed(&options, B230400);
//Set the baud rates to 230400
cfsetospeed(&options, B230400);
cfmakeraw(&options);
options.c_cflag |= (CLOCAL | CREAD); //Enable the receiver and set local mode
options.c_cflag &= ~CSTOPB; //1 stop bit
options.c_cflag &= ~CRTSCTS; //Disable hardware flow control
options.c_cc[VMIN] = 1;
options.c_cc[VTIME] = 2;
//Set the new attributes
if((rc = tcsetattr(fd, TCSANOW, &options)) < 0){
fprintf(stderr, "failed to set attr: %d, %s\n", fd, strerror(errno));
exit(EXIT_FAILURE);
}
////////////////////////////////
//Simple Read/Write Code Here//
////////////////////////////////
//Close file descriptor & exit
close(fd);
return EXIT_SUCCESS;
}
Juste pour clarifier, l'émetteur et le récepteur utilisent 8 bits de données, 1 bit d'arrêt et pas de bit de parité.
OriginalL'auteur sj755 | 2013-04-08
Vous devez vous connecter pour publier un commentaire.
Je préfère Série Guide de Programmation POSIX Systèmes d'Exploitation.
Vous devez supprimer le
fcntl(mainfd, F_SETFL)
déclaration, puisqu'il n'est pas nécessaire et mal mis en œuvre (F_GETFL pas fait avant et disparus de la troisième argument).Essayez d'utiliser cfmakeraw pour l'installation de non-canonique de la mode, depuis votre code d'initialisation est incomplète:
Pour les non-canonique de la mode, vous devez également définir
1 et 2 sont juste des valeurs suggérées.
Ajouter les tests de l'état de retour après tous les appels système.
Essayer de tester avec un ralentissement de la baudrates (par exemple, 115200 ou même 9600).
J'ai fait une mise à jour et posté mon code actuel. Pour une raison quelconque, le programme est incapable de lire quoi que ce soit de la commission, il attend simplement sur la fonction de lecture. Toutes les pensées?
Vous n'avez pas besoin
c_cflag &= ~PARENB
depuiscfmakeraw()
va gérer cela. Vous n'avez probablement besoinc_cflag &= ~CSTOPB
etc_cflag &= ~CRTSCTS
qui a été supprimé! L'un de ces pourrait tuer la lecture.J'ai ajouté le 1 bit d'arrêt drapeau et de désactiver le contrôle de flux matériel, mais il programme, attend toujours sur la fonction de lecture. Le code d'origine a tendance à provoquer la panne du programme, mais à l'occasion, il n'est lu à partir de la carte correctement, de sorte que le conseil est certainement la transmission de quelque chose. Toutes les autres pensées?
Si ces modifications ont été faites correctement, alors je ne vois pas le problème. Peut-être que vous pourriez appliquer ces modifications à la "mise à jour" dans le Q? La lecture de code pourrait être un problème. Vous pouvez isoler le problème si vous avez un port COM ou USB-RS232 adaptateur: faire une boucle de liant TxD à RxD (à court terme, les broches 2 & 3 de la DB9). Puis pirater votre code pour envoyer des données avant de le lire. Vous pouvez également comparer votre code pour ce code testé, bien que le port est ouvert pour les non-blocage I/O.
OriginalL'auteur sawdust