Communication UART transfert données dans variable

Bonjour,

Je suis en train de communiquer d'un raspberry vers un arduino mega en USB et je me suis rendu compte que les infos transmises initialement n'était pas correctement assimilées par le code arduino (données de 0 à 65535 coté raspberry, mais arduino relit de -32766 à 32768 environ) ==> chose qui ne me convient pas.

J'ai cependant réussi à contourner cette problématique en adaptant le code, mais je n'arrive à correctement affecter la valeur envoyée à une variable de l'arduino.

le code est le suivant (il permet bien de récupérer les données => visible dans le moniteur) :

void loop() {
  if (Serial.available() ) 
  {
    int datalength = Serial.readBytes(buf, BUFFER_SIZE);
    {
       for(int i = 0; i < datalength; i++)
        {
             Serial.print(buf[i]);
        }
    }
  }
}

J'avais eu l'idée de mettre un : variable = Serial.print(buf[i]) mais ça casse le réassemblage de la donnée.
Comment je peux faire pour qu'a la fin de la boucle for, je puisse affecter le contenu du tableau à une variable ?

En vous remerciant.

Bonjour, pour commencer variable = Serial.print(buf[i]) signifie que tu veux affecter à la variable "variable" la valeur de retour de la fonction d'affichage, qui je crois est "void" (aucun retour).

Je suppose que ce n'est pas le code que tu donne qui affiche une valeur sur 16bits.
Le soucis que tu rencontre est que la valeur "binaire" est assigné au mauvais type "int" au lieu d'un " Unsigned int"

Il pourrait y avoir une autre cause au problème.
Tu codes sur 2 plateformes différentes et le type int est plateforme dépendant.
Si tu veux échanger des données entre 2 plateformes différentes et avoir le contrôle sur le type de celles-ci, il faut :

  • soit échanger les valeurs en texte avec des printf(), et faire la conversion avec atoi() à la réception
  • soit échanger les valeurs en binaire avec des write(). Dans ce cas pour maitriser le format des données utiliser des types non ambigus, uint16_t par exemple pour passer des entiers non signés sur 16 bits.

Il faut aussi définir un minimum de protocole pour savoir retrouver les données afin de reconstruire les nombres correctement.

Bonjour, merci pour vos réponses.
Typiquement coté raspberry, j'envoie les datas via :

#code python
val = 592100   # une valeur comprise entre 0 et 65535
ser.write(str(val).encode('utf-8')+b'\n')

coté arduino, j'utilise le code du premier poste et il reçoit bien la valeur envoyée, mais chiffre par chiffre. Ce qui est normal, mais j'aimerai concaténer les valeurs reçues afin d'affecter la valeur envoyée (dans l'exemple 592100) à la variable.
Je vais essayer avec strcat...

Oui est non, l'ordre du poids fort ou fiable, change la valeur mais le signe, si les ombres sont signé des deux cotés.

Si tu lit caractère par caractère coté Arduino, c'est que le problème vient de ta sérialisation du coté python.
Désolé, avec ton code, je ne vois d'où peut venir le problème.
Peut être que si tu affiche exactement ce que tu envois et tu reçois ?

voici le code coté raspberry :

#!/usr/bin/env python
#executer avec python3

import epics
import time
import serial

if __name__ == '__main__':
	ser = serial.Serial('/dev/ttyACM0', 115200, timeout=1)
	while True:
		val = 59210
		print ("rpi =",val)
		ser.write(str(val).encode('utf-8')+b'\n')
		time.sleep(0.5)
		line = ser.readline().decode('utf-8')
		print (line)

ici le code arduino :


unsigned char prescaler = 0b00001101;   // variable d'ajustement du prescaler en fonction de la valeur de frequence
int valeur = 65535;                    // frequenceInt 
int prescal = 0;
const int BUFFER_SIZE = 50;
char buf[BUFFER_SIZE];
char val[5];


void setup () {
  delay(10000);
  Serial.begin(115200);
  }
 
// =================
// Boucle principale
// =================
void loop () 
{
  if (Serial.available())                         // ici on regarde si qqechose vient de l USB
  {
    int rlen = Serial.readBytes(buf, BUFFER_SIZE);
    for(int i = 0; i < rlen; i++)
    {
      Serial.println(buf[i]);
    }

  }

}

et le retour moniteur en image piece jointe :

Bonjour wawann

Essaies de lire ton port série avec Serial.readStringUntil('\n'); ainsi:

unsigned char prescaler = 0b00001101;   // variable d'ajustement du prescaler en fonction de la valeur de frequence
int valeur = 65535;                    // frequenceInt
int prescal = 0;
const int BUFFER_SIZE = 50;
char buf[BUFFER_SIZE];
char val[5];


void setup () {
	delay(10000);
	Serial.begin(115200);
}

// =================
// Boucle principale
// =================
void loop ()
{
	if (Serial.available())                         // ici on regarde si qqechose vient de l USB
	{
		String chiffreRecuSerie = Serial.readStringUntil('\n');
		chiffreRecuSerie.trim();     // Ecentuellement pour nettoyer la réception
		long chiffreRecu = chiffreRecuSerie.toInt();
	}

}

C'est pas essayé "en vrai" :wink:

Cordialement
jpbbricole

Pour debugger, il serait plus intéressant d'afficher "str(val).encode('utf-8')+b'\n'"

En tous cas ton output me semble correspondre à tes attentes :slight_smile:
tu envoi 59210 et tu reçois bien 5 9 2 1 0 + un caractère, peut être le \n, mais je n'ai pas l'impression.

Salut.

Avec ce code, tu lis bien une suite d'octets qui correspond à ce qu'envoie le code PYTHON.
Mais il y a deux problèmes :

  • ce que tu lis est de l'ASCII, c'est à dire "59210\n"
  • un timeout de 1s allonge le temps de lecture, car ton code C ne tient pas compte du '\n'

Si tu veux convertir la valeur "59210\n" en valeur numérique, utilise atol(), ou mieux, strtol()

Si tu veux éliminer la seconde d'attente, utilise Serial.readBytesUntil() au lieu de Serial.readBytes()

int rlen = Serial.readBytesUntil('\n', buf, BUFFER_SIZE);

alors en utilisant le code :

void loop () 
{
  if (Serial.available())                         // ici on regarde si qqechose vient de l USB
  {
    String chiffrerec = Serial.readStringUntil('\n');
    chiffrerec.trim();
    long chiffre = chiffrerec.toInt();
    Serial.println(chiffre);
  }
}

cela me retourne la même chose qu'avec le précédent code, c'est à dire :

Comment faire pour réassemble les chiffres 5 9 2 ... ?

Il y a probablement un zéro de trop ...

Si tu veux convertir un nombre <= 65535, tu as deux solutions :

  • utiliser un type long et atol() ou strtol(), car 65535 ne tiendra pas dans un int
  • utiliser un type unsigned int et sscanf()
unsigned int var;
sscanf(buf, "%u", &var);

Attention le type de la variable var doit être correct :
%u : unsigned int
%d : int
%l : long.

De plus ,tu peux tester la valeur retournée par sscanf(). Elle retourne le nombre d'éléments scannés, dans ton cas : 1.

Bonjour wawann

La variable chiffre (long chiffre = chiffrerec.toInt();) contient le rassemblement.
Serial.println(chiffre);

Cordialement
jpbbricole

Effectivement pour le 592100 , mon doit a un peu forcé sur la touche... je veux toujours une valeur inférieur à 65535.

La question est vague.
Soit tu veux concaténer 5, 9, 2, etc. dans une chaîne, et ça c'est déjà fait.
Soit tu veux les transformer en valeur numérique, et je t'ai donné plusieurs solutions.

un autre test que j'avais fait précédement c'est :

if (Serial.available())
{
   valeur = Serial.readStringUntil('\n').toInt();
   Serial.println(valeur);   // ou Serial.print(valeur);
}

qui me retourne les valeurs entre -32XXX et +32XXX

Capture2

dans l'idée cette solution me convenait bien, mais j'aurai voulu avoir des valeurs de 0 à 65535..

Merci, je suis en train de regarder tes propositions.

Ok ça semble marcher avec unsigned valeur...

Merci pour votre aide !

Tout d'abord ce n'est pas le moniteur, c'est le terminal dans lequel tu as lancé PYTHON

Ton problème se situe côté PYTHON.
ser.readline() attend une chaîne terminée par '\n', mais là je ne vois pas de prime abord pourquoi print() affiche un seul caractère à la fois.

Bonjour wawann

Comment est déclarée la variable valeur?

Dans ma proposition:

		String chiffreRecuSerie = Serial.readStringUntil('\n');
		chiffreRecuSerie.trim();     // Ecentuellement pour nettoyer la réception
		long chiffreRecu = chiffreRecuSerie.toInt();

chiffreRecuSerie.toInt(); retourne, en réalité, une variable de type long.

Cordialement
jpbbricole