SAGNES Christophe / Mbed 2 deprecated Le_Pont_V10116

Dependencies:   mbed

Fork of Le_Pont_V10116 by 3R

Files at this revision

API Documentation at this revision

Comitter:
CS
Date:
Thu Jun 22 09:33:04 2017 +0000
Commit message:
V10116 initiale

Changed in this revision

Constantes.h Show annotated file Show diff for this revision Revisions of this file
Gemma.cpp Show annotated file Show diff for this revision Revisions of this file
Gemma.h Show annotated file Show diff for this revision Revisions of this file
Modbus.cpp Show annotated file Show diff for this revision Revisions of this file
Modbus.h Show annotated file Show diff for this revision Revisions of this file
Pilote.cpp Show annotated file Show diff for this revision Revisions of this file
Pilote.h Show annotated file Show diff for this revision Revisions of this file
Port_Serie.cpp Show annotated file Show diff for this revision Revisions of this file
Port_Serie.h Show annotated file Show diff for this revision Revisions of this file
Synchronisation.cpp Show annotated file Show diff for this revision Revisions of this file
Synchronisation.h Show annotated file Show diff for this revision Revisions of this file
Variable.cpp Show annotated file Show diff for this revision Revisions of this file
Variable.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Constantes.h	Thu Jun 22 09:33:04 2017 +0000
@@ -0,0 +1,192 @@
+//***********************************************************************************/
+//
+//          Constantes Pont Bacalan
+//
+//************************************************************************************/
+#ifndef _CONST_
+#define _CONST_
+
+typedef  char           U8 ;
+typedef  short          S16 ;
+typedef  unsigned short U16 ;
+typedef  float          F32 ;
+typedef  int            S32 ;
+
+#ifndef TRUE
+#define TRUE            1
+#endif
+
+#ifndef FALSE
+#define FALSE           0
+#endif
+
+#define REG_INPUT_START             0
+#define REG_INPUT_NREGS             260
+#define SLAVE_ID                    0x01
+
+#define EPSILON                     1E-9
+
+#define ARRET                       0
+#define MONTE                       1
+#define DESCEND                     2
+
+#define MODE_ARRET                  0
+#define MODE_MANUEL                 1
+#define MODE_AUTOMATIQUE            2
+#define MODE_PARAMETRAGE            3
+#define MODE_ETALONNAGE             4
+#define MODE_ALIGNEMENT             5
+
+#define AUCUN                       0
+#define DEUX_VITESSES               1
+#define RD_SUIT_RG                  2
+#define RG_SUIT_RD                  3
+#define CUSTOM                      4
+
+#define TAILLE_TABLEAU_HAUTEURS     6
+
+#define Version_Soft                Memoire_S16[1]
+
+// Boutons
+#define BTN_Arret                   Memoire_S16[120]
+#define BTN_Monte                   Memoire_S16[121]
+#define BTN_Descend                 Memoire_S16[122]
+#define BTN_Etalonnage              Memoire_S16[140]
+
+
+#define BTN_Monte_RD                Memoire_S16[125]
+#define BTN_Descend_RD              Memoire_S16[126]
+
+#define BTN_Monte_RG                Memoire_S16[130]
+#define BTN_Descend_RG              Memoire_S16[131]
+
+
+#define BTN_Frein                   Memoire_S16[141]
+#define BTN_Aligne                  Memoire_S16[142]
+
+//Temps de scrutation
+#define Duree_Boucle_us             Memoire_S16[2]
+#define Periode_Scrutation_ms       Memoire_S16[3]
+
+//Modes de fonctionnement
+#define Mode_Fonctionnement         Memoire_S16[15]
+#define Mode_Synchro                Memoire_S16[16]
+
+//Informations rive droite
+#define Etat_RD                     Memoire_S16[20]
+#define Hauteur_RD                  Memoire_S16[21]
+#define Vitesse_RD                  Memoire_S16[22]
+#define Couple_RD                   Memoire_S16[23]
+#define Acceleration_RD             Memoire_S16[24]
+#define Mesure_RD                   Memoire_S16[25]
+#define Etat_COM_RD                 Memoire_S16[26]
+#define Compteur_Timeout_RD         Memoire_S16[27]
+#define Consigne_Vitesse_RD         Memoire_S16[28]
+#define Consigne_Hauteur_RD         Memoire_S16[29]
+
+#define Hauteur_RD1_mm              Memoire_S16[35]
+#define Hauteur_RD2_mm              Memoire_S16[36]
+#define Hauteur_RD1_pts             Memoire_S16[37]
+#define Hauteur_RD2_pts             Memoire_S16[38]
+
+//Informations rive gauche
+#define Etat_RG                     Memoire_S16[40]
+#define Hauteur_RG                  Memoire_S16[41]
+#define Vitesse_RG                  Memoire_S16[42]
+#define Couple_RG                   Memoire_S16[43]
+#define Acceleration_RG             Memoire_S16[44]
+#define Mesure_RG                   Memoire_S16[45]
+#define Etat_COM_RG                 Memoire_S16[46]
+#define Compteur_Timeout_RG         Memoire_S16[47]
+#define Consigne_Vitesse_RG         Memoire_S16[48]
+#define Consigne_Hauteur_RG         Memoire_S16[49]
+
+#define Hauteur_RG1_mm              Memoire_S16[55]
+#define Hauteur_RG2_mm              Memoire_S16[56]
+#define Hauteur_RG1_pts             Memoire_S16[57]
+#define Hauteur_RG2_pts             Memoire_S16[58]
+
+//Informations pont
+#define Etat_P                      Memoire_S16[60]
+#define Hauteur_P                   Memoire_S16[61]
+#define Vitesse_P                   Memoire_S16[62]
+#define Couple_P                    Memoire_S16[63]
+#define Acceleration_P              Memoire_S16[64]
+
+#define Consigne_Vitesse_Manu       Memoire_S16[67]
+#define Consigne_Vitesse_Auto       Memoire_S16[68]
+#define Consigne_Haute_P            Memoire_S16[69]
+#define Consigne_Basse_P            Memoire_S16[70]
+
+#define Anticipation_Synchro        Memoire_S16[80]
+#define KP_Synchro                  Memoire_S16[81]
+#define KI_Synchro                  Memoire_S16[82]
+#define KD_Synchro                  Memoire_S16[83]
+
+
+#define Hauteur_mini                Memoire_S16[100]
+#define Hauteur_maxi                Memoire_S16[101]
+#define Vitesse_mini                Memoire_S16[102]
+#define Vitesse_maxi                Memoire_S16[103]
+
+#define Ecart_Synchronisation       Memoire_S16[110]
+#define Defaut_Mineur_Synchro       Memoire_S16[111]
+#define Defaut_Majeur_Synchro       Memoire_S16[112]
+#define Defaut_Critique_Synchro     Memoire_S16[113]
+#define Correction_Synchro          Memoire_S16[114]
+
+//Parametres variateur rive droite
+#define Param_Version_RD            Memoire_S16[150]
+#define Param_Startup_RD            Memoire_S16[151]
+#define Param_Increment_RD          Memoire_S16[152]
+#define Param_Seuil_Demarrage_RD    Memoire_S16[153]
+#define Param_Acceleration_RD       Memoire_S16[154]
+#define Param_Deceleration_RD       Memoire_S16[155]
+#define Param_Kpv_RD                Memoire_S16[156]
+#define Param_Kiv_RD                Memoire_S16[157]
+#define Param_Kdv_RD                Memoire_S16[158]
+#define Param_Kav_RD                Memoire_S16[159]
+#define Param_Consigne_RD           Memoire_S16[160]
+
+//Parametres variateur rive gauche
+#define Param_Version_RG            Memoire_S16[200]
+#define Param_Startup_RG            Memoire_S16[201]
+#define Param_Increment_RG          Memoire_S16[202]
+#define Param_Seuil_Demarrage_RG    Memoire_S16[203]
+#define Param_Acceleration_RG       Memoire_S16[204]
+#define Param_Deceleration_RG       Memoire_S16[205]
+#define Param_Kpv_RG                Memoire_S16[206]
+#define Param_Kiv_RG                Memoire_S16[207]
+#define Param_Kdv_RG                Memoire_S16[208]
+#define Param_Kav_RG                Memoire_S16[209]
+#define Param_Consigne_RG           Memoire_S16[210]
+
+//Commandes de sauvegarde mémoire
+#define Sauver_Vers_Flash           Memoire_S16[245]
+
+//Autres paramètres
+#define Sauvegarde_automatique      Memoire_S16[246]
+#define Etalonnage_effectue         Memoire_S16[247]
+#define Etalonnage_en_cours         Memoire_S16[248]
+#define RAZ                         Memoire_S16[249]
+#define Mode_Debug                  Memoire_S16[250]
+
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Gemma.cpp	Thu Jun 22 09:33:04 2017 +0000
@@ -0,0 +1,315 @@
+//******************************************************************
+//
+//      Gemma
+//
+//  Logiciel de gestion des modes de marche et d'arret du Pont Bacalan
+//
+// 
+//
+//********************************************************************
+
+#include "Gemma.h"
+
+Serial PC3(USBTX, USBRX) ;
+// Chronomètre
+Timer   Chrono_Param ;
+AnalogOut   Consigne_aout (p18) ;
+
+U8  No_Parametre ;
+S16  *pParametres_Console_RG ;
+S16  *pParametres_Console_RD ;
+
+void    vGemma_Init () 
+    {
+    Chrono_Param.start () ;
+    pParametres_Console_RG = &Param_Version_RG ;
+    pParametres_Console_RD = &Param_Version_RD ;
+    No_Parametre = 0 ;
+    Consigne_aout.write ( 0.0 ) ;
+    }
+
+void    vGemma ( Pilote* pRive_Droite , Pilote* pRive_Gauche )
+    {
+    // Fonctionnement des differents modes
+    PC3.printf("\r\n Mode: %i", Mode_Fonctionnement) ;
+    if ( Mode_Fonctionnement == MODE_MANUEL )
+        // En mode manuel, pas d'action maintenue, les 2 rives sont indépendantes
+        {
+        //Raz des parametres de synchronisation
+        vSynchro_Initialise ( ) ;
+        
+        if ( BTN_Monte_RD )  
+            {// Montée rive droite
+            if ( ( Hauteur_RD - Hauteur_RG ) < Defaut_Critique_Synchro )
+                {
+                PC3.printf("\t Monte RD") ;
+                pRive_Droite->Marche ( MODE_MANUEL, MONTE, Hauteur_maxi , Consigne_Vitesse_Manu  ) ;             
+                }
+            BTN_Descend_RD = 0 ;
+            }
+        else if ( BTN_Descend_RD )             
+            {// Descente rive droite
+            if ( ( Hauteur_RG - Hauteur_RD ) < Defaut_Critique_Synchro )
+                {
+                PC3.printf("\t Descend RD") ;
+                pRive_Droite->Marche ( MODE_MANUEL, DESCEND, Hauteur_mini , Consigne_Vitesse_Manu  ) ;         
+                }
+            BTN_Monte_RD = 0 ;
+            }
+        else            
+            {// Arrêt rive droite
+            pRive_Droite->Arret() ;
+            BTN_Descend_RD = 0 ;
+            BTN_Monte_RD = 0 ;
+            //PC3.printf("\r\n Arret RD") ;
+            }
+        if ( BTN_Monte_RG )
+            {// Montée rive gauche
+            if ( ( Hauteur_RG - Hauteur_RD ) < Defaut_Critique_Synchro )
+                {
+                PC3.printf("\t Monte RG") ;
+                pRive_Gauche->Marche ( MODE_MANUEL, MONTE, Hauteur_maxi , Consigne_Vitesse_Manu  ) ;
+                Consigne_aout.write ( (F32) Consigne_Vitesse_Manu / V_MAX ) ;
+                }
+            BTN_Descend_RG = 0 ;
+            }
+        else if ( BTN_Descend_RG )
+            {// Descente rive gauche
+            if ( ( Hauteur_RD - Hauteur_RG ) < Defaut_Critique_Synchro )
+                {
+                PC3.printf("\t Descend RG") ;
+                pRive_Gauche->Marche ( MODE_MANUEL, DESCEND, Hauteur_mini , Consigne_Vitesse_Manu  ) ;
+                Consigne_aout.write ( (F32) Consigne_Vitesse_Manu / V_MAX ) ;
+                }
+            BTN_Monte_RG = 0 ;
+            }
+        else
+            {// Arret rive gauche
+            pRive_Gauche->Arret() ;
+            BTN_Monte_RG = 0 ;
+            BTN_Descend_RG = 0 ;
+            Consigne_aout.write ( 0.0 ) ;
+            //PC3.printf("\r\n Arret RG") ;
+            }
+        if ( BTN_Frein )  
+            {// Liberation des freins
+            if ( !BTN_Monte_RG && !BTN_Descend_RG && !!BTN_Monte_RD && !BTN_Descend_RD )
+                {
+                if (pRive_Gauche->Etat_Frein == SERRE ) pRive_Gauche->Frein( DESSERRE ) ;
+                if (pRive_Droite->Etat_Frein == SERRE ) pRive_Droite->Frein( DESSERRE ) ;
+                }                            
+            }
+        else              
+            {// Serrage des freins
+            if ( !BTN_Monte_RG && !BTN_Descend_RG && !!BTN_Monte_RD && !BTN_Descend_RD )
+                {
+                if (pRive_Gauche->Etat_Frein == DESSERRE ) pRive_Gauche->Frein( SERRE ) ;
+                if (pRive_Droite->Etat_Frein == DESSERRE ) pRive_Droite->Frein( SERRE ) ;
+                }                  
+            }
+        }
+        
+    else if ( Mode_Fonctionnement == MODE_AUTOMATIQUE )
+        {// En mode automatique, les rives sont synchronisées, avec consigne de vitesse et hauteur cible                     
+        if ( BTN_Arret )      
+            {// Arret du pont
+            BTN_Monte = 0 ;
+            BTN_Descend = 0 ;
+            BTN_Arret = 0 ;
+            pRive_Droite->Arret() ;
+            pRive_Gauche->Arret() ;
+            Consigne_aout.write ( 0.0 ) ;   
+            
+            vSynchro_Initialise ( ) ;
+               
+            //PC3.printf("\r\n Btn Arret") ;    
+            }
+         else
+            {// Vérification de l'ecart de synchronisation: différence de hauteur entre droite et gauche
+            if ( abs( Hauteur_RD - Hauteur_RG ) > Defaut_Critique_Synchro )
+                {// Si l'ecart depasse le seuil critique: on arrete tout!
+                BTN_Arret = 0 ;
+                BTN_Descend = 0 ;
+                BTN_Monte = 0 ;
+                pRive_Droite->Arret() ;
+                pRive_Gauche->Arret() ;
+                Consigne_aout.write ( 0.0 ) ;
+                PC3.printf("\r\n Defaut Critique") ; 
+                }
+            else if ( BTN_Monte )
+                {// Si on est en haut
+                if (  ( Hauteur_P >= Consigne_Haute_P )
+                    ||( Hauteur_RD >= Consigne_Haute_P )
+                    ||( Hauteur_RG >= Consigne_Haute_P ) )
+                    {
+                    BTN_Monte = 0 ;
+                    pRive_Droite->Arret() ;
+                    pRive_Gauche->Arret() ;
+                    PC3.printf("\r\n En Haut") ; 
+                    }
+                else
+                    {// Montée
+                    PC3.printf("\t Monte Auto mode: %i", Mode_Synchro) ;
+                    vSynchronise ( Mode_Synchro , MONTE ) ;                                             
+                    pRive_Droite->Marche ( MODE_AUTOMATIQUE, MONTE, Consigne_Haute_P , Consigne_Vitesse_RD ) ;
+                    pRive_Gauche->Marche ( MODE_AUTOMATIQUE, MONTE, Consigne_Haute_P , Consigne_Vitesse_RG ) ;
+                    Consigne_aout.write ( (F32) Consigne_Vitesse_RG / V_MAX ) ;
+                    }
+                
+                BTN_Arret = 0 ;
+                BTN_Descend = 0 ;
+                }
+            else if ( BTN_Descend )
+                {
+                if (  ( Hauteur_P <= Consigne_Basse_P )
+                    ||( Hauteur_RD <= Consigne_Basse_P )
+                    ||( Hauteur_RG <= Consigne_Basse_P ) )
+                    {// Si on est en bas
+                    BTN_Descend = 0 ;
+                    pRive_Droite->Arret() ;
+                    pRive_Gauche->Arret() ;
+                    PC3.printf("\r\n En Bas") ; 
+                    }
+                else
+                    {// Descente du pont
+                    PC3.printf("\t Descend Auto") ;
+                    PC3.printf("\t Descend Auto mode: %i", Mode_Synchro) ;
+                    vSynchronise ( Mode_Synchro , DESCEND ) ;
+                    Consigne_Vitesse_RD = Consigne_Vitesse_Auto ;
+                    Consigne_Vitesse_RG = Consigne_Vitesse_Auto ;
+                    
+                    pRive_Droite->Marche ( MODE_AUTOMATIQUE, DESCEND, Consigne_Basse_P , Consigne_Vitesse_RD ) ;
+                    pRive_Gauche->Marche ( MODE_AUTOMATIQUE, DESCEND, Consigne_Basse_P , Consigne_Vitesse_RG ) ;
+                    Consigne_aout.write ( (F32) Consigne_Vitesse_RG / V_MAX ) ;
+                    }
+
+                BTN_Arret = 0 ;
+                BTN_Monte = 0 ;
+                }
+            
+            else
+                {
+                pRive_Droite->Arret() ;
+                pRive_Gauche->Arret() ;
+                Consigne_aout.write ( 0.0 ) ;
+                }   
+            }
+        }
+    else if ( Mode_Fonctionnement == MODE_PARAMETRAGE )
+        {// En mode parametrage, 
+        //PC3.printf("\r\n No Param = %i " , No_Parametre) ; 
+        
+        if ( Chrono_Param.read_ms() > PERIODE_MAJ_PARAM )
+            {
+            Chrono_Param.reset () ;
+            // Vérifie si le dernier parametre lu est a jour
+            if ( *(pParametres_Console_RG + No_Parametre ) != (S16) ( pRive_Gauche->Parametres_Vario_S32 [ No_Parametre ] ) )
+                {// Sinon, on l'écrit dans le variateur
+                PC3.printf("\r\n No Param RG= %i - %i " , *(pParametres_Console_RG + No_Parametre ) , pRive_Gauche->Parametres_Vario_S32 [ No_Parametre ] ) ; 
+                pRive_Gauche->Configure ( No_Parametre , (S32) *(pParametres_Console_RG + No_Parametre ) ) ;
+                }
+            // Vérifie si le dernier parametre lu est a jour
+            if ( *(pParametres_Console_RD + No_Parametre ) != (S16) ( pRive_Droite->Parametres_Vario_S32 [ No_Parametre ] ) )
+                {// Sinon, on l'écrit dans le variateur
+                PC3.printf("\r\n No Param RD= %i - %i " , *(pParametres_Console_RD + No_Parametre ) , pRive_Droite->Parametres_Vario_S32 [ No_Parametre ] ) ;
+                pRive_Droite->Configure ( No_Parametre , (S32) *(pParametres_Console_RD + No_Parametre ) ) ;
+                }
+            No_Parametre++ ;
+            if ( No_Parametre >= NB_PARAM_VARIATEUR )
+                {
+                No_Parametre = 0 ;
+                }
+            // Lecture du parametre suivant
+            pRive_Gauche->Lecture ( No_Parametre ) ;
+            pRive_Droite->Lecture ( No_Parametre ) ;
+            
+            }                   
+
+        }
+    else if ( Mode_Fonctionnement == MODE_ETALONNAGE )
+        {// Etalonnage
+        if ( BTN_Etalonnage )
+            {
+            pRive_Droite->Etalonnage (Hauteur_RD1_pts , Hauteur_RD1_mm , Hauteur_RD2_pts , Hauteur_RD2_mm ) ;
+            pRive_Gauche->Etalonnage (Hauteur_RG1_pts , Hauteur_RG1_mm , Hauteur_RG2_pts , Hauteur_RG2_mm ) ;
+            BTN_Etalonnage = 0 ;
+            wait(0.1) ;
+            } 
+        pRive_Droite->Arret() ;
+        pRive_Gauche->Arret() ;                   
+        }
+    
+    else if ( Mode_Fonctionnement == MODE_ALIGNEMENT )
+        {
+        if ( BTN_Aligne)
+            {// Alignement des hauteurs de pile pour le mode automatique
+            if ( abs( Hauteur_RD - Hauteur_RG ) < Defaut_Mineur_Synchro / 2 )
+                {// Si l'ecart de hauteur est faible, on arrête tout
+                BTN_Aligne = 0 ;
+                pRive_Droite->Arret() ;
+                pRive_Gauche->Arret() ;
+                PC3.printf("\r\n Aligne") ; 
+                }
+            else if ( Hauteur_RD > Hauteur_RG )
+                {// La pile droite est plus haute
+                if ( Hauteur_RD > Consigne_Basse_P )               
+                    {// On descend la pile droite                      
+                    Consigne_Vitesse_RD = Consigne_Vitesse_Manu ;                      
+                    pRive_Droite->Marche ( MODE_AUTOMATIQUE, DESCEND, Hauteur_RG , Consigne_Vitesse_RD ) ;
+                    }
+                else
+                    {
+                    pRive_Droite->Arret() ;
+                    }
+                if ( Hauteur_RG < Consigne_Haute_P )
+                    {// On monte la pile gauche                      
+                    Consigne_Vitesse_RG = Consigne_Vitesse_Manu ;                      
+                    pRive_Gauche->Marche ( MODE_AUTOMATIQUE, MONTE, Hauteur_RD , Consigne_Vitesse_RG ) ;
+                    }
+                else
+                    {
+                    pRive_Gauche->Arret() ;
+                    }
+                }      
+            else if ( Hauteur_RD < Hauteur_RG )
+                {// La pile gauche est plus haute
+                if ( Hauteur_RD < Consigne_Haute_P )                
+                    {// On monte la pile droite                      
+                    Consigne_Vitesse_RD = Consigne_Vitesse_Manu ;                      
+                    pRive_Droite->Marche ( MODE_AUTOMATIQUE, MONTE, Hauteur_RG , Consigne_Vitesse_RD ) ;                    
+                    }
+                else
+                    {
+                    pRive_Droite->Arret() ;
+                    }
+                if ( Hauteur_RG > Consigne_Basse_P )
+                    {// On descend la pile gauche                      
+                    Consigne_Vitesse_RG = Consigne_Vitesse_Manu ;                      
+                    pRive_Gauche->Marche ( MODE_AUTOMATIQUE, DESCEND, Hauteur_RD , Consigne_Vitesse_RG ) ;
+                    
+                    }
+                else
+                    {
+                    pRive_Gauche->Arret() ;
+                    }
+                }
+            }
+        else
+            {
+            pRive_Droite->Arret() ;
+            pRive_Gauche->Arret() ;
+            }
+        }
+    else
+        // Si le mode est inconnu, mode arret!
+        {
+        Mode_Fonctionnement = MODE_ARRET ;
+        pRive_Droite->Arret() ;
+        pRive_Gauche->Arret() ;
+        BTN_Arret = 1 ;
+        BTN_Monte = 0 ;
+        BTN_Descend = 0 ;
+        Consigne_aout.write ( 0.0 ) ;
+        PC3.printf("\r\n Mode Inconnu") ; 
+        }
+    }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Gemma.h	Thu Jun 22 09:33:04 2017 +0000
@@ -0,0 +1,26 @@
+//******************************************************************
+//
+//      Gemma
+//
+//  Logiciel de gestion des modes de marche et d'arret du Pont Bacalan
+//
+// 
+//
+//********************************************************************
+#ifndef _Gemma_
+#define _Gemma_
+
+#include "mbed.h"
+
+#include "Constantes.h"
+#include "Variable.h"
+#include "Pilote.h"
+#include "Synchronisation.h"
+
+#define PERIODE_MAJ_PARAM   50
+#define V_MAX               3260
+
+extern void    vGemma_Init () ;
+extern void    vGemma ( Pilote* Rive_Droite , Pilote* Rive_Gauche );
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Modbus.cpp	Thu Jun 22 09:33:04 2017 +0000
@@ -0,0 +1,263 @@
+/***********************************************************************************/
+//
+//          Gestion du Modbus
+//
+//************************************************************************************/
+
+#include <mbed.h>
+#include "Modbus.h"
+#include "Port_Serie.h"
+
+
+//volatile    U8  Numero_Ordre_En_Cours_U8 ;
+volatile    Ordre_Modbus_t  Ordres[TAILLE_PILE_ORDRES] ;
+
+
+Serial PC7(USBTX, USBRX) ;
+
+/************ Initialisation du Modbus ************************/
+void    vModbus_Init(int Baudrate) 
+    {
+    U8  Numero_Ordre_U8 ;
+    
+    vPort_Serie_Init( Baudrate ) ;
+    
+    for ( Numero_Ordre_U8 = 0 ; Numero_Ordre_U8 < TAILLE_PILE_ORDRES ; Numero_Ordre_U8++ )
+        {
+        // Effacement des ordres
+        Ordres[Numero_Ordre_U8].Etat_U8 = ARRET ;
+        Ordres[Numero_Ordre_U8].Nb_Caracteres_Recus_U8 = 0 ;
+        Ordres[Numero_Ordre_U8].Nb_Caracteres_A_Emettre_U8 = 0 ;
+        Ordres[Numero_Ordre_U8].Code_Erreur = 0 ;
+        }
+    
+    
+    PC7.printf("\r\n    Modbus : Init ") ;
+    }
+       
+ 
+/************* Demarrage du Modbus ****************************/
+void    vModbus_Start() 
+    {
+    //Ordres[Numero_Ordre_En_Cours_U8].Etat_U8 = ATTENTE ;
+    vPort_Serie_Ouvre() ;
+    //vPort_Serie_Reception ( 0 ) ;
+    PC7.printf("\r\n    Modbus : Start ") ;
+    }
+
+static const U8 aucCRCHi[] = {
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+    0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
+    0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+    0x00, 0xC1, 0x81, 0x40
+};
+
+static const U8 aucCRCLo[] = {
+    0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7,
+    0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E,
+    0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9,
+    0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
+    0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
+    0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32,
+    0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D,
+    0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 
+    0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF,
+    0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
+    0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1,
+    0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
+    0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 
+    0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
+    0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
+    0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
+    0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97,
+    0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E,
+    0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89,
+    0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
+    0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83,
+    0x41, 0x81, 0x80, 0x40
+};
+
+
+U16 CRC16( U8 * pucFrame, U8 usLen )
+{
+    U8           ucCRCHi = 0xFF;
+    U8          ucCRCLo = 0xFF;
+    int             iIndex;
+
+    while( usLen-- )
+    {
+        //PC7.printf("/ %X /", *pucFrame) ;
+        iIndex = ucCRCLo ^ *( pucFrame++ );
+        ucCRCLo = ( U8 )( ucCRCHi ^ aucCRCHi[iIndex] );
+        ucCRCHi = aucCRCLo[iIndex];
+    }
+    //PC7.printf("\n\r CRC: %X",(ucCRCHi << 8 | ucCRCLo)) ;
+    return ( U16 )( ucCRCHi << 8 | ucCRCLo );
+}
+
+/************* Traitement du Modbus ****************************/
+void    vModbus() 
+    {
+    U8  Numero_Ordre_U8 ;
+    U16 Valeur_U16 ;
+    U8  Ordres_Arretes_U8 = 0 ;
+    U8  Index_CRC_U8 ;
+    U8  Index_Caractere_U8 ;
+    U16 Index_Memoire_U16 ;
+    
+    for ( Numero_Ordre_U8 = 0 ; Numero_Ordre_U8 < TAILLE_PILE_ORDRES ; Numero_Ordre_U8++ )
+        {
+        
+        if ( Ordres[Numero_Ordre_U8].Etat_U8 == RECU )
+            {// Puisque la trame est complete, on peut la traiter
+            //PC7.printf("\n\rOrdre : %i recu",Numero_Ordre_U8) ;
+            if ( Numero_Ordre_U8 < ( TAILLE_PILE_ORDRES - 1 ) )
+                {// Enclenche l'ordre suivant
+                vPort_Serie_Reception ( Numero_Ordre_U8 + 1 ) ;
+                }
+            else
+                {// Enclenche l'ordre 0
+                vPort_Serie_Reception ( 0 ) ;
+                }
+            // Adresse
+            Ordres[Numero_Ordre_U8].Trame_Reponse_aU8[0] = SLAVE_ID ;
+            // Fonction
+            Ordres[Numero_Ordre_U8].Trame_Reponse_aU8[1] = Ordres[Numero_Ordre_U8].Trame_Recue_aU8[1] ;
+            
+            if (( Ordres[Numero_Ordre_U8].Trame_Recue_aU8[1] == MB_FUNC_READ_HOLDING_REGISTER )
+                || ( Ordres[Numero_Ordre_U8].Trame_Recue_aU8[1] == MB_FUNC_READ_INPUT_REGISTER ))
+                {// Fonction 3 ou 4, Lecture de registres
+                // Nombre d'octets
+                //PC7.printf("\n\rOrdre Func: %i",Ordres[Numero_Ordre_U8].Trame_Recue_aU8[1]) ;
+                Ordres[Numero_Ordre_U8].Trame_Reponse_aU8[2] = 2 * Ordres[Numero_Ordre_U8].Trame_Recue_aU8[5] ;
+                // Registre de départ = Hi * 256 + Lo + Base
+                Index_Memoire_U16 = REG_INPUT_START + (U16)(Ordres[Numero_Ordre_U8].Trame_Recue_aU8[2]) * 256 
+                                                    + (U16)Ordres[Numero_Ordre_U8].Trame_Recue_aU8[3] ;
+                //PC7.printf("\r\n %i :",Index_Memoire_U16) ;
+                Index_Caractere_U8 = 0 ;
+                while ( Index_Caractere_U8 < Ordres[Numero_Ordre_U8].Trame_Reponse_aU8[2] )
+                    {
+                    // Octet de poids fort du registre
+                    Ordres[Numero_Ordre_U8].Trame_Reponse_aU8[ Index_Caractere_U8 + 3] = (U8) (Memoire_S16 [ Index_Memoire_U16 ] >> 8 ) ;
+                    // Octet de poids faible
+                    Ordres[Numero_Ordre_U8].Trame_Reponse_aU8[ Index_Caractere_U8 + 4] = (U8) ( Memoire_S16 [ Index_Memoire_U16 ] & 0xFF ) ;
+                    //PC7.printf("/ %X / %X /",Ordres[Numero_Ordre_U8].Trame_Reponse_aU8[ Index_Caractere_U8 + 3],Ordres[Numero_Ordre_U8].Trame_Reponse_aU8[ Index_Caractere_U8 + 4]) ;
+                    Index_Caractere_U8 = Index_Caractere_U8 + 2 ;
+                    Index_Memoire_U16++ ;
+                    }
+                
+                // Calcul de la position du CRC
+                Index_CRC_U8 = 3 + Ordres[Numero_Ordre_U8].Trame_Reponse_aU8[2] ;
+                // Calcul du CRC
+                Valeur_U16 = CRC16 ( (U8 *) &(Ordres[Numero_Ordre_U8].Trame_Reponse_aU8[0]) , Index_CRC_U8 ) ;
+                
+                // CRC Poids fort
+                Ordres[Numero_Ordre_U8].Trame_Reponse_aU8[ Index_CRC_U8 ] = (U8) ( Valeur_U16 & 0xFF ) ;
+                // CRC Poids faible
+                Ordres[Numero_Ordre_U8].Trame_Reponse_aU8[ Index_CRC_U8 + 1 ] = (U8) ( Valeur_U16 >> 8 ) ;
+                // Longueur de trame à emettre
+                Ordres[Numero_Ordre_U8].Nb_Caracteres_A_Emettre_U8 = Index_CRC_U8 + 2 ;
+                }
+            else if ( Ordres[Numero_Ordre_U8].Trame_Recue_aU8[1] == MB_FUNC_WRITE_MULTIPLE_REGISTERS )
+                {// Fonction 16 (0x10) écriture multiple
+                //PC7.printf("\n\rOrdre Func: %i",Ordres[Numero_Ordre_U8].Trame_Recue_aU8[1]) ;
+                // Registre de départ poids fort
+                Ordres[Numero_Ordre_U8].Trame_Reponse_aU8[2] = Ordres[Numero_Ordre_U8].Trame_Recue_aU8[2] ;
+                // Registre de départ poids faible
+                Ordres[Numero_Ordre_U8].Trame_Reponse_aU8[3] = Ordres[Numero_Ordre_U8].Trame_Recue_aU8[3] ;
+                // Nombre de registres poids fort
+                Ordres[Numero_Ordre_U8].Trame_Reponse_aU8[4] = Ordres[Numero_Ordre_U8].Trame_Recue_aU8[4] ;
+                // Nombre de registres poids faible
+                Ordres[Numero_Ordre_U8].Trame_Reponse_aU8[5] = Ordres[Numero_Ordre_U8].Trame_Recue_aU8[5] ;
+                
+                // Registre de départ = Hi * 256 + Lo + Base
+                Index_Memoire_U16 = REG_INPUT_START + (U16)(Ordres[Numero_Ordre_U8].Trame_Recue_aU8[2]) * 256
+                                                    + (U16)Ordres[Numero_Ordre_U8].Trame_Recue_aU8[3] ;
+                Index_Caractere_U8 = 0 ;                                    
+                while ( Index_Caractere_U8 < Ordres[Numero_Ordre_U8].Trame_Recue_aU8[6] )
+                    {
+                    // Ecriture des registres 
+                    Memoire_S16 [ Index_Memoire_U16 ] = (S16) (Ordres[Numero_Ordre_U8].Trame_Recue_aU8[ 7 + Index_Caractere_U8 ]) * 256
+                                                        + (S16) Ordres[Numero_Ordre_U8].Trame_Recue_aU8[ 8 + Index_Caractere_U8 ];
+                    Index_Caractere_U8 = Index_Caractere_U8 + 2 ;
+                    Index_Memoire_U16++ ;
+                    
+                    }
+                // Calcul du CRC
+                Valeur_U16 = CRC16 ( (U8 *) &(Ordres[Numero_Ordre_U8].Trame_Reponse_aU8[0]) , 6 ) ;
+                // Calcul de la position du CRC
+                Index_CRC_U8 = 6 ;
+                Ordres[Numero_Ordre_U8].Trame_Reponse_aU8[ Index_CRC_U8] = (U8) ( Valeur_U16 & 0xFF ) ;
+                Ordres[Numero_Ordre_U8].Trame_Reponse_aU8[ Index_CRC_U8 + 1 ] = (U8) ( Valeur_U16 >> 8 );
+                // Longueur de trame à emettre
+                Ordres[Numero_Ordre_U8].Nb_Caracteres_A_Emettre_U8 = 8 ;
+                }
+            // La trame de réponse est terminée
+            Ordres[Numero_Ordre_U8].Etat_U8 = TRAITE ;
+            //PC7.printf("\n\rOrdre %i Etat: %i",Numero_Ordre_U8,TRAITE) ;
+            // Lancement de l'émission de la réponse
+            vPort_Serie_Emission ( Numero_Ordre_U8 ) ;
+            }
+            
+        else if ( Ordres[Numero_Ordre_U8].Etat_U8 == FIN )
+            {// La réponse est émise, cloture l'ordre
+            Ordres[Numero_Ordre_U8].Etat_U8 = ARRET ;
+            //PC7.printf("\n\rOrdre %i Etat: %i",Numero_Ordre_U8,FIN) ;
+            }
+        else if ( Ordres[Numero_Ordre_U8].Etat_U8 == EMISSION )
+            {// L'emission de la réponse n'est pas terminée, re-essaie
+            //PC7.printf("\n\rOrdre %i Etat: %i",Numero_Ordre_U8,EMISSION) ;
+            vPort_Serie_Emission ( Numero_Ordre_U8 );
+            }
+        else if ( Ordres[Numero_Ordre_U8].Etat_U8 == ARRET )
+            {// Compte les ordres arretés
+            //PC7.printf("\n\rOrdre %i Etat: %i",Numero_Ordre_U8,ARRET) ;
+            Ordres_Arretes_U8++ ;
+            }
+        else if ( Ordres[Numero_Ordre_U8].Etat_U8 == RECEPTION )
+            {// Controle si les temps ne sont pas dépassés
+            //PC7.printf("\n\rOrdre %i Etat: %i",Numero_Ordre_U8,RECEPTION) ;
+            //Ordres[Numero_Ordre_U8].Etat_U8 = cControle_Reception( Numero_Ordre_U8 );
+            }
+        else if ( Ordres[Numero_Ordre_U8].Etat_U8 == ATTENTE )
+            {// Controle si les temps ne sont pas dépassés
+            //PC7.printf("\n\rOrdre %i Etat: %i",Numero_Ordre_U8,ATTENTE) ;
+            }
+        else if ( Ordres[Numero_Ordre_U8].Etat_U8 == TIMEOUT )
+            {// Les temps sont dépassés
+            Ordres[Numero_Ordre_U8].Etat_U8 = ARRET;
+            }
+        //PC7.printf("\r\n    Modbus : %i \t %i \r\n",Numero_Ordre_U8,Ordres[Numero_Ordre_U8].Etat_U8 );
+        }
+    if (Ordres_Arretes_U8 >= TAILLE_PILE_ORDRES )
+        {// Si tous les ordres sont arretés, le prochain aura l'index 0
+        vPort_Serie_Reception ( 0 ) ;
+        }
+    }
+
+ extern void    vModbus_Stop() 
+ {
+     }
+ extern void    vModbus_Reset() 
+ {
+     }
+     
+     
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Modbus.h	Thu Jun 22 09:33:04 2017 +0000
@@ -0,0 +1,96 @@
+/*******************************************************************/
+/*                                                                 */
+/*                 Modbus                                          */
+/*                                                                 */
+/*  Gestion de la liaison Modbus esclave                           */
+/*                                                                 */
+/*                                                                 */
+/*******************************************************************/
+#ifndef _MODBUS_
+#define _MODBUS_
+
+#include "mbed.h"
+#include <Serial.h>
+
+#include "Constantes.h"
+#include "Variable.h"
+
+#include "time.h"
+
+
+
+/***** Etats **********/
+#define ARRET       0
+#define ATTENTE     1
+#define RECEPTION   2
+#define RECU        3
+#define TRAITE      4
+#define EMISSION    5
+#define FIN         6
+#define ERREUR      7
+#define TIMEOUT     8
+
+/* ----------------------- Defines ------------------------------------------*/
+#define MB_ADDRESSE_BROADCAST                 ( 0 )   /*! Modbus adresse de broadcast */
+#define MB_ADDRESSE_MIN                       ( 1 )   /*! Smallest possible slave address. */
+#define MB_ADDRESSE_MAX                       ( 247 ) /*! Biggest possible slave address. */
+#define MB_FUNC_NONE                          (  0 )
+#define MB_FUNC_READ_COILS                    (  1 )
+#define MB_FUNC_READ_DISCRETE_INPUTS          (  2 )
+#define MB_FUNC_WRITE_SINGLE_COIL             (  5 )
+#define MB_FUNC_WRITE_MULTIPLE_COILS          ( 15 )
+#define MB_FUNC_READ_HOLDING_REGISTER         ( 3 )
+#define MB_FUNC_READ_INPUT_REGISTER           (  4 )
+#define MB_FUNC_WRITE_REGISTER                (  6 )
+#define MB_FUNC_WRITE_MULTIPLE_REGISTERS      ( 16 )
+#define MB_FUNC_READWRITE_MULTIPLE_REGISTERS  ( 23 )
+#define MB_FUNC_DIAG_READ_EXCEPTION           (  7 )
+#define MB_FUNC_DIAG_DIAGNOSTIC               (  8 )
+#define MB_FUNC_DIAG_GET_COM_EVENT_CNT        ( 11 )
+#define MB_FUNC_DIAG_GET_COM_EVENT_LOG        ( 12 )
+#define MB_FUNC_OTHER_REPORT_SLAVEID          ( 17 )
+#define MB_FUNC_ERROR                         ( 128 )
+/* ----------------------- Type definitions ---------------------------------*/
+    typedef enum
+{
+    MB_EX_NONE = 0x00,
+    MB_EX_ILLEGAL_FUNCTION = 0x01,
+    MB_EX_ILLEGAL_DATA_ADDRESS = 0x02,
+    MB_EX_ILLEGAL_DATA_VALUE = 0x03,
+    MB_EX_SLAVE_DEVICE_FAILURE = 0x04,
+    MB_EX_ACKNOWLEDGE = 0x05,
+    MB_EX_SLAVE_BUSY = 0x06,
+    MB_EX_MEMORY_PARITY_ERROR = 0x08,
+    MB_EX_GATEWAY_PATH_FAILED = 0x0A,
+    MB_EX_GATEWAY_TGT_FAILED = 0x0B
+} Code_Erreur_t ; 
+
+#define TAILLE_MESSAGE_MAXI  20
+
+typedef struct
+    {
+    U8  Etat_U8 ;
+    U8  Code_Erreur ;
+    U8  Trame_Recue_aU8 [TAILLE_MESSAGE_MAXI] ;
+    U8  Nb_Caracteres_Recus_U8 ;
+    U8  Trame_Reponse_aU8 [TAILLE_MESSAGE_MAXI] ;
+    U8  Nb_Caracteres_A_Emettre_U8 ;
+    }   Ordre_Modbus_t ;
+
+#define TAILLE_PILE_ORDRES  5
+
+
+ extern  volatile    Ordre_Modbus_t  Ordres[TAILLE_PILE_ORDRES] ;
+
+
+ 
+ extern void    vModbus_Init(int Baudrate) ;   
+ extern void    vModbus_Start() ;
+ extern void    vModbus_Stop() ;
+ extern void    vModbus_Reset() ;
+ extern void    vModbus() ;
+
+
+
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pilote.cpp	Thu Jun 22 09:33:04 2017 +0000
@@ -0,0 +1,568 @@
+/*******************************************************************/
+/*                                                                 */
+/*                 Pilote                                          */
+/*                                                                 */
+/*  Objet de pilotage de variateur                                 */
+/*                                                                 */
+/*                                                                 */
+/*******************************************************************/
+
+
+#include "Pilote.h"
+
+Serial PC2(USBTX, USBRX) ;
+/** Class Pilote
+*
+*/
+
+    Pilote::Pilote ( S16 Id )
+        {
+        Hauteur_Cible = 0 ;
+        Etat_Deplacement = ARRET ;
+        Chaine_A_Emettre[0] = 0 ;
+        pReception = &Chaine_Recue[0] ;
+        Nb_Caracteres_Recus = 0 ;
+        Statut_Ordre_En_Cours = AUCUN ;
+        
+        Parametres_Vario_S32 [ VERSION ] = 100 ;
+        Parametres_Vario_S32 [ STARTUP ] = 500 ;
+        Parametres_Vario_S32 [ INCREMENT ] = 20 ;
+        Parametres_Vario_S32 [ SEUIL_DEMARRAGE ] = 10 ;
+        Parametres_Vario_S32 [ ACCELERATION ] = 20 ;
+        Parametres_Vario_S32 [ DECELERATION ] = 20 ;
+        Parametres_Vario_S32 [ KPV ] = 1000 ;
+        Parametres_Vario_S32 [ KIV ] = 100 ;
+        Parametres_Vario_S32 [ KDV ] = 0 ;
+        Parametres_Vario_S32 [ KA ] = 1000 ;
+        Parametres_Vario_S32 [ CONSIGNE ] = 1500 ;
+        
+        };
+
+
+/*******************************************************************/ 
+/*                                                                 */
+/*                 Init                                            */
+/*                                                                 */
+/*  Initialisation de l'objet de pilotage de variateur             */
+/*                                                                 */
+/*                                                                 */
+/*******************************************************************/  
+    void    Pilote::Init ( int Baudrates , int bits , int Stop )
+        {
+        U8  Index ;
+        // Initialisation du port série
+        pPort->baud ( Baudrates );
+        pPort->format ( bits , Serial::None , Stop ) ;
+        
+        while ( pPort->readable() )
+        {
+        // Réception des caractères pour vider le buffer
+        Index = pPort->getc() ;
+        }
+        // RAZ des chaines recues et à emettre
+        for ( Index=0 ; Index < LONGUEUR_CHAINE_EMISSION ; Index++ )
+            {
+            Chaine_A_Emettre[Index] = 0 ;
+            }
+        for ( Index=0 ; Index < LONGUEUR_CHAINE_RECEPTION ; Index++ )
+            {
+            Chaine_Recue[Index] = 0 ;
+            }
+         
+        Chrono_Pilote.start() ;   
+        Chrono_Arret.start() ;
+        Debut_Emission_ms = Chrono_Pilote.read_ms () ;
+        COM_OK = TRUE ;
+        Compteur_Timeout = 0 ;
+        Dernier_Ordre_Confirme = ORDRE_ARRET ;
+        Etat_Deplacement = ARRET ;
+        
+        }
+        
+/*******************************************************************/ 
+/*                                                                 */
+/*                 Marche                                          */
+/*                                                                 */
+/*        Ordre de marche automatique                              */
+/*                                                                 */
+/*                                                                 */
+/*******************************************************************/ 
+    void    Pilote::Marche ( U8 Mode, U8 Sens, S16 Hauteur , S16 Consigne_Vitesse )
+        {
+        F32 Valeur_F32 ;
+        
+        // Construction de la trame de marche    
+        Chaine_A_Emettre[0] = 0x02 ;
+        
+        if ( Sens == MONTE )
+            {
+            Chaine_A_Emettre [1] = ORDRE_MONTE ; // M
+            Etat_Deplacement = MONTE ;
+            }
+        else
+            {
+            Chaine_A_Emettre [1] = ORDRE_DESCEND ; // D
+            Etat_Deplacement = DESCEND ;
+            }
+        
+        if ( Consigne_Vitesse > Vitesse_maxi )
+            {
+            Consigne_Vitesse = Vitesse_maxi ;
+            }
+        else if ( Consigne_Vitesse < 0 )
+            {
+            Consigne_Vitesse = 0 ;
+            }
+        Chaine_A_Emettre [2] = Consigne_Vitesse / 256 ; // Poids fort
+        Chaine_A_Emettre [3] = Consigne_Vitesse % 256 ; // Poids faible
+        
+        if ( Hauteur > Hauteur_maxi )
+            {
+            Hauteur = Hauteur_maxi ;
+            }
+        else if ( Hauteur < Hauteur_mini )
+            {
+            Hauteur = Hauteur_mini ;
+            }
+            
+        Hauteur_Cible = Hauteur ;
+        
+        //Calcul de la mesure à atteindre
+        Valeur_F32 = ( (F32) Hauteur - MM_Offset ) / MM_par_Points ;
+        
+        Chaine_A_Emettre [4] = (S16)Valeur_F32 / 256 ; // Poids fort
+        Chaine_A_Emettre [5] = (S16)Valeur_F32 % 256 ; // Poids faible
+        
+        Chaine_A_Emettre [6] = 0x03 ;
+        Chaine_A_Emettre [7] = 0x00 ;
+        
+        if( Statut_Ordre_En_Cours != ATTENTE )
+            {
+            Ordre_En_Cours = Chaine_A_Emettre [1] ;
+            Emission ( &Chaine_A_Emettre [0] , 7 ) ;
+            Statut_Ordre_En_Cours = ATTENTE ;
+            
+            }
+        }
+
+/*******************************************************************/ 
+/*                                                                 */
+/*                 Arret                                           */
+/*                                                                 */
+/*        Ordre d'arret                                            */
+/*                                                                 */
+/*                                                                 */
+/*******************************************************************/ 
+    void    Pilote::Arret (void)
+        {
+        Chaine_A_Emettre[0] = 0x02 ;
+        Chaine_A_Emettre[1] = ORDRE_ARRET ;
+        Chaine_A_Emettre[2] = 0x03 ;
+        Chaine_A_Emettre[3] = 0x00 ;
+       
+        //PC2.printf("\r\n Chrono %i: %i ms COM: %i \r\n" ,Id, Chrono_Arret.read_ms() , COM_OK ) ;
+        
+        if ( ( Dernier_Ordre_Confirme == ORDRE_ARRET )
+          &&  ( Chrono_Arret.read_ms() > DELAI_COMMANDE_ARRET_ms ) 
+          ||  ( Ordre_En_Cours != ORDRE_ARRET ) 
+          ||  ( Statut_Ordre_En_Cours == DEFAUT ))
+            {
+            Chrono_Arret.reset() ;
+            Emission ( &Chaine_A_Emettre [0] , 3 ) ;
+            Etat_Deplacement = ARRET ;
+            Statut_Ordre_En_Cours = ATTENTE ;
+            Ordre_En_Cours = Chaine_A_Emettre [1] ;
+            }
+        else 
+            {
+            //PC2.printf("\r\n Chrono %i: %i ms Ordre: %i \r\n" ,Id, Chrono_Arret.read_ms() , Ordre_En_Cours ) ;
+            }
+            
+        }
+/*******************************************************************/ 
+/*                                                                 */
+/*                 Etalonnage                                      */
+/*                                                                 */
+/*        Ordre d'étalonnage de hauteur                            */
+/*                                                                 */
+/*                                                                 */
+/*******************************************************************/ 
+   // Etalonnage de hauteur
+   void    Pilote::Etalonnage (S16 Points1, S16 Hauteur1 , S16 Points2 , S16 Hauteur2 )
+    {
+    F32     Valeur_F32 ;
+    
+    Valeur_F32 = (F32) ( Points2 - Points1 ) ;
+    
+    if ( abs( Valeur_F32 ) > EPSILON )
+        {
+        MM_par_Points = (F32) ( Hauteur2 - Hauteur1 ) / Valeur_F32 ;
+        }
+    else
+        {
+        MM_par_Points = 0.0 ;
+        }
+        
+    MM_Offset = (F32)Hauteur1 - MM_par_Points * (F32)Points1 ;
+    
+    //PC2.printf("\r\n MM par pts %i: %f \r\n" ,Id, MM_par_Points) ;
+    //PC2.printf("\r\n Offset %i: %f \r\n" ,Id,MM_Offset) ;
+    
+    }
+/*******************************************************************/ 
+/*                                                                 */
+/*                 Frein                                           */
+/*                                                                 */
+/*        Ordre d'activation du frein                              */
+/*                                                                 */
+/*                                                                 */
+/*******************************************************************/    
+    void    Pilote::Frein ( U8 Etat )
+        {
+        Chaine_A_Emettre[0] = 0x02 ;
+        Chaine_A_Emettre[1] = ORDRE_FREIN ;
+        Chaine_A_Emettre[2] = Etat ;
+        Chaine_A_Emettre[3] = 0x03 ;
+        Chaine_A_Emettre[4] = 0x00 ;
+        
+        if( Statut_Ordre_En_Cours != ATTENTE )
+            {
+            Ordre_En_Cours = Chaine_A_Emettre [1] ;
+            Emission ( &Chaine_A_Emettre [0] , 4 ) ;
+            Statut_Ordre_En_Cours = ATTENTE ;
+            Etat_Frein = Etat ;
+            }
+        } 
+/*******************************************************************/ 
+/*                                                                 */
+/*                 Lecture                                         */
+/*                                                                 */
+/*        Ordre de lecture d'un parametre de variateur             */
+/*                                                                 */
+/*                                                                 */
+/*******************************************************************/        
+    void    Pilote::Lecture ( U16 Num_Parametre ) 
+        {
+        Chaine_A_Emettre[0] = 0x02 ;
+        Chaine_A_Emettre[1] = ORDRE_LECTURE ;
+        Chaine_A_Emettre[2] = Num_Parametre ;
+        Chaine_A_Emettre[3] = 0x03 ;
+        Chaine_A_Emettre[4] = 0x00 ;
+        
+        if( Statut_Ordre_En_Cours != ATTENTE )
+            {
+            Ordre_En_Cours = Chaine_A_Emettre [1] ;
+            Emission ( &Chaine_A_Emettre [0] , 4 ) ;
+            Statut_Ordre_En_Cours = ATTENTE ;
+            
+            }
+        }
+/*******************************************************************/ 
+/*                                                                 */
+/*                 Configure                                       */
+/*                                                                 */
+/*        Ordre de configuration d'un parametre variateur          */
+/*                                                                 */
+/*                                                                 */
+/*******************************************************************/ 
+    void    Pilote::Configure ( U16 Num_Parametre , S32 Valeur_S32 ) 
+        {
+        
+        Chaine_A_Emettre[0] = 0x02 ;
+        Chaine_A_Emettre[1] = ORDRE_CONFIGURE ;
+        Chaine_A_Emettre[2] = Num_Parametre ;
+        Chaine_A_Emettre[6] = (U8)( Valeur_S32 & 0x000000FF) ;
+        Valeur_S32 = Valeur_S32 >> 8 ;
+        Chaine_A_Emettre[5] = (U8)( Valeur_S32 & 0x000000FF) ;
+        Valeur_S32 = Valeur_S32 >> 8 ;
+        Chaine_A_Emettre[4] = (U8)( Valeur_S32 & 0x000000FF) ;
+        Valeur_S32 = Valeur_S32 >> 8 ;
+        Chaine_A_Emettre[3] = (U8)( Valeur_S32 & 0x000000FF) ; 
+        Chaine_A_Emettre[7] = 0x03 ;
+        Chaine_A_Emettre[8] = 0x00 ;
+        
+        if( Statut_Ordre_En_Cours != ATTENTE )
+            {
+            Ordre_En_Cours = Chaine_A_Emettre [1] ;
+            Emission ( &Chaine_A_Emettre [0] , 8 ) ;
+            Statut_Ordre_En_Cours = ATTENTE ;
+            
+            }
+        }     
+/*******************************************************************/ 
+/*                                                                 */
+/*                 Emission                                        */
+/*                                                                 */
+/*        Emission d'une trame vers le variateur                   */
+/*                                                                 */
+/*                                                                 */
+/*******************************************************************/ 
+    void Pilote::Emission ( U8 *pChaine , U8 Longueur ) 
+        {
+        U8  Index = 0 ; 
+    
+        if ( pPort->writeable() )
+            {
+            // Mesure du timeout
+            Debut_Emission_ms = Chrono_Pilote.read_ms() ;
+        
+            while ( Index < Longueur )
+                {
+                pPort->putc( *pChaine ) ;
+                //PC2.printf("\r\n  %i: %i \r\n" ,Id, *pChaine) ;
+                pChaine++ ;
+                Index++ ;              
+                } 
+            }
+        else
+            {
+            PC2.printf("\r\n  %i: Bloque \r\n" ,Id) ;
+            }
+            
+        }
+/*******************************************************************/ 
+/*                                                                 */
+/*                 Reception                                       */
+/*                                                                 */
+/*        Reception de la reponse du variateur                     */
+/*                                                                 */
+/*                                                                 */
+/*******************************************************************/    
+    void Pilote::Reception ( void ) 
+        {
+        U8  Index1 = 0 ;
+        U8  Index2 = 0 ; 
+        S16 Valeur_S16 ;
+        S32 Valeur_S32 ;
+        U8  *pChaine ;
+        
+        while ( pPort->readable() )
+            {
+            // Réception des caractères si il y en a
+            *pReception = pPort->getc() ;
+            //PC2.printf("\r\n %i",*pReception ) ;
+            pReception++ ;
+            Nb_Caracteres_Recus++ ;               
+            }
+        
+        pChaine = &Chaine_Recue[0] ;
+        
+        // La plus petite trame comporte 3 caractères
+        if ( Nb_Caracteres_Recus > 2 )
+            {
+            while ( *pChaine != 0x02 )
+                {
+                // Recherche d'un début de trame: STX = 0x02            
+                if ( Index2 == Nb_Caracteres_Recus )
+                    {
+                    // Pas de début de trame, on ecrase les caractères reçus et on s'en va!
+                    pReception = &Chaine_Recue[0] ;
+                    Nb_Caracteres_Recus = 0 ;
+                    //PC2.printf("\r\n Poubelle %i \r\n" ,Id) ;
+                    return ;
+                    }
+                pChaine++ ;
+                Index2++ ;
+                }
+            /**********************************************************************************/  
+            // Ordre d'arret
+            if ( *(pChaine+1) == ORDRE_ARRET )
+                {
+                //PC2.printf("\r\n Ordre d'Arret %i\r\n" ,Id) ;
+                if ( Nb_Caracteres_Recus < ( Index2 + 4 ) )
+                    {
+                    // Trame incomplete, on reviendra
+                    //PC2.printf("\r\n Arret incomplet %i \r\n" ,Id) ;
+                    return ;
+                    }
+                // Vérifie le caractere de fin de trame
+                if ( *(pChaine+4) == 0x03 )
+                    {
+                    // Trame OK, on efface
+                    //PC2.printf("\r\n Arret OK %i\r\n" ,Id) ;
+                    // On lit la mesure
+                    Valeur_S16 = (S16)(*(pChaine+2) ) * 256 + (S16)(*(pChaine+3)) ;
+                    Mesure_Courante = ( Mesure_Courante + Valeur_S16 ) / 2 ;
+                    
+                    // Calcule la hauteur en mm
+                    Valeur_S16= (S16)((F32) Mesure_Courante * MM_par_Points + MM_Offset ) ;
+                    
+                    if (   ( Valeur_S16 > Hauteur_mini )
+                        && ( Valeur_S16 < Hauteur_maxi ) )
+                        {
+                        Hauteur_Courante = ( Valeur_S16 + Hauteur_Courante ) / 2 ;
+                        }
+                    Vitesse_Courante = 0 ;
+                    // On recale la trame réponse
+                    Index2 = Index2 + 5 ;
+                    
+                    if ( Ordre_En_Cours == ORDRE_ARRET )
+                        {
+                        Statut_Ordre_En_Cours = VALIDE ;
+                        Fin_Reception_ms = Chrono_Pilote.read_ms() ;
+                        Dernier_Ordre_Confirme = ORDRE_ARRET ;
+                        COM_OK = TRUE ;
+                        }
+                    }
+                }
+            /***************************************************************************************/
+            // Ordre de mouvement automatique
+            else if ( ( *(pChaine+1) == ORDRE_DESCEND )
+                    ||( *(pChaine+1) == ORDRE_MONTE ) )
+                {
+                //PC2.printf("\r\n Ordre de mouvement %i\r\n",Id ) ;
+                if ( Nb_Caracteres_Recus < ( Index2 + 6 ) )
+                    {
+                    // Trame incomplete, on reviendra
+                    //PC2.printf("\r\n Mouvement Incomplet %i \r\n",Id ) ;
+                    return ;
+                    }
+                // Vérifie le caractere de fin de trame
+                if ( *(pChaine+6) == 0x03 )
+                    {
+                    // Trame OK, on lit la vitesse
+                    Valeur_S16= (S16) (*(pChaine+2)) * 256 + (S16) (*(pChaine+3)) ;
+                    Vitesse_Courante = ( Valeur_S16 + Vitesse_Courante ) / 2 ;
+                    // et la mesure
+                    Valeur_S16 = (S16) (*(pChaine+4)) * 256 + (S16) (*(pChaine+5)) ;
+                    Mesure_Courante = ( Mesure_Courante + Valeur_S16 ) / 2 ;
+                    
+                    // Calcule la hauteur en mm
+                    Valeur_S16 = (S16)((F32) Mesure_Courante * MM_par_Points + MM_Offset ) ;
+                    if (   ( Valeur_S16 > Hauteur_mini )
+                        && ( Valeur_S16 < Hauteur_maxi ) )
+                        {
+                        Hauteur_Courante = ( Valeur_S16 + Hauteur_Courante ) / 2 ;
+                        }
+                    
+                    
+                    // On recale la trame réponse
+                    Index2 = Index2 + 7 ;
+                    //PC2.printf("\r\n Ordre de mouvement %i OK\r\n",Id ) ;
+                    
+                    if ( Ordre_En_Cours == *(pChaine+1) )
+                        {
+                        Statut_Ordre_En_Cours = VALIDE ;
+                        Fin_Reception_ms = Chrono_Pilote.read_ms() ;
+                        COM_OK = TRUE ;
+                        Dernier_Ordre_Confirme = Ordre_En_Cours ;
+                        }
+                    }
+                }
+            /**********************************************************************************/  
+            // Ordre de frein
+            if ( *(pChaine+1) == ORDRE_FREIN )
+                {
+                //PC2.printf("\r\n Ordre Frein %i\r\n" ,Id) ;
+                if ( Nb_Caracteres_Recus < ( Index2 + 2 ) )
+                    {
+                    // Trame incomplete, on reviendra
+                    //PC2.printf("\r\n Frein incomplet %i \r\n" ,Id) ;
+                    return ;
+                    }
+                // Vérifie le caractere de fin de trame
+                if ( *(pChaine+2) == 0x03 )
+                    {
+                    // Trame OK
+                    //PC2.printf("\r\n Frein OK %i\r\n" ,Id) ;
+                    // On recale la trame réponse
+                    Index2 = Index2 + 3 ;
+  
+                    if ( Ordre_En_Cours == ORDRE_FREIN )
+                        {
+                        Statut_Ordre_En_Cours = VALIDE ;
+                        Fin_Reception_ms = Chrono_Pilote.read_ms() ;
+                        Dernier_Ordre_Confirme = ORDRE_FREIN ;
+                        COM_OK = TRUE ;
+                        }
+                    }
+                }
+            /**********************************************************************************/  
+            // Ordre de lecture parametre
+            if ( *(pChaine+1) == ORDRE_LECTURE )
+                {
+                //PC2.printf("\r\n Ordre Frein %i\r\n" ,Id) ;
+                if ( Nb_Caracteres_Recus < ( Index2 + 7 ) )
+                    {
+                    // Trame incomplete, on reviendra
+                    //PC2.printf("\r\n Frein incomplet %i \r\n" ,Id) ;
+                    return ;
+                    }
+                // Vérifie le caractere de fin de trame
+                if ( *(pChaine+7) == 0x03 )
+                    {
+                    // Trame OK
+                    //PC2.printf("\r\n Frein OK %i\r\n" ,Id) ;
+                    // Lecture du parametre
+                    Valeur_S32 = (S32) (*(pChaine+3)) * 256 + (S32) (*(pChaine+4)) ;
+                    Valeur_S32 = Valeur_S32 * 256 + (S32) (*(pChaine+5)) ;
+                    Parametres_Vario_S32[*(pChaine+2)] = Valeur_S32 * 256 + (S32) (*(pChaine+6)) ; 
+                    // On recale la trame réponse
+                    Index2 = Index2 + 8 ;
+  
+                    if ( Ordre_En_Cours == ORDRE_LECTURE )
+                        {
+                        Statut_Ordre_En_Cours = VALIDE ;
+                        Fin_Reception_ms = Chrono_Pilote.read_ms() ;
+                        Dernier_Ordre_Confirme = ORDRE_LECTURE ;
+                        COM_OK = TRUE ;
+                        }
+                    }
+                }
+            /**********************************************************************************/  
+            // Ordre de configuration parametre
+            if ( *(pChaine+1) == ORDRE_CONFIGURE )
+                {
+                //PC2.printf("\r\n Ordre Frein %i\r\n" ,Id) ;
+                if ( Nb_Caracteres_Recus < ( Index2 + 3 ) )
+                    {
+                    // Trame incomplete, on reviendra
+                    //PC2.printf("\r\n Frein incomplet %i \r\n" ,Id) ;
+                    return ;
+                    }
+                // Vérifie le caractere de fin de trame
+                if ( *(pChaine+3) == 0x03 )
+                    {
+                    // Trame OK
+                    //PC2.printf("\r\n Ecriture OK %i\r\n" ,Id) ;
+                    // Ecriture du parametre
+                    // On recale la trame réponse
+                    Index2 = Index2 + 4 ;                   
+  
+                    if ( Ordre_En_Cours == ORDRE_CONFIGURE )
+                        {
+                        Statut_Ordre_En_Cours = VALIDE ;
+                        Fin_Reception_ms = Chrono_Pilote.read_ms() ;
+                        Dernier_Ordre_Confirme = ORDRE_CONFIGURE ;
+                        COM_OK = TRUE ;
+                        }
+                    }
+                }
+            /**********************************************************************************/  
+            // La trame est traitée, on réaligne le reste des caracteres recus
+            Index1 = 0 ;
+            while ( Index2 < Nb_Caracteres_Recus )
+                {
+                Chaine_Recue [ Index1 ] = Chaine_Recue [ Index2 ] ;
+                Chaine_Recue [ Index2 ] = 0 ;
+                //PC2.printf("\t %i:%i",Index1,Chaine_Recue [ Index1 ]);
+                Index1++ ;
+                Index2++ ;
+                
+                }
+            Nb_Caracteres_Recus = Index1 ;
+            pReception = &Chaine_Recue[Nb_Caracteres_Recus] ;
+            }
+            // Gestion du timeout
+            if ( Statut_Ordre_En_Cours == ATTENTE )
+                {
+                if ( ( Chrono_Pilote.read_ms() - Debut_Emission_ms ) > TIMEOUT_RECEPTION_ms )
+                    {
+                    Statut_Ordre_En_Cours = DEFAUT ;
+                    Compteur_Timeout++ ;
+                    COM_OK = FALSE ;
+                    //PC2.printf("\n\r *********** Timeout : %i - %i \n\r",Id,Compteur_Timeout);
+                    }
+                }
+    }
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pilote.h	Thu Jun 22 09:33:04 2017 +0000
@@ -0,0 +1,153 @@
+/*******************************************************************/
+/*                                                                 */
+/*                 Pilote                                          */
+/*                                                                 */
+/*  Objet de pilotage de variateur                                 */
+/*                                                                 */
+/*                                                                 */
+/*******************************************************************/
+#ifndef _PILOTE_
+#define _PILOTE_
+
+#include "mbed.h"
+#include <Serial.h>
+#include "Constantes.h"
+#include "Variable.h"
+#include "time.h"
+
+// Etat des ordres variateur
+#define AUCUN               0
+#define ATTENTE             1
+#define VALIDE              2
+#define DEFAUT              3
+
+// Ordres variateur
+#define ORDRE_AUCUN         0x0
+#define ORDRE_ARRET         0x41
+#define ORDRE_MONTE         0x4D
+#define ORDRE_DESCEND       0x44
+#define ORDRE_FREIN         0x46
+#define ORDRE_LECTURE       0x4C
+#define ORDRE_CONFIGURE     0x43
+
+// Parametres variateur
+#define NB_PARAM_VARIATEUR  15
+#define VERSION             0x00
+#define STARTUP             0x01
+#define INCREMENT           0x02
+#define SEUIL_DEMARRAGE     0x03
+#define ACCELERATION        0x04
+#define DECELERATION        0x05
+#define KPV                 0x06
+#define KIV                 0x07
+#define KDV                 0x08
+#define KA                  0x09
+#define CONSIGNE            0x0A
+#define ETAT_EL             0x0B
+#define ETAT_SL             0x0C
+
+// Etats du frein du moteur
+#define SERRE               0
+#define DESSERRE            1
+
+#define LONGUEUR_CHAINE_EMISSION    100
+#define LONGUEUR_CHAINE_RECEPTION   100
+
+#define TIMEOUT_RECEPTION_ms       200
+#define DELAI_COMMANDE_ARRET_ms    500
+
+/**     Class Pilote
+*       Pilotage de variateur de pile de pont via liaison série et protocole 3R
+*/
+class Pilote
+{
+public:
+    /**     Constructeur
+    *       @param Id : Identifiant de l'instance
+    */
+    Pilote ( S16 Id);
+    
+    /**     Initialise et ouvre le port série
+    *       @param Baudrates  : Vitesse de la liaison série
+    *       @param bits       : Bits de données
+    *       @param Stop       : Bits de stop
+    */
+    void    Init ( int Baudrates, int bits,  int Stop) ;
+    /**     Ordre de marche de la pile
+    *       @param Mode       : Mode de fonctionnement
+    *       @param Sens       : Sens de déplacement
+    *       @param Hauteur    : Hauteur cible (mm)
+    *       @param Vitesse    : Consigne de vitesse (tr/min)
+    */
+    void    Marche ( U8 Mode, U8 Sens, S16 Hauteur, S16 Vitesse ) ;
+    /**     Ordre d'arret de la pile
+    */
+    void    Arret (void) ;
+    /**     Commande manuelle du frein
+    *       @param Etat       : Etat du frein {SERRE,DESSERRE}
+    */
+    void    Frein ( U8 Etat ) ;
+    /**     Lecture d'un parametre du variateur
+    *       @param Num_Parametre       : numéro du parametre à lire
+    */
+    void    Lecture ( U16 Num_Parametre ) ;
+    /**     Configuration d'un parametre du variateur
+    *       @param Num_Parametre       : numéro du parametre à configurer
+    *       @param Valeur              : nouvelle valeur du parametre
+    */
+    void    Configure ( U16 Num_Parametre , S32 Valeur ) ;
+    /**     Etalonnage de hauteur de la pile
+    *       @param Points1             : Hauteur en points de la mesure basse
+    *       @param Hauteur1            : Hauteur en mm de la mesure basse
+    *       @param Points2             : Hauteur en points de la mesure haute
+    *       @param Hauteur2            : Hauteur en mm de la mesure haute
+    */
+    void    Etalonnage (S16 Points1, S16 Hauteur1 , S16 Points2 , S16 Hauteur2 ) ; 
+    /**     Reception de la réponse du variateur
+    */ 
+    void    Reception ( void ) ;
+    
+    /**Pointeur du port série*/
+    Serial* pPort ;  
+    /**Hauteur courante de la pile (mm)*/ 
+    S16     Hauteur_Courante ;
+    /**Vitesse courante de la pile*/
+    S16     Vitesse_Courante ;
+    ///Hauteur de la pile (pts)
+    S16     Mesure_Courante ;
+    ///Hauteur cible du mouvement en cours (mm)
+    S16     Hauteur_Cible ;
+    ///Identifiant de l'instance
+    S16     Id ;
+    ///Compteur de timeouts de la liaison série
+    S16     Compteur_Timeout ;
+    ///Deplacement en cours (ARRET, MONTE, DESCEND)
+    U8      Etat_Deplacement ;
+    ///Etat de la commande manuelle de frein (SERRE, DESSERRE)
+    U8      Etat_Frein ;
+    ///Etat de la liaison série
+    U8      COM_OK ; 
+    ///Tableau de paramètres du variateur
+    S32     Parametres_Vario_S32[NB_PARAM_VARIATEUR] ;
+    
+private:
+    void    Emission ( U8 *pChaine , U8 Longueur ) ;
+    U8      Chaine_A_Emettre[LONGUEUR_CHAINE_EMISSION] ;   
+    U8      Chaine_Recue[LONGUEUR_CHAINE_RECEPTION] ;
+    Timer   Chrono_Pilote ;
+    Timer   Chrono_Arret ;
+    U8      *pEmission ;
+    U8      *pReception ;
+    U8      Nb_Caracteres_Recus ;
+    U8      Statut_Ordre_En_Cours ;
+    U8      Ordre_En_Cours ;
+    U8      Dernier_Ordre_Confirme ;
+    F32     MM_par_Points ;
+    F32     MM_Offset ;
+    int     Debut_Emission_ms ;
+    int     Fin_Reception_ms ;
+    int     Age_Ordre_Arret_ms ;
+    
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Port_Serie.cpp	Thu Jun 22 09:33:04 2017 +0000
@@ -0,0 +1,247 @@
+/*******************************************************************/
+/*                                                                 */
+/*                 Port Série                                      */
+/*                                                                 */
+/*  Gestion du port série par interruption                         */
+/*                                                                 */
+/*                                                                 */
+/*******************************************************************/
+
+#include "mbed.h"
+#include "Port_Serie.h"
+#include "Modbus.h"
+
+Serial  RS(p28 , p27) ;
+Serial PC8(USBTX, USBRX) ;
+Timer   Chrono_Serie ;
+
+volatile    U8  Buffer_Emission_U8[TAILLE_BUFFER_EMISSION] ;
+volatile    U8  Pointeur_Emission_U8 ;
+volatile    U8  Nb_Caracteres_A_Emettre_U8 ;
+volatile    U8  Buffer_Reception_U8[TAILLE_BUFFER_RECEPTION] ;
+volatile    U8  Pointeur_Reception_U8 ;
+volatile    U8  Nb_Caracteres_Attendus ;
+volatile    U8  Numero_Ordre_En_Reception_U8 ;
+volatile    U8  Numero_Ordre_En_Emission_U8 ;
+volatile    U8  Index ;
+volatile    S32 Date_Dernier_Caractere_S32 ;
+volatile    S32 Temps_alloue_Reception_S32 ;
+static      S32 Temps_alloue_Caractere_S32 ;
+
+/******* Réception sous interruption ***************************/
+void    iReception_Serie ()
+    { 
+    U8 Car ; 
+    // Si premier caractere recu, enclenche le chrono
+    if ( Pointeur_Reception_U8 == 0 )
+        {
+        //Chrono_Serie.start() ;
+        }
+    // Si il y a des caractères dans le buffer
+    while ( RS.readable() )
+        {// Réception d'un caractère
+        Car=RS.getc();
+        Buffer_Reception_U8 [ Pointeur_Reception_U8 ] = Car ;
+        //RS.putc(Car) ;
+        Pointeur_Reception_U8++ ;
+        }
+    if ( ( Pointeur_Reception_U8 > 0 )
+        &&( Ordres[Numero_Ordre_En_Reception_U8].Etat_U8 == ATTENTE ) )
+        {// Si au moins un caractère recu, la réception est en cours
+        Ordres[Numero_Ordre_En_Reception_U8].Etat_U8 = RECEPTION ;
+        }
+    //PC8.printf("\r\n    Serie : Reception %s ", &Buffer_Reception_U8 [0]) ;
+    
+    //Date_Dernier_Caractere_S32 = Chrono_Serie.read_us() ;
+    // Analyse de la trame
+    if ( ( Buffer_Reception_U8 [ 0 ] == SLAVE_ID )
+        || ( Buffer_Reception_U8 [ 0 ] == MB_ADDRESSE_BROADCAST ) )
+        {// Adresse de l'esclave, ou Adresse de broadcast
+        //PC8.printf("\r\n    Serie : Adresse %i ", Buffer_Reception_U8 [0]) ;
+        if ( Pointeur_Reception_U8 >= 6 ) 
+            {
+            //PC8.printf("\r\n    Serie : Func %i ", Buffer_Reception_U8 [1]) ;           
+            if (( Buffer_Reception_U8 [ 1 ] == MB_FUNC_READ_HOLDING_REGISTER )
+                ||( Buffer_Reception_U8 [ 1 ] == MB_FUNC_READ_INPUT_REGISTER ))
+                {// Fonction 3 ou 4, Lecture de registres
+                Nb_Caracteres_Attendus = 8 ;
+                //PC8.printf("\r\n    Serie : Func %i ", Buffer_Reception_U8 [1]) ;
+                }
+            else if ( Buffer_Reception_U8 [ 1 ] == MB_FUNC_WRITE_MULTIPLE_REGISTERS )
+                {// Fonction 16 (0x10), écriture de registres
+                Nb_Caracteres_Attendus = 9 + Buffer_Reception_U8 [ 5 ] * 2 ;
+                }
+            }  
+            
+        if ( Pointeur_Reception_U8 >= Nb_Caracteres_Attendus )
+            {
+            // On a recu une trame complète
+            //PC8.printf("\r\n    Serie : trame %d complete %d / %d",Numero_Ordre_En_Reception_U8,Pointeur_Reception_U8,Nb_Caracteres_Attendus) ;
+
+                Index = 0 ;
+                //Chrono_Serie.stop() ;
+                while( Index <  Pointeur_Reception_U8 )
+                    {// Copie la trame dans l'ordre en cours de réception
+                    Ordres[Numero_Ordre_En_Reception_U8].Trame_Recue_aU8[Index] = Buffer_Reception_U8 [ Index ] ;
+                    Index++ ;
+                    }
+            // Nombre de caractères de l'ordre
+            Ordres[Numero_Ordre_En_Reception_U8].Nb_Caracteres_Recus_U8 = Pointeur_Reception_U8 ;   
+            // Fin de réception
+            Ordres[Numero_Ordre_En_Reception_U8].Etat_U8 = RECU ;
+            
+            }
+        
+        }
+    else 
+        {
+        // Le message n'est pas pour nous, on purge le buffer
+        Pointeur_Reception_U8 = 0 ;
+        Ordres[Numero_Ordre_En_Reception_U8].Etat_U8 = ATTENTE ;
+        Nb_Caracteres_Attendus = TAILLE_BUFFER_RECEPTION ;
+        //Chrono_Serie.stop() ;
+        PC8.printf("\r\n    Serie : pas pour nous %i ",Buffer_Reception_U8 [ 1 ]) ;
+        }
+    
+    }
+/************ Enclenchement de la réception *****************/  
+void    vPort_Serie_Reception ( U8 Numero_Ordre_U8 ) 
+    {
+    if ( (Ordres[Numero_Ordre_En_Reception_U8].Etat_U8 != RECEPTION )
+        && (Ordres[Numero_Ordre_En_Reception_U8].Etat_U8 != ATTENTE ))
+        {// La réception en cours est terminée
+        if ( ( Ordres[Numero_Ordre_U8].Etat_U8 == RECU )
+            ||( Ordres[Numero_Ordre_U8].Etat_U8 == TRAITE )
+            ||( Ordres[Numero_Ordre_U8].Etat_U8 == ARRET ) )
+            {// L'ordre est pret à être recu
+            Numero_Ordre_En_Reception_U8 =  Numero_Ordre_U8 ;
+            Ordres[Numero_Ordre_En_Reception_U8].Etat_U8 = ATTENTE ;
+            Pointeur_Reception_U8 = 0 ;
+            Nb_Caracteres_Attendus = TAILLE_BUFFER_RECEPTION ;
+            //PC8.printf("\r\n Debut reception %i Etat %i ",Numero_Ordre_En_Reception_U8,Ordres[Numero_Ordre_En_Reception_U8].Etat_U8) ;
+            }
+        //PC8.printf("\r\n Reception1 %i Etat %i ",Numero_Ordre_U8,Ordres[Numero_Ordre_U8].Etat_U8) ;
+        }
+    //PC8.printf("\r\n Reception2 %i Etat %i ",Numero_Ordre_En_Reception_U8,Ordres[Numero_Ordre_En_Reception_U8].Etat_U8) ;
+    }
+/************ Emission de la trame ************************/
+void    iEmission ( void )
+    {
+    // Si le buffer n'est pas saturé et qu'il reste des caractères à émettre
+    while ( ( Pointeur_Emission_U8 < Nb_Caracteres_A_Emettre_U8 ) )  
+        {// Emission d'un caractère
+        RS.putc( (U8) Buffer_Emission_U8[ Pointeur_Emission_U8 ] ) ;
+        Pointeur_Emission_U8++ ;
+        //PC8.printf("\r\n    Serie : Emission %i ", Buffer_Emission_U8[ Pointeur_Emission_U8-1 ]) ;
+        }
+    if (  Pointeur_Emission_U8 >= Nb_Caracteres_A_Emettre_U8 )
+        {// Tous les caractères sont émis, cloture l'émission
+        Ordres[Numero_Ordre_En_Emission_U8].Etat_U8 = FIN ;
+        Pointeur_Emission_U8 = 0 ;
+        Nb_Caracteres_A_Emettre_U8 = 0 ;
+        }
+    else
+        {// Le buffer est saturé, on reviendra plus tard
+        
+        }
+    }  
+/************ Emission de la réponse ************************/
+void    vPort_Serie_Emission ( U8   Numero_Ordre_U8 )
+    {
+    U8  Index_U8 ;
+    
+    
+    if (Ordres[Numero_Ordre_En_Emission_U8].Etat_U8 != EMISSION )
+        {// L'émission en cours est terminée
+        if (Ordres[Numero_Ordre_U8].Etat_U8 == TRAITE )
+            {// L'ordre est pret à être émis
+            Ordres[Numero_Ordre_U8].Etat_U8 = EMISSION ;
+            Numero_Ordre_En_Emission_U8 = Numero_Ordre_U8 ;
+            Nb_Caracteres_A_Emettre_U8 = Ordres[Numero_Ordre_U8].Nb_Caracteres_A_Emettre_U8 ;
+            Index_U8 = 0 ;
+            // Copie la trame dans le buffer
+            while( Index_U8 < Nb_Caracteres_A_Emettre_U8 )
+                {
+                Buffer_Emission_U8 [ Index_U8 ] = Ordres[Numero_Ordre_U8].Trame_Reponse_aU8 [Index_U8] ;
+                Index_U8++ ;
+                }
+            Pointeur_Emission_U8 = 0 ;
+            }
+        
+        //PC8.printf("\r\n    Serie : Emission %i : %i/%i",Numero_Ordre_En_Emission_U8, Pointeur_Emission_U8,Nb_Caracteres_A_Emettre_U8) ; 
+        }
+    // Emission de la trame
+    iEmission() ;
+    }
+/************ Initialisation du Port ************************/
+void    vPort_Serie_Init(int Baudrate) 
+    {
+    // Initialisation du port RS
+    RS.baud(Baudrate) ;
+    // Purge des buffers
+    for ( Pointeur_Emission_U8 = 0 ; Pointeur_Emission_U8 < TAILLE_BUFFER_EMISSION ; Pointeur_Emission_U8++ )
+        {
+        Buffer_Emission_U8[Pointeur_Emission_U8] = 0 ;
+        }
+    for ( Pointeur_Reception_U8 = 0 ; Pointeur_Reception_U8 < TAILLE_BUFFER_RECEPTION ; Pointeur_Reception_U8++ )
+        {
+        Buffer_Reception_U8[Pointeur_Reception_U8] = 0 ;
+        }
+    
+    Pointeur_Emission_U8 = 0 ;
+    Pointeur_Reception_U8 = 0 ;
+    Numero_Ordre_En_Reception_U8 = 0 ;
+    Numero_Ordre_En_Emission_U8 = 0 ;
+    //PC8.printf("\r\n    Serie : Init %i ", Baudrate) ;
+    // Temps alloué pour 1 caractere = 10bits / Baudrate x 1E6 us
+    Temps_alloue_Caractere_S32 = 10000000 / Baudrate * 3 ;
+    }
+    
+/************ Ouverture du port Série **********************/
+void    vPort_Serie_Ouvre(void) 
+    {
+    // Purge du buffer de réception
+    while( RS.readable() )
+        {
+        Buffer_Reception_U8[0] = RS.getc() ;
+        }
+    Buffer_Reception_U8[0] = 0 ;
+    
+    vPort_Serie_Reception ( 0 ) ;
+    RS.attach (&iReception_Serie , RS.RxIrq) ;
+    
+    //RS.printf ("Debut") ;
+    //PC8.printf("\r\n    Serie : Attach ") ;
+    
+    }
+ 
+/************ Controle de réception **********************/    
+U8    cControle_Reception( U8 Numero_Ordre_U8 )
+    {/*
+    if ( Numero_Ordre_U8 != Numero_Ordre_En_Reception_U8 )
+        {// La réception est arrétée
+        //Chrono_Serie.stop() ;
+        return ( ARRET ) ;
+        }
+    if ( Chrono_Serie.read_us() > ( Temps_alloue_Caractere_S32 * Nb_Caracteres_Attendus ) )
+        {// Dépassement du temps alloué
+        //Chrono_Serie.stop() ;
+        Numero_Ordre_En_Reception_U8++ ;
+        Pointeur_Reception_U8 = 0 ;
+        Nb_Caracteres_Attendus = TAILLE_BUFFER_RECEPTION ;
+        
+        return ( TIMEOUT ) ;
+        }*/
+    return ( RECEPTION ) ;
+    }
+   
+/************ Fermeture du port Série **********************/   
+void    vPort_Serie_Ferme( void ) 
+    {
+    //RS.detach() ;
+    }
+ 
+/************ Cloture du port Série **********************/    
+void    vPort_Serie_Cloture( void ) 
+    {
+    }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Port_Serie.h	Thu Jun 22 09:33:04 2017 +0000
@@ -0,0 +1,33 @@
+/*******************************************************************/
+/*                                                                 */
+/*                 Port Série                                      */
+/*                                                                 */
+/*  Gestion du port série par interruption                         */
+/*                                                                 */
+/*                                                                 */
+/*******************************************************************/
+#ifndef _PORT_SERIE_
+#define _PORT_SERIE_
+
+#include "mbed.h"
+#include <Serial.h>
+
+#include "Constantes.h"
+#include "Variable.h"
+
+#include "time.h"
+
+#define TAILLE_BUFFER_EMISSION  128
+#define TAILLE_BUFFER_RECEPTION  128
+
+
+
+extern  void    vPort_Serie_Init(int Baudrate) ;
+extern  void    vPort_Serie_Ouvre( void ) ;
+extern  void    vPort_Serie_Ferme( void ) ;
+extern  void    vPort_Serie_Cloture( void ) ; 
+extern  void    vPort_Serie_Emission ( U8 Numero_Ordre_U8 ) ;
+extern  U8      cControle_Reception( U8 Numero_Ordre_U8 ) ;
+extern  void    vPort_Serie_Reception ( U8 Numero_Ordre_U8 ) ;
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Synchronisation.cpp	Thu Jun 22 09:33:04 2017 +0000
@@ -0,0 +1,155 @@
+/*******************************************************************/
+/*                                                                 */
+/*                Synchronisation                                  */
+/*                                                                 */
+/*  Procédures de synchronisation des piles du pont Bacalan        */
+/*                                                                 */
+/*  Creation : 3R MONTAUBAN                                        */
+/*******************************************************************/
+
+#include "Synchronisation.h"
+
+S16 Ecart_Synchro_Avant ;
+F32 Cumul_Ecarts_Synchro_F32 ;
+F32 Correction_Synchro_F32 ;
+
+/**     void    vSynchro_Initialise ( void )
+*       Procédure appelée à chaque mise en route en mode automatique (synchronisé)
+*/
+void    vSynchro_Initialise ( void )
+    {// Initialisation des variables de synchronisation
+    Ecart_Synchro_Avant = 0 ;
+    Cumul_Ecarts_Synchro_F32 = 0.0 ;
+    Correction_Synchro_F32 = (F32) Correction_Synchro ;
+    }
+
+void    vSynchronise ( U8 Mode_Synchronisation, U8 Sens )
+    {
+    F32 Correction_F32 ;
+    
+    switch ( Mode_Synchronisation )
+        {
+        case CUSTOM :
+            {
+            // Ecrivez ici votre code personnalisé pour la synchronisation des piles du pont
+            Consigne_Vitesse_RD = Consigne_Vitesse_Auto ;
+            Consigne_Vitesse_RG = Consigne_Vitesse_Auto ;
+            break ;
+            }
+        case DEUX_VITESSES :
+            {
+            // Calcul de l'écart de synchronisation
+            Ecart_Synchronisation = ( Hauteur_RD - Hauteur_RG + Ecart_Synchro_Avant ) / 2 ;
+            Ecart_Synchro_Avant = Ecart_Synchronisation ;
+                 
+            if ( abs( Ecart_Synchronisation ) < Defaut_Mineur_Synchro )
+                {// Pas d'écart de synchronisation significatif: meme vitesse pour les 2 rives
+                Consigne_Vitesse_RD = Consigne_Vitesse_Auto ;
+                Consigne_Vitesse_RG = Consigne_Vitesse_Auto ;
+                }
+            
+            else if ( Sens == MONTE )
+                {// Le pont monte, et l'ecart de synchronisation nécessite une correction de vitesse
+                if ( Ecart_Synchronisation > Defaut_Majeur_Synchro )        
+                    {// Montée et Hauteur_RD > Hauteur_RG
+                    Consigne_Vitesse_RD = (S16)( (F32)Consigne_Vitesse_Auto * Correction_Synchro_F32 / 100.0 ) ;
+                    Consigne_Vitesse_RG = Consigne_Vitesse_Auto ;
+                    }
+                else if ( Ecart_Synchronisation < -Defaut_Majeur_Synchro )  
+                    {// Montée et Hauteur_RD < Hauteur_RG
+                    Consigne_Vitesse_RD = Consigne_Vitesse_Auto ;
+                    Consigne_Vitesse_RG = (S16)( (F32)Consigne_Vitesse_Auto * Correction_Synchro_F32 / 100.0 ) ;
+                    }
+        
+                }
+            else if ( Sens == DESCEND )
+                {// Le pont descend, et l'ecart de synchronisation nécessite une correction de vitesse
+                if ( Ecart_Synchronisation > Defaut_Majeur_Synchro )            
+                    {// Descente et Hauteur_RD > Hauteur_RG
+                    Consigne_Vitesse_RD = Consigne_Vitesse_Auto ;
+                    Consigne_Vitesse_RG = (S16)( (F32)Consigne_Vitesse_Auto * Correction_Synchro_F32 / 100.0 ) ;
+                    }
+                else if ( Ecart_Synchronisation < (-Defaut_Majeur_Synchro) )    
+                    {// Descente et Hauteur_RD < Hauteur_RG
+                    Consigne_Vitesse_RD = (S16)( (F32)Consigne_Vitesse_Auto * Correction_Synchro_F32 / 100.0 ) ;
+                    Consigne_Vitesse_RG = Consigne_Vitesse_Auto ;
+                    }
+                }
+            break ;
+            }
+            
+        case RD_SUIT_RG :
+            {
+            // Calcul de l'écart de synchronisation
+            if ( Sens == MONTE )
+                {
+                Ecart_Synchronisation = ( Hauteur_RG - Hauteur_RD + Ecart_Synchro_Avant ) / 2 ;
+                }
+            else
+                {
+                Ecart_Synchronisation = ( Hauteur_RD - Hauteur_RG + Ecart_Synchro_Avant ) / 2 ;
+                }
+            Cumul_Ecarts_Synchro_F32 = Cumul_Ecarts_Synchro_F32 + (F32) Ecart_Synchronisation ;
+                            
+            Consigne_Vitesse_RG = Consigne_Vitesse_Auto ;
+            
+            // Anticipation
+            Correction_F32 = (F32) Consigne_Vitesse_Auto * (F32) Anticipation_Synchro / 100.0 ;
+            
+            // Proportionnel
+            Correction_F32 = Correction_F32 + (F32) KP_Synchro * (F32) Ecart_Synchronisation / 100.0 ;
+            
+            // Intégral
+            Correction_F32 = Correction_F32 + (F32) KI_Synchro * (F32) Cumul_Ecarts_Synchro_F32 / 100.0 ;
+            
+            // Dérivé
+            Correction_F32 = Correction_F32 + (F32) KD_Synchro * ( (F32) Ecart_Synchronisation - (F32) Ecart_Synchro_Avant ) / 100.0 ;
+            
+            Consigne_Vitesse_RD = (S16) Correction_F32 ;
+            
+            Ecart_Synchro_Avant = Ecart_Synchronisation ;
+            break ;
+            }
+            
+        case RG_SUIT_RD :
+            {
+            // Calcul de l'écart de synchronisation
+            if ( Sens == MONTE )
+                {
+                Ecart_Synchronisation = ( Hauteur_RD - Hauteur_RG + Ecart_Synchro_Avant ) / 2 ;
+                }
+            else
+                {
+                Ecart_Synchronisation = ( Hauteur_RG - Hauteur_RD + Ecart_Synchro_Avant ) / 2 ;
+                }
+            
+            Cumul_Ecarts_Synchro_F32 = Cumul_Ecarts_Synchro_F32 + (F32) Ecart_Synchronisation ;
+                            
+            Consigne_Vitesse_RD = Consigne_Vitesse_Auto ;
+            
+            // Anticipation
+            Correction_F32 = (F32) Consigne_Vitesse_Auto * (F32) Anticipation_Synchro / 100.0 ;
+            
+            // Proportionnel
+            Correction_F32 = Correction_F32 + (F32) KP_Synchro * (F32) Ecart_Synchronisation / 100.0 ;
+            
+            // Intégral
+            Correction_F32 = Correction_F32 + (F32) KI_Synchro * (F32) Cumul_Ecarts_Synchro_F32 / 100.0 ;
+            
+            // Dérivé
+            Correction_F32 = Correction_F32 + (F32) KD_Synchro * ( (F32) Ecart_Synchronisation - (F32) Ecart_Synchro_Avant ) / 100.0 ;
+            
+            Consigne_Vitesse_RG = (S16) Correction_F32 ;
+            
+            Ecart_Synchro_Avant = Ecart_Synchronisation ;
+            break ;
+            }
+        case AUCUN :
+        default :
+            {
+            // Pas de correction de vitesse pour la synchronisation
+            Consigne_Vitesse_RD = Consigne_Vitesse_Auto ;
+            Consigne_Vitesse_RG = Consigne_Vitesse_Auto ;
+            }
+        }
+    }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Synchronisation.h	Thu Jun 22 09:33:04 2017 +0000
@@ -0,0 +1,40 @@
+/*******************************************************************/
+/*                                                                 */
+/*                Synchronisation                                  */
+/*                                                                 */
+/*  Procédures de synchronisation des piles du pont Bacalan        */
+/*                                                                 */
+/*                                                                 */
+/*******************************************************************/
+#ifndef _SYNCHRO_
+#define _SYNCHRO_
+
+#include "mbed.h"
+#include "Constantes.h"
+#include "Variable.h"
+
+
+
+/**     void    vSynchronise ( U8 Mode_Synchronisation, U8 Sens )
+*       Procédure appelée à chaque cycle (100ms) pour corriger la vitesse des piles en fonction de leur hauteur
+*       @param <Mode_Synchronisation>   Mode choisi par l'utilisateur
+*                                       CUSTOM : votre procedure de synchronisation est utilisée
+*                                       DEUX_VITESSES : La pile en avance passe en vitesse lente pour se laisser rattraper
+*                                       AUCUN : La consigne de vitesse est constante pour les 2 piles
+*
+*       @param <Sens>                   Sens du déplacement
+*                                       MONTE
+*                                       DESCEND
+*
+*       Utilise les variables:
+*       Consigne_Vitesse_Auto           Consigne de vitesse demandé par l'utilisateur (tr/min)
+*       Consigne_Vitesse_RD             Consigne de vitesse calculée pour la rive droite (tr/min)
+*       Consigne_Vitesse_RG             Consigne de vitesse calculée pour la rive gauche (tr/min)
+*       Hauteur_RG                      Hauteur de la pile gauche (mm)
+*       Hauteur_RD                      Hauteur de la pile droite (mm)
+*/
+extern  void    vSynchronise ( U8 Mode_Synchronisation, U8 Sens ) ;
+extern  void    vSynchro_Initialise ( void ) ;
+
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Variable.cpp	Thu Jun 22 09:33:04 2017 +0000
@@ -0,0 +1,114 @@
+//***********************************************************************************/
+//
+//          Variables globales du Pont Bacalan
+//
+//************************************************************************************/
+
+#include <mbed.h>
+#include "Constantes.h"
+
+int i, j;
+
+
+
+U16 usRegInputStart = REG_INPUT_START;
+S16 Memoire_S16[REG_INPUT_NREGS];
+
+//****************************************************************************
+//
+//      Initialisation des variables
+//
+//****************************************************************************
+bool Init_Variables(void) 
+    {
+    // Initialise some registers
+    for (i = 0; i < REG_INPUT_NREGS; i++) 
+        {
+        Memoire_S16[i] = 0;
+        } 
+    
+    //Paramètres Memoire
+    Sauvegarde_automatique = 0;
+    Etalonnage_effectue = 0;
+    Sauver_Vers_Flash =0;
+    Etalonnage_en_cours=0;
+    
+    RAZ =0;
+    
+    Mode_Debug = 1;
+    Periode_Scrutation_ms = 100 ;    // 0.1s
+
+    Mode_Fonctionnement = MODE_ARRET ;
+    Mode_Synchro = RD_SUIT_RG ;
+    
+    BTN_Arret = 1 ;
+    BTN_Monte = 0 ;
+    BTN_Descend = 0 ;
+    
+    BTN_Descend_RD = 0 ;
+    BTN_Monte_RD = 0 ;
+    
+    BTN_Monte_RG = 0 ;
+    BTN_Descend_RG = 0 ;
+    
+    Consigne_Vitesse_Auto = 2500 ;
+    Consigne_Vitesse_Manu = 1500 ;
+    Consigne_Haute_P = 450 ;
+    Consigne_Basse_P= 5 ;
+
+
+    Hauteur_mini = -10 ;
+    Hauteur_maxi = 470 ;
+    Vitesse_mini = 0 ;
+    Vitesse_maxi = 4000 ;
+    
+    // Synchronisation
+    Defaut_Mineur_Synchro = 5 ;
+    Defaut_Majeur_Synchro = 10 ;
+    Defaut_Critique_Synchro = 35 ;
+    Correction_Synchro = 90 ;
+    Anticipation_Synchro = 100 ;
+    KP_Synchro = 2000 ;
+    KI_Synchro = 100 ;
+    KD_Synchro = 0 ;
+    
+    
+    // Etalonnage
+    Hauteur_RD1_mm = 0 ;    //0
+    Hauteur_RD2_mm = 400 ;  //500
+    Hauteur_RD1_pts = 80 ; //100
+    Hauteur_RD2_pts = 2600 ; //3400
+    Hauteur_RG1_mm = 0 ;    //0
+    Hauteur_RG2_mm = 400 ;  //500
+    Hauteur_RG1_pts = 80 ; //100
+    Hauteur_RG2_pts = 2600 ; //3400
+    
+    // Parametres variateur  
+    Param_Version_RD = 100 ;
+    Param_Startup_RD = 1000 ;
+    Param_Increment_RD = 50 ;
+    Param_Seuil_Demarrage_RD = 500 ;
+    Param_Acceleration_RD = 20 ;
+    Param_Deceleration_RD = 20 ;
+    Param_Kpv_RD = 1000 ;
+    Param_Kiv_RD = 200 ;
+    Param_Kdv_RD = 0 ;
+    Param_Kav_RD = 1000 ;
+    Param_Consigne_RD = 1500 ;
+
+    //Parametres variateur rive gauche
+    Param_Version_RG = 100 ;
+    Param_Startup_RG = 1000 ;
+    Param_Increment_RG = 50 ;
+    Param_Seuil_Demarrage_RG = 500 ;
+    Param_Acceleration_RG = 20 ;
+    Param_Deceleration_RG = 20 ;
+    Param_Kpv_RG = 1000 ;
+    Param_Kiv_RG = 200 ;
+    Param_Kdv_RG = 0 ;
+    Param_Kav_RG = 1000 ;
+    Param_Consigne_RG = 1500 ;
+
+    return (1);
+    }
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Variable.h	Thu Jun 22 09:33:04 2017 +0000
@@ -0,0 +1,32 @@
+//***********************************************************************************/
+//
+//          Variables globales du thermocube
+//
+//************************************************************************************/
+#ifndef _VAR_
+#define _VAR_
+
+#include <mbed.h>
+#include "Constantes.h"
+//#include "mb.h"
+#include "time.h"
+
+
+extern  int i,j ; 
+
+
+
+extern  float Coefficient;
+
+//extern  S16   Mode_Fonctionnement;
+
+extern  U16   usRegInputStart ;
+extern  S16   Memoire_S16[REG_INPUT_NREGS];
+
+extern  bool Init_Variables (void);
+extern  void Init_Mode_Libre();
+
+#endif
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Thu Jun 22 09:33:04 2017 +0000
@@ -0,0 +1,152 @@
+//******************************************************************
+//
+//      Pont Bacalan
+//
+//  Logiciel de pilotage du Pont Bacalan:
+//  - Afficheur Modbus autonome via RS422 4 fils
+//  - 2 variateur en RS422 4 fils
+//  - ? sorties logiques
+//  - ? entrées logiques
+// 
+//
+//********************************************************************
+
+#include "mbed.h"
+
+#include "Constantes.h"
+#include "Variable.h"
+#include "Pilote.h"
+#include "Modbus.h"
+#include "Synchronisation.h"
+#include "Gemma.h"
+
+
+#define VERSION_SOFT    10116
+
+// Objet liaison série sur USB pour mode debug
+Serial PC1(USBTX, USBRX) ;
+
+// Objet liaison série vers les variateurs
+Serial VAR_RD (p13, p14) ;
+Serial VAR_RG (p9, p10) ;
+
+// Objet pilote, de gestion du dialogue avec les variateurs
+Pilote Rive_Droite (1) ;
+Pilote Rive_Gauche (2) ;
+
+// Chronomètre
+Timer   Chrono ;
+
+int main()
+    {
+
+    int debut_boucle_us;
+    int fin_boucle_us;
+    int Duree_us;
+
+    F32 Valeur_F32 ;
+    F32 Hauteur_Avant_F32 [TAILLE_TABLEAU_HAUTEURS] ;
+    F32 Vitesse_Avant_F32 = 0.0 ;
+       
+    S16 Index ;
+    
+    // Initialisation du Modbus
+    vModbus_Init(115200) ;
+    vModbus_Start() ;
+
+    //Initialisation des variables
+    Init_Variables();
+    Version_Soft = VERSION_SOFT ;
+    
+    Index = 0 ;
+    while ( Index < TAILLE_TABLEAU_HAUTEURS )
+        {
+        Hauteur_Avant_F32 [ Index] = 0.0 ;
+        Index++ ;
+        }
+    
+    // Initialisation des pilotes de varialeur
+    Rive_Droite.pPort = &VAR_RD ;
+    Rive_Gauche.pPort = &VAR_RG ;
+    
+    Rive_Droite.Init ( 115200 , 8 , 1 ) ;
+    Rive_Droite.Id = 1 ;
+    Rive_Gauche.Init ( 115200 , 8 , 1 ) ;
+    Rive_Gauche.Id = 2 ;
+    
+    Rive_Droite.Etalonnage (Hauteur_RD1_pts , Hauteur_RD1_mm , Hauteur_RD2_pts , Hauteur_RD2_mm ) ;
+    Rive_Gauche.Etalonnage (Hauteur_RG1_pts , Hauteur_RG1_mm , Hauteur_RG2_pts , Hauteur_RG2_mm ) ;   
+    
+    //Ininialise_Rampes () ;
+    //Affiche_Motif ( 0 ) ;
+    
+    // Initialisation du Gemma
+    vGemma_Init () ;
+    
+    Chrono.start() ;
+    
+    while (true) 
+        {
+        // Lecture du temps en début de boucle
+        debut_boucle_us = 0;//Chrono.read_us() ;
+        Chrono.reset();
+        fin_boucle_us = debut_boucle_us + (int)Periode_Scrutation_ms * 1000.0 ;  
+              
+        // Gestion du Modbus
+        vModbus() ;
+        
+        // Gestion du mode de fonctionnement
+        vGemma ( &Rive_Droite ,  &Rive_Gauche ) ;
+        
+        // Gestion de l'eclairage des rampes
+        //vRampe_RGB () ; 
+            
+        // Duree de la boucle en µs
+        Duree_us =  Chrono.read_us() - debut_boucle_us  ;
+        Duree_Boucle_us = (S16)( Duree_us ) ;
+        
+        //PC1.printf("\r\n Duree : %d \r\n",Duree_us) ;
+        //PC1.printf("\r\n Duree : %d / %X \r\n",Duree_us,Duree_Boucle_us);
+        
+        while( Chrono.read_us() < fin_boucle_us )
+            {
+            Rive_Droite.Reception () ;
+            Rive_Gauche.Reception () ;
+            vModbus() ;
+            wait_us(200) ;
+            }
+
+          
+        // Traitement des réponses des variateurs
+        Mesure_RD = Rive_Droite.Mesure_Courante ;
+        Vitesse_RD = Rive_Droite.Vitesse_Courante ;
+        Hauteur_RD = Rive_Droite.Hauteur_Courante ;
+        Etat_COM_RD = Rive_Droite.COM_OK  ;
+        Compteur_Timeout_RD = Rive_Droite.Compteur_Timeout ;
+        PC1.printf("\r\n RD : %i \t %i \t %i \t %i\r\n",Mesure_RD,Hauteur_RD,Vitesse_RD,Compteur_Timeout_RD);
+        
+        Mesure_RG = Rive_Gauche.Mesure_Courante ;
+        Vitesse_RG = Rive_Gauche.Vitesse_Courante ;
+        Hauteur_RG = Rive_Gauche.Hauteur_Courante ;
+        Etat_COM_RG = Rive_Gauche.COM_OK  ;
+        Compteur_Timeout_RG = Rive_Gauche.Compteur_Timeout ;
+        PC1.printf("\r\n RG : %i \t %i \t %i \t %i\r\n",Mesure_RG,Hauteur_RG,Vitesse_RG,Compteur_Timeout_RG);
+        
+        Hauteur_P = ( Hauteur_RD + Hauteur_RG ) / 2 ;
+        Ecart_Synchronisation =  Hauteur_RD - Hauteur_RG ; 
+        //PC1.printf("\r\n Hauteur P : %i  \r\n",Hauteur_P);
+        //PC1.printf("0") ;
+        
+        //Valeur_F32 = (F32)Hauteur_P - Hauteur_Avant_F32 [ TAILLE_TABLEAU_HAUTEURS - 1 ] ;
+        Valeur_F32 = (F32) ( Vitesse_RG + Vitesse_RD ) / 2.0 ;
+        Valeur_F32 = Valeur_F32 * 19.5 * 3.14156 / 100.0 ;
+        Valeur_F32 = ( Vitesse_Avant_F32 + Valeur_F32 ) / 2.0 ;
+        Vitesse_Avant_F32 = Valeur_F32 ;
+        Vitesse_P = (S16) Valeur_F32 ;
+
+        }
+
+ }   
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Thu Jun 22 09:33:04 2017 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/031413cf7a89
\ No newline at end of file