Détecter un arrêt de réception du port série

Bonjour, je suis sur un projet d'émetteur-récepteur avec antenne NRF24L01, jusque-là tout va bien, mais j'ai un souci pour créer une sorte d'alarme en cas de perte de signal.
En effet quand le récepteur perd le signal le port série s'arrête, jusque-là normal. Mais j'aimerais allumer une LED pour signaler que le port série est arrêté ou vide.

Merci d'avance

:warning:
Post mis dans la mauvaise section, on parle anglais dans les forums généraux. déplacé vers le forum francophone.

Merci de prendre en compte les recommandations listées dans Les bonnes pratiques du Forum Francophone

Bonsoir hazrod

Tu veux dire par là qu'il n'y a plus de caractère qui arrive sur Serial?
Si oui, tu crée un timer qui est réactivé à chaque réception sur Serial, si ce timer est échu, tu allumes ta LED.
Mets ton programme ou la partie concernée en ligne pour voire où on peut implémenter ça.

A+
Cordialement
jpbbricole

Voici le code, pour l'instant l'émetteur possède 2 boutons qui vont activer les deux relais sur le récepteur et j'aimerai une LED s'active sur l'émetteur et le récepteur quand il perd le signal.
Émetteur :

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

#define buttonPin1 3
#define buttonPin2 4

int buttonState1 = 0;
int buttonState2 = 0;
RF24 radio(9, 8); // CE, CSN

const byte address[6] = "00002";

void setup() {
  pinMode(buttonPin1, INPUT_PULLUP);
  pinMode(buttonPin2, INPUT_PULLUP);
  Serial.begin(9600);
  radio.begin();
  radio.openWritingPipe(address);
  radio.setPALevel(RF24_PA_MIN);
  radio.stopListening();
}
void loop() {
  buttonState1 = digitalRead(buttonPin1);
  buttonState2 = digitalRead(buttonPin2);

  if (buttonState1 == 1)
  {
    buttonState1 = 1;
  }
  else  if (buttonState1 == 0)
  {
    buttonState1 = 0;
  }
  if (buttonState2 == 1)
  {
    buttonState2 = 3;
  }
  else  if (buttonState2 == 0)
  {
    buttonState2 = 2;
  }
  Serial.print(buttonState1);
  Serial.print("\t");
  Serial.println(buttonState2);
  radio.write(&buttonState1, sizeof(buttonState1));
  radio.write(&buttonState2, sizeof(buttonState2));
}

Recepteur :

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

#define led1 A0
#define led2 A1

int buttonState = 0;

RF24 radio(9, 8); // CE, CSN
const byte address[6] = "00002";

void setup() {
  Serial.begin(9600);
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  digitalWrite(led1, HIGH);
  digitalWrite(led2, HIGH);
  radio.begin();
  radio.openReadingPipe(0, address);
  radio.setPALevel(RF24_PA_MIN);
}
void loop() {
  radio.startListening();
  while (!radio.available());
  radio.read(&buttonState, sizeof(buttonState));
  Serial.println(buttonState);

  if (buttonState == 1) {
    digitalWrite(led1, LOW);
  }
  else  if (buttonState == 0) {
    digitalWrite(led1, HIGH);
  }
  else if (buttonState == 3) {
    digitalWrite(led2, LOW);
  }
  else  if (buttonState == 2) {
    digitalWrite(led2, HIGH);
  }
}

Bonjour hazrod

J'ai mal interpreté ton premier message, je voyais un problème de Serial, alors que tu veux un warning si la liaison NRF24L01 venait a être interrompue. J'ai juste?

J'ai beaucoup moins d'expérience que dans Serial.

Mais pour ce faire, dans le récepteur, tu fait une routine qui envoie, régulièrement toutes les secondes par ex.,une donnéec de check à l'émetteur, celui-ci a un watchdog qui surveille la régularité de la réception de ces check et alarme quand le temps est échu.
Si tu sait faire l'émission du check depuis récepteur et la réception de ce check à l'émetteur, je peux te montrer comment faire la watchdog.

Cordialement
jpbbricole

J'avoue qu'un peu d'aide ne serait pas de refus. :sweat_smile:

L'émetteur envoie déjà des messages boutons 0, 1, 2, 3.
Il est assez facile d'envoyer régulièrement un message de vie, auquel le récepteur répond, s'il le reçoit.
Le timer peut être implémenté à l'aide de millis(), des deux côtés (voir l'exemple BlinkWithoutDelay).

Remarque : pour l'instant les messages sont envoyés de manière continue. Il serait sans doute plus judicieux d'envoyer uniquement les changements d'état des boutons.

Quelque part, c'est déjà un signal de vie du coup....

Oui, un peu rapide tout de même. Et le récepteur ne répond pas, donc l'émetteur ne sait pas s'il a capté.

Merci pour les informations les gars, je vous avoue que je ne connais pratiquement rien en code et j'essaye de récupéré des bout de code à droite à gauche.

En gros, l'idée est d'activer deux relais depuis l'émetteur au récepteur et d'avoir un retour d'information sur l'émetteur que les deux relais on bien été activer par le récepteur et également que l'émetteur s'assure que le récepteur est bien à porter via une led pour signaler la perte du récepteur.

Ce petit projet est pour me faciliter au travail, car je travaille très souvent seul et me permettrai de tester des câbles électriques sans avoir à faire 100 Km par jour... :sweat_smile:

retour d'information = acquittement (acknowledge)
Je te propose d'étudier cet exemple :

Bonjour hazrod

J'ai, un peu, "étudié" ton problème, la difficulté est que le RF24 n'est pas bidirectionnel, c'est à dire qu'il faut basculer émission/réception, des 2 côtés. En plus ton programme n'est pas bien tourné et rend difficile la transmission de l'état de tes boutons.
Je termine mes essais et te transmettrai une solution, documentée au maximum afin que tu puisses comprendre le pourquoi du comment :wink:

A+
Cordialement
jpbbricole

C'est juste un problème de protocole.
L'émetteur est maitre. Le récepteur est en réception par défaut.

  1. L'émetteur passe en émission
  2. il envoie un message. Ce message contient une commande ou une simple demande d'état
  3. l'émetteur passe en réception
  4. le récepteur reçoit le message,
  5. le récepteur passe en émission, il répond
  6. le récepteur repasse en réception
  7. l'émetteur reçoit la réponse, tout va bien
  8. délai puis retour au pas 1

Coté récepteur, s'il ne reçoit pas un message toutes les n secondes (n à déterminer) il indique visuellement une erreur
Coté émetteur, s'il ne reçoit pas une réponse dans les m secondes suivant l'émission d'un message (m à déterminer) il indique visuellement une erreur.

Avec la gestion des acquittements, c'est encore plus simple :

// Dans setup(), activer les acquittements des deux côtés :
  radio.begin();
  radio.enableAckPayload();
  // etc.
// Dans loop() : 
// L'émetteur envoie un message :
    bool report = radio.write(&buttonState1, sizeof(buttonState1));
    // report contiendra l'acquittement
    if (report) {
      // tout va bien
    }
    else {
      // allumer la LED sur l'émetteur
    }
// le récepteur reçoit le message, et l'acquitte : 
    radio.read(&buttonState, sizeof(buttonState));
    radio.writeAckPayload(1, &buttonState, sizeof(buttonState));
// délai puis retour au pas 1

En activant la gestion des acquittements, les retournements sont automatiques.
S'il faut allumer également une LED sur le récepteur, il faut gérer un timer avec millis().

Bonsoir hazrod

Excellente motivation, si je peux participer à ton confort :wink:

J'ai "réaménagé", un peu ton programme, surtout au niveau de la gestion des boutons, qui ne sont plus pris individuellement:

int buttonState1 = 0;
int buttonState2 = 0;

mais mis en tableau:

int buttonsState[] = {0, 0};    // Tableau contenant l'état des boutons (envoyé au récepteur)
int ledState[] = {0, 0};     // Etat des LED, recu en quittance du récepteur

Le tableau ledState[] est surtout là pour la démo.
Ainsi, mis en tableau, l'état des boutons se transmet "d'un coup":
radio.write(&buttonsState, sizeof(buttonsState)); // Envoi de l'état des boutons
et est reçu de même:
radio.read(&buttonsState, sizeof(buttonsState)); // Réception de l'état des boutons Ce qui facilite grandement les choses.

Ainsi, les boutons sont lus à l'émetteur (void boutonsLecture()), transmis au récepteur qui lui remets à jour les LED (void ledEcriture()) et le récepteur envoie en retour, comme quittance (ACK), l'état des LED, à l'émetteur.
Attention, la console à passé de 9600 à 115200.
A l'émetteur, dans la console, défile l'état des LED du récepteur.
Au récepteur, défile l'état des boutons.

Des 2 côtés il y a un watchdog qui, s'il n'y a plus de réception, allume une LED, sur la pin:
const int watchdogLedPin = 7;

L'émetteur:

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

#define buttonPin1 3
#define buttonPin2 4


int buttonsState[] = {0, 0}; // Tableau contenant l'état des boutons
int ledState[] = {0, 0}; // Etat des LED, recu en quittance du récepteur


RF24 radio(9, 8);     // CE, CSN

const byte address[6] = "00002";
const byte addressB[6] = "00003";

const unsigned long rf24SendTempo = 250;     // Toutes les 1/4 de seconde
unsigned long rf24SendMillis = millis();     // Chronomètrwe

const unsigned long rf24watchdogTempo = 750;     // Toutes les 1/2 de seconde
unsigned long rf24watchdogdMillis = millis();     // Chronomètrwe
const int watchdogLedPin = 7;
const int watchdogLedEtatOn = HIGH;     // Etat pour allumer la LED du watchdog

void setup()
{
	pinMode(buttonPin1, INPUT_PULLUP);
	pinMode(buttonPin2, INPUT_PULLUP);
	pinMode(watchdogLedPin, OUTPUT);
	digitalWrite(watchdogLedPin, !watchdogLedEtatOn);     // Eteindre la LED
	
	Serial.begin(115200);
	radio.begin();

	radio.openWritingPipe(address);    // Canal d'envoi de données (sont croisés sur récepteur)
	radio.openReadingPipe(0, addressB);    // Canal de réception de données
	
	radio.setPALevel(RF24_PA_MIN);

	radio.startListening();     // Radio en mode écoute
}
void loop()
{
	if (millis() - rf24SendMillis >= rf24SendTempo)    // Si temporisation envoi échue
	{
		boutonsLecture();

		radio.stopListening();     // Radio en mode émission
		radio.write(&buttonsState, sizeof(buttonsState));     // Envoi de l'état des boutons (tableau)
		radio.startListening();     // Radio en mode écoute

		unsigned long start_timeout = millis();     // Si éventuellement pas de réponse
		while (!radio.available())     // Attente de la réponse
		{
			if (millis() - start_timeout > 200)     // Attente 200 millisecondes
			break;
		}

		if (radio.available())     // Si recu des données
		{ 
			radio.read(&ledState, sizeof(ledState));     // Réception de l'état des LED (tableau) comme acquittement (ACK)

			Serial.print(F("\nEtat des LED\t")) ; Serial.print(ledState[0]);
			Serial.print("\t"); Serial.print(ledState[1]);

			rf24watchdogdMillis = millis();     // Mise à jour watchdog
		}
		rf24SendMillis = millis();     // Redémarrer le timer d'envoi
	}

	//--------------------------------- Watchdog
	if (millis() - rf24watchdogdMillis >= rf24watchdogTempo)     // Si plus de transmission du récepteur
	{
		digitalWrite(watchdogLedPin, watchdogLedEtatOn);     // Allumer la LED
	}
	else
	{
		digitalWrite(watchdogLedPin, !watchdogLedEtatOn);     // Eteindre la LED
	}
}

void boutonsLecture()
{
	buttonsState[0] = digitalRead(buttonPin1);
	buttonsState[1] = digitalRead(buttonPin2);
}

Le récepteur:

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

#define led1 A0
#define led2 A1

int buttonsState[] = {0, 0};     // Etat des boutons (recu)
int ledState[] = {0, 0};     // Rtat des LED, envoyés en quittance

RF24 radio(9, 8); // CE, CSN
const byte address[6] = "00002";
const byte addressB[6] = "00003";

const unsigned long rf24watchdogTempo = 750;     // Temps avant alerte
unsigned long rf24watchdogdMillis = millis();     // Chronomètrwe
const int watchdogLedPin = 7;
const int watchdogLedEtatOn = HIGH;     // Etat pour allumer la LED du watchdog


void setup()
{
	Serial.begin(115200);
	
	pinMode(led1, OUTPUT);
	pinMode(led2, OUTPUT);
	digitalWrite(led1, HIGH);
	digitalWrite(led2, HIGH);
	pinMode(watchdogLedPin, OUTPUT);
	digitalWrite(watchdogLedPin, !watchdogLedEtatOn);     // Eteindre la LED

	radio.begin();

	radio.openWritingPipe(addressB);    // Canal d'envoi de données (sont croisés sur émetteur)
	radio.openReadingPipe(0, address);    // Canal de réception de données

	radio.setPALevel(RF24_PA_MIN);
	radio.startListening();     // Radio en mode écoute
}
void loop()
{
	if (radio.available())
	{
		while (!radio.available());
		{
			radio.read(&buttonsState, sizeof(buttonsState));     // Réception de l'état des boutons de l'émetteur (tableau)
			rf24watchdogdMillis = millis();     // Mise à jour watchdog
		}
		radio.stopListening();     // Radio en mode émission
		delay(20);     // Petite attente pour "retournement" de la transmission

		ledEcriture();     // Commande des LED en fonction de l'état des boutons
		ledLecture();     // Lecture de l'état des LED

		radio.write(&ledState, sizeof(ledState));     // Envoi de^l'état des LED comme acquittement (ACK)
		radio.startListening();     // Radio en mode écoute

		Serial.print(F("\nEtat des boutons\t")) ; Serial.print(buttonsState[0]);
		Serial.print("\t"); Serial.print(buttonsState[1]);
	}

	//--------------------------------- Watchdog
	if (millis() - rf24watchdogdMillis >= rf24watchdogTempo)     // Si plus de transmission de l'émetteur
	{
		digitalWrite(watchdogLedPin, watchdogLedEtatOn);     // Allumer la LED
	}
	else
	{
		digitalWrite(watchdogLedPin, !watchdogLedEtatOn);     // Eteindre la LED
	}
}

void ledLecture()
{
	ledState[0] = digitalRead(led1);
	ledState[1] = digitalRead(led2);
}

void ledEcriture()
{
	digitalWrite(led1, !buttonsState[0]);     // ! = inversion vu que les boutons, au repos donnent un HIGH (PULL_UP)
	digitalWrite(led2, !buttonsState[1]);
}

A ta disposition pour toutes questions, amuses toi bien :wink:.

Cordialement
jpbbricole

Franchement, merci, ça fonctionne nickel, je vais essayer de regarder pour ajouter le retour d'état du récepteur pour allumer les leds de confirmation que les relais ont bien été activer.

Bonsoir hazrod

Super, j'en suis ravi!

Coté émetteur, tu as déjà l'information dans le tableau ledState[], dans ledState[0] et ledState[1].

Bonne nuit.
cordialement
jpbbricole

@jpbbricole Hello, je n'ai malheureusement pas trouvé comment rallumer les 2 leds pour confirmer que les 2 relais ont bien été activer. Pourrais-tu m'indiquer quoi intégrer au code du transmetteur ?

Bonsoir hazrod

Voilà comment, les LED sont connectées sur:
const int ledRelaisEtatPin[] = {5, 6}; // Pin des LED etat relais du récepteur

et, pour le détail, recherches tout ce qui concerne ledRelaisEtatPin.

Le programme:

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

#define buttonPin1 3
#define buttonPin2 4

int buttonsState[] = {0, 0};    // Tableau contenant l'état des boutons (envoyé au récepteur)
int ledState[] = {0, 0};     // Etat des LED, recu en quittance du récepteur
const int ledRelaisEtatPin[] = {5, 6};     // Pin des LED etat relais du récepteur

RF24 radio(9, 8);     // CE, CSN
//RF24 radio(9, 10);     // CE, CSN jpbbricole

const byte address[6] = "00002";
const byte addressB[6] = "00003";

const unsigned long rf24SendTempo = 250;     // Toutes les 1/4 de seconde
unsigned long rf24SendMillis = millis();     // Chronomètrwe

const unsigned long rf24watchdogTempo = 750;     // Toutes les 1/2 de seconde
unsigned long rf24watchdogdMillis = millis();     // Chronomètrwe
const int watchdogLedPin = 7;
const int watchdogLedEtatOn = HIGH;     // Etat pour allumer la LED du watchdog

void setup()
{
	Serial.begin(115200);
	delay(500);
	
	pinMode(buttonPin1, INPUT_PULLUP);
	pinMode(buttonPin2, INPUT_PULLUP);
	pinMode(watchdogLedPin, OUTPUT);
	digitalWrite(watchdogLedPin, !watchdogLedEtatOn);     // Eteindre la LED
	
	for (int l = 0; l < 2; l ++)     // Initialisation des pin des LED etat relais du récepteur
	{
		pinMode(ledRelaisEtatPin[l], OUTPUT);
	}

	radio.begin();

	radio.openWritingPipe(address);    // Canal d'envoi de données (sont croisés sur récepteur)
	radio.openReadingPipe(0, addressB);    // Canal de réception de données
	
	radio.setPALevel(RF24_PA_MIN);

	radio.startListening();     // Radio en mode écoute
}
void loop()
{
	if (millis() - rf24SendMillis >= rf24SendTempo)    // Si temporisation envoi échue
	{
		boutonsLecture();

		radio.stopListening();     // Radio en mode émission
		radio.write(&buttonsState, sizeof(buttonsState));     // Envoi de l'état des boutons (tableau)
		radio.startListening();     // Radio en mode écoute

		unsigned long start_timeout = millis();     // Si éventuellement pas de réponse
		while (!radio.available())     // Attente de la réponse
		{
			if (millis() - start_timeout > 200)     // Attente 200 millisecondes
			break;
		}

		if (radio.available())     // Si recu des données
		{ 
			radio.read(&ledState, sizeof(ledState));     // Réception de l'état des LED (tableau) comme acquittement (ACK)

			Serial.print(F("\nEtat des LED\t")) ; Serial.print(ledState[0]);
			Serial.print("\t"); Serial.print(ledState[1]);
			
			// Echo de l'état relais du récepteur sur LED locales
			for (int l = 0; l < 2; l ++)  
			{
				digitalWrite(ledRelaisEtatPin[l], ledState[l]);
			}

			rf24watchdogdMillis = millis();     // Mise à jour watchdog
		}
		rf24SendMillis = millis();     // Redémarrer le timer d'envoi
	}

	//--------------------------------- Watchdog
	if (millis() - rf24watchdogdMillis >= rf24watchdogTempo)     // Si plus de transmission du récepteur
	{
		digitalWrite(watchdogLedPin, watchdogLedEtatOn);     // Allumer la LED
	}
	else
	{
		digitalWrite(watchdogLedPin, !watchdogLedEtatOn);     // Eteindre la LED
	}
}

void boutonsLecture()
{
	buttonsState[0] = digitalRead(buttonPin1);
	buttonsState[1] = digitalRead(buttonPin2);
}

Et en retour, expliques moi comment ça fonctionne, l'allumage des LED en fonction de l'état des relais du récepteur.

A+
Cordialement
jpbbricole

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.