Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

  1. #1
    Nouveau Candidat au Club
    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 :Sélectionner tout -Visualiser dans une fenêtre à part
    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
    124
    125
     
     
    #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.

  2. #2
    Membre averti
    Salut mrkonan,

    Il y a longtemps que je n'ai pas joué avec des communications série sous Linux, et c'est plein de finesses. La difficulté avec ton type de problèmes est qu'à moins d'être équipés du même genre de matériel utilisé dans le même contexte, on ne peut répliquer ton problème ou t'aider à déboguer aisément. C'est peut-être le ressenti d'autres membres du forum, comme ton message ne reçoit pas de réponse.

    Alors à défaut de te donner une réponse toute faite, voilà quelques pistes, qui pourront peut-être t'aider.

    Je comprends que les données que tu récupères sont binaires, alors peut-être cet exemple posté par sawdust dans SO te sera utile : https://stackoverflow.com/questions/...l-in-c-program. Le même utilisateur sawdust a de nombreuses autres interventions dans SO sur le sujet et que tu trouveras peut-être utiles.

    Autrement, puisque tu semble être sous Linux et que ton matériel supporte modbus, as-tu pensé à utiliser libmodbus ?

    C'est une bibliothèque qui existe de longue date et est disponible dans les dépôts des distributions Linux, par exemple sur Debian : https://packages.debian.org/buster/libmodbus-dev

    La doc est là : https://libmodbus.org/docs/v3.1.6/ et sous forme de pages de manuel lorsque tu l'installes

    et tu as des exemples de code utilisant la bibliothèque un peu partout, par exemple : https://stackoverflow.com/questions/...ng-modbus-in-c

  3. #3
    Membre éclairé
    Interrogation ?
    Bonjour,

    Je présume que les exemples sont fictifs car les deux lignes suivantes ont le même CRC :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    Trame maitre pour esclave 1 : 01 03 18 92 00 08 EF 58
    ...
    Trame maitre pour esclave 2 : 02 03 18 92 00 08 EF 58


    Le problème cité semble plus un problème de gestion de la transmission série qu'un problème ModBus (qui viendront après).

    Pour détecter le premier caractère d'une trame Modbus, il suffit de prendre le premier caractère qui se présente après un silence > 3.5 caractères (soit environ 5 ms en 9600 bps). Il n'est donc pas utile (voire dangereux) de lire tous les caractères jusqu'à trouver le 2 salvateur qui pourrait ne pas être celui de l'entête (par exemple le 2 du 92 de l'exemple de trame maitre pour esclave 1).

    Par ailleurs, je ne comprends pas trop cette histoire de stop bit qui ne doit pas être le problème puisqu'une première lecture semble correcte.

    Salutations
    Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better. (Samuel Beckett)

  4. #4
    Nouveau Candidat au Club
    Bonjour à tous,

    Tout d'abord, merci beaucoup d'avoir répondu à mon sujet car oui, je n'avais pas énormément de réponse ou de solution.

    J'ai voulu m'acharner à résoudre mon problème en voulant tout simplement créer une communication série en C sous Linux.

    Mais je pense que la solution est dans une librairie déjà existante que Eks a donné, libmodbus.

    J'ai déjà essayé de l'utiliser et d'adapter leur code au mien mais j'ai toujours des problèmes de compilation, à cause d'include de la librairie ect...

    Du coup, j'ai laissé de côté cette librairie. Je vais relire tous les liens que tu m'as donnés Eks et regarder la documentation pour mieux comprendre comment utiliser la librairie libmodbus.

    Si jamais tu connais bien cette librairie, je veux bien de ton aide et je te remercie infiniment pour ça.

    Pour répondre à Guesset, oui ce sont bien des exemples fictifs. Oui je pense pas que ça vienne du modbus mais plutôt de la gestion de transmission.

    Pour expliquer le bit stop, pour moi ce bit servait à indiquer la fin de la trame donc dans la logique, si on détecte la fin de la trame, on peut avoir le début de la trame suivante.

    C'est pour ça que je pense/pensais que c'était un problème avec le bit stop. D'où la "mauvaise" potentielle configuration de ma communication RS485.

    Je vous tiendrai au courant pour l'utilisation de la librairie Libmodbus.

    Merci.

###raw>template_hook.ano_emploi###