Problème de lecture de trame port série RS485 - Protocole modbus
Bonjour à tous,
J'ai un soucis très spécifique dans le domaine des automates.
Je vais tenté de vous expliquer au mieux et je vous remercie d'avance pour votre future aide.
Pour contextualiser, je dois envoyer des données issues d'un lidar à un automate en protocole Modbus RTU via une communication série RS485.
Dans cet exemple, je suis considéré comme le second esclave, pas le premier.
Je dois dans un premier temps, lire la trame de mon maitre automate, avec la fonction lecture puis les stocker dans un tableau de char, regarder si la trame que j'ai reçu est adressé à l'esclave 2, puis si c'est le cas envoyer les données que je souhaite via la fonction write.
Je ne sais pas si j'ai bien déclaré mes paramètres de mon port série RS485 mais j'ai un soucis uniquement pour la partie lecture de la trame du maitre.
Lors que je lis ma trame, il ne s'arrête pas au bit stop. Donc je n'arrive pas à avoir les bonnes trames au bon format Modbus.
Je précise qu'en modbus ou dans n'importe quel communication série, l'ordre est toujours le même :
Trame Maitre pour Esclave 1 - Trame Réponse de l'esclave 1 - Trame Maitre pour Esclave 2 - Trame réponse de l'esclave - 2 ect .....
Trame maitre pour esclave 1 : 01 03 18 92 00 08 EF 58
Trame réponse de l' esclave 1 : 01 03 18 92 10 00 00 00 00 00 00 00 00 EF A8
Trame maitre pour esclave 2 : 02 03 18 92 00 08 EF 58
Trame réponse de l' esclave 2 : 02 03 18 92 10 00 00 00 00 00 00 00 00 EF A8
Moi je veux que ma fonction lecture de trame, lise le début de la trame et s'arrête au bit stop, puis relise à nouveau la trame puis s'arrête au bit stop. Jusqu'à ce que je détecte dans lecture[0] la valeur de 2 car je suis l'esclave 2.
Je pense que j'ai un réel problème sur mes flags, donc sur la fonction fcntl().
La première trame que je lis est toujours bonne mais dès qu'il lis la deuxième , il lis pas au début de la trame mais de manière aléatoire.
Au lieu d'avoir dans ma variable lecture ça :
Maitre pour esclave 1 --------- > lecture[0]= 1 ; lecture[1] = 6 ; lecture [2] =18 ....
Esclave 1 ---------- > lecture[0]= 1 ; lecture[1] = 6 ; lecture [2] =18 ....
J'ai
Maitre pour esclave 1 --------- > lecture[0]= 1 ; lecture[1] = 6 ; lecture [2] =18 ; lecture [3] =18 ....
Esclave 1 ---------- > lecture[0]= 18 ; lecture[1] = 90 ; lecture [2] =00 ....
Il ne lis pas au bon moment après la première fois.
Alors qu'il devrait me donner chaque trame au bon moment donc après le bit stop.
Le mieux ça serait mettre le flag à 1 au début de réception de la première trame du maitre, mettre le flag à 0 à la fin de la réception de la trame du maitre, mettre le flag à 1 au début de la trame de l'esclave 1, mettre le flag à 0 à la fin de la trame de l'esclave 1 et ainsi de suite.
Voici un exemple de mon code, je sais qu'il y a une fonction flush à mettre mais je sais pas trop comment ..
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
| #include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <termios.h>
#include <asm/ioctls.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////// Program ////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int main() {
//initialisation du rs485
char dev[] = "/dev/ttyUSB1";
char lecture[10]={0};
int baudrate = B19200;
int status;
int serial_port;
struct termios ti;
serial_port = open(dev, O_RDWR|O_NONBLOCK | O_NOCTTY);
if (serial_port < 0) {
printf("ERROR! Failed to open %s\n", dev);
return -1;
}
// configurarion du port serie en rs485
tcgetattr(serial_port, &ti); // Lire l ancienne config du serial port
cfsetospeed(&ti,baudrate); // configurer vitesse TX
cfsetispeed(&ti,baudrate); // Configurer vitesse RX
ti.c_cflag |= CS8; // 8 bit de data
ti.c_iflag |= IGNPAR; // ignorer les erreurs de parités
ti.c_cflag &= ~PARENB; //pas de parité
ti.c_cflag &= ~CSTOPB; // 1 bit de stop
ti.c_cflag &= ~CSIZE; //option a 0
ti.c_cflag &= ~CRTSCTS;
ti.c_iflag &= ~(IXON | IXOFF | IXANY);
ti.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL);
cfmakeraw(&ti);
tcsetattr(serial_port, TCSANOW, &ti); // configurer la nouvelle config serial port
ti.c_cc[VTIME] = 0; // Wait for up to 1s (10 deciseconds), returning as soon as any data is received.
ti.c_cc[VMIN] = 0;
while (1)
{
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Tableau d'échange ///////////////////////////////////
printf("lecture des donnees en cours \n");
printf("tableau d echange :\n");
// On met le flag a zero et on va lire la trame du maitre
int flag = fcntl(serial_port,F_GETFL,0);
fcntl(serial_port,F_SETFL,flag);
read(serial_port, lecture, sizeof(lecture));
int l;
for (l=0;l<8;l++)
{
printf("message recu %X ",lecture[l]);
}
printf("\n");
} |
J'espère sincèrement que quelqu'un va trouver une solution à mon problème et je vous remercie beaucoup.