Un char n'est d'autre qu'un octet, soit 2 nombres hexa à la suite. Si tu n'utilise pas le port série pour envoyer des caractères ASCII rien ne t'empêche de dire dans ton code qu'un char du port série équivaut à 2 nombres hexa. Sinon tu peux juste envoyer ton hexa comme un caractère ASCII ('0', '1', ... 'E', 'F').
Enfin tu peux passer par le %x dans les chaines de format (le\x sert juste à écrire des hexa correcte)
Merci beaucoup pour ta réponse mais je n'ai pas compris le "rien ne t'empêche de dire dans ton code qu'un char du port série équivaut à 2 nombres hexa. Sinon tu peux juste envoyer ton hexa comme un caractère ASCII ('0', '1', ... 'E', 'F')"
Peux-tu expliciter un peu plus s'il te plaît, ou me donner un exemple.
Le but c'est vraiment d'envoyer en hexadécimal une seule variable qui contient toutes mes valeurs hexadécimales.
char, octet... ce ne sont que des valeurs numérique que tu traites, quelque soit leur représentation: binaire, hexadécimal, décimal, octal... ça ne change pas leur valeur. Faut pas mélanger la valeur et sa représentation visuel !
Oui je me doute qu'il y a une différence entre la représentation visuelle et leur valeur. Dans tous les cas je n'arrive pas à envoyer de l'hexa sur mon port série. Mon automate reçois de l'ASCII. Et j'ai essayé de trouver une solution mais je ne sais pas comment.
un char est considérer en C comme un octet (0b00000000 = '\0')
le port série n'envoie que des octets (char), il faut donc feinter pour envoyer des hexadécimales (0b0000 = 0x0). Pour envoyer ton hexa 2 choix se porte à toi :
- convertir chaque chiffre hexa en octet (donc char) et les envoyer (soit envoyer pour 0x3 : 0b00000011 ou un 3 en valeur ASCII : 0b00110011)
- ou alors découper ton octet en 2 pour envoyer 2 hexa à la fois (0b00000000 = 0b0000 + (0b0000 décaler de 4 bits à gauche)). C'est plus optimiser pour l'envoie (plus rapide) mais cela demande un peu de logique pour récupérer les valeurs. Tu peux utilisé la méthode du décalage de bits que je n'expliquerais pas ici ou un mask :
// on suppose qu'on stock l'hexa dans un char
char double_hexa_recu; // c'est l'octet reçu en paramètre ou autre, qu'on a toujours pas traité
char premier_hexa, second_hexa; // osef de la valeur de départ on les assigne après
char mask_bas = 0b00001111, mask_haut = 0b11110000; // mask_haut récupère premier_hexa et mask_bas recupère second_hexa
// attention à l'ordre d'envoi des hexa !!
premier_hexa = double_hexa_recu & mask_haut; // on utilise le ET bit à bit
second_hexa = double_hexa_recu & mask_bas;
/*
pour expliquer le fonctionnement on doit partir de la table de vérité du ET
A B S
0 0 0
0 1 0
1 0 0
1 1 1
On remarque que l'on recopie B sur S si A est vrai (1)
donc 0b01010101 & 0b00001111 = 0b00000101
et traduit en hexa on a :
0x55 & 0x0F = 0x05
Magique non ?
*/
J'ai compris qu'on envoie que des octets par le port série, donc avec ma fonction "write(port_serie,data,size of data)" , ma variable data contient les octets que je souhaite envoyer.
Pour revenir avec tes 2 méthodes, je pense que le mieux serait la deuxième, envoyer 2 hexa à la fois.
J'ai regardé en détail l'exemple de code que tu as envoyé mais je ne vois pas comment l'adapter à mon cas. J'ai l'impression que ça fonctionne qu'avec une seule donnée hexa, sauf que si tu remontes plus haut dans le topic, j'ai 13 données à concaténer ensemble en hexa.
Je souhaite avoir UNE SEULE variable qui contient toutes mes valeurs hexa concaténées ensemble grâce à la fonction sprintf. Puis j'envoie cette variable avec la fonction "write(port_serie,data,size of data)".
Je suis pas expert dans le langage C et j'imagine que c'est triviale pour toi mais j'aimerais vraiment comprendre. Si tu peux m'expliquer avec mon cas pour que puisse faire un lien avec mon cas.
il faut simplement utiliser un tableau comme tu l'as fais
Un petit problème que je vois avec cette méthode est qu'on peut envoyer qu'un nombre paire d'hexa (on ne peut pas différencier le 0x0 et le "rien")
Tout dépendant comme tu obtiens ta chaine que tu as envoyé. Je suppose que tu reçoit le tableau en entier avant de la traiter :
// compresse la list d'hexa unique dans src (selon la taille src_size) et place le résultat dans dest<br>// dest doit avoir une taille mininum de src_size/2 (arrondi au paire supérieur) + 1 et maximum de 255
int zipHexa(char* src, int src_size, char* dest){
if(src_size > 254){ // 255 -1 pour la taille
return EXIT_FAILURE;
}else{
dest[0] = src_size;
}
for(int i=0; i < src_size; i++){
if(i%2 == 0){
dest[(int)i/2 +1] = src[i] << 4;
}else{
dest[(int)i/2 +1] = src[i] | dest[(int)i/2 +1];
}
}
return EXIT_SUCCESS;
}
// envoie la trame compressé
int envoie(char* trame){
// certaines verifie à faire ici
write(serial_port, trame, (int) (trame[0]/2 + (trame[0]/2)%2 +1));
return EXIT_SUCCESS;
}
// renvoie une list d'hexa unique ainsi que sa taille après avoir reçu une list compressé d'hexa
int recevoir(char* hexa_list, int* size_list){
char hexa_zip[128]; // reception ici
*size_list = hexa_list[0];
char mask_haut = 0xF0, mask_bas = 0x0F;
for(int i=0; i < *size_list; i++){
if(i%2 == 0){
hexa_list[i] = hexa_zip[(int)i/2 +1] & mask_haut;
}else{
hexa_list[i] = hexa_zip[(int)i/2 +1] & mask_bas;
}
}
return EXIT_SUCCESS;
}
ici j'ai renseigné la taille avec les hexa car je ne sais pas comment est fait la fonction recevoir du port série. Il se peut qu'il y est des erreurs (notamment au niveau des décalages sur les index ou l'ordre des opérations haut/bas).
Je penses que la méthode avec les caractères ASCII est plus simple mais moins fun ^^.
Ça me semble partir dans des usines à gaz pour un truc qui est surement simple au départ.
Il faudrait déjà savoir ce qu'attend ton automate ? La réponse doit être autre chose que de l'hexa ! C'est une suite octets ok, mais ils représentent quoi ?
Ça me semble partir dans des usines à gaz pour un truc qui est surement simple au départ.
Il faudrait déjà savoir ce qu'attend ton automate ? La réponse doit être autre chose que de l'hexa ! C'est une suite octets ok, mais ils représentent quoi ?
C'est une méthode comme une autre. Plus rapide à l'envoi mais plus lourd à la compression/décompression, je penses qu'un simple envoie d'hexa par octet est plus simple (soit en valeur numérique ou ASCII) et reste tout de même efficace.
Cette trame doit absolument être en héxadécimal et non en Ascii.
Tu y tiens !
C'est plutôt les données brut que tu veux envoyer. Dans ce cas, il ne faut pas construire de chaines de caractère comme tu fais ! donc pas de sprintf !
Tu peux mettre tes données dans un tableau de char tel quel dans l'ordre voulu.
Par exemple si tu veux mettre des valeurs dans ton tableau, tu doit faire :
Oui autant pour moi, lorsque j'utilise mon analiseur de trame en mode modbus. Il voit bien la trame que j'envoie mais il l''interprète en ASCII. Je sais que ce sont des octet à la base mais peut être que je m'exprime mal.
Mais il faut que ça soit de l'hexa et non du ASCII. C'est pas que j'y tiens, c'est que mon automate est en protocole RTU donc pas d'ASCII que de l'hexa.
Pour ta méthode de mettre les valeurs dans un tableau, je suis partant pour ça. Le problème c'est que, comment tu veux mettre sous la forme "0x" plusieurs variables.
Ce que tu ne comprends pas, c'est qu'il n'y a pas de difference entre "maVariable" et "0xmaVariable". Dans tous les cas c'est un octet, la base hexadecimale c'est juste pour le representer, mais ton automate ne fait pas la différence.
Donc si tu envoies un octet, tu ne peut pas dire qu'il est en hexa, c'est une valeur.
char a = 0x33;
// est équivalent à
char a = 51;
// qui est équivalent à
char a = 0b00110011;
Fort probable, et c'est quoi ce truc avec l'hexa et l'ascii ? On s'en fiche, la valeur D#52 peut indifféremment être notée H#34, O#64 B#110100 ou '4', c'est exactement la même valeur et la même suite de bits.
De toute façon, à part faire de l'envoie de trame à des imprimantes type videojet, on se fiche de l'ascii, mais pour autant, je dois quand-même lui envoyer H#34 ou '4' pour qu'elle m'imprime un 4. (sans parler des start / stop).
Le mieux serait de nous dire ce que tu veux faire plutôt que comment tu veux le faire, parce qu'à mon avis c'est tellement simple que tu te prends la tête pour rien.
Ton PC fait quoi ? C'est ton IHM ? Qui est le maître ? Tu veux envoyer et relire des paramètres ? si oui, le RTU serait une très mauvaise idée. Que doit contenir ta trame à part adresse / instruction ? Des soucis d'endianess (genre Siemens S300/S400) ?
Bref, décris l'application que tu veux créer et non comment tu as envisagé de le faire, selon moi, nous somme clairement dans un cas de problème XY...
En essayant de deviner, j'ai l'impression que tu as une chaîne de caractère genre "145887" que tu veux transformer en sa valeur 145887 ?
Je vous remercie infiniment pour votre aide et c'est Rouloude qui a trouvé une solution.
Je suis bête et je me suis compliqué la tâche pour rien.
Dans le code que j'ai envoyé, je "restransforme" en ASCII mes données que je souhaite envoyer par la suite sur le port série via la fonction sprintf. Alors qu'il suffit juste de mettre les valeurs brutes un tableau et c'est tout. Comme ici
Mon analiseur de trame me montre bien qu'il reçoit des données brutes en hexa.
A force de tourner en rond sur l'objectif, je me suis perdu.
Merci DRX pour ton message. Oui la solution était simple. Juste que je me compliqué la tête à essayer de concater toutes mes variables dans une seule variable via la fonction sprintf. Mais c'était clairement pas la bonne idée.
Je vais relire ton exemple Rouloude, ça va peut être m'aider à perfectionner mon code.
Encore merci tout le monde !!
Là j'ai un autre soucis de timing d'envoie de trame et de reception de trame mais je ferai un autre topic pour ça !
Comme c'est toi qui rempli le tableau, tu sais combien d'octets sont à envoyer. Regarde l'exemple de rouloude: il met 14 en clair car il sait qu'il a rempli 14 octets dans trame.
Mais c'est le genre de truc qui peut se calculer si les trames ne sont pas toutes identiques: si tu mets 5 char et 3 int, ça fait 5+3*sizeof(int) octets à envoyer.
- Edité par edgarjacobs 9 septembre 2020 à 15:35:35
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
La source des ennuis c'est qu'en C, le mot clé char désigne un type d'entier signé codé sur un octet en mémoire (entre -128 et +127, donc).
Il se trouve que si on manipule toujours des caractères codés sur 7 ou 8 bits (ASCII, ISO-8859), ça rentre dans un char. Et comme les américains ne connaissaient que ça à l'époque, ça induit une confusion.
---
Sur un port série, tu veux envoyer une trame, qui est contenue une succession d'octets qui représentent tes données. Très bien. La question, c'est de savoir comment tu veux coder tes données dans la trame. C'est à dire comment tu construit cette trame.
Imaginons, tu veux envoyer juste un entier. Nombre = 33;
Tu peux décider d'envoyer le nombre codé sur 4 octets, en décidant de l'ordre : poids fort d'abord. Ces octets contiendront
00000000 00000000 00000000 00100001 -. Pour y arriver en C, un truc comme ça
sprintf(trame, "%u08d", nombre);
// ou
sprintf(trame, "%u08x", nombre);
---
Il est probable que quand tu écrivais "envoyer en hexadécimal", tu pensais "envoyer en binaire", parce que tu as manipulé jusque là les nombres binaires à travers de la notation hexadécimale.
En fait, envoyer (des nombres) en hexadécimal, ça veut plutot dire "envoyer une chaine de caractères qui est la représentation sous forme de texte de la valeur hexadécimale". C'est pas pareil.
- Edité par michelbillaud 9 septembre 2020 à 16:14:19
Maintenant j'aimerais savoir combien la longueur de ma trame, c'est à dire combien il y a de chiffre ou de caractère dans ma trame.
La longueur de ta trame, c'est le nombre d'octets que tu as mis dans ton buffer et que tu souhaites envoyer.
un char fait un octets, un int fait sizeof(int) octets. (souvent 4 octets, mais ce n'est pas forcé, c'est pour cela que je mets sizeof).
C'est donc à toi de compter ce que tu mets dedans !
Dans mon code, j'ai mis 14 car je l'ai ai compté de tête.
Mais tout a la fin du code, juste avant le return 0, tu rajoute cette ligne :
printf("\n%u", ptrame-trame);
Tu verra que ça affiche 14, tu peut donc le calculer dans ton programme. C'est d'ailleurs comme cela qu'il est préférable de faire. parce que 14 ça suggère que les int fasses 4 octets, ce qui n'est pas certain.
en fait, tu ne nous a toujours pas expliqué ce que tu veux faire, avec quel automate, comme je l'ai demandé plus haut.
Toujours est-il que tes numériques doivent être formatés selon qu'en face tu vas les stocker dans un byte, word ou un dword. Les automates, c'est comme les ordinateurs, la taille de l'entier naturel peut varier selon la marque.
C'est pour ça qu'il faut qu'on sache quel automate, un Siemens type 400 va stocker le résultat brut du buffer dans le DB de com, il pourrait donc aussi y avoir du traitement pour l'endianess.
Définir une trame, c'est comme pour l'écriture des fichiers, ce doit être formaté à l'octet qui reste le seul type encore fiable, on ne peut pas être certain de la taille des autres types. µDonc si tu veux un valeur sur 4 octets, tu prend 4 char, pas un int.
Alors je reviens vous donner à tous des nouvelles de mon problème de départ.
Tout d'abord merci à Rouloude, Brigitte, Michel, Edgar, Thetui et drx d'avoir pris le temps de m'aider.
Pour répondre à drx, j'imagine que selon l'automate, les tailles des données peuvent varier. Pour le modèle de l'automate, je n'ai pas vraiment pas la main dessus car je ne suis pas automaticien.
On m'a juste donné l'automate, les spécificités des trames (19200 baudes, 1 bit de stop ect...) et je devais "me demerder" pour envoyer des trames.
Mais merci de m'avoir pousser à me renseigner un peu plus sur les automates.
Donc j'ai réussi grâce à vous, à "transformer" mes données ASCII en hexa.
J'ai aussi trouver la longueur de ma trame, merci Rouloude.
Donc le problème est résolu.
Encore merci à tous, je vais me concentrer sur les timings d'envoie de trame qui pose problème donc je reviendrai sur un nouveau Topic.
Bonne continuation à tous
Envoie de trame en Hexadécimal sur un port série
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Bonhomme !! | Jeu de plateforme : Prototype.
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
Le Tout est souvent plus grand que la somme de ses parties.
Bonhomme !! | Jeu de plateforme : Prototype.