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