Transmettre un floats sur port série TX/RX

Bonjour a tous

Je suis jeune retraité et commence tout juste sur arduino.

Je cherche a envoyer une (au moins) variable de type float d'un uno vers un mega, par une liaison série TX/RX.
Pour info la variable est issue d'un ds18b20 (enfin, 4 en l’occurrence).
Les branchements sont ok, car j'arrive a envoyer un int sans problème.

Malgré avoir lu beaucoup de blogs (Eskimon, zeste, et d'autres), je n'arrive pas a mes fins.

J'ai fait 2 progs d'essais en assemblant des infos prises un peu partout, mais bon...
Dans l'état actuel je ne reçoit que des 0.

Je me permet de vous envoyer les 2 progs.(on ne rigole pas)

Émission

#include <SoftwareSerial.h>
///================   UNO ===================

#include <SoftwareSerial.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
int potarPin = A0;
int potarValue = 0;
long temp = 0;
//long val = 0x74CBB1;
//float temp=0;

LiquidCrystal_I2C lcd(0x27, 20, 4);
SoftwareSerial mySerial(10, 11); // RX, TX

void setup()
{
  Serial.begin(9600);
  mySerial.begin(2400);

  lcd.init();
  lcd.backlight();
  lcd.clear();
}
void loop() {
  potarValue = analogRead(potarPin);
  temp = potarValue * (30.0 / 1023.0); // force la valeur entre 0 et 30

  Serial.print(0xff); // la valeur envoyée est 0xFF
  Serial.print((temp >> 24) & 0xFF); // la valeur envoyée est 0x0
  Serial.print((temp >> 16) & 0xFF); // la valeur envoyée est 0x74
  Serial.print((temp >> 8) & 0xFF); // la valeur envoyée est 0xCB
  Serial.print(temp & 0xFF); // la valeur envoyée est 0xB1

  lcd.setCursor(0, 0);
  lcd.print("potar=");
  lcd.setCursor(6, 0);
  lcd.print("    ");
  lcd.setCursor(6, 0);
  lcd.print(potarValue);

  lcd.setCursor(0, 1);
  lcd.print("temp=");
  lcd.setCursor(6, 1);
  lcd.print("    ");
  lcd.setCursor(6, 1);
  lcd.print(temp, 1);

  delay(100);
}

Réception

// Réception sur Mega 2560
// SDA=20  SCL=21
// Serial 1 (TX 18, RX 19)
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
LiquidCrystal_I2C lcd(0x3F, 20, 4);
int val = 0;
int val2 = 0;
int val3 = 0;
int val4 = 0;
float valeur = 0;
//float var;

void setup() {
  lcd.init();
  lcd.backlight();
  lcd.clear();

  Serial.begin(9600);
  Serial1.begin(2400);
  Serial.println("Attente réception !");
}
void loop() {

  while (Serial1.available() >= 5) {
    if (Serial1.read() == 0xff) {
      val = Serial1.read();
      val2 = Serial1.read();
      val3 = Serial1.read();
      val4 = Serial1.read();
      Serial1.flush();

      valeur = ((val4 << 24) | (val3 << 16) | (val2 << 8) | (val));
    }
  }
  Serial.println(valeur);

  lcd.setCursor(0, 0);
  lcd.print("recu =");
  lcd.setCursor(6, 0);
  lcd.print("    ");
  lcd.setCursor(6, 0);
  lcd.print(valeur, 1);
}

Merci de votre attention et de vos conseils avisés.

Bonjour,

Tu envoies tes valeur en ASCII avec print et tu les interprètes comme du binaire en réception.
En plus tu envoies un long et tu reçois un float

Tu n'as pas besoin de découper en octet pour envoyer. Il suffit de faire:

  Serial.write((byte *)&temp, sizeof temp);

En réception:

  long valeur;
  if (Serial1.available())
  {
    Serial1.readBytes((byte *)&valeur, sizeof valeur);
    Serial.println(valeur);
  }

Bonjour

Merci pour ta réponse rapide.

En effet j'envoyais un long, parce que il ne voulait pas de mon float, mais j'espérais recevoir...quelque chose.

J’essaie dès que possible et revient vers vous.

Nickel,

Le prochain soucis, c'est que je dois envoyer 4 valeurs float.
pour envoyer, je pense pas de souci, mais a la réception, comment faire pour que la valeur reçue arrive a la bonne variable?
Sur le principe, je pense qu'il faut envoyer un "identifiant", mais de là a le faire...

Encore merci

Le plus simple est de créer une structure et d'envoyer/recevoir la structure d'un seul bloc.

par exemple:
émission

  struct SValeurs
  {
    float val1;
    float val2;
    float val3;
    float val4;
  };
  SValeurs valeurs;
  valeurs.val1 = 123;
  valeurs.val2 = 20.7;
  // ...
  Serial.write((byte *)&valeurs, sizeof valeurs);

réception:

  struct SValeurs
  {
    float val1;
    float val2;
    float val3;
    float val4;
  };
  
  SValeurs valeurs;
  if (Serial1.available())
  {
    Serial1.readBytes((byte *)&valeurs, sizeof valeurs);
    Serial.println(valeurs.val1);
    Serial.println(valeurs.val2);
  }

+1. Même conclusion. Si l'ordre des variables est fixe, aucun besoin d'identifiants :

struct temp
{
  float temp1;
  float temp2;
  float temp3;
  float temp4;
};

void setup() {
  Serial.begin(115200);
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);
}

void loop() {
  struct temp temperatures;

  if (Serial.available()) {
    Serial.readBytes((byte *)&temperatures, sizeof temperatures);
    digitalWrite(13, HIGH);
    Serial.println(temperatures.temp1);
    Serial.println(temperatures.temp2);
    Serial.println(temperatures.temp3);
    Serial.println(temperatures.temp4);
  }
}

Pour la mise au point tu peux tester avec un code PYTHON comme émetteur sur PC :

#!/usr/bin/env python

import time, serial, struct

if __name__ == "__main__":
	ser = serial.Serial('/dev/ttyUSB1', baudrate=115200)
	ser.timeout = 3
	time.sleep(2)
	data = struct.pack('<ffff', 12.5, 23.4, 24.7, 34.8)
	ser.write(data)
	print len(data)
	data = ser.read_until('\n').strip('\r\n')
	print data
	data = ser.read_until('\n').strip('\r\n')
	print data
	data = ser.read_until('\n').strip('\r\n')
	print data
	data = ser.read_until('\n').strip('\r\n')
	print data
$ python serial-bin.py 
16 bytes transmitted
12.50
23.40
24.70
34.80

Merci pour la(les) réponses.

Pas encore testé l'exemple de kamill, mais puis-je mettre en même temps du int et du float sans problème?
Et l'ordre des variables ne changera pas.

@hbachetti,

Je pense tester directement sur les arduinos, mais sinon par curiosité, pour tester un code python
sur pc, il faut un logiciel spécifique je suppose? (ça peut être intéressant).

Pas encore testé l'exemple de kamill, mais puis-je mettre en même temps du int et du float sans problème?

Tu mets ce que tu veux dans la structure.
L'essentiel est qu'elle soit identique des deux côtés.

pour tester un code python
sur pc, il faut un logiciel spécifique je suppose? (ça peut être intéressant).

Python

Je travaille en PYTHON 2.7 par habitude mais rien ne t'empêche de commencer en PYTHON 3.

La communication sur la ligne série nécessite un module pyserial :

PYTHON 2.7 :

PYTHON 3 :

Ok, merci pour les infos, je vais regarder attentivement, mais pas de suite.

j'ai mélangé int et float et c'est ok, plus qu'a augmenter la vitesse de transmission.

A propos j’ai environ dix mètres de distance entre 2 arduinos, je peux espérer quoi comme vitesse, avec du câble téléphone.

Je vais me consacrer a mon projet actuel.
C'est a dire remplacer les picaxes sur une installe pour le chauffage que j'ai fait avec picaxes en liaisons.
4 ds18b20, moteur pas a pas, 2 écrans 1602 et 2004 etc...

Le truc c'est que je veux en faire plus, mais les picaxes (sans dénigrer hein!, j'aime bien) au niveau vitesse, ça ne suis plus.

J'attends un nextion 4.3" et deux petits 0.96" un en spi et l'autre en i2C .

Je pense que des questions suivront.

A propos j'ai environ dix mètres de distance entre 2 arduinos, je peux espérer quoi comme vitesse, avec du câble téléphone.

Il faut essayer. Tout dépend de la qualité du câble.
Je dirais au moins 19200.

Par contre il est difficile de garantir la fiabilité de la transmission sur de grandes longueurs (à cause des parasites, champs magnétiques, etc.) sans un minimum de sécurité.
On peut par exemple ajouter un CRC à la fin de chaque message.

Tout dépend de ce que l'on fait des données.

Bon, en même temps ce ne sont que des valeurs de températures et de consigne, rien de critique en terme de vitesse.

Mais être sur des données reçues, c'est très intéressant et sécuritaire.

C'est difficile a mettre en œuvre un crc ? (si mes souvenirs sont exacts c'est un polynôme).

Un exemple me plairait bien :slight_smile:

J'ai ça.
Ce code fait partie d'une librairie protocole que j'ai développé mais cela me semble trop complexe pour un débutant.

sdltp-serial-protocol

Les petits morceaux en rapport avec le CRC :

// Dans le fichier sdltp.cpp :

const uint16_t sdltp_crctbl[] =    // use to calculate crc value
{
  0x0000, 0x1081, 0x2102, 0x3183,
  0x4204, 0x5285, 0x6306, 0x7387,
  0x8408, 0x9489, 0xA50A, 0xB58B,
  0xC60C, 0xD68D, 0xE70E, 0xF78F
};

// Dans le fichier sdltp.h :

#define update_crc(crc, c)    crc = (crc >> 4) ^ sdltp_crctbl[(c ^ crc) & 0x0F]; \
                              crc = (crc >> 4) ^ sdltp_crctbl[((c >> 4) ^ crc) & 0x0F];

// Utilisation côté émetteur :
  uint16_t crc = 0;
  // pour chaque caractère c à émettre :
  update_crc(crc, c);
  // ensuite il faut émettre le CRC.
  // le CRC peut très bien faire partie de ta structure de données.


// Utilisation côté récepteur :
  uint16_t crc = 0;
  // pour chaque caractère c reçu :
  update_crc(crc, c);
  // ensuite il faut comparer le CRC reçu avec la variable crc.
  // si les deux sont différents -> erreur de transmission

L'article :
arduino-un-protocole-serie