Problème de communication entre deux Uno via Rx-Tx

bonjour le forum,
pour un projet de compteur de passages avec envoi du nombre par mail, j'utilise deux Arduino (le code pour l'envoi du mail prend à lui seul 90% de mémoire):
un Uno maître, pour le compteur et l'horloge / alarme;
un Uno R4 WiFi esclave, pour l'envoi du mail;
les deux fonctionnent bien séparément, mais pas quand ils sont reliés via les Rx-Tx (croisés, avec un Gnd commun); même pas avec les codes basiques ci-dessous (téléversés en ayant débranché les liaisons Tx/Rx)
Merci d'avance pour votre aide

code maître

void setup() {
  Serial.begin(9600); 
}

void loop() {
  Serial.write("test envoi valeur");
  delay(8000); 
}

code esclave

String readString;

void setup() {
  Serial1.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
  // Serial.println("serial delimit test 1.0");
}

void loop() {
   if (Serial1.available())  {
    char c = Serial1.read();
    if (c == ',') {
      if (readString.length() >0) {
        Serial1.print(readString); 
        digitalWrite(LED_BUILTIN, HIGH); 
        delay(1000);                       
        digitalWrite(LED_BUILTIN, LOW);    
        delay(1000);  
        readString=""; //clears variable for new input
      }
    }  
  }
}

J’ai déplacé votre sujet dans la catégorie générale francophone du forum qui est la plus appropriée - ce n'est pas un tuto...

À l’avenir, veuillez prendre un moment pour choisir la catégorie du forum qui correspond le mieux au sujet de votre message. En haut de chaque catégorie se trouve un sujet intitulé « À propos de la catégorie ___ » qui en explique la finalité.

C’est une partie importante d’une utilisation responsable du forum, comme expliqué dans le guide Les bonnes pratiques du Forum Francophone”.

Ce guide contient aussi beaucoup d’autres informations utiles.

Merci d’avance pour votre coopération.

Bonjour, et merci
c'est mon premier post, je n'avais pas bien perçu les différentes catégories ;-(
je vais regarder de plus près !
Belle journée

Bonjour bridgingolfingjp

Pourquoi ne mets tu pas tout ça dans le R4 ?

Si tu restes avec 2 UNO, mets tes 2 programmes en ligne.

A+
Cordialement
jpbbricole

merci jpbbricole
j'aurais bien voulu n'utiliser que le R4, mais le code pour le mail (ESP) prend déjà 91% de la mémoire, trop pour pouvoir y rajouter le code du compteur et du déclencheur d'envoi du mail

j'ai mis les deux programmes dans mon 1er post: le code maître pour compteur et déclencheur, et le code esclave pour le mail

Autre solution, prendre un ESP32 ?

le code mail est dans le R4 wifi, et le R3 contient le code compteur et déclencheur
Je peux poster le code des deux, mais je pensais que tant que je n'avais pas solutionné le problème de communication avec les deux programmes test du début, c'était inutile de rajouter les autres...
Et je suis un peu pressé par le temps pour changer de carte...

j'ai bien un Giga en stock, qui conviendrait certainement, mais sans encore les connaissances suffisantes pour y adapter les codes prévus pour les uno

Je vais te "dépatouiller" tes programmes, mais ça sera pour la fin de l'après midi :wink:

merci beaucoup pour ton écoute! depuis plusieurs jours je tente pas mal d'essais infructueux
Voici le code prévu pour le Uno maître


#include "Arduino.h"
#include "Wire.h"
#include <RTClib.h>

#define ButtonState

#define SUNDAY    0
#define MONDAY    1
#define TUESDAY   2
#define WEDNESDAY 3
#define THURSDAY  4
#define FRIDAY    5
#define SATURDAY  6

#define JANUARY   1
#define FEBRUARY  2
#define MARCH     3
#define APRIL     4
#define MAY       5
#define JUNE      6
#define JULY      7
#define AUGUST    8
#define SEPTEMBER 9
#define OCTOBER   10
#define NOVEMBER  11
#define DECEMBER  12


RTC_DS3231 rtc;
  
const int buttonPin = 2; // contact (NO du relais de la barrière)IR
const int resetPin = 3; 

int counter = 0;           // compteur du nombre de passages
int buttonState = 0;      // état du contact IR (Haut ou Bas)
int lastButtonState = 0;  // dernier état du contact IR

void setup() {
  while (!Serial) ;
  Serial.begin(9600);
  pinMode(buttonPin, INPUT);
  pinMode(resetPin, INPUT);
   Wire.begin();
 
  bool buttonPressed = false;  // Boolean flag to track button press

 // SETUP RTC MODULE
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    // Serial.flush();
    while (1);
}
 
  // rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // time du PC
    rtc.adjust(DateTime(2025, 10, 9, 20, 59, 0));       // entrée manuelle time A M J h m s
 }

void loop() {

   buttonState = digitalRead(buttonPin);  // lecture de l'état du contact IR
  if (digitalRead(buttonPin) == HIGH) {
    counter++;
    Serial.println(counter);
    delay (2000);
}
    lastButtonState = buttonState;  // enregistre l'état du contact IR comme dernier état
  
 DateTime now = rtc.now();

 // alarme envoi mail val counter
if (now.hour()== 21 && now.minute()== 0 && now.second()== 0) {
   Serial.write("counter val"); // pour Tx au R4 envoi par mail
   delay (1000);
}
      
 // alarme reset
if (now.hour()== 21 && now.minute()== 1 && now.second()== 0) {
     counter = 0;  // reset counter
     delay (1000);
     Serial.println(counter);
  }

et le code pour envoi du mail par le R4Wifi, pour lequel je n'ai pas encore travaillé à voir comment mettre dans le corps du mail la valeur "counter" envoyée par le R3

#include "Arduino.h"
#include "Wire.h"
#include "WiFiS3.h"
#include "RTC.h"
#include "ESP_Mail_Client.h"

#define WIFI_SSID "xxxxxxxxx"
#define WIFI_PASSWORD "xxxxxxxxx"
#define SMTP_HOST "xxxxxxxxx"
#define SMTP_PORT 465
#define AUTHOR_EMAIL "xxxxxxxxx"
#define AUTHOR_PASSWORD "xxxxxxxxx"
#define RECIPIENT_EMAIL "xxxxxxxxx"

SMTPSession smtp;

int counter = 0;

void setup(){
  Serial.begin(9600);
  while (!Serial) ;
  Serial.println();
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
 
  MailClient.networkReconnect(true);
  smtp.debug(1);
  
  Session_Config config;  
  config.server.host_name = SMTP_HOST;
  config.server.port = SMTP_PORT;
  config.login.email = AUTHOR_EMAIL;
  config.login.password = AUTHOR_PASSWORD;
  config.login.user_domain = "";

  config.time.ntp_server = F("pool.ntp.org,time.nist.gov");
  
  SMTP_Message message; // classe de message
  message.sender.name = F("xxxxxxxxx");
  message.sender.email = AUTHOR_EMAIL;
  message.subject = F("ESP Test Email");
  message.addRecipient(F("moi"), RECIPIENT_EMAIL);
   
  String textMsg = "depuis xxxxxxxxx";
  message.text.content = textMsg.c_str();
  message.text.charSet = "us-ascii";
  message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit;
  message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low;
  message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay;

 if (!smtp.connect(&config)){  
    ESP_MAIL_PRINTF("Connection error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str());
    return;
 }
    if (!MailClient.sendMail(&smtp, &message)){  // envoi du message
    ESP_MAIL_PRINTF("Error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str());
}
}

 void loop() {
}

Bonsoir bridgingolfingjp

Voilà, je t'ai refait le Maser et le slave du post#1

Le Master envoie les données au slave, toutes les sendValeursTempo millisecondes et, pour le "scénario", counter est incrémenté toutes les counterTempo millisecondes.

Tu remarquera l'absence de temporisations en delay();, c'est à bannir dans ce genre de transactions. En effet cette fonction a le défaut de bloquer ton Arduino pendant la durée du délais.
Toutes les temporisations se font avec les millis (regarde cet exemple de clignotement de LED)

Si tu prévois de transmettre plus d'une valeur, dis le tout de suite afin que je structure tes communications en conséquence.

Il y a des lien dans le Slave, concernant les fonctions de réception.

Le programme Master:


int counter = 0; // Valeur à transmettre

const unsigned long sendValeursTempo = 3000; // Envoi toutes les xxx millisecondes
unsigned long sendValeursMillis = millis(); // Envoi toutes les xxx millisecondes, chrono

const unsigned long counterTempo = 750; // Incrément du compteur toutes les xxx millisecondes
unsigned long counterMillis = millis(); // Incrément du compteur toutes les xxx millisecondes, chrono

void setup()
{
	Serial.begin(9600); // Rx (0) sur R4 Tx (1)   Tx (1) sur R4 Rx (0)

}

void loop()
{
	//--------------------------------- Counter
	if (millis() - counterMillis >= counterTempo) // Si moment d'incrémenter counter
	{
		counter ++;
		counterMillis = millis(); // Redémarrer le chrono
	}

	//--------------------------------- Envoi des données
	if (millis() - sendValeursMillis >= sendValeursTempo) // Si moment d'envoyer les données
	{
		Serial.println(counter); // Envoi de la donnée
		sendValeursMillis = millis(); // Redémarrer le chrono
	}

}

Le programme Slave:

/*
	readStringUntil(); https://docs.arduino.cc/language-reference/en/functions/communication/serial/readStringUntil/
	trim(); https://docs.arduino.cc/built-in-examples/strings/StringLengthTrim/
	toInt(); https://docs.arduino.cc/language-reference/en/variables/data-types/stringObject/Functions/toInt/
*/

int counter = 0; // Valeur reçue

void setup()
{
	Serial.begin(115200); // Liaison USB
	Serial1.begin(9600); // Liaison Master Rx (0) sur R3 Tx (1)   Tx (1) sur R3 Rx (0)

}

void loop()
{
	if (Serial1.available()) // Si réception du Master
	{
		String rxMaster = Serial1.readStringUntil('\n'); // Réception de Master 
		rxMaster.trim(); // Nettoyage de la chaîne reçue 
		
		counter = rxMaster.toInt(); // Extraction decounter
		
		Serial.println("Nouvelle donnée reçue: " + String(counter));
	}

}

C'est essayé en vrai :wink:

A+
Cordialement
jpbbricole

merci jpbbricole pour cette réponse détaillée, que je vais étudier.
Une seule valeur est en jeu, celle du compteur (de passage de clients d'un petit magasin), donc une variable entière positive inférieure à 256.
Concernant les millis je vais regarder, mais déjà:
je dois déclencher deux actions quotidiennes, soit un envoi de la valeur du compteur à 21h, et un reset du compteur à 22.
Je suppose que je devrai mettre sendValeursTempo = 24 x 3600 x 1000 , et 25x... pour la 2ème?
Belle soirée, cordialement
Jp

Bonsoir bridgingolfingjp

Non, la fonction millis() ne te donne pas une heure, mais le nombre de millisecondes depuis le démarrage de l'Arduino, donc aucune référence de 21h ou autre.
Mais ce n'est pas nécessaire, puisque tu as une RTC et, dans ton post#11, il y a déjà des actions pour ces 2 événements.

	// alarme reset
	if (now.hour()== 21 && now.minute()== 1 && now.second()== 0) {
		counter = 0;  // reset counter
		delay (1000);
		Serial.println(counter);
	}
	// alarme envoi mail val counter
	if (now.hour()== 21 && now.minute()== 0 && now.second()== 0) {
		Serial.write("counter val"); // pour Tx au R4 envoi par mail
		delay (1000);
	}

Il te faut uniquement modifier la façon d'envoyer counter, comme vu dans le programme master du post#13

	// alarme envoi mail val counter
	if (now.hour()== 21 && now.minute()== 0 && now.second()== 0) {
		Serial.println(counter); // Envoi de la donnée
//		Serial.write("counter val"); // pour Tx au R4 envoi par mail
//		delay (1000);
	}

Il faut, bien sûre, côté Slave, adapter la réception comme l'exemple du post#13.

Tu remarquera que j'ai mis en remarque le delay(1000);
Quand il y a des communications, ces délais sont du "poison", à éviter pour autant que faire ce peut :wink:

Bonne soirée
jpbbricole

en fait souvent quand il y a un test comme cela

Vous aurez une attente d'une seconde car si la loop() boucle très vite, la RTC dira qu'on est toujours à 21:00:00 car il y a 1000 ms pendant lesquelles ce test est vrai. l'attente de 1s est là pour que la prochaine fois que l'on passe dans le test, s'il avait été vrai auparavant, on soit à 21:00:01 au moins et donc on ne redéclenchera pas. (si on veut éviter le délai qui n'est certes pas ideal, il faut rajouter de l'info, par exemple si c'est une fois par jour on peut vérifier que le N° du jour a changé)

je n'ai pas lu le code, mais si ce n'est que du côté de l'émetteur ce n'est pas très grave - il envoie les données quand il veut .

Notez que vous utilisez readStringUntil

qui bloque la loop... mais c'est pour la bonne cause..

Oui, mais le temps de lire 3 ou 4 octets, donc pas grand chose, environ 3,5 millisecondes.

à condition que l'émetteur ait bien envoyé le \n

Avec Serial.println(counter); // Envoi de la donnée
pas de souci.

Mais on peut toujours mettre, par sécurité, un timout:
Serial.setTimeout(20)
de 20 millisecondes, qui sera le temps d'attente maximum.
Sans timout, c'est 1000 millisecondes.

oui mais ensuite en ne sait pas dans le code si on a reçu tout le message :slight_smile:

c'est pour cela que je n'aime pas trop les fonctions bloquantes avec timeout arduino, elles fonctionnent quand tout se passe bien, mais si la ligne série et bruitée ou qu'il y a un souci côté émetteur on va recevoir une donnée incomplète sans pouvoir le détecter