Bonjour, désolé de vous solliciter derechef.
Suite à mon montage anémomètre qui marche très bien avec un nano et un mega 2560, je tente de passer au même projet, mais avec trois nanos. (Un seul nano récepteur ne peut encaisser suffisamment de mémoire pour un LCD, une horloge temps réel et une carte SD). Ci-joint le schéma global. Je choisirai ensuite celui des deux montages fonctionnant le mieux.
HC-12_ANEMO_61_Emetteur-Récepteur-LCD_Récepeur-DS3231-Carte SD.zip (73.5 KB)
Le HC-12(1) du nano émetteur envoie les signaux de l’anémomètre donnant ainsi la fréquence qui est reçue par le HC-12(2) du nano récepteur A. Ce dernier effectue des calculs (void « CALCULATEUR() ») pour différentes données affichées sur un LCD I2c 20X4 avec le void « AFFICHEUR ()». Cette étape fonctionne très bien. Voici le code du recepteur A :
/*
LE PROGRAMME UTILISE LE HC-12 B du Namo 2 POUR RECEVOIR TOUTES LES SECONDES LA VALEUR DE LA fREQUENCE
LE CALCULATEUR PASSE LES DONNEES A L'AFFICHEUR POUR L'ECRAN LCD I2C 20x4
TOUTES LES MIN LE HC-12 B PASSE AU CANAL 2 POUR ENVOYER LES DONNEES AU HC-12 C PUIS REPREND LE CANAL 1
*/
// INCLUSION LIBRAIRIES ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <Arduino.h>
#include <LiquidCrystal_I2C.h> //LCD_TAG
#include <Wire.h>
LiquidCrystal_I2C lcd(0x27,20,4); // LCD_TAG set the LCD address to 0x27 for a 20 chars and 4 line display
// Déclaratiion HC-12
#include <SoftwareSerial.h>
SoftwareSerial hc12(8,9); // OK pour le NANO !
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//*************************************************************************************************************************************************************************************************************************
// COMMENTAIRES CONFIGURATION HARDWARE ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// D3 = INPUT logic pour remise à zero v max par interruption
// D4 = OUTPUT logic anemo pour diode lumineuse signal anemometre
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//*************************************************************************************************************************************************************************************************************************
// ALLOCATION INPUT/OUTPUT ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const byte ResetVmaxPin = 3; // D3 = INPUT, remise à zero v max par front changeant
const byte pinSDA = 4; // D4 pour le SDA de l"écran LCD
const byte pinSCL = 5; // D5 pour le SCL de l"écran LCD
const byte pinSet_HC12 = 7; // Pour mise à 0 pour changer de canal
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//*************************************************************************************************************************************************************************************************************************
// DECLARATION VARIABLES //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Données enregistrements à envoyer par HC-12 B à HC-12 C du 3ème Nano
int x = 0; //rang enregistrement
int data0;
float data1;
float data2;
float data3;
float data4;
String data5 = "";
String data6 = "";
String typeRafale;
String typeVent;
// Timing 1 min période d'envoi des données pour enregistrements sur carte SD du Nano 3
unsigned long tpsAct_1MIN = 0;
static unsigned long tpsPrec_1MIN = 0;
unsigned long delta_T = 0;
const unsigned long duree = 20000UL;
// Grandeurs Vinst, Vmax et Vmoy
boolean affiche = 1; // si le v_max_inst (v instantanée max obtenue depuis dernier affichage) a été affiché, il ne l'affichera plus et passera à la prochaine valeur obtenue suite nouveau front montant
byte grandeur_v_max_inst = 0; // entre deux affichages, prend la valeur max des vitesse instantanées obtenues et l'affiche comme vitesse instantanée
byte grandeur_v_max = 0; // vitesse max relevée depuis lancement du programme, se remet à zero manuellement via pin d'interruption D3
byte grandeur_v_moy = 0;
//
static unsigned long temps_precedent = 0; // temps précédent (µs) est une mémoire qui permet le calcul le delta t entre deux fronts desc. (avec "nouveau_temps"
float v = 0; // vitesse calculée entre deux fronts descendants
float v_precedente = 0; // vitesse calculée entre deux fronts descendants
byte nb_v_calc = 0;
byte depassement = 0;
float v_max = 0; // vitesse max obtenue depuis le lancement du programme, sera mise à zéro manuellement par une interruption.
float v_max_inst = 0; // vitesse max instantanée obtenue depuis dernier affichage des valeurs
float v_max_inst_bargraph = 0;
static unsigned long duree_v_nulle = 0; // durée pendant laquelle aucun front montant anemomètre => sert à mettre à 0 V_max_inst et donc pour afficher vitesse nulle
boolean memoire_vmax_zero = 0;
static unsigned long TEMPS_milli = 0; // variable temps en ms pour les besoins de la cadence d'affichage
static unsigned long TEMPS_micros = 0; // variable temps en
unsigned long t_debut_affichage = 0; // pour gérer cadence affichage
unsigned long t_ecoule_affichage = 0; // pour gérer cadence affichage
unsigned long t_debut_bargraph = 0; // pour gérer cadence affichage
unsigned long t_ecoule_bargraph = 0; // pour gérer cadence affichage
//////// CONSTANTES POUR VITESSE MOYENNE GLISSANTE SUR 10s //////////////////////////
//// /////// int NB_PULSE = 0 // incrément du nombre de fronts descendants pour 10s
static unsigned int NB_PULSE_10s_INCREMENT = 0; // incrément du nombre de fronts descendants vus en 10s
int MOY_temps_ecoule = 0; // temps écoulé sur l'observation du nombre de fronts descendants
unsigned long MOY_temps_debut = 0; // temps de départ fenêtre de moyennage 10s
unsigned int NB_PULSE_10s_TOTAL = 0; // nb fronts descendants obtenus sur 10s
int MOY_temps_ecoule_10s = 0; // temps écoulé de 10s
int i = 0;
unsigned int PULSE[60]; // tableau de 60 valeurs (chacune des valeurs est le nb de fronts descendants observés en 10s. 60x10s=600s=10mn
float nb_blocs_10s_calcules = 0; // nombre de valeurs rentrées dans le tableau PULSE (sert quand le tableau n'est pas complètement rempli de ne calculer la V moy que sur les valeurs entrées
float nb_pulses_10mn = 0; // somme des 60 valeurs du tableau PULSE
float MOY_VMOY = 0; // vitesse moyenne obtenue sur 10mn , donc moyenne des 60 valeurs du tableau PULSE
/// assignation durée précise (10s) sur chacun des blocs de 10s dans le tableau MOY_DUREE_BLOC
unsigned int DUREE_BLOC_10s[60]; // durée exacte des blocs de 10s (60 blocs de 10 s donne 10mn)
float DUREE_BLOC_10s_SOMME = 0; // somme durée exacte des blocs de 10s (60 blocs de 10 s donne 10mn)
float DUREE_BLOC_10s_MOY = 0; // moyenne de durée exacte des blocs de 10s
float RAFALES_MAX_10_DERNIERES_MN = 0;
byte grandeur_M_10_D_MN = 0;
//// CONSTANTES POUR tableau des écarts (rafales)
float v_max_bloc_10s = 0; // vmax observée sur un bloc de 10s, même bloc que pour calcul moy sur bloc 10s
float vitesse_relevee = 0;
float vitesse_max_10mn = 0;
float V_max_bloc[60];
byte grandeur_vitesse_max_10mn = 0;
byte classification_vent = 0;
byte classification_rafales = 0;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//************************************************************************************************************************************************************************************************************************
// CONSTANTES DE REGLAGE /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
unsigned long cadence_affichage = 1000; // cadence affichage (ms)
unsigned long cadence_bargraph = 200;
volatile unsigned long duree_remise_zero = 2500000; // valeur en µs, durée 2.5s à partir de laquelle sans signal anemomètre, la vitesse instantannée est mise à zero
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//************************************************************************************************************************************************************************************************************************
// CONSTANTES BARRE DE PROGRESSION ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// /* Constantes pour la taille de l'écran LCD */
const int LCD_NB_ROWS = 4;
const int LCD_NB_COLUMNS = 20;
// Valeur en pourcentage de la barre de progression */
static byte percent = 0;
static float pourcentage = 0;
/* Caractères personnalisés */
byte DIV_0_OF_5[8] = {
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000
}; // 0 / 5
byte DIV_1_OF_5[8] = {
B00000,
B10000,
B10000,
B10000,
B10000,
B10000,
B10000,
B10000
}; // 1 / 5
byte DIV_2_OF_5[8] = {
B00000,
B11000,
B11000,
B11000,
B11000,
B11000,
B11000,
B11000
}; // 2 / 5
byte DIV_3_OF_5[8] = {
B00000,
B11100,
B11100,
B11100,
B11100,
B11100,
B11100,
B11100
}; // 3 / 5
byte DIV_4_OF_5[8] = {
B00000,
B11110,
B11110,
B11110,
B11110,
B11110,
B11110,
B11110
}; // 4 / 5
byte DIV_5_OF_5[8] = {
B00000,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111
}; // 5 / 5
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//************************************************************************************************************************************************************************************************************************************************
// SETUP PROGRESS BAR //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Fonction de configuration de l'écran LCD pour la barre de progression.
// Utilise les caractères personnalisés de 0 à 5 (6 et 7 restent disponibles).
void setup_progressbar()
{
/* Enregistre les caractères personnalisés dans la mémoire de l'écran LCD */
lcd.createChar(0, DIV_0_OF_5);
lcd.createChar(1, DIV_1_OF_5);
lcd.createChar(2, DIV_2_OF_5);
lcd.createChar(3, DIV_3_OF_5);
lcd.createChar(4, DIV_4_OF_5);
lcd.createChar(5, DIV_5_OF_5);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//************************************************************************************************************************************************************************************************************************************************
// VOID CALCULATEUR_10mn ////// VOID CALCULATEUR_10mn //////// VOID CALCULATEUR_10mn //////// VOID CALCULATEUR_10mn ////////// VOID CALCULATEUR_10mn //////
void CALCULATEUR_10mn()
{
MOY_temps_ecoule = TEMPS_milli - MOY_temps_debut; // pour faire des paquets d'observation de 10s (sert à remplir le tableau PULSE)
if (MOY_temps_ecoule >= 10000) // toutes les 10s, crée un bloc, total de 60 blocs.
{
if(nb_blocs_10s_calcules < 61) // une fois atteint le nombre de 60 valeurs, on n'incrémente plus le nombre de valeurs présente dans le tableau PULSE
{
nb_blocs_10s_calcules++; // pour première valeur erronnée "NB_PULSE_10s_TOTAL", nb_blocs_10s_calcules vaut 1.
//Vaut 2 quand première valeur bonne. Donc nb valeurs bonne dans PULSE[] vaut (nb_blocs_10s_calcules-1)
}
NB_PULSE_10s_TOTAL = NB_PULSE_10s_INCREMENT; // durant 10s, NB_PULSE_10s_INCREMENT a été incrémenté (nombre de front descendants observés. Cette valeur alimentera une case du tableau PULSE (10s par case)
NB_PULSE_10s_INCREMENT = 0; // compteur de fronts descendants remis à 0 en vu de sa nouvelle incrémentation à venir pour le prochain paquet de 10s
MOY_temps_debut = TEMPS_milli; // relève l'instant de départ de la nouvelle fenêtre d'observation de 10s
MOY_temps_ecoule_10s = MOY_temps_ecoule;
/// ETAPE 1 - 1/3 => DECALER TABLEAU PULSE///
if(nb_blocs_10s_calcules > 2) // à la première moy suite aux 10s, la valeur est faussée et nb_blocs_10s_calcules est à 1.
{
//Donc c'est à partir de > 2 que je décale vers le bas les valeurs afin de faire entrer les nouvelles
for(i = 59;i > 0;i = i-1)
{
PULSE[i] = PULSE[i-1];
}
}
/// ETAPE 1 - 2/3 => DECALER TABLEAU MOY_DUREE_BLOC///
if(nb_blocs_10s_calcules > 2) // à la première moy suite aux 10s, la valeur est faussée et nb_blocs_10s_calcules est à 1. Donc c'est à partir de > 2 que je décale vers le bas les valeurs afin de faire entrer les nouvelles
{
for(i = 59;i > 0;i = i-1)
{
DUREE_BLOC_10s[i] = DUREE_BLOC_10s[i-1];
}
}
/// ETAPE 1 - 3/3 => DECALER TABLEAU v_max_bloc_10s ///
if(nb_blocs_10s_calcules>2) // à la première moy suite aux 10s, la valeur est faussée et nb_blocs_10s_calcules est à 1. Donc c'est à partir de > 2 que je décale vers le bas les valeurs afin de faire entrer les nouvelles
{
for(i = 59 ;i > 0 ;i = i-1){
V_max_bloc[i] = V_max_bloc[i-1];
}
}
/// ETAPE 2 1/3 => FAIRE ENTRER NOUVELLE VALEUR DANS L'INDICE 0 DE PULSE ///
PULSE[0] = NB_PULSE_10s_TOTAL;
//////////////////////////////////
/// ETAPE 2 2/3 => FAIRE ENTRER NOUVELLE VALEUR DANS L'INDICE 0 MOY DUREE BLOC ///
DUREE_BLOC_10s[0] = MOY_temps_ecoule_10s;
//////////////////////////////////
/// ETAPE 3 1/3 => CALCUL SOMME du nb de pulse par bloc de 10s (somme de PULSE) ///
nb_pulses_10mn = 0;
for(i = 0;i < 60;i++)
{
nb_pulses_10mn = nb_pulses_10mn + PULSE[i];
}
//////////////////////////////////
/// ETAPE 3 2/3 => CALCUL SOMME DES DUREES DE BLOC sur tout le tableau MOY_DUREE_BLOC ///
DUREE_BLOC_10s_SOMME = 0; // cette somme de DUREE de tous les 60 blocs sera en ms, 10s=10000ms, 10mn=600s = 600000ms
for(i = 0;i < 60;i++)
{
DUREE_BLOC_10s_SOMME = DUREE_BLOC_10s_SOMME + DUREE_BLOC_10s[i];
}
//////////////////////////////////
DUREE_BLOC_10s_MOY = (DUREE_BLOC_10s_SOMME / (nb_blocs_10s_calcules - 1));
//MOY_VMOY=(nb_pulses_10mn/(nb_blocs_10s_calcules-1)*180/192)/(DUREE_BLOC_10s_MOY*0.001); // V=F*(180/192), cette v moyenne est sur un bloc de 10s moyen, vitesse par 10s en fait
MOY_VMOY = 3 + (nb_pulses_10mn / (nb_blocs_10s_calcules-1) * 0.8) / (DUREE_BLOC_10s_MOY * 0.001); // V=0.8 x F+3
/// ETAPE 2 3/3 => FAIRE ENTRER NOUVELLE VALEUR DANS tableau V_max_bloc ///
V_max_bloc[0] = v_max_bloc_10s;
v_max_bloc_10s = 0;
//////////////////////////////////
/// ETAPE 3 3/3 => CALCUL MAX sur 10 dernières mn / sur chacun des blocs de 10s
vitesse_max_10mn = 0; // initialisation à 0 de la vitesse max avant analyse des 60 blocs de 10s ci-dessous
for(i = 0;i < 60;i++)
{
vitesse_relevee = V_max_bloc[i];
if(vitesse_relevee > vitesse_max_10mn)
{
vitesse_max_10mn = vitesse_relevee; // DU COUP EN FAIT vitesse_max représente V MAX sur les 10 dernières MN
}
}
//////////////////////////////////
////////////////// CALCUL DES RAFALES MAX sur les 10 dernières minutes //////////////////////
RAFALES_MAX_10_DERNIERES_MN = vitesse_max_10mn - MOY_VMOY; // EN FAIT MAX_10_DERNIERES_MN représente RAFALES sur 10 dernières mn (max ecart par rapport moyenne)
/////////////////////////////////////////////////////////////////////////////////////////////////////////
} //////////// FIN SI MOY temps écoulé > 10s //////////////////////// FIN SI MOY temps écoulé > 10s ///////////
} //// FIN VOID "CALCULATEUR_10mn"//// FIN VOID "CALCULATEUR_10mn"//// FIN VOID "CALCULATEUR_10mn"//// FIN VOID "CALCULATEUR_10mn"//// FIN VOID "CALCULATEUR_10mn"
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//************************************************************************************************************************************************************************************************************************************************
// VOID AFFICHEUR //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void AFFICHEUR(){
//////////////////////////////LIGNE 1 - AFFICHAGE V instananée //////////////////////////////////////////
if (v_max_inst < 9.95) // je vais à 2 chiffres après virgule car j'affiche 1 chiffre après virgule
{
grandeur_v_max_inst = 1;
}
if (v_max_inst < 99.95 && v_max_inst >= 9.95) // je vais à 2 chiffres après virgule car j'affiche 1 chiffre après virgule
{
grandeur_v_max_inst = 2;
}
if (v_max_inst <999.95 && v_max_inst >= 99.95) // je vais à 2 chiffres après virgule car j'affiche 1 chiffre après virgule
{
grandeur_v_max_inst = 3;
}
lcd.setCursor (0,0); // LCD_TAG go to start of 1er line
switch(grandeur_v_max_inst){
case 1: lcd.print("V / max: ");break; // LCD_TAG
case 2: lcd.print("V / max: ");break;
case 3: lcd.print("V / max: ");break;
}
lcd.print(v_max_inst, 1); // LCD_TAG
/////////////////////////////// LIGNE 1 - AFFICHAGE v max //////////////////////////////////////
if (v_max < 9.95) // je vais à 2 chiffres après virgule car j'affiche 1 chiffre après virgule
{
grandeur_v_max = 1;
}
if (v_max < 99.95 && v_max >= 9.95) // je vais à 2 chiffres après virgule car j'affiche 1 chiffre après virgule
{
grandeur_v_max = 2;
}
if (v_max < 999.95 && v_max >= 99.95) // je vais à 2 chiffres après virgule car j'affiche 1 chiffre après virgule
{
grandeur_v_max = 3;
}
switch(grandeur_v_max)
{
case 1: lcd.print(" ");break; // LCD_TAG
case 2: lcd.print(" ");break;
case 3: lcd.print(" ");break;
}
lcd.print(v_max,1); // LCD_TAG
///////////////////////////// LIGNE 2 - AFFICHAGE v moy //////////////////////////////////////////
if (MOY_VMOY <= 3.1) //// AJOUT pour passer à 0 la vitesse moyenne si elle est < 3.1 (calcul dit v=3.0 si aucun vent)
{
grandeur_v_moy = 0;
MOY_VMOY = 0;
}
if (MOY_VMOY < 9.5 && MOY_VMOY > 3.1) // je vais à 1 chiffre après virgule car j'affiche 0 chiffre après virgule
{
grandeur_v_moy = 1;
}
if (MOY_VMOY < 99.5 && MOY_VMOY >= 9.5) // je vais à 1 chiffre après virgule car j'affiche 0 chiffre après virgule
{
grandeur_v_moy = 2;
}
if (MOY_VMOY < 999.5 && MOY_VMOY >= 99.5) // je vais à 1 chiffre après virgule car j'affiche 0 chiffre après virgule
{
grandeur_v_moy = 3;
}
lcd.setCursor (0,1); // LCD_TAG go to start of 2nd line
switch(grandeur_v_moy)
{
case 0: lcd.print("moy/R/M: <3 / /");break;
case 1: lcd.print("moy/R/M: ");break; // LCD_TAG
case 2: lcd.print("moy/R/M: ");break;
case 3: lcd.print("moy/R/M: ");break;
}
if (grandeur_v_moy > 0) //// AJOUT pour passer à 0 la vitesse moyenne si elle est < 3.1 (calcul dit v=3.0 si aucun vent)
{
lcd.print(MOY_VMOY,0);
}
//////////////////////////////LIGNE 2 - AFFICHAGE RAFALES MAX SUR LES 10 DERNIERES MINUTES //////////////////////
if (grandeur_v_moy == 0)
{
grandeur_M_10_D_MN = 0;
}
if (RAFALES_MAX_10_DERNIERES_MN < 9.5) // je vais à 1 chiffre après virgule car j'affiche 0 chiffre après virgule
{
grandeur_M_10_D_MN = 1;
}
if (RAFALES_MAX_10_DERNIERES_MN < 99.5 && RAFALES_MAX_10_DERNIERES_MN >= 9.5) // je vais à 1 chiffre après virgule car j'affiche 0 chiffre après virgule
{
grandeur_M_10_D_MN = 2;
}
if (RAFALES_MAX_10_DERNIERES_MN < 999.5 && RAFALES_MAX_10_DERNIERES_MN >= 99.5) // je vais à 1 chiffre après virgule car j'affiche 0 chiffre après virgule
{
grandeur_M_10_D_MN = 3;
}
switch(grandeur_M_10_D_MN)
{
case 0: break;
case 1: lcd.print(" ");break;
case 2: lcd.print(" ");break;
case 3: lcd.print(" ");break;
}
if (grandeur_v_moy>0)
{
lcd.print(RAFALES_MAX_10_DERNIERES_MN, 0);
}
///////////////////// LIGNE 2 - AFFICHAGE vitesse max sur les 10 dernières mn (60 blocs de 10s analyses) /////////////
if (grandeur_v_moy == 0)
{
grandeur_vitesse_max_10mn = 0;
}
if (vitesse_max_10mn < 9.5) // je vais à 1 chiffre après virgule car j'affiche 0 chiffre après virgule
{
grandeur_vitesse_max_10mn = 1;
}
if (vitesse_max_10mn<99.5 && vitesse_max_10mn >= 9.5) // je vais à 1 chiffre après virgule car j'affiche 0 chiffre après virgule
{
grandeur_vitesse_max_10mn = 2;
}
if (vitesse_max_10mn < 999.5 && vitesse_max_10mn >= 99.5) // je vais à 1 chiffre après virgule car j'affiche 0 chiffre après virgule
{
grandeur_vitesse_max_10mn = 3;
}
switch(grandeur_vitesse_max_10mn)
{
case 0: break;
case 1: lcd.print(" ");break;
case 2: lcd.print(" ");break;
case 3: lcd.print(" ");break;
}
if (grandeur_v_moy>0)
{
lcd.print(vitesse_max_10mn,0);
}
///////////// LIGNE 3 - AFFICHAGE denominations vents + rafales //////////////////////
if (MOY_VMOY < 1)
{
classification_vent = 1;
}
if (MOY_VMOY >= 1 && MOY_VMOY < 6)
{
classification_vent = 2;
}
if (MOY_VMOY >= 6 && MOY_VMOY < 12)
{
classification_vent = 3;
}
if (MOY_VMOY >= 12 && MOY_VMOY <20)
{
classification_vent = 4;
}
if (MOY_VMOY >= 20 && MOY_VMOY < 29)
{
classification_vent=5;
}
if (MOY_VMOY >= 29 && MOY_VMOY < 39)
{
classification_vent = 6;
}
if (MOY_VMOY >= 39 && MOY_VMOY < 50)
{
classification_vent = 7;
}
if (MOY_VMOY >= 50 && MOY_VMOY < 62)
{
classification_vent = 8;
}
if (MOY_VMOY >= 62 && MOY_VMOY < 75)
{
classification_vent = 9;
}
if (MOY_VMOY >= 75 && MOY_VMOY < 89)
{
classification_vent = 10;
}
if (MOY_VMOY >= 89 && MOY_VMOY < 103)
{
classification_vent = 11;
}
if (MOY_VMOY >= 103 && MOY_VMOY < 117)
{
classification_vent = 12;
}
if (MOY_VMOY >= 117)
{
classification_vent = 13;
}
// Serial.print("classification_vent : ");
// Serial.println(classification_vent);
// Serial.print("MOY_VMOY : ");
// Serial.println(MOY_VMOY);
lcd.setCursor (0,2);
switch(classification_vent)
{
case 1: lcd.print("CALME "); typeVent = "CALME"; break;
case 2: lcd.print("TRES LEGERE BRISE "); typeVent = "TRES LEGERE BRISE"; break;
case 3: lcd.print("LEGERE BRISE "); typeVent = "LEGERE BRISE"; break;
case 4: lcd.print("PETITE BRISE "); typeVent = "PETITE BRISE"; break;
case 5: lcd.print("JOLIE BRISE "); typeVent = "JOLIE BRISE"; break;
case 6: lcd.print("BONNE BRISE "); typeVent = "BONNE BRISE"; break;
case 7: lcd.print("VENT FRAIS "); typeVent = "VENT FRAIS"; break;
case 8: lcd.print("GRAND FRAIS "); typeVent = "GRAND FRAIS"; break;
case 9: lcd.print("COUP DE VENT "); typeVent = "COUP DE VENT"; break;
case 10: lcd.print("FORT COUP DE VENT"); typeVent = "FORT COUP DE VENT"; break;
case 11: lcd.print("TEMPETE "); typeVent = "TEMPETE"; break;
case 12: lcd.print("VIOLENTE TEMPETE "); typeVent = "VIOLENTE TEMPETE"; break;
case 13: lcd.print(" !!! OURAGAN !!! "); typeVent = "!!! OURAGAN !!!"; break;
}
/////////////////////////// LIGNE 3 - DENOMINATION RAFALES /////////////////////////////////
if (RAFALES_MAX_10_DERNIERES_MN < 18)
{
classification_rafales = 1; // aucune rafales
}
if (RAFALES_MAX_10_DERNIERES_MN >= 18 && RAFALES_MAX_10_DERNIERES_MN < 28)
{
classification_rafales = 2; // rafales
}
if (RAFALES_MAX_10_DERNIERES_MN >= 28 && RAFALES_MAX_10_DERNIERES_MN < 46)
{
classification_rafales = 3; // fortes rafales
}
if (RAFALES_MAX_10_DERNIERES_MN >= 46)
{
classification_rafales = 4; // violentes rafales
}
lcd.setCursor (18,2);
switch(classification_rafales){
case 1: lcd.print("--"); typeRafale = "--"; break;
case 2: lcd.print("-R"); typeRafale = "-R"; break;
case 3: lcd.print("FR"); typeRafale = "FR"; break;
case 4: lcd.print("VR"); typeRafale = "VR"; break;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
t_debut_affichage = TEMPS_milli;
affiche = 1; // si le v_max_inst (v instantanée max obtenue depuis dernier affichage) a été affiché, il ne l'affichera plus et passera à la prochaine valeur obtenue suite nouveau front montant
}// FIN VOID AFFICHEUR////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//************************************************************************************************************************************************************************************************************************************************
//VOID REMISE A ZERO V MAX //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void REMISE_ZERO_VMAX () // Déclenchée par ISR D3
{
v_max = 0;
} // FIN VOID REMISE_ZERO_VMAX
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//************************************************************************************************************************************************************************************************************************************************
//VOID PROGRESS BAR - LIGNE 4 - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void draw_progressbar(byte percent)
{
/* Déplace le curseur sur la ligne 4 */
lcd.setCursor(0, 3); // 3 au lieu 1
/* Map la plage (0 ~ 100) vers la plage (0 ~ LCD_NB_COLUMNS * 5) */
byte nb_columns = map(percent, 0, 100, 0, LCD_NB_COLUMNS * 5);
/* Dessine chaque caractère de la ligne */
for (byte i = 0; i < LCD_NB_COLUMNS; ++i)
{
/* En fonction du nombre de colonnes restant à afficher */
if (nb_columns == 0) // Case vide
{
lcd.write((byte) 0);
} else if (nb_columns >= 5) // Case pleine
{
lcd.write(5); // il en remplie 5 sur 100
nb_columns -= 5; // il retranche 5 au total de colonnes à afficher
} else // Derniére case non vide
{
lcd.write(nb_columns);
nb_columns = 0;
}
}
v_max_inst_bargraph = 0;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//************************************************************************************************************************************************************************************************************************************************
//////// BARGRAPH ZERO //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////*********************************** VOID CREATION CHAÏNE DES DONNEES A ENVOYER ************************************** ////////////////////////////////////////////////////////////////////////////////////////////////////////////
void createDataString(String &data)
{
data0 = x++;
data1 = v_max_inst;
data2 = v_max;
data3 = MOY_VMOY;
data4 = vitesse_max_10mn;
data5 = typeRafale;
data6 = typeVent;
data = "*" + String(data0) + "*" + String(data1) + "*" + String(data2) + "*" + String(data3) + "*" + String(data4) + "*" + String(data5) + "*" + String(data6);
Serial.println(data);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//************************************************************************************************************************************************************************************************************************************************
// SETUP /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup()
{
Serial.begin(9600);
// D3 = INPUT interruption pin pour remise à zero v max
pinMode(ResetVmaxPin, INPUT);
// Déclaration de l'ISR DE REMISE 0 ZERO DE VMAX AVEC BOUTON POUSSOIR
attachInterrupt(digitalPinToInterrupt(3),REMISE_ZERO_VMAX,CHANGE);
// initialize the lcd 20x4
lcd.init();
lcd.backlight(); // LCD_TAG // retroeclairage lcd 20x4
lcd.begin(LCD_NB_COLUMNS, LCD_NB_ROWS);
setup_progressbar(); // Mémorise les séries de caractères spéciaux
lcd.setCursor (0,0); // LCD_TAG go to start of 1er line
lcd.print("ANEMOMETRE V.58");
lcd.setCursor (0,1); // LCD_TAG go to start of 1er line
lcd.print("03 Mars 2024");
lcd.setCursor (0,2); // LCD_TAG go to start of 1er line
lcd.print("Thomas CAUNES R.P.");
lcd.setCursor (0,3); // LCD_TAG go to start of 1er line
lcd.print("V = 3 + 0.8 F km/h");
delay(5000); // 2s insuffisant !
lcd.clear();
hc12.begin(9600); // Initialisation du HC-12
// // ******************* Declaration du canal 1 par defaut ***************************************
// pinMode(pinSet_HC12, OUTPUT); // Déclaration du pin du SET pour changement de canal
// digitalWrite(pinSet_HC12, LOW); // Mettre le SET à la masse pour entrer en mode commande AT
// Serial.println("Configuration du canal du HC-12");
// delay(100); // Attente de la stabilisation de la connexion
// hc12.print("AT+C001"); // Commande AT pour le canal 2 du HC-12 C
// ///////delay(1000); // Attente pour s'assurer que la commande est bien prise en compte
// digitalWrite(pinSet_HC12, HIGH); // Mettre le SET à la masse pour entrer en mode commande AT
} // FIN SETUP
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//************************************************************************************************************************************************************************************************************************************************
// BOUCLE LOOP ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop()
{
float freq = 0; // Déclaration de la donnée reçue
if (hc12.available()) // Si réception OK DE LA FREQUENCE
{
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
freq = hc12.parseFloat(); //Décodage de la réception : freq = NB_PULSE reçus de l'émetteur en 1s
temps_precedent = micros(); // Pour la mesure d'absence d'affichage en fin de loop
NB_PULSE_10s_INCREMENT = NB_PULSE_10s_INCREMENT + freq; // incrémente le nombre de front descendants observés en 10s (remis à 0 après 10s dans "Calculateur 10 min)
///////Serial.println(NB_PULSE_10s_INCREMENT);
memoire_vmax_zero = 0; // permet de ne mettre à 0 la v instantannée max qu'une seule fois lorsque plus de 2.5s sans signal anemomètre
// Conversion fréquence en vitesse
if (freq == 0.0)
{
v = 0;
}
else if (freq <= 3.0)
{
v = 0.8 * freq ;
}
else
{
v = 3 + 0.8 * freq ;
}
// Calcul v_max_inst
if (affiche == 1) // s'il y a eu affichage de la v_max_inst, elle est remise à zer
{
v_max_inst = 0; // remise à zero v_max_inst, de ce fait elle évolura entre l'affichage qui vient d'avoir lieu et le nouvel affichage à venir (toutes les 500ms)
affiche = 0; // on déclare que l'affichage est à faire pour la prochaine v max inst
}
if (v == 0)
{
v_max_inst = 0;
}
if (v > v_max_inst && v < 200)
{
v_max_inst = v; // évolution de la vitesse instantannée (je prends la vitesse instantanée maximale obtenue entre 2 affichages (affichage toutes les 500ms)
}
if (v > v_max_inst_bargraph && v < 200)
{
v_max_inst_bargraph = v; // évolution de la vitesse instantannée (je prends la vitesse instantanée maximale obtenue entre 2 affichages (affichage toutes les 500ms)
}
if (v > v_max && v < 200)
{
v_max = v; // évolution vitesse max.
}
//(1.8*v_precedente)) était 1.5 // calcul v max obtenue sur durée bloc de 10s, le coeff
//1.5 évite les aberrations de vitesse doublée qu'il y avait parfois
if (v > v_max_bloc_10s && v < 200)
{
v_max_bloc_10s = v; // évolution vitesse max. sert AUX CALCULS DES RAFALES
}
//////////////// ?????????????????? /////////////
//pourcentage=(v);
// pourcentage = (v_max_inst_bargraph);
// percent = byte(pourcentage);
t_ecoule_bargraph = TEMPS_milli - t_debut_bargraph;
if (t_ecoule_bargraph > cadence_bargraph)
{
//pourcentage=(v);
pourcentage = (v_max_inst_bargraph);
if (pourcentage > 0) // Suppression du flash dû au "0" reçu avant la valeur
{
percent = byte(pourcentage);
}
draw_progressbar(percent);
t_debut_bargraph = millis();
}
if (v < 200)
{
v_precedente = v;
}
}
//FIN IF hc12.available() ////////////////// FIN IF HC12 AVAILABLE /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TEMPS_milli = millis(); // instant (ms) nécessaires pour cadence d'affichage
TEMPS_micros = micros(); // instant (µs) nécessaires remise à zero v instantanée "V_max_inst" si plus de 2 s sans signal
CALCULATEUR_10mn(); // appelle fonction de calcul des éléments sur 10mn d'observation
t_ecoule_affichage = TEMPS_milli - t_debut_affichage; // pour gérer cadence affichage
//////////////////////////////////////////////////////////////////////////////////
if (t_ecoule_affichage > cadence_affichage) // affichage selon cadence choisie mais au début, tant qu'il n'y a pas eu assez de front descendants, n'affiche rien
{
AFFICHEUR(); // appelle fonction d'affichage (appelée tts les 1s)
duree_v_nulle = TEMPS_micros - temps_precedent; // temps écoulé depuis le dernier front montant (sert à la mise à zero de la vitesse si pas de signal pendant plus de 2s
if ((duree_v_nulle > duree_remise_zero) && memoire_vmax_zero == 0) // si plus de 2 s sans signal anemo, v max est mise à 0 et affiche une seule fois
{
v_max_inst = 0;
memoire_vmax_zero = 1; // variable mémoire qui permet de ne mettre à zero la vitesse instantannée qu'une seule fois. Est remise à 0 quand nouveau front montant
percent = 0;
draw_progressbar(percent);
}
} //// FIN IF temps d'affichage dépassé ////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////// ENVOI DES DONNEES RECUPEREES DE L'AFFICHEUR /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////******************************** TIMING TOUTES LES MINUTES ************************************///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Calcul durée pour 1 min
tpsAct_1MIN = millis();
// Serial.print("tpsAct = ");
// Serial.print(tpsAct_10MIN);
// Serial.print("- tpsPrec = ");
// Serial.println(tpsPrec_10MIN);
delta_T = tpsAct_1MIN - tpsPrec_1MIN;
Serial.print("delta_T = ");
Serial.println(delta_T);
if (delta_T >= duree)
{
/////////************************** CHANGEMENT DE CANAL DU HC-12 (DU 1 A 2) *******************************///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// digitalWrite(pinSet_HC12, LOW); // Mettre le SET à la masse pour entrer en mode commande AT
// Serial.println("Configuration du canal 2 ");
// //delay(100); // Attente de la stabilisation de la connexion
// hc12.print("AT+C002"); // Commande AT pour le canal 2 du HC-12 C
// delay(100); // Attente pour s'assurer que la commande est bien prise en compte
// digitalWrite(pinSet_HC12, HIGH); // Mettre le SET à la masse pour entrer en mode commande AT
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////************************************ ENVOI DES DATAS *******************************/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
String dataString = "";
createDataString(dataString);
hc12.print(dataString);
hc12.write('\n');
Serial.println(dataString);
Serial.println(data0); //x++;
Serial.println(data1);
Serial.println(data2);
Serial.println(data3);
Serial.println(data4);
Serial.println(data5);
Serial.println(data6);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////************************** CHANGEMENT DE CANAL DU HC-12 (DU 2 A 1) *******************************//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// digitalWrite(pinSet_HC12, LOW); // Mettre le SET à la masse pour entrer en mode commande AT
// Serial.println("Configuration du canal 1");
// //delay(100); // Attente de la stabilisation de la connexion
// hc12.print("AT+C001"); // Commande AT pour le canal 2 du HC-12 C
// delay(100); // Attente pour s'assurer que la commande est bien prise en compte
// digitalWrite(pinSet_HC12, HIGH); // Mettre le SET à la masse pour entrer en mode commande AT
tpsPrec_1MIN = millis();
} ////////// FIN TRAVAIL 1 MINUTE ////////////////////////// FIN TRAVAIL 1 MINUTE //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}
///// FIN LOOP ///////////// FIN LOOP ///////////// FIN LOOP ///////////// FIN LOOP ///////////// FIN LOOP ////////// FIN LOOP ///////////// FIN LOOP ///////////// FIN LOOP ///////////// FIN LOOP ////////////////////////
Ces données doivent être alors envoyées au HC-12(3) du nano récepteur B pour les enregistrements des données sur carte SD avec date et heure.
J’ai pour cette dernière étape deux problèmes.
- Je suis parti sur l’idée de changer le canal du HC-12(2) (canal 1 à 2) pour l’envoi des données au HC-12(3) paramétré sur le canal 2, puis revenir au canal 1. Cela ne fonctionne pas.
- De plus, l’utilisation d’un envoi des données par concaténation de strings dysfonctionne (le « createDataString »). Comment envoyer les données float et string autrement ? En plusieurs fois ?
Ci-joint le code du récepteur B (je n'active pas les déclarations de l'horloge et de la carte SD. Seules les données reçues m'intéressent en priorité avant d'aller plus loin.)
/*
LE PROGRAMME UTILISE LE HC-12 C POUR RECEVOIR TOUTES LES MINUTES LES DONNEES ISSUES DE L'AFFICHEUR DU RECEPTEUR A
LE RECEPTEUR B EST SUR LE CANAL 2 DU HC-12 C. IL RECOIT LES DONNEES DU RECEPTEUR A VIA LE CANAL 2
LA DATE ET L'HEURE SONT RECUPEREES AVANT LA RECEPTION
*/
///////////////// INCLUSION LIBRAIRIES DS3231 - Carte SD - HC-12 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <Arduino.h>
// Déclaratiion HC-12
#include <SoftwareSerial.h>
SoftwareSerial hc12(8,9); // OK pour le NANO !
// Déclaration des bibliothèques de la DS3231 et de laCarte SD
/*#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include <RTClib.h> // Declaration de DS3231 (0x68)
RTC_DS3231 rtc;
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//*************************************************************************************************************************************************************************************************************************
// DECLARATION VARIABLES PAPOU //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// /////// HC-12 : pin SET
#define pinSet_HC12 6 // LOW pour définition du canal de communication
/*
// /////// DS3231 :
// Declaration des types de variables à concatener pour afficher la date et l'heure
String stringPoints = ":";
String stringSlash = "/";
///////String dateActuelle;
String heureActuelle = "";
volatile int an, mois, jour, heure, minut;
// /////// CARTE SD :
// Déclaration du pin de détection de présence de la carte SD en pin 48
#define SDmissing 7
boolean testCarteInseree;
// Déclaration du fichier d'enregistrements
File fichier;
File root;
int tailleFichier=0;
String nomFichier;
// Timing 1 min période enregistrements
unsigned long tpsAct_1MIN = 0;
static unsigned long tpsPrec_1MIN = 0;
unsigned long delta_T = 0;
const unsigned long duree = 60000UL;
*/
// Données enregistrements
int x = 0; //rang enregistrement
int data0;
float data1;
float data2;
float data3;
float data4;
String data5 = "";
String data6 = "";
String typeRafale;
String typeVent;
/*
//-------------------------------------------------------------------------------------------------------------------
// ROUTINE RECUPERATION DATE ET HEURE DE LA DS3231
//-------------------------------------------------------------------------------------------------------------------
void DateEtHeure()
{
DateTime now = rtc.now(); //recuperation date et heure
// Recuperation date et heure
//////int jour = now.day(), mois = now.month(), an = now.year();
jour = now.day(), mois = now.month(), an = now.year();
////// dateActuelle = jour + stringSlash + mois + stringSlash + an;
////// Serial.print(dateActuelle);
////// Serial.print(" ");
////// int heure = now.hour() , minut = now.minute();
heure = now.hour() , minut = now.minute();
heureActuelle = heure + stringPoints + minut;
// Serial.println(heureActuelle);
// Serial.println();
}
//--------------------------------------------------------------------------------------------------------------------
// ROUTINE REINITIALISATION DE LA CARTE
//--------------------------------------------------------------------------------------------------------------------
void initSDCard()
{
while (!SD.begin())
{
Serial.print("---");
Serial.print("Carte SD non disponible !");
Serial.println("---");
SD.end(); // Fonction non incluse dans la bib de l'IDE
delay(100);
}
return;
}
*/
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//************************************************************************************************************************************************************************************************************************************************
// SETUP /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() //fonction d'initialisation de la carte
{
Serial.begin(9600);
/*
// ******************** INITIALISATION DS3231 **********************************************************************
if (!rtc.begin())
{
Serial.println("Couldn't find RTC");
Serial.flush();
//while (1);
}
else
{
Serial.println("DS3231 OK !");
}
// ******************** INITIALISATION CARTE SD **********************************************************************
pinMode(SDmissing, INPUT_PULLUP); // Pin détection Carte insérée noInterrupts()
initSDCard(); // Routine de détection de présence de la carte
Serial.println("Communication etablie avec la carte SD !"); // Quand initSDCard est ok
*/
// ******************** INITIALISATION CANAL 2 DE COMMUNICATION DU HC-12C **********************************************************************
hc12.begin(9600); // Initialisation du HC-12 C
pinMode(pinSet_HC12, OUTPUT);
digitalWrite(pinSet_HC12, LOW); // Mettre le SET à la masse pour entrer en mode commande AT
Serial.println("Configuration du canal du HC-12");
delay(10); // Attente de la stabilisation de la connexion
hc12.print("AT+C002"); // Commande AT pour le canal 2 du HC-12 C
///////delay(1000); // Attente pour s'assurer que la commande est bien prise en compte
digitalWrite(pinSet_HC12, HIGH); // Mettre le SET à la masse pour entrer en mode commande AT
} // FIN SETUP
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//************************************************************************************************************************************************************************************************************************************************
// BOUCLE LOOP ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop()
{
if (hc12.available() >0)
{
data0 = x++;
data1 = hc12.parseFloat();
data2 = hc12.parseFloat();
data3 = hc12.parseFloat();
data4 = hc12.parseFloat();
data5 = hc12.readString();
data6 = hc12.readString();
//sensorData4 = hc12.Serial.readStringUntil('\n');
Serial.print("data0 : ");
Serial.println(data0);
Serial.print("data1 : ");
Serial.println(data1);
Serial.print("data2 : ");
Serial.println(data2);
Serial.print("data3 : ");
Serial.println(data3);
Serial.print("data4 : ");
Serial.println(data4);
Serial.print("data5 : ");
Serial.println(data5);
Serial.print("data6: ");
Serial.println(data6);
}
} ///// FIN LOOP ///////////// FIN LOOP ///////////// FIN LOOP ///////////// FIN LOOP ///////////// FIN LOOP ////////// FIN LOOP ///////////// FIN LOOP ///////////// FIN LOOP ///////////// FIN LOOP ///////////// FIN LOOP
Merci pour vos avis et votre aide éventuelle.
Bébert