Lecture /dev/ttyUSB0 en C
ABouras
Messages postés
26
Date d'inscription
Statut
Membre
Dernière intervention
-
totof31 Messages postés 163 Date d'inscription Statut Membre Dernière intervention -
totof31 Messages postés 163 Date d'inscription Statut Membre Dernière intervention -
Bonjour!
Je voudrais lire des trames de données envoyées par un GPS par protocole XBee. La clé USB XStick reçoit les données suivantes :
et ainsi de suite ... J'arrive à les lire en tapant dans le terminal la commande :
Mais j'aimerais pouvoir afficher ces coordonnées de la même manière, mais avec un programme écrit en C. Voici ce que j'ai fais pour l'instant :
Mais ça ne fonctionne pas, il me sors "reception error" correspondant et le code errno est 11, c'est à dire "Try again" ...
Pouvez-vous m'aider svp ?
Merci d'avance !
Je voudrais lire des trames de données envoyées par un GPS par protocole XBee. La clé USB XStick reçoit les données suivantes :
CHARS : 15931 SENTENCES = 0 CHECKSUM : 58 Heading : 55 Tilt: -46 Roll:2 CHARS : ....
et ainsi de suite ... J'arrive à les lire en tapant dans le terminal la commande :
$ screen /dev/ttyUSB0
Mais j'aimerais pouvoir afficher ces coordonnées de la même manière, mais avec un programme écrit en C. Voici ce que j'ai fais pour l'instant :
#include <stdio.h> #include <stdlib.h> #include <termios.h> #include <sys/fcntl.h> #include <unistd.h> #include <errno.h> #include <string.h> #include "serial_port.h" void read_Serial_Port(const char* DEVICE_PORT) { int file; struct termios options; unsigned int nCountMax = 60; bool b; file = open(DEVICE_PORT, O_RDONLY | O_NOCTTY | O_NDELAY); if(file == -1){perror("Unable to open the serial port\n");} printf("Serial port open successful !\n"); tcgetattr(file, &options); cfsetispeed(&options, B9600); cfsetospeed(&options, B9600); options.c_cflag |= (CLOCAL | CREAD); options.c_cflag |= PARENB; //No parity options.c_cflag |= PARODD; options.c_cflag &= ~CSTOPB; options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; //8 bits options.c_iflag |= (INPCK | ISTRIP); tcsetattr(file, TCSANOW, &options); fcntl(file, F_SETFL, FNDELAY); printf("Reading serial port ...\n\n"); b = readMessage(file, nCountMax); if (b == 0){printf("Error while reading serial port\n");} else printf("Serial port read successful\n"); close(file); printf("Serial port closed\n"); }; bool readMessage(int file, unsigned int nCountMax) { int nbCharToRead; int i; if (file != 0) { i = 0; char message[100]; char data[100]; while (i<nCountMax && data != ".") { printf("\n%d\n",read(file,data,1)); if (read(file,data,1) == -1) { printf("reception error\n"); printf("errno = %d\n", errno); return false; } else { message[i] = *data; printf("%c", message[i]); i++; } } message[i] = 0; return true; } };
Mais ça ne fonctionne pas, il me sors "reception error" correspondant et le code errno est 11, c'est à dire "Try again" ...
Pouvez-vous m'aider svp ?
Merci d'avance !
A voir également:
- Lecture /dev/ttyUSB0 en C
- Dev c++ - Télécharger - Langages
- Massgrave dev - Accueil - Windows
- Dev home. - Télécharger - Développement
- Lecture epub sur pc - Guide
- Dev pascal - Télécharger - Édition & Programmation
11 réponses
Mon programme est le suivant :
Cette fois-ci, plus d'erreurs, mais les caractères affichés sont étranges :
les dollars $$$$ sont représentés par des carrés contenant 4 chiffres, bref .... je rappel que je voudrais avoir :
J'ai essayé en mettant %c, %d, %x dans le printf, mais évidemment aucun ne fonctionne correctement ...
Merci !
bool readMessage(int file, unsigned int nCountMax) { int i; size_t nbytes; ssize_t bytes_read; if (file != -1) { i = 0; char message[100]; char data[100]; while (i<nCountMax && data != ".") { if (read(file, data, 1) == -1) { printf("reception error\n"); printf("code errno = %d\n", errno); return false; } else { nbytes = sizeof(data); bytes_read = read(file, data, nbytes); message[i] = *data; printf("%c", message[i]); i++; } } message[i] = 0; return true; } };
Cette fois-ci, plus d'erreurs, mais les caractères affichés sont étranges :
$$$$QUC U$C $$$$JQMJ' J$Cz(HSQ'Q'y UKUNiQUMJ
les dollars $$$$ sont représentés par des carrés contenant 4 chiffres, bref .... je rappel que je voudrais avoir :
CHARS : 15931 SENTENCES = 0 CHECKSUM : 58 Heading : 55 Tilt: -46 Roll:2 CHARS : .....
J'ai essayé en mettant %c, %d, %x dans le printf, mais évidemment aucun ne fonctionne correctement ...
Merci !
Salut,
Je ne comprends pas très bien :
bytes_read = read(file, data, nbytes);
retourne bytes_read caractères (au maximum nbytes)
Avec :
message[i] = *data;
printf("%c", message[i]);
tu ne lis et n'affiches qu'un seul caractère !
Il faut regarder la valeur retournée par bytes_read. Il ne faut donc pas faire :
if (read(file, data, 1) == -1)
mais :
bytes_read = read(file, data, nbytes); // A UN SEUL ENDROIT
if (bytes_read...
else...
Je ne comprends pas très bien :
bytes_read = read(file, data, nbytes);
retourne bytes_read caractères (au maximum nbytes)
Avec :
message[i] = *data;
printf("%c", message[i]);
tu ne lis et n'affiches qu'un seul caractère !
Il faut regarder la valeur retournée par bytes_read. Il ne faut donc pas faire :
if (read(file, data, 1) == -1)
mais :
bytes_read = read(file, data, nbytes); // A UN SEUL ENDROIT
if (bytes_read...
else...
Ok, maintenant j'ai le code suivant :
Et j'obtient le code errno 11 [Resource temporarily unavailable] ... pourquoi ?
Merci.
#include <stdio.h> #include <stdlib.h> #include <termios.h> #include <sys/fcntl.h> #include <unistd.h> #include <errno.h> #include <string.h> #include "serial_port.h" void read_Serial_Port(const char* DEVICE_PORT) { int file; struct termios options; unsigned int nCountMax = 60; bool b; file = open(DEVICE_PORT, O_RDONLY | O_NOCTTY | O_NDELAY); if(file == -1){perror("Unable to open the serial port\n");} printf("Serial port open successful !\n"); tcgetattr(file, &options); cfsetispeed(&options, B9600); cfsetospeed(&options, B9600); options.c_cflag |= (CLOCAL | CREAD); options.c_cflag |= PARENB; options.c_cflag |= PARODD; options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; printf("Reading serial port ...\n\n"); b = readMessage(file, nCountMax); if (b == 0){printf("Error while reading serial port\n");} else printf("\nSerial port read successful\n"); close(file); printf("Serial port closed\n"); }; bool readMessage(int file, unsigned int nCountMax) { int i; size_t nbytes; ssize_t bytes_read; if (file != -1) { i = 0; char message[100] = {0}; char data[1] = ""; nbytes = sizeof(data); while (i<nCountMax) { bytes_read = read(file, data, nbytes); if (bytes_read < 0) { printf("read failed, errno code = %d [%s]\n", errno, strerror(errno)); return false; } else { message[i] = *data; printf("%c", message[i]); i++; } } message[i] = 0; return true; } }
Et j'obtient le code errno 11 [Resource temporarily unavailable] ... pourquoi ?
Merci.
Je ne me focaliserais pas trop sur le cas d'erreur pour l'instant. Attention également à ton test :
- si bytes_read est nul, tu affiches quand même un caractère...
- si bytes_read est > à 1, tu n'affiches qu'un seul caractère alors que tu en as dépilés plusieurs
Avec un minimum de changements, je te suggère d'essayer le code suivant :
et laisse tomber errno pour l'instant. Tu pourras toujours sortir avec un ctrl-C si ça ne marche pas.
Si ça marche, tu pourras améliorer en faisant un truc du genre :
Autres choses :
- tu ne donnes pas le code qui appelle read_Serial_Port
- tu fais bien un tcgetattr pour modifier les paramètres de com, mais tu dois ensuite enregistrer les valeurs modifiées avec tcsetattr (est-ce bien nécessaire d'ailleurs, d'où viennent ces valeurs/ce code ? Tu utilises un périphérique USB qui émule un port série, il n'est pas toujours nécessaire dans ce cas de changer la vitesse de com qui est potentiellement fictive)
- si bytes_read est nul, tu affiches quand même un caractère...
- si bytes_read est > à 1, tu n'affiches qu'un seul caractère alors que tu en as dépilés plusieurs
Avec un minimum de changements, je te suggère d'essayer le code suivant :
bytes_read = read(file, data, 1); if (bytes_read > 0) { message[i] = *data; printf("%c", message[i]); i++; }
et laisse tomber errno pour l'instant. Tu pourras toujours sortir avec un ctrl-C si ça ne marche pas.
Si ça marche, tu pourras améliorer en faisant un truc du genre :
bytes_read = read(file, data, nbytes); if (bytes_read > 0) { for (j=0;j<bytes_read;j++) printf("%c", data[j]); i+=bytes_read; ...
Autres choses :
- tu ne donnes pas le code qui appelle read_Serial_Port
- tu fais bien un tcgetattr pour modifier les paramètres de com, mais tu dois ensuite enregistrer les valeurs modifiées avec tcsetattr (est-ce bien nécessaire d'ailleurs, d'où viennent ces valeurs/ce code ? Tu utilises un périphérique USB qui émule un port série, il n'est pas toujours nécessaire dans ce cas de changer la vitesse de com qui est potentiellement fictive)
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question
Merci pour ta réponse, en faisant la première modif que tu me proposes :
J'obtiens sur le prompteur ceci :
Mais les caractères sont incompréhensibles ...
bool readMessage(int file, unsigned int nCountMax) { int i; size_t nbytes; ssize_t bytes_read; if (file != -1) { i = 0; char message[100] = {0}; char data[1] = ""; nbytes = sizeof(data); while (i<nCountMax) { bytes_read = read(file, data, 1); if (bytes_read >0) { message[i] = *data; printf("%c", message[i]); i++; } } message[i] = 0; return true; } }
J'obtiens sur le prompteur ceci :
Start read_Serial_Port function ... Serial port open successful ! Reading serial port ... CJ*$ CzQC*H Q$U$u[-CJQ$U$[CJ CJQ$U$0 S SCJMQ$U$ Serial port read successful Serial port closed
Mais les caractères sont incompréhensibles ...
Alors essaie tout de même de jouer sur la vitesse de com :
- fait bien un tcsetattr()
- et si ça ne marche toujours pas, essaie d'autres vitesses standards
- fait bien un tcsetattr()
- et si ça ne marche toujours pas, essaie d'autres vitesses standards
Non toujours pas, quelque soit la vitesse en Baud, je reçois ces caractères bizzares.
Autre chose, tu me demandais l'utilisation de la fonction read_Serial_Port(const char* DEVICE_PORT), j'ai juste fais un main() :
De plus, je remarque qu'en faisant cat /dev/ttyUSB0, j'obtiens les même caractères bizarres, mais si je fais un screen /dev/ttyUSB0, j'obtiens les bonnes données ... Comment faire pour afficher correctement mes données comme avec la commande screen au lieu de cat ?
Autre chose, tu me demandais l'utilisation de la fonction read_Serial_Port(const char* DEVICE_PORT), j'ai juste fais un main() :
int main() { const char* DEVICE_PORT = "/dev/ttyUSB0"; printf("Start read_Serial_Port function ...\n"); read_Serial_Port(DEVICE_PORT); }
De plus, je remarque qu'en faisant cat /dev/ttyUSB0, j'obtiens les même caractères bizarres, mais si je fais un screen /dev/ttyUSB0, j'obtiens les bonnes données ... Comment faire pour afficher correctement mes données comme avec la commande screen au lieu de cat ?
C'est bon ça marche !!!!!!!!!!!!!!!!!! merci beaucoup !!!!!!!!!
Dernière chose, j'aimerais recevoir les données :
de manière régulière, bloc par bloc. Là je reçois genre une seule fois, 60 caractères d'un coup (j'ai mis nCountMax = 60 dans la fonction pour essayer) :
puis si je réexecute :
Bref ... comment faire pour recevoir les données régulièrement ? Il faudrait que j'affiche les bloc en commençant par CHARS, puis que le bloc s'arrête sur le nombre de Roll, ensuite il recommence sur CHARS, ainsi de suite ...
Ensuite j'essayerai d'écrire ces données dans un fichier texte proprement de cette manière :
Dernière chose, j'aimerais recevoir les données :
CHARS : 15931 SENTENCES = 0 CHECKSUM : 58 Heading : 55 Tilt: -46 Roll:2 CHARS : .....
de manière régulière, bloc par bloc. Là je reçois genre une seule fois, 60 caractères d'un coup (j'ai mis nCountMax = 60 dans la fonction pour essayer) :
: -47 Roll: 1 CHARS : 3CHARS : 3809 SENTENCES : 0 CHECKSU
puis si je réexecute :
t: -46 Roll: 1 CHARS : CHECKSUM : 53 Heading: 53 Tilt: -46
Bref ... comment faire pour recevoir les données régulièrement ? Il faudrait que j'affiche les bloc en commençant par CHARS, puis que le bloc s'arrête sur le nombre de Roll, ensuite il recommence sur CHARS, ainsi de suite ...
Ensuite j'essayerai d'écrire ces données dans un fichier texte proprement de cette manière :
CHARS : 15931 SENTENCES = 0 CHECKSUM : 58 Heading : 55 Tilt: -46 Roll:2 CHARS : 15931 SENTENCES = 1 CHECKSUM : 59 Heading : 55 Tilt: -46 Roll:1 CHARS : 15931 SENTENCES = 0 CHECKSUM : 58 Heading : 54 Tilt: -45 Roll:1 ...
Cool !
Qu'as-tu fait pour que ça marche finalement ?
Pour afficher les blocs il faut repérer les séquences qui t'intéressent. Il y a plusieurs façons de faire, essaie de regarder les fonctions strstr ou strtok ou sscanf...
Qu'as-tu fait pour que ça marche finalement ?
Pour afficher les blocs il faut repérer les séquences qui t'intéressent. Il y a plusieurs façons de faire, essaie de regarder les fonctions strstr ou strtok ou sscanf...
Ok je vais regarder ça ... Voici mon code :
D'ailleurs il n'y a pas une fonction pour compter le nombre de caractère reçu en un seul paquet ? parce que moi pour l'instant j'utilise à la main nCountMax = 60 ce qui m'affiche exactement 60 caratères, mais j'ai pris cette valeur pif juste pour tester ...
#include <stdio.h> #include <stdlib.h> #include <termios.h> #include <sys/fcntl.h> #include <unistd.h> #include <errno.h> #include <string.h> #include "serial_port.h" void read_Serial_Port(const char* DEVICE_PORT) { int file; struct termios options; unsigned int nCountMax = 60; bool b; file = open(DEVICE_PORT, O_RDONLY | O_NOCTTY | O_NDELAY); if(file == -1){perror("Unable to open the serial port\n");} printf("Serial port open successful !\n"); tcgetattr(file, &options); cfsetispeed(&options, B9600); cfsetospeed(&options, B9600); options.c_cflag |= (CLOCAL | CREAD); options.c_cflag |= PARENB; options.c_cflag |= PARODD; options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; printf("Reading serial port ...\n\n"); b = readMessage(file, nCountMax); if (b == 0){printf("Error while reading serial port\n");} else printf("\nSerial port read successful\n"); close(file); printf("Serial port closed\n"); }; bool readMessage(int file, unsigned int nCountMax) { int i,j; ssize_t bytes_read; if (file != -1) { i = 0; char data[1] = ""; while (i<nCountMax) { bytes_read = read(file, data, sizeof(data)); if (bytes_read > 0) { printf("%c", data[0]); i += bytes_read; } } return true; } };
D'ailleurs il n'y a pas une fonction pour compter le nombre de caractère reçu en un seul paquet ? parce que moi pour l'instant j'utilise à la main nCountMax = 60 ce qui m'affiche exactement 60 caratères, mais j'ai pris cette valeur pif juste pour tester ...
Si, c'est justement la fonction read : elle retourne au maximum sizeof(data), mais ce qui dans ton cas vaut 1. Essaie :
char data[1000];
int j;
bytes_read = read(file, data, sizeof(data));
if (bytes_read > 0)
{
for (j=0; j < bytes_read; j++)
printf("%c", data[j]);
}
Ton problème, c'est que des données sont envoyées en permanence, donc pas facile de savoir si tu as tout reçu ou pas, ou si tu commences à recevoir de nouvelles données, etc.
Si le rythme d'envoi des données est suffisamment lent, tu peux éventuellement utiliser un compteur qui s'incrémente à chaque fois que bytes_read est <= 0. Au delà d'une certaine valeur, tu peux ainsi savoir que tu as atteint la fin d'un bloc
char data[1000];
int j;
bytes_read = read(file, data, sizeof(data));
if (bytes_read > 0)
{
for (j=0; j < bytes_read; j++)
printf("%c", data[j]);
}
Ton problème, c'est que des données sont envoyées en permanence, donc pas facile de savoir si tu as tout reçu ou pas, ou si tu commences à recevoir de nouvelles données, etc.
Si le rythme d'envoi des données est suffisamment lent, tu peux éventuellement utiliser un compteur qui s'incrémente à chaque fois que bytes_read est <= 0. Au delà d'une certaine valeur, tu peux ainsi savoir que tu as atteint la fin d'un bloc