Paramètres boucle PID

Bonjour tout le monde,

Sur un Atmega328, j'utilise une librairie Arduino PID: je rentre une consigne analogique, le capteur me renvoie également sa position en analogique, et le moteur est piloté en PWM. Tout cela fonctionne très bien.

Je voudrais y ajouter 3 afficheurs (pilotés par des MAX7219) et 3 codeurs rotatifs pour pouvoir paramétrer en direct les 3 paramètres P, I et D.
Cette partie là fonctionne également mais seule.

Je me pose maintenant la question de comment réunir le tout. Car le problème qui risque de se poser, c'est que quand je vais régler une valeur, le processeur va devoir gérer l'affichage et le codeur rotatif. Pendant ce temps là, l'asservissement sera mis en "pause"...

Ne faut-il pas mieux garder le premier µC uniquement pour la partie PID et ajouter un deuxième µC pour la partie codeurs rotatifs et afficheurs ? L'appuis sur un bouton "valider", une fois la valeur sélectionnée, envoie cette valeur via le bus i2c au µC PID ?

Merci pour vos conseils :slight_smile:

si tu as 2 Arduinos, celui qui gère les boutons va devoir envoyer un message à celui qui régule. Et donc ça ne change rien sur le fond : celui qui régule va devoir traiter les messages, et pendant ce temps il ne régule plus :sob:

Maintenant, tout dépend de la "rapidité" de la régulation. Tu fais une mesure + une consigne tout les combien de temps ?
Et quel est le besoin (en termes de timing) en fait ?

Bonjour bobow57

Je suis entrain de développer quelque chose avec ce type de structure, un système qui gère une machine numérique (CNC) dont les "boutons et autres" sont décentralisés sur Arduino pupitre afin d'être plus proches de l'opérateur. Ce pupitre décentralisé, slave sur le bus i2C, gère 2 joystick, un codeur rotatif et quelques boutons. Il tient à jour une structure:

struct i2CpacketDataDef
{byte index; byte function; float floatVal[4]; int rotencPosition; word rotencPbEvents; word digitalInputs;};

qui est périodiquement lue par le master i2C.
Il doit être possible, d'inverser les attributs, c'est à dire le master qui gère les réglages et s'occupe de l'affichage, master qui envoie au slave PID les paramètres sélectionnés.

Su tu le désires je pourrais essayer de te faire un "échantillon" dans ce sens.

Cordialement
jpbbricole

Bonjour
En faisant en sorte que la modification de la valeur ne soit pas bloquante (sans les delay) je ne pense pas que l'on puisse ralentir l'arduino , les imprimante 3D gère bien 2 PID 5 moteurs et 1 écran LCD en même temps sans problème.

@+

Bonjour et merci pour vos réponses :slight_smile:

==> BIGGIL: voici mon programme PID, tu as la fréquence de calcul de 1000Hz mais qui pourra varier également:

// Paramètres
int PWM_f = 1000;      // PWM frequency [Hz]
int f = 1000;        // PID calculation frequency [Hz]
int WindowSize = 1023;    //Output resolution
double Sensor, Input, Output; //Variables connected to the PID object

// Paramètres de PID
double Kp1 = 185;  //  P
double Ki1 = 310;   //  I
double Kd1 = 7.2; //  D


//Creates PID object and sets initial parameters
PID myPID(&Sensor, &Output, &Input, Kp1, Ki1, Kd1, DIRECT);


void setup()
{
  //Sets pin D3 in OUTPUT mode
  pinMode(PIN_MOSFET, OUTPUT);
  
  //sets PWM frequency
  InitTimersSafe(); SetPinFrequencySafe(PIN_MOSFET, PWM_f);
 
  //sets PID calculation frequency
  myPID.SetSampleTime(1000/f);
  
  //sets output resolution
  myPID.SetOutputLimits(0, WindowSize);

  //turn on PID calculation
  myPID.SetMode(AUTOMATIC);
}



void loop()
{
  //Reads set point and sensor values
  Input = analogRead(PIN_INPUT);
  Sensor = analogRead(PIN_SENSOR);
  

  //Converts voltages into output resolution
  voltageWindow(&Input);
  voltageWindow(&Sensor);

  
  //computes output signal
  myPID.Compute();
 
  //writes output signal
  pwmWrite(PIN_MOSFET,Output);
}


//function to convert input voltage (from 0 to 1023) into the ouput resolution (from 0 to WindowSize)
void voltageWindow(double* voltage)
{
  *voltage=*voltage/1023.0*WindowSize;
}

Le but étant de pouvoir modifier ces paramètres grâce à une interface. Si l'asservissement venait à "bloquer" quelques ms durant la com. i2c, je ne pense pas que cela soit grave. Il s'agit d'asservir un petit moteur de pompe en fonction d'un débit de produit.

Du coup, le µC qui embarque le PID est esclave. Le maitre étant l'interface, c'est lui qui déclenchera la com i2c pour mettre à jours les paramètres.

Si je comprends bien ton code, quand tu fais une com i2c, tu renvois le packet de variables struct i2CpacketDataDef ?

De mon côté, c'est l'appuis sur un bouton de validation qui déclenchera la com i2c vers le slave et donc la mise à jour des variables.

Bonjour bobow57

Je te fais un résumé du fonctionnement.

A+
Cordialement
jpbbricole

Bonjour bobow57

Voilà une explication un peu plus détaillée de "l'idée"

Dans ce système on a 2 Arduino connectés ensemble via un bus i2C.
Le côté commandes, master sur le bus i2C (MM), qui contient les codeurs rotatifs et autres données digitales.
Le côté exécution slave sur le bus i2C (MS), qui gère le PID qui, lui, reçoit ses paramètres du MM et tient les siens à disposition du MM.

Les paramètres transitent sur i2C par des structures de données:
Sens MM > MS

struct i2CpacketMmDef     // Structure du MM
{byte pktIndex; byte rotEncPos[3]; word digitalInputs;};

Sens MS > MM

struct i2CpacketMsDef     // Structure du MS
{byte pktIndex; int pwmValue; int capteurValue; word digitalInputs;};

Les paquetes de données sont crées ainsi:

i2CpacketMmDef mmDataPacket;
i2CpacketMsDef msDataPacket;

Le MM tient à jour les données de mmDataPacket (void mmDataUpdate()) et au moment de la pression du bouton de validation, mmDataPacket est envoyé au MS.

MS tient à jour les données de msDataPacket (void msDataUpdate()).

Au moyen d'une temporisation, MM envoie un request à MS, qui répond avec msDataPacket.

Ainsi, MS travaille "dans son coin", reçoit ses paramètres de MM et tiens à disposition du MM le résultat de ses déductions au moyen de msDataPacket.pwmValue, msDataPacket.capteurValue et msDataPacket.digitalInputs.

J'ai constitué ces 2 structures de façon purement imaginaire et elle sont simplement ajustable à tes besoins.
Pour la compilation, pour rendre les choses pratiques, il faut un fichier commun, je t'expliquerai où le placer.
Avantage du système, tu pourrais avoir plusieurs MS gérés par un seul MM.

Voilà, en gros, l'idée.
Si tu est partant, je peux te fournir une base de départ.
Si tu as un ou des affichage sur bus i2C, ils seront commandés depuis MM.
Perso, je mets 1,5k contre +5V sur SDA et SCL pour polariser le bus, les liaisons se font au moyen de câble plat 4 fils de téléphone et des connecteurs RJ 11/12.

A+
Cordialement
jpbbricole

Génial ! Je comprends mieux le fonctionnement de ce bus sur Arduino.

Résumons:

D'un côté j'ai un MM composé de:

  • 3 codeurs rotatifs
  • 3 afficheurs
  • un bouton poussoir

De l'autre côté, le MS qui gère le PID

Principe de fonctionnement:

  • A la mise sous tension, le MM demande au MS de lui transférer les valeurs des 3 variables P, I et D stockées en EEPROM et les affiche sur les 3 afficheurs et le PID démarre.
  • Si on tourne un codeur, disons celui de P, la valeur change sur l'afficheur en direct.
  • On appuis sur le BP pour valider et le paquet crée dans MM est envoyé au MS.

C'est ma façon, de voir les choses et si tu as des idées quant au fonctionnement je suis preneur.

Tu parles de mettre en place une tempo, mais cela risque pas de gêner le fonctionnement du PID ?
Car si à la limite le PID est perturbé au moment de l'appuis sur un BP ce n'est pas grave, par contre si je laisse tourner le système durant 24H, il ne faudrait pas que je vois une perturbation régulière du PID due à la tempo. Surtout que si on ne touche pas aux réglages, inutile de faire des com i2c.

En tout cas c'est cool, je découvre le fonctionnement des Arduino grâce à vous !

Bonsoir bobow57

Je ne vois rien de plus, dans la "base" que je te prépare, j'orienterai les structures dans ce sens.
Pour ce qui est des fonctions décrites dans "Principe de fonctionnement" seul la détection de validation est traitée comme exemple, le reste est ton travail.

Cette tempo est au niveau du MM, la seule gêne au niveau du PID dans le MS, est le traitement de la réception i2C, ce qui est certainement négligeable.
J'avais proposé cette temporisation, au cas ou le MM voudrait être renseigné, de façon périodique, de un ou des capteurs au niveau du MS.
On peut très bien supprimet cette temporisation et demander ces valeurs à chaque validations.

Je te prépare ça.

Cordialement
jpbbricole

D'accord :slight_smile:

Oui de mon côté j'ai déjà fais fonctionner mes afficheurs, mes codeurs ect tout fonctionne très bien.

Le MM n'as pas besoin d'être renseigné pour le moment, mais je garde cette idée sous le coude, cela pourrait être utile un jour.

J'ai hâte de pouvoir tester tout ca :smiley:

Bonsoir bobow57

Je fonce!

Cordialement
jpbbricole

Bonjour bobow57

Voilà la version « finale »

Dans ce système on a 2 Arduino connectés ensemble via un bus i2C.
Le côté commandes, master sur le bus i2C (MM), qui contient les codeurs rotatifs et autres données digitales.
Le côté exécution slave sur le bus i2C (MS), qui gère le PID qui, lui, reçoit ses paramètres du MM et tient les siens à disposition du MM.

Les paramètres transitent sur i2C par des structures de données:
Sens MM > MS
struct i2CpacketMmDef // Structure du MM
{byte pktIndex; byte rotEncPID[3]; word digitalInputs;};

pktIndex = numérotation des paquets sur le bus
rotEnc[3] = position des 3 encodeurs P I D
digitalInputs = positions de boutons commutateurs etc.

Sens MS > MM
struct i2CpacketMsDef // Structure du MS
{byte pktIndex; byte pidValeurs[3]; word digitalInputs;};

pktIndex = numérotation des paquets sur le bus
pidValeur[3] = Valeurs P, I, D
digitalInputs = positions de boutons commutateurs etc.

Les paquets de données sont crées ainsi:
i2CpacketMmDef mmDataPacket;
i2CpacketMsDef msDataPacket;

Le MM tient à jour les données de mmDataPacket (void mmDataUpdate()) et au moment de la pression du bouton de validation, mmDataPacket est envoyé au MS.

MS tient à jour les données de msDataPacket (void msDataUpdate()).

Ainsi, MS travaille "dans son coin", reçoit ses paramètres de MM et tiens à disposition du MM le résultat de ses déductions au moyen de msDataPacket*.*

Ces 2 structures sont ajustables, simplement, à tes besoins.

Pour la démo, MM, sur pression du bouton validation, envoie ses données au MS
qui, lui, les renvoie au MM suite à un request.
Les données d’essai sont « triturées » dans void mmDataUpdate() et void msDataUpdate()

Il y a beaucoup de Serial.println( qui donnent beaucoups d’indications dans les console, sur la « mécanique » de transfert des données.

Avantage du système MM MS, tu pourrais avoir plusieurs MS gérés par un seul MM.

Pour le montage d’essai, MM = Nano et MS = UNO, je mets 1,5k contre +5V sur SDA et SCL pour polariser le bus, les liaisons se font au moyen de câble plat 4 fils plat de téléphone et des connecteurs RJ 11/12.

Pour la compilation, pour rendre les choses pratiques, il faut un fichier commun. #include <i2C_MasterParametres_Common.h>
Qui contient les structures ainsi que l’adresse du MS sur le bus.

Pour rendre un fichier commun, il faut créer un répertoire _Common_i2C_MasterSlave par exemple, dans lequel tu mets i2C_MasterParametres_Common.h, répertoire que tu mets

Dans le répertoire libraries d’ Arduino.

Le côté MM

/*'************************************************************************************************
	Name    : i2C_MasterParameters.ino
	Author  : jpbbricole

	Date    : 25.06.2021

	Notes	:	gestion de paramètres destinés à un PID décentralisé dans un
				Arduino slave qui gère ce PID (par exemple)	
'**************************************************************************************************
*/

#include <i2C_MasterParametres_Common.h>
#include <Wire.h>

//===================================== i2C network
unsigned long i2busRequestTime = 2000;     // Période d'interrogation du MS
unsigned long i2busRequestTimer = millis();

//===================================== i2C Data
i2CpacketMmDef mmDataPacket;
i2CpacketMsDef msDataPacket;


unsigned long lcdRefreshTime = 2;                                   // Période de rafraichissement secondes
unsigned long lcdRefreshTimer = millis();

#define btnValiderPin 7     // Bouton valider

void setup()
{
	Serial.begin(115200);

	Wire.begin();
	Wire.setTimeout(250);

	pinMode(btnValiderPin, INPUT_PULLUP);

	delay(500);	

	i2cMsRequestData(msAdresse);     // Demander les données au MS (msDataPacket)
	i2cMsReceivedtData();
}

void loop()
{
	//--------------------------------- Affichagetou
	if (millis()-lcdRefreshTimer >= lcdRefreshTime * 1000)
	{
		mmDataUpdate();
		mmDisplayRefresh();
		
		lcdRefreshTimer = millis();
	}
	////--------------------------------- Bus i2C request périodique (Pas en service)
	//if (millis()- i2busRequestTimer >= i2busRequestTime)
	//{
		//Serial.println("\nInterrogation du MS  0x" + String(msAdresse, HEX));
		//
		//i2cMsRequestData();     // Demander les données au MS (msDataPacket)
		//i2cMsReceivedtData();
				//
		//i2busRequestTimer = millis();
	//}
	//--------------------------------- Pression bouton valider
	if (digitalRead(btnValiderPin) == 0)
	{
		Serial.println("\n> > > Bouton valider < < <");
		i2cMsSendData(msAdresse);     // Envoi des données du MM au MS (i2CpacketMmDef)
		
		delay(100);
		i2cMsRequestData(msAdresse);     // Demander les données au MS (msDataPacket)
		i2cMsReceivedtData();
		
		while(digitalRead(btnValiderPin) == 0){}     // Attente du relâchement du bouton valider
	}
}

//------------------------------------- Mise à jour des données pour du MM pour le MS
void mmDataUpdate()
{
	// Pour l'exercice on met des valeurs bidon qui changent
	mmDataPacket.rotEncPID[pidIndexP] = mmDataPacket.rotEncPID[pidIndexP] += 1;
	mmDataPacket.rotEncPID[pidIndexI] = mmDataPacket.rotEncPID[pidIndexI] += 5;
	mmDataPacket.rotEncPID[pidIndexD] = mmDataPacket.rotEncPID[pidIndexD] += 15;
	mmDataPacket.digitalInputs = mmDataPacket.rotEncPID[pidIndexP] + mmDataPacket.rotEncPID[pidIndexI] + mmDataPacket.rotEncPID[pidIndexD];
}

//------------------------------------- Demande de données du MS
void i2cMsRequestData(int adresse)
{
	if (!msi2CstatusOk(adresse, true))     // Si MS pas connecté
	{
		return;
	}
	
	Wire.requestFrom(adresse, sizeof mmDataPacket);
	Wire.readBytes((byte*)&msDataPacket, sizeof msDataPacket);
}

//------------------------------------- Envoi de données au MS

void i2cMsSendData(int adresse)
{
	if (!msi2CstatusOk(adresse, true))     // Si MS pas connecté
	{
		return;
	}
		
	Serial.println("\n> > > Donnees Envoyees au MS  0x" + String(msAdresse, HEX));
	Serial.println("RotEncP " + String(mmDataPacket.rotEncPID[pidIndexP]));
	Serial.println("RotEncI " + String(mmDataPacket.rotEncPID[pidIndexI]));
	Serial.println("RotEncD " + String(mmDataPacket.rotEncPID[pidIndexD]));
	Serial.println("DigInp  " + String(mmDataPacket.digitalInputs, BIN));

	mmDataPacket.pktIndex ++;
	
	byte i2Cheader = 1;    // Start

	Wire.beginTransmission (adresse);
	Wire.write(i2Cheader);                                     // Pour differencier du scan i2c qui vaut -1
	Wire.write((byte *)&mmDataPacket, sizeof mmDataPacket);
	Wire.endTransmission();
}

//------------------------------------- Réception de données du MS
void i2cMsReceivedtData()
{
	Serial.println("\n< < < Donnees recue du MS  0x" + String(msAdresse, HEX));
	Serial.println("P =\t" + String(msDataPacket.pidValeurs[pidIndexP]));
	Serial.println("I =\t" + String(msDataPacket.pidValeurs[pidIndexI]));
	Serial.println("D =\t" + String(msDataPacket.pidValeurs[pidIndexD]));
	Serial.println("DigInp =\t" + String(msDataPacket.digitalInputs, BIN));
}

void mmDisplayRefresh()
{
	Serial.println("\nDisplay Refresh");
	
	Serial.println(F("Parametres pour PID"));
	Serial.print("RotEncP " + String(mmDataPacket.rotEncPID[pidIndexP]));
	Serial.print("\tRotEncI " + String(mmDataPacket.rotEncPID[pidIndexI]));
	Serial.print("\tRotEncD " + String(mmDataPacket.rotEncPID[pidIndexD]));
	Serial.println("\tDigInp " + String(msDataPacket.digitalInputs, BIN));
}
//------------------------------------- Contrôle de la liaison avec le MS
boolean msi2CstatusOk(int msAdresse, boolean avecMessage)
{
	byte wireStatus;
	
	Wire.beginTransmission(msAdresse);
	wireStatus =  Wire.endTransmission();

	if (wireStatus == 0)
	{
		return true;
	}
	else
	{
		Serial.println("Le MS  0x" + String(msAdresse, HEX) + " est OFFLINE !!!");
		return false;
	}
}

Le côté MS

/*'************************************************************************************************
	Name    : i2C_SlavePID.ino 
	Author  : jpbbricole

	Date    : 25.06.2021

	Notes	:	Réception de paramètres reçus de i2C_MasterParameters
				contenant les paramètrage du PID
'**************************************************************************************************
*/

#include <i2C_MasterParametres_Common.h>
#include <Wire.h>

//===================================== i2C Data
i2CpacketMsDef msDataPacket;
i2CpacketMmDef mmDataPacket;

void setup()
{
	Serial.begin(115200);
		
	Wire.begin(msAdresse);     // join i2c bus with address msAdresse
	Wire.onRequest(i2cRequestEvent);     // Traitement request recu du MM
	Wire.onReceive(i2cCommandReceived);     // traitement commande recu du MM

	Serial.println("Taille des trames: "  + String(sizeof(msDataPacket)+1) + "  (Max. 32)");
}

void loop()
{


}

//------------------------------------- Appelé a chaque request du MM et renvoie la structure msDataPacket
void i2cRequestEvent()
{
	msDataUpdate();                                        // Remise a jour des donnees du MS

	Serial.println("\n> > > Donnees envoyees au MM");
	Serial.println("P =\t" + String(msDataPacket.pidValeurs[pidIndexP]));
	Serial.println("I =\t" + String(msDataPacket.pidValeurs[pidIndexI]));
	Serial.println("D =\t" + String(msDataPacket.pidValeurs[pidIndexD]));
	Serial.println("DigInp =\t" + String(msDataPacket.digitalInputs, BIN));

	msDataPacket.pktIndex ++;
	
	Wire.write((byte *)&msDataPacket, sizeof msDataPacket);     // Envoi des données sur i2C
}
//------------------------------------- Appelé a chaque réception de la structure mmDataPacket dpuis le MM
void i2cCommandReceived(int rxBytes)
{
	char i2Cheader = Wire.read();    // Premier caractere pour permettre le scanner i2C

	if (i2Cheader != -1)            // Si pas byte de test pour scan i2C
	{
		Wire.readBytes((byte*)&mmDataPacket, sizeof mmDataPacket);
		
		i2cMsReceivedtData();
	}
	else
	{
		//Serial.println("Scan i2C\t" + String(msAdresse)  + "\t0x" + String(msAdresse, HEX));
	}

}

void i2cMsReceivedtData()
{
	Serial.println("\n< < < Donnees Recues du MM");
	Serial.println("RotEncP\t" + String(mmDataPacket.rotEncPID[pidIndexP]));
	Serial.println("RotEncI\t" + String(mmDataPacket.rotEncPID[pidIndexI]));
	Serial.println("RotEncD\t" + String(mmDataPacket.rotEncPID[pidIndexD]));
	Serial.println("DigInp\t" + String(mmDataPacket.digitalInputs, BIN));
}

//===================================== Mise à jour des données du MS
void msDataUpdate()
{
	// Pour l'exercice, on mets les données du MM dans celles du MS
	msDataPacket.pidValeurs[pidIndexP] = mmDataPacket.rotEncPID[pidIndexP];
	msDataPacket.pidValeurs[pidIndexI] = mmDataPacket.rotEncPID[pidIndexI];
	msDataPacket.pidValeurs[pidIndexD] = mmDataPacket.rotEncPID[pidIndexD];
	msDataPacket.digitalInputs = msDataPacket.pidValeurs[pidIndexP] + msDataPacket.pidValeurs[pidIndexI] + msDataPacket.pidValeurs[pidIndexD];
}

Les Communs

//------------------------------------- Structure des paquets de donnees transmises sur le bus i2c max 32 bytes
struct i2CpacketMmDef     // Structure du MM
{byte pktIndex; byte rotEncPID[3]; word digitalInputs;};

struct i2CpacketMsDef     // Structure du MS
{byte pktIndex; byte pidValeurs[3]; word digitalInputs;};

//-------------------------------------- Module slave (ms)
const byte msAdresse = 0x46;     // 70

//------------------------------------- PID
enum pidIndex {pidIndexP, pidIndexI, pidIndexD, pidIndexNombre};

A toi de jouer, je suis à ton entière disposition pour toutes questions

A+

Cordialement

Jpbbricole

1 Like

Salut Jpbbricole, tout d'abord merci pour toutes ces explications et le code !

Je vais dans un premier temps imprimer le code et relire tout ca histoire de bien comprendre l'ensemble. Cela me permettra de faire des annotations.

Et ensuite je teste !

PS: en relisant tu disais que tu faisais un pupitre déporté via une liaison i2c, mais j'ai lu que cette liaison ne supporte pas plus d'un mètre de distance. Tu y as pensé ? Sinon il faut utiliser des drivers de bus.

Bonne soirée @+

bobow57

J'ai aussi lu ça, mais aussi entre 1 mètre et 10 mètres pour une vitesse 100 Kbauds et 10 Kbauds.
Avec les spécifications que je t'ai signalé, 1.5k de polarisation, câble plat de téléphone er RJ11-12, j'arrive facilement à 4 mètres, mais je ne sait pas à quelle vitesse, mais largement suffisante. il faut essayer.

Surtout n'hésites pas de me poser des questions.

A+
Cordialement
jpbbricole

1 Like

Bonjour Jpbbricole !

J'ai essayé le programme et tout fonctionne parfaitement !
Le moniteur série est très utile pour savoir ce qu'il se passe (je découvre).

Maintenant je vais essayer d'inclure proprement mes différentes fonctions en commençant par le master. (afficheurs, codeurs ect)

Question: c'est quoi la fonction "lcdrefresh" dans le master ?

Bon dimanche

La résistance de pull-up maximale est basée sur le temps de montée nécessaire de l'horloge (en fonction de la fréquence d'horloge I2C) et de la capacité totale sur le bus.. donc c'est un peu au pif-au-mètre quand on choisit juste une résistance de pull up.(enfin, ça se calcule si on peut faire des mesures)

Si vous ne voulez pas galérer avec de l'I2C sur longue distance, un petit composant bien pratique:


sinon pour revenir à la question d'origine:

il faudrait tester si les interruptions liées à la lecture des encodeurs rotatifs et la mise à jour de l'affichage sont plus couteuses que l'interruption I2C.

pour le moment vous appelez myPID.Compute(); à la vitesse max à laquelle tourne la loop(). Est-ce nécessaire ? à quelle vitesse évolue le processus sous jacent ?

Bonjour bobow57

Super!

C'est une temporisation "outil" , elle s'appelle lcd... parce que, dans les premières versions du programme il y avait un affichage LCD. Ca pourrait très s'appeler updateTime et update Timer.
Ce n'est pas indispensable au déroulement du programme et pourrait très bien supprimée.
Il faudrait juste ajouter mmDataUpdate();; ici:

	//--------------------------------- Pression bouton valider
	if (digitalRead(btnValiderPin) == 0)
	{
		Serial.println("\n> > > Bouton valider < < <");
		mmDataUpdate();
		i2cMsSendData(msAdresse);     // Envoi des données du MM au MS (i2CpacketMmDef)

Cordialement
jpbbricole

C'est ce que je vais faire ^^

Il y'a un truc que je ne comprends pas, c'est comment sont géré les types de variables transmises dans le paquet.
Je ne vois pas la déclaration des variables...

Dans mon cas je dois transmettre 3 variables de type "double" et d'autres de type "int". Comment sont-elles transmises ?

Bonjour bobow57

Tout se passe dans le fichier commun i2C_MasterParametres_Common.h

//------------------------------------- Structure des paquets de donnees transmises sur le bus i2c max 32 bytes
struct i2CpacketMmDef     // Structure du MM
{byte pktIndex; byte rotEncPID[3]; word digitalInputs;};

struct i2CpacketMsDef     // Structure du MS
{byte pktIndex; byte pidValeurs[3]; word digitalInputs;};

Où on défini la structure des données MM > MS i2CpacketMmDef et les données MS > MM i2CpacketMsDef

Ces structures sont déclarées, dans le MM

//===================================== i2C Data
i2CpacketMmDef mmDataPacket;
i2CpacketMsDef msDataPacket;

et dans le MS:


//===================================== i2C Data
i2CpacketMsDef msDataPacket;
i2CpacketMmDef mmDataPacket;

Comme toutes ces variables sont "emballées" dans une structure, elles sont envoyées et reçue en une opération.

// Envoi MM > MS
	Wire.write((byte *)&mmDataPacket, sizeof mmDataPacket);
// Reception dans le MS
		Wire.readBytes((byte*)&mmDataPacket, sizeof mmDataPacket);

Les structures de données MM et MS ne doivent pas être forcément les mêmes.

A+
Cordialement
jpbbricole