Passionnement
Bonjour et bienvenu,

Bonjour et bienvenu sur le forum. Ici tu verra, la bonne humeur et l'entraide sont de mise.
Pas de reproche ni de prise de tête. Respect et Amitié sont de rigueur.
Pour la convivialité, nous te demandons de prendre 5mn pour te présenter a tout le monde et de renseigner ton profil le plus précisément possible.

Pour cela, ==> clique ici <== et tu créer un nouveaux sujet (une petite explication est en haut de la page).

Si tu ne fait pas de présentation, ton compte sera supprimé automatiquement après 48H.

Sans présentation, tu n'aura pas accès a la totalité du forum (qui comporte plus de 30.000 messages). Quand tu aura fait ta présentation, un modérateur ou administrateur te donnera les droits pour le forum dans sa totalité dans les 24 h.

Le Staff
Connexion

Récupérer mon mot de passe

Décembre 2017
LunMarMerJeuVenSamDim
    123
45678910
11121314151617
18192021222324
25262728293031

Calendrier Calendrier

Rechercher
 
 

Résultats par :
 

 


Rechercher Recherche avancée

Derniers sujets
» Module Hobbyzone de chez Makétis
Lun 4 Déc 2017 - 21:33 par dany-om

» Mini World Lyon Un projet fou ..................
Sam 2 Déc 2017 - 21:18 par dany-om

» Le blog de Vince Belgium
Mer 29 Nov 2017 - 23:11 par Vince Belgium

» Le train des alpes de Altaya sujet de discussion.
Dim 26 Nov 2017 - 8:21 par dany-om

» Annonce Märklin SNCF
Sam 25 Nov 2017 - 11:56 par dany-om

» Ballast, décor et réalisme facile selon Vince
Sam 25 Nov 2017 - 11:40 par dany-om

» Wagon à louer??????
Sam 25 Nov 2017 - 9:04 par likiki

» Ballast, décor et réalisme facile selon Vince
Ven 24 Nov 2017 - 19:38 par Vince Belgium

» Les blagues de LIKIKI (et des autres). M D R
Jeu 23 Nov 2017 - 20:56 par Cousin Hub

» CS3 ... Découverte et utilisation
Jeu 23 Nov 2017 - 18:36 par Fred Glmt

» L'informatisation d'un réseau.
Jeu 23 Nov 2017 - 9:03 par Vince Belgium

» Le train des alpes de Altaya par Aiguillage
Jeu 23 Nov 2017 - 5:23 par likiki

» T E R " Toul Expo Rail" 2018
Ven 17 Nov 2017 - 17:15 par lherve54

» Littérature ferroviaire hors revues
Dim 5 Nov 2017 - 21:38 par dany-om

» VOL d'objets du Musée du train de Nimes
Mer 1 Nov 2017 - 9:11 par lherve54

» Changement d'adresse sur décodeur Marklin
Sam 14 Oct 2017 - 18:08 par dany-om

» La SNCF, une sacré entreprise.
Jeu 12 Oct 2017 - 1:05 par Cousin Hub

» La photo Mystère ........
Mar 3 Oct 2017 - 21:09 par dany-om

» Information Märklin 7286
Dim 1 Oct 2017 - 10:13 par likiki

» Clés pour le train miniature.
Dim 1 Oct 2017 - 9:20 par dany-om


Animation d'un Va-et-Vient automatique (centrale DCC Arduino complète)

Voir le sujet précédent Voir le sujet suivant Aller en bas

Animation d'un Va-et-Vient automatique (centrale DCC Arduino complète)

Message par Sixtysix le Mar 27 Mai 2014 - 16:57

Bonjour à toutes et tous,

Ma dernière petite centrale semble bien fonctionner, je viens de rédiger un beau document qui la décrit et j'ai décidé de vous en donner la primeur.   

Mais là j'ai 2 solutions possibles :

- soit je mets mon document à votre disposition, ce qui peut aller vite car il est ici pour les impatients   

- soit je découpe le sujet et je rempli des pages sur ce forum, ce que je vais faire pour vous faire réagir.

   

Dominique
avatar
Sixtysix
Petit nouveau
Petit nouveau

Localisation : Ollainville
Humeur : M'enfin ...
Messages : 81
Age : 70
Emploi/loisirs : Retraite, modelisme, rando

http://bultez.fr

Revenir en haut Aller en bas

Re: Animation d'un Va-et-Vient automatique (centrale DCC Arduino complète)

Message par likiki le Mar 27 Mai 2014 - 17:50

Je m'instal et j'attend.   


   
avatar
likiki
Administrateur
Administrateur

Localisation : Saintry Sur Seine
Humeur : De tout coeur avec les victimes des attentats en France.
Messages : 11150
Age : 50
Emploi/loisirs : Gérant de son BET Ascenseurs

http://Webacappelliens.fr

Revenir en haut Aller en bas

Re: Animation d'un Va-et-Vient automatique (centrale DCC Arduino complète)

Message par Sixtysix le Mar 27 Mai 2014 - 19:25

Présentation de la centrale 


Elle est réalisée à partir d'une plaque de plexi transparent !
Au centre, 2 potentiomètres : Vitesse en Marche Avant et Vitesse en Marche arrière

A droite, de bas en haut :
- 1 interrupteur ON/OFF : arrêt de la Centrale vers le bas, marche vers le haut.
- 1 Led verte : présence d’une alimentation 12 à 15 V.
- 2 Leds jaunes : présence de l’énergie (DCC) sur les rails (une led pour chaque polarité de la tension).
- 1 Led rouge : arrêt du signal DCC (manuel ou sur défaut).
- 1 interrupteur d’envoi de l’énergie DCC sur les rails (arrêt en bas, marche en haut).
le résultat est affiché sur les 2 Leds jaunes (présence) ou la Led rouge (arrêt).

A gauche, de bas en haut :
- 1 Led jaune : mouvement du train en marche arrière.
- 1 Led rouge : arrêt du train ou passage d’un détecteur infrarouge.
- 1 Led verte : mouvement du train en marche avant.

A gauche/centre, de bas en haut :
- 1 clé Lumière (fonction FL) : arrêt vers le bas, marche vers le haut.
- 1 clé Auto / Manuel : Manuel vers le bas, Auto vers le haut.
- 1 bouton poussoir Mode (choix des affichages et configuration)

En dessous, un écran LCD de 2 lignes de 16 caractères rétro-éclairé.

Fonctionnalités

Pilotage d’une seule locomotive ou train en mode DCC, 128 crans de vitesse. L’adresse DCC est programmable.
Un écran LCD permet de visualiser les paramètres de fonctionnement.
Deux réglages de vitesse indépendants pour la marche avant et la marche arrière:
- en mode manuel, c’est la vitesse la plus grande qui impose le sens de la marche;
- en mode automatique, chaque sens dispose de sa propre vitesse;
- en mode configuration, les valeurs de 0 à 128 sont obtenues par l’addition de la rotation des 2 boutons.
Un commutateur permet la mise en ou hors service de l’éclairage de la locomotive.
Un commutateur permet le choix entre un pilotage manuel ou un Va-et-Vient automatique.
Un bouton poussoir « MODE » permet de choisir parmi 3 affichages et 10 écrans de configuration.
3 Leds, à gauche, visualisent la marche du train :
- vert : marche avant
- rouge : arrêt.  Cette Led s’allume aussi au passage du train devant un capteur IR
- jaune : marche arrière
3 Leds, à droite, visualisent le fonctionnement de la centrale
- vert : présence tension si une alimentation 12 à 15 V est raccordée et en service
- rouge : aucun courant n’est envoyé aux rails (arrêt du Booster)
- jaune (paire) : visualise la tension sur les rails (l’inversion du courant permet d’allumer les 2 Leds)
Un commutateur Arrêt/Marche allume la centrale qui démarre une séquence d’initiatisation.
Un commutateur d’alimentation des rails autorise l’envoi du courant DCC sur les rails (il est recommandé de couper l’alimentation DCC des rails avant d’installer ou retirer une loco).

Mise en route

Le commutateur ON/OFF permet la mise en route de la centrale. Les séquence suivantes se déroulent :
- l’écran LCD s’allume
- la Led rouge DCC Stop s’allume
- L’écran LCD affiche successivement :

   Initialisations
DCC:4 RAM:1247

L’écran affiche l’adresse DCC enregistrée et la mémoire disponible 

EEP 4 3 2 5 5
80 25 25 20 6 

L’écran affiche ensuite les valeurs de configuration stockées en EEProm

DCC V DIR AV AR
  4   1  >>  1   1

L’écran 1 ci-dessus affiche l’adresse DCC, la vitesse (en crans DCC), la direction (>> avant, << arrière) en usage et les valeurs de vitesse données par les potentiomètres.

A ce stade, si le commutateur Auto/Manuel est en position Manuel, le train peut être piloté avec les 2 potentiomètres.
La lumière est commandée par le commutateur Lumière 
Un appui sur le bouton MODE permet d’afficher :

V DIR Canton Pas
 1  >>   0      0

L’écran 2 ci-dessus affiche la vitesse du train, sa direction et l’état d’automate (utile seulement en mode AUTO)

Un dernier appui sur le bouton MODE permet d’afficher :

Vit  Km/h  Cm/s
 30    69    12

L’écran 3 ci-dessus affiche la vitesse du train, en Crans DCC, en Km/h et en Cm/s

Un nouvel appui revient à l’écran 1, si les 2 commutateurs Lumière et Auto/Manu ne sont pas en position basse (Lumière éteinte et mode Manuel). Sinon, la centrale passe en mode configuration.

Configuration

Si les 2 commutateurs Lumière et Auto/Manu sont en position basse (Lumière éteinte et mode Manuel), la centrale stoppe le train (Leds DCC Rails éteintes, DCC stop allumée) et permet de modifier les 10 paramètres suivants. 

Pour changer un paramètre, tourner les 2 potentiomètres de vitesse jusqu’à l’affichage de la valeur désirée, puis lever le commutateur de Lumière et appuyer sur le bouton Mode (l’indication « OK » reflète l’enregistrement du paramètre). Remettre aussitôt le commutateur Lumière en position basse.

Si le commutateur Lumière n’est pas levé avant l’appui sur Mode, le paramètre n’est pas modifié.

L’appui sur Mode permet de passer au paramètre suivant.

Adresse DCC :  
  4 -> x     
1- L’adresse DCC de la loco doit être comprise entre 1 et 127.

Vitesse min :  
  3 -> x 
2- La vitesse (cran DCC) minimal de la loco peut être déterminée en marche manuelle (tester en marche avant et arrière)

Acceleration : 
  2 -> x 
3- Les incréments de crans de vitesse en accélération permettent un réalisme plus grand.

T arret gare 1: 
  5 -> x
4- La durée d’arrêt en gare de départ (gare 1) en secondes

T arret gare 2: 
  5 -> x
5- La durée d’arrêt en gare d’arrivée (gare 2) en secondes

L canton ligne: 
  80 -> x
6- La longueur du canton central, entre les 2 capteurs IR, en Cm

L canton gare 1:
  25 -> x
7- La longueur du canton de départ, entre la gare 1 et le capteur IR 1, en Cm

L canton gare 2:
  25 -> x
8- La longueur du canton d’arrivée, entre la gare 2 et le capteur IR 2, en Cm

Time-out n 1/2s:
  20 -> x
9- La durée maximum supportée de transit entre les 2 capteurs IR (évite le dépassement de la gare si un capteur ne fonctionne pas)

Nb 1/2s Vmin : 
  6 -> x
10- La durée en 1/2 sec de la phase finale à vitesse minimale, avant arrêt au quai.

Mode Manuel

Le commutateur Auto/Manuel est en position « Manuel ». 

Les potentiomètres de vitesse sont au minimum (vitesse affichée : 1).

Le commutateur Alim Rails est en position haute et les Leds DDC Rails sont allumées (sinon manoeuvrer le commutateur vers le bas puis vers le haut car seuls les changements sont pris en compte).

Tourner le potentiomètre de Vitesse Avant si la poco est en gare 1 ou le potentiomètre de Vitesse Arriere si la poco est en gare 2. La loco démarre 

Consulter la vitesse (Crans DCC) sur l’afficheur LCD : 


La vitesse est calculée à partir du temps séparant les passages des détecteurs et la distance configurée dans le paramètre 6.

Il est possible de connaitre la vitesse réelle, mesurée entres les passages devant les 2 capteurs Infrarouges en appuyant sur le bouton Mode, le commutateur Lumière étant en position haute (allumé). Cette mesure facilite la configuration par la connaissance de la vitesse en cm/s et la mesure des sections de voies. 


Il est important de procéder à quelques trajets manuels car le logiciel enregistre les durées de passage et détermine certains paramètres à partir de cette expérience.
Si un fonctionnement erratique est constaté en mode automatique, il se peut que cela soit dû à une insuffisance de tests de trajets en mode manuel.

Mode Automatique

Le train doit, au préalable être placé au niveau de la gare de départ (gare 1).

Lorsque la clé Auto/Manuel est levée, le fonctionnement en mode Automatique démarre.

Les séquences suivantes se déroulent automatiquement :


  • 1/2 arrêt en gare de départ (valeur en configuration, paramètre 4);
  • accélération constante : incrément de vitesse ajouté toutes les 1/2 secondes (paramètre 3) jusqu’à ce que la vitesse Avant (potentiomètre haut) soit atteinte;
  • vitesse constante jusqu’à détection de la loco par le détecteur 2;
  • décélération géométrique (4/5 de la vitesse calculés toutes les 1/2 secondes) jusqu’à atteinte de la vitesse minimum;
  • avancement à vitesse minimum pendant la durée du paramètre 10;
  • arrêt en gare d’arrivée (2). 


Exemple de courbe de vitesse typique.

Le processus se déroule de façon symétrique dans l’autre sens :

  • 1/2 arrêt en gare de d’arrivée (valeur en configuration, paramètre 5);
  • accélération constante : incrément de vitesse ajouté toutes les 1/2 secondes (paramètre 3) jusqu’à ce que la vitesse Arriere (potentiomètre bas) soit atteinte;
  • vitesse constante jusqu’à détection de la loco par le détecteur 2;
  • décélération géométrique (4/5 de la vitesse calculés toutes les 1/2 secondes) jusqu’à atteinte de la vitesse minimum;
  • avancement à vitesse minimum pendant la durée du paramètre 10;
  • arrêt en gare de départ (1).


Le passage entre les 2 capteurs donne toujours lieu à un calcul de la vitesse. La centrale connait donc la vitesse du train au passage du capteur d’arrivée, au début de la séquence de décélération.
Puisqu’elle connait la distance entre ce capteur et le point d’arrivée, elle peut assurer l’arrêt du train à ce point.

Réglages en mode automatique :
- placer la loco à la gare de départ
- tourner la clé en mode AUTO
- régler la vitesse Avant avec le potentiomètre haut
- régler la vitesse Arrière avec le potentiomètre bas
- observer le mouvement du train
- si nécessaire, modifier les paramètres de configuration

On peut observer le déroulement des phases de l’automate en affichant l’écran N°2 qui présente la vitesse, la direction, le N° de Canton et le pas qui se décréments dans ce canton : 

Les connexions entre la centrale et le réseau sont représentées sur ce schéma. La centrale a besoin d’une alimentation (12 à 15 V maximum). Elle alimente directement les 2 rails (DCC Rails). Les 2 détecteurs de passage sont reliés chacun par 3 fils (+5v, masse/Gnd et signal) 



Connexions vues de dessous



avatar
Sixtysix
Petit nouveau
Petit nouveau

Localisation : Ollainville
Humeur : M'enfin ...
Messages : 81
Age : 70
Emploi/loisirs : Retraite, modelisme, rando

http://bultez.fr

Revenir en haut Aller en bas

Re: Animation d'un Va-et-Vient automatique (centrale DCC Arduino complète)

Message par Sixtysix le Mar 27 Mai 2014 - 19:43

Les ingrédients 


Vu le faible nombre de ports nécessaires, j'ai choisi un Arduino Nano, tout à fait suffisant avec ses 22 ports. 

Au départ je n’avais pas prévu d’écran LCD car j’utilisais abondamment la console série de l’IDE Arduino, pour la mise au point, la configuration, l’affichage des informations pertinentes. Par la suite, j’ai décidé de ne pas  utiliser d’ordinateur extérieur : il a fallu greffer l’écran LCD. 

Ne disposant pas de ports en nombre suffisant pour une connexion parallèle (7 au minimum, dont un pour le rétro-éclairage), j’ai choisi un écran LCD équipé d’un convertisseur Série SerLCD : 3 fils suffisent pour le faire fonctionner (+5, 0v et Tx1).

Il faut évidemment le booster LMD18200, capable de délivrer 3 A: Ne pas oublier de relier la borne Brake au 0v.


Puis 2 détecteurs à barrières infrarouge (faits maison selon le schéma ci-dessous):  

Et enfin : 2 potentiomètres (10 K), 7 Leds (2 vertes, 3 jaunes et 2 rouges), 4 interrupteurs (inverseurs à clé) et un bouton poussoir. Sans oublier du fil de diverses couleurs, quelques résistance, fer à souder et soudure et des dominos de raccordement.


Schéma de la centrale:  



La première étape de la construction consiste à relier tous les composants.



Caractéristiques de l’Arduino Nano

Microcontrolleur : Atmel ATmega328
Voltage (niveau logique) : 5 V
Voltage (alimentation recommendée) : 7-12 V
Voltage (limites d’alimentation) : 6-20 V
Ports Digitaux I/O : 14 (of which 6 provide PWM output)
Ports Analogiques : 8
Port USB (programmation et alimentation) : 1
Current maximum par port I/O : 40 mA
Mémoire Flash : 32 KB (ATmega328) dont 2 KB occupés par le bootloader
SRAM :  2 KB (ATmega328)
EEPROM :  1 KB (ATmega328)
Vitesse d’horloge : 16 MHz
Dimensions : 1,85 x 4,32 cm

Remarques :

  • La mémoire Flash permet de stocker le programme visé sans problème. celui-ci n’occupe que la moitié de la place disponible et permet donc de futures extensions.
  • La mémoire EEPROM est réservée au stockage des paramètres de configuration
  • La mémoire SRAM est petite (2K) et nécessitera des optimisations qui sont expliquées dans le code.


La compilation du logiciel décrit ci-après indique :
Binary sketch size: 16004 bytes (of a 30720 byte maximum, 52.10 percent).

Estimated memory use: 531 bytes (of a 2048 byte maximum, 25.93 percent).
avatar
Sixtysix
Petit nouveau
Petit nouveau

Localisation : Ollainville
Humeur : M'enfin ...
Messages : 81
Age : 70
Emploi/loisirs : Retraite, modelisme, rando

http://bultez.fr

Revenir en haut Aller en bas

Re: Animation d'un Va-et-Vient automatique (centrale DCC Arduino complète)

Message par Sixtysix le Mar 27 Mai 2014 - 19:45

Réalisation du logiciel avec l’IDE Arduino

Installation de l’IDE Arduino
Tous les détails de l’installation sont décrits sur le site Arduino : http://arduino.cc/en/Main/Software
L’installation est possible sous MacOS, Linux et Windows.
Pour plus de détails : http://arduino.cc/en/Guide/Environment
Et en français : http://www.mon-club-elec.fr/pmwiki_reference_arduino/pmwiki.php?n=Main.DebuterPresentationLogiciel

Pour ma part, j’ai installé également le logiciel Sublime Text : http://www.sublimetext.com
et son extension Arduino Stino : https://github.com/Robot-Will/Stino
Celle-ci apporte un confort supplémentaire par rapport à l’IDE Arduino seul.
Seule petite restriction : cela impose de placer les dossiers de librairies dans le dossier 

On trouvera ici le site français d’Arduino avec les références su langage C / C++ utilisé : http://www.mon-club-elec.fr/pmwiki_reference_arduino/pmwiki.php?n=Main.ReferenceEtendue

Ensuite il faut installer les librairies nécessaires, par la méthode décrite ici : http://arduino.cc/en/Guide/Libraries

Définition des librairies Arduino utilisées
// LIBRAIRIE CMDRARDUINO
#include <DCCPacket.h>              // librairie CmdrArduino
#include <DCCPacketQueue.h>         // idem
#include <DCCPacketScheduler.h>     // idem

Cette librairie prend en charge la génération du signal DCC sur la Pin 9 (elle se charge de l’initialisation de cette Pin).
On trouvera cette librairie ici : https://github.com/Railstars/CmdrArduino
Cette librairie est basée sur la gestion du Timer 1 (sous interruption) qui mobilise aussi la Pin 10. Celle-ci ne DOIT donc plus être utilisée.

// AUTRES LIBRAIRIES
#include <EEPROM.h>                 // librairie de gestion memoire EEPROM
Cette librairie permet de lire et écrire dans la mémoire EEPROM qui est non-volatile.

#include <Bounce.h>                 // librairie deboucing pour boutons et inters
Cette librairie permet de lire de façon fiable les actions sur les inters et boutons. En effet, ces contacts mécaniques ont l’inconvénient de « rebondir » et d’entrainer de fausses comandes que cette librairie permet d’éviter.

#include <avr/pgmspace.h>           // librairie de gestion memoire Flash
Cette librairie permet d’accéder à certaines variables internes

#include <SoftwareSerial.h>
Cette librairie est nécessaire pour la librairie serLCD

#include <serLCD.h>                 // librairie de gestion d'un LCD 16x2 via port Tx
Cette librairie permet la gestion d’un écran LCD (2 lignes de 16 caractères) avec les ordres habituels Serial.print et des commandes de positionnement simples.

Définition des Ports utilisés de l’Arduino

// Pins ARDUINO
#define Pot_AV             A0    // Analog IN : potar vitesse Avant
#define Pot_AR             A1    // Analog IN : potar vitesse Arriere
#define Current_Sense      A2    // Analog IN : courant Booster
#define Thermal_Sense      A3    // Analog IN : temperature Booster
#define Pin_AutoManu       A4    // IN  : commutateur de mode manuel (LOW) 
// ou automatique (HIGH)
#define Pin_SW_FL          A5    // IN  : commutateur d'eclairage (HIGH = ON, LOW = OFF)
                                 // les Pins 0 et 1 sont réservées pour Rx 
// et Tx (port série)
#define Pin_Tx             1     // Pour connexion au LCD via serLCD                                 
#define Pin_MAV            2     // OUT : led marche avant
#define Pin_MAR            3     // OUT : led marche arriere
#define Pin_Arret          4     // OUT : led arret
#define Pin_ZoneAV         5     // IN  : detecteur zone d'arret avant
#define Pin_ZoneAR         6     // IN  : detecteur zone d'arret arriere
#define Fin_De_Voie        7     // IN  : detecteur de fin de voie (les 2 combinées)
#define Pin_Mode           8     // IN  : poussoir de mode
#define Pin_Out_DIR        9     // OUT : Signal DIR pour LMD18200 
// pilote par CmdrArduino/Timer1
                                 // pin 10 reservee Timer 1 (ne peut être utilisée)
#define Pin_Out_PWM        11    // OUT : Signal PWM pour LMD18200
// HIGH en marche, LOW = stop
#define Pin_DCC            12    // IN  : commutateur marche/arret signal DCC 
#define Pin_Led_Booster    13    // OUT : led DCC OFF (continu) 
// ou surcharge booster (clignotant)

Définitions des variables

Pour fonctionner, le programme a besoin de manipuler des données dites « variables » qui sont stockées dans le SRAM. 
Les principales variables utilisées sont :

Pour la librairie CmdrArduino
// DCC handler
#define _stop 1                        // pour CmdrArduino 0->eStop et 1->regular stop
DCCPacketScheduler dps;                 // structure pour la librairie CmdrArduino
boolean DCC_EnService = false;          // autorise le Booster si true
boolean _erreurDPSS, _erreurDPSL = false; // pour une éventuelle détection d’erreur

Pour la configuration
typedef struct
{
    int dcc_adresse;                // @ DCC 128 crans. Attention, elle occupe 2 octets.
    byte vitesse_min;               // 2..10 a determiner en pilotage manuel
    byte increment_acceleration;    // 1..10
    byte duree_arret_gare1;         // 0..255 secondes
    byte duree_arret_gare2;         // 0..255 secondes
    byte distance_ligne;            // 1..255 centimetres
    byte distance_gare1;            // 1..255 centimetres
    byte distance_gare2;            // 1..255 centimetres
    byte pas_tempo_ligne;           // 1..255 pas de 1/2 seconde
    byte Nb_Vmin;                   // 1..20  nb de 1/2 secondes à Vmin avant Stop
} configuration;
configuration Config_Init;          // record de configuration copié en EEPROM

Pour le mouvement du train
unsigned int AV_value = 0;           // lecture du potentiometre vitesse avant
unsigned int AR_value = 0;           // lecture du potentiometre vitesse arriere
byte speed_AV, old_speed_AV = 0;     // vitesse AV (courante, précédente)
byte speed_AR, old_speed_AR = 0;     // vitesse AR
byte _speed, vitesse = 0;            // vitesse instantannee (selon direction)
boolean change_V = false;            // si true => change donc nouvelle commande DCC
byte DIR = 1;                        // marche avant: gare1>gare2 (1) 
    // ou arriere: gare2>gare1 (0)
byte Canton = 0;                     // 0=arret quai gare1, 1=depart acceleration, 
    // 2=ligne, 3=arrivee ralentissement, 
    // 4= vitesse min, 5=arret quai gare2
#define NBCantons 6                  // 6 cantons = 6 etats automate
#define NBPAS 10                     // nombre de pas de 1/2 sec par etat automate et 
    // par defaut si le detecteur n'a pas fonctionne
byte PasAV[NBCantons];               // pas en Avant : 1 valeur par canton 
byte PasAR[NBCantons];               // pas en Ariere : 1 valeur par canton 
byte TO;                             // time-out passage canton ligne calculé d'après 
    // le temps de passage entre capteurs
unsigned long TC, MTC, VKM, VCM = 0; // duree de passage entre capteurs, moyenne, 
    // vitesse (km/h) et vitesse (cm/s)
unsigned int MMA, DDS;               // Nb de millimetre restant a parcourir 

Boutons et Capteurs
Bounce B_Mode = Bounce(Pin_Mode, 100); // bouton MODE
byte prev_BM_state = 1;                // etat anterieur du poussoir Mode
byte BM = 0;                           // inactif (0) ou actif (1)
boolean Mode_Config = false;
byte Mode_EnCours = 0;                 // mode 0 : normal, affichage "DCC V DIR AV AR "
                                       // mode 1 : normal, affichage "V DIR Canton Pas"
                                       // mode 2 : normal, affichage vitesse reelle
                                       // mode 3 : config : @ dcc
                                       // mode 4 : config : V min
                                       // mode 5 : config : acceleration
                                       // mode 6 : config : t arret gare 1
                                       // mode 7 : config : t arret gare 2
                                       // mode 8 : config : l canton ligne
                                       // mode 9 : config : l canton gare 1
                                       // mode 10: config : l canton gare 2
                                       // mode 11: config : time-out n 1/2s
                                       // mode 12: config : nb 1/2s a Vmin
                                       
Bounce B_AutoManu = Bounce(Pin_AutoManu, 20); // clé AUTO/MANUEL
byte prev_AutoManu_state = 0;          // etat anterieur du commutateur auto-manuel
byte AutoManu = 0;                     // manuel (0) ou automatique (1)

Bounce B_SW_FL = Bounce(Pin_SW_FL, 20); // clé LUMIERE
byte prev_FL_state = 0;                // etat anterieur du bouton lumiere FL
byte FL = 0;                           // eclairage éteint (0) ou allumé (1)

Bounce B_DCC = Bounce(Pin_DCC, 20);    // clé ARRET/MARCHE DCC
byte prev_ON_DCC_state = 0;            // etat anterieur du bouton de signal DCC (pour etre OFF à l'init)
byte ON_DCC = 0;                       // DCC off (0) ou on (1)

Pour la tâche de clignotement des Leds
byte surchargeBooster = 0;     // 0 = OK, >0 = surcharge : clignote 1 éteint ou 3 allumé
byte Rouge_Clignotant = 0;     // 0 = normal, >0 (true) =  clignote 1 éteint ou 3 allumé
byte Jaune_Clignotant = 0;     // 0 = normal, >0 (true) =  clignote 1 éteint ou 3 allumé
byte Vert_Clignotant = 0;      // 0 = normal, >0 (true) =  clignote 1 éteint ou 3 allumé

Pour les Détecteurs de passage
boolean alarme_temperature = true;      // LOW si T>145°C au capteur, 
      //inversé à la mesure
int mesure_courant = 0; 
int detecteur_ZAV, prev_detecteur_ZAV, etat_detecteur_ZAV = 0;      
// detecteur de zones AV (gare 2)
int detecteur_ZAR, prev_detecteur_ZAR, etat_detecteur_ZAR = 0;      
// detecteur de zones AR (gare 1)
unsigned long IRdebounce_time;
#define IRdebtime  100                  // 10 milliseconde
byte IRdebounceAVH, IRdebounceAVL, IRdebounceARH, IRdebounceARL = 0;

Pour les taches périodiques
unsigned long time500, looptime;
int loopduration;                      // pour avoir idee de la duree de LOOP
int max_loopduration;

Pour l’écran LCD
serLCD lcd(Pin_Tx);
Cette ligne définit la classe « lcd » et initialise le port 1 

On définit ici les chaines de caractères qui seront affichées en 1ère ligne sur l’écran LCD
Ces chaines sont définies pour être stockées en mémoire Flash (avec le programme) et récupérées au coup par coup et une seule à la fois en SRAM, pour éviter de la saturer (plantage assuré).
prog_char string_0[]  PROGMEM = "DCC V DIR AV AR ";   // Mode_EnCours = 0
prog_char string_1[]  PROGMEM = "V DIR Canton Pas";   // Mode_EnCours = 1
prog_char string_2[]  PROGMEM = "Vit  Km/h  Cm/s ";   // Mode_EnCours = 2
prog_char string_3[]  PROGMEM = "Adresse DCC :   ";   // Mode_EnCours = 3  
                                                      // mode configuration à partir de 3
prog_char string_4[]  PROGMEM = "Vitesse min :   ";   // Mode_EnCours = 4
prog_char string_5[]  PROGMEM = "Acceleration :  ";   // Mode_EnCours = 5
prog_char string_6[]  PROGMEM = "T arret gare 1: ";   // Mode_EnCours = 6
prog_char string_7[]  PROGMEM = "T arret gare 2: ";   // Mode_EnCours = 7
prog_char string_8[]  PROGMEM = "L canton ligne: ";   // Mode_EnCours = 8
prog_char string_9[]  PROGMEM = "L canton gare 1:";   // Mode_EnCours = 9
prog_char string_10[] PROGMEM = "L canton gare 2:";   // Mode_EnCours = 10
prog_char string_11[] PROGMEM = "Time-out n 1/2s:";   // Mode_EnCours = 11
prog_char string_12[] PROGMEM = "Nb 1/2s Vmin :  ";   // Mode_EnCours = 12

PROGMEM const char *string_table[] =    // table des adresses
{   
  string_0,
  string_1,
  string_2,
  string_3,
  string_4,
  string_5,
  string_6,
  string_7,
  string_8,
  string_9,
  string_10,
  string_11,
  string_12
 };

char buffer[16];    // tampon de recopie en RAM (doit etre au moins aussi grand que le plus grand STRING


Dernière édition par Sixtysix le Mar 27 Mai 2014 - 23:24, édité 1 fois
avatar
Sixtysix
Petit nouveau
Petit nouveau

Localisation : Ollainville
Humeur : M'enfin ...
Messages : 81
Age : 70
Emploi/loisirs : Retraite, modelisme, rando

http://bultez.fr

Revenir en haut Aller en bas

Re: Animation d'un Va-et-Vient automatique (centrale DCC Arduino complète)

Message par Filou le Mar 27 Mai 2014 - 20:03

Hé ben j'ai mal au crane  affraid
avatar
Filou
Bannis du forum

Localisation : Pas de Calais.
Messages : 6852

Revenir en haut Aller en bas

Re: Animation d'un Va-et-Vient automatique (centrale DCC Arduino complète)

Message par Sixtysix le Mar 27 Mai 2014 - 20:16

Ben moi aussi !

L'éditeur de ce Forum ne se laisse pas faire si facilement     
J'ai remarqué des choses bizarres comme le tag "size" dans le code    
... finalement je n'utilise plus l'outil "code" et je règle la police sur Courrier New 13

... et le style qui change d'un message à l'autre  confused 
... avec des lignes en trop, du centrage quand on l'a pas demandé, etc...

Je crois que le mieux est de lire tranquillement le soft à partir du document qui est ici : http://bultez.fr/public/Centrale_Va-et-Vient_Arduino.pdf  Sleep

Mais faut pas s'avouer vaincu, je vais aller jusqu'au bout  


Dernière édition par Sixtysix le Mar 27 Mai 2014 - 23:28, édité 1 fois
avatar
Sixtysix
Petit nouveau
Petit nouveau

Localisation : Ollainville
Humeur : M'enfin ...
Messages : 81
Age : 70
Emploi/loisirs : Retraite, modelisme, rando

http://bultez.fr

Revenir en haut Aller en bas

Re: Animation d'un Va-et-Vient automatique (centrale DCC Arduino complète)

Message par likiki le Mar 27 Mai 2014 - 20:52

Moi je dit bravo, c'est un sacré boulot.

  
avatar
likiki
Administrateur
Administrateur

Localisation : Saintry Sur Seine
Humeur : De tout coeur avec les victimes des attentats en France.
Messages : 11150
Age : 50
Emploi/loisirs : Gérant de son BET Ascenseurs

http://Webacappelliens.fr

Revenir en haut Aller en bas

Re: Animation d'un Va-et-Vient automatique (centrale DCC Arduino complète)

Message par Sixtysix le Mar 27 Mai 2014 - 23:37

Initialisations (fonction setup)


void setup() {


  lcd.setBrightness(25); // rétro-éclairage du LCD 0..30
  lcd.clear();         // effacement du LCD
  lcd.print("Initialisations "); // affichage en 1ère ligne
  lcd.selectLine(2);         // positionnement en 2è ligne


  ///////////// initialisation des Pins
  //pinMode(Pot_AV, INPUT);         // entree analogique donc pas nécessaire
  //pinMode(Pot_AR, INPUT);         // entree analogique donc pas nécessaire
  //pinMode(Current_Sense, INPUT);  // entree analogique donc pas nécessaire
  pinMode(Thermal_Sense, INPUT_PULLUP);
  pinMode(Pin_AutoManu, INPUT_PULLUP);
  pinMode(Pin_SW_FL, INPUT_PULLUP);
  pinMode(Pin_Mode, INPUT_PULLUP);
  pinMode(Pin_DCC, INPUT_PULLUP);
  pinMode(Pin_Out_PWM, OUTPUT);
  //pinMode(Pin_Out_DIR, OUTPUT);       // initialisé par CmdrArduino
  digitalWrite(Pin_Out_PWM, LOW);       // DCC OFF
  pinMode(Pin_Led_Booster, OUTPUT);
  digitalWrite(Pin_Led_Booster, HIGH);  // Booster OFF (allume) ou CLIGNOTANT (surcharge)
  pinMode(Pin_MAV, OUTPUT);
  pinMode(Pin_MAR, OUTPUT);
  pinMode(Pin_Arret, OUTPUT);
  pinMode(Pin_ZoneAV, INPUT_PULLUP);
  pinMode(Pin_ZoneAR, INPUT_PULLUP);
  pinMode(Fin_De_Voie, INPUT_PULLUP);


  ////////////// initialisation de la librairie CmdrArduino
  dps.setup();                  // initialise les Pins 9 et 10


  prev_ON_DCC_state = B_DCC.read();   // force l'etat DCC off
  // il faut une transition bas -> haut de Alim Rails
  // pour autoriser l’alimentation des rails
   
  ////////////// Recuperation des valeurs de configuration en EEPROM 
  _Recup_EEPROM(); // voir le détail de cette fonction plus loin
  
  lcd.print("DCC:"); // affichage de l’adresse DCC en configuration
  lcd.print(Config_Init.dcc_adresse);


  Mode_EnCours = 0; // initialisation de la variable
  Mode_Config = false; // pas de mode configuration 
  
  // test de la configuration : si l’adresse DCC == 0 ou FF (EEPROM vierge):       
  // passage obligatoire en configuration
  if ((Config_Init.dcc_adresse == 0) || (Config_Init.dcc_adresse == 255))
  {
    Mode_EnCours = 3;
    Mode_Config = true;
    _Configuration();    // voir le détail de cette fonction plus loin
  }


  // iniialisation des compteurs de temps pour les taches periodiques
  time500 = millis(); // pour déclencher la fonction SR_demiseconde()
  looptime = micros(); // pour mesurer la durée moyenne de la LOOP()
  IRdebounce_time = millis(); // pour l’anti-rebond des boutons


  lcd.print(" RAM:");
  lcd.print(_RamFree());
  delay(2000);


  Print_EEPROM();   // voir le détail de cette fonction plus loin
} // fin de la fonction setup()


La fonction setup() a fait appel aux 3 fonctions suivantes :
_Recup_EEPROM() à laquelle on ajoutera la fonction symétrique _Program_EEPROM(), puis Print_EEPROM()
et enfin _Configuration()




//////////////////////////////////////
void _Recup_EEPROM()
{
  int i;
  int s = sizeof(Config_Init);
  byte b[s]; // tableau de lecture de l’EEPROM
  
  for (i = 0; i < s; i++)
  {
    b[i] = EEPROM.read(i);
    delay(10);
  }
// puis affectation des variables
  Config_Init.dcc_adresse = b[0]*256 + b[1]; 
// on assemble les 2 octets pour faire un ‘int'
  Config_Init.vitesse_min = b[2];
  Config_Init.increment_acceleration = b[3]; 
  Config_Init.duree_arret_gare1 = b[4];
  Config_Init.duree_arret_gare2 = b[5];
  Config_Init.distance_ligne = b[6];
  Config_Init.distance_gare1 = b[7];
  Config_Init.distance_gare2 = b[8];
  Config_Init.pas_tempo_ligne = b[9];
  Config_Init.Nb_Vmin = b[10];
}


//////////////////////////////////////
void _Program_EEPROM()
{
  int i;
  int s = sizeof(Config_Init);
  byte b[s];
  
  b[0] = highByte(Config_Init.dcc_adresse);  // séparation du int en 2 bytes
  b[1] = lowByte(Config_Init.dcc_adresse);
  b[2] = Config_Init.vitesse_min;
  b[3] = Config_Init.increment_acceleration;
  b[4] = Config_Init.duree_arret_gare1;
  b[5] = Config_Init.duree_arret_gare2;
  b[6] = Config_Init.distance_ligne;
  b[7] = Config_Init.distance_gare1;
  b[8] = Config_Init.distance_gare2;
  b[9] = Config_Init.pas_tempo_ligne;
  b[10] = Config_Init.Nb_Vmin;
 for (i = 0; i < s; i++)
  {
    EEPROM.write(i, b[i]);        //
    delay(10);                    // un petit délai pour garantir une bonne écriture
  }
}


///////////////////////////////////////
void Print_EEPROM() // cette fonction n’est pas très esthétique
{ // mais elle permet de vérifier le bon fonctionnement
  lcd.clear();
  lcd.print("EEP ");                             //4
  lcd.print(Config_Init.dcc_adresse);            //+3=7
  lcd.print(" ");
  lcd.print(Config_Init.vitesse_min);            //+2=9
  lcd.print(" ");
  lcd.print(Config_Init.increment_acceleration); //+2=11
  lcd.print(" ");
  lcd.print(Config_Init.duree_arret_gare1);      //+2=13
  lcd.print(" ");
  lcd.print(Config_Init.duree_arret_gare2);      //+2=15
  lcd.selectLine(2);
  lcd.print(Config_Init.distance_ligne);         //3
  lcd.print(" ");
  lcd.print(Config_Init.distance_gare1);         //+3=6
  lcd.print(" ");
  lcd.print(Config_Init.distance_gare2);         //+3=9
  lcd.print(" ");
  lcd.print(Config_Init.pas_tempo_ligne);        //+3=12
  lcd.print(" ");
  lcd.print(Config_Init.Nb_Vmin);                //+3=15
  delay(2000);

}
avatar
Sixtysix
Petit nouveau
Petit nouveau

Localisation : Ollainville
Humeur : M'enfin ...
Messages : 81
Age : 70
Emploi/loisirs : Retraite, modelisme, rando

http://bultez.fr

Revenir en haut Aller en bas

Re: Animation d'un Va-et-Vient automatique (centrale DCC Arduino complète)

Message par Sixtysix le Mar 27 Mai 2014 - 23:46

Fonction de Configuration

La fonction _Configuration() est plus compliquée. Elle met en oeuvre un écran LCD par paramètre. 
Le texte de la question apparait sur la 1ere ligne du LCD
La valeur pré-existante est affichée sur la 2e ligne, suivie de « -> » 
Puis la valeur définie par l’opérateur à l’aide des 2 potentiomètres de vitesse !

Cette méthode permet de se passer d’un clavier 0..9. On utilise les potentiomètres car il est possible de lire leur position angulaire qui, après conversion analogique-digitale, donnera une valeur comprise entre 0 et 1023. Mais la précision des potentiomètres n’est pas bonne et il est nécessaire de « démultiplier » la valeur lue pour la ramener dans l’échelle 0..127.

Pour ce faire, on ajoute les lectures des 2 potentiomètres (résultat compris entre 0 et 2048) puis on divise le résultat par 16 : on obtient une plage comprise entre 0 et 127

Ce résultat est affiché à droite de « -> ».

La fonction tourne en boucle en affichant cette valeur tant qu’on n’appuie pas sur le bouton MODE.

Pour enregistrer une nouvelle valeur (affichée à droite de « -> »), il faut lever la clé LUMIERE puis appuyer sur MODE, puis abaisser la clé LUMIERE.
Dans ce cas, la valeur est écrite en EEPROM (« OK » apparait pendant 1 seconde) puis la configuration passe au paramètre suivant.
Sinon, rien n’est changé et le passage au paramètre suivant est réalisé. On peut ainsi consulter la configuration en laissant la clé LUMIERE en bas et en appuyant successivement sur MODE.

La fonction _Configuration() fait appel aux fonctions _questionB() et _questionC().
_questionB() traite uniquement le cas de l’adresse DCC qui occupe 2 octets de configuration en EEPROM

_questionC() traite les autres paramètres qui occupent seulement 1 octet.

void _Configuration()
{
  // version LCD (remplace la version Console via USB)
  // entrée : mode manuel, LUMIERE=0 - si OK suite de questions
  // sortie avec suite d’appuis sur bouton mode
  // Mode_EnCours = 3 à 13 (index des questions)
  
  // arret du train, stop DCC booster, vitesse AV/AR=0, pots à 0
  vitesse = _stop;
  dps.setSpeed128(Config_Init.dcc_adresse,DCC_SHORT_ADDRESS,vitesse);
  ON_DCC = 0;
  digitalWrite(Pin_Out_PWM, ON_DCC);      // 0 = arret
  digitalWrite(Pin_Led_Booster, !ON_DCC); // 1 = led allumee 
  lcd.clear();
  
  // recopie de la chaine en Flash vers notre buffer
  // Cast et dereferencement nécessaire
  strcpy_P(buffer, (char*)pgm_read_word(&(string_table[Mode_EnCours]))); 

  lcd.print(buffer);                    // affichage 1ere ligne
  lcd.setCursor(2, 1); // adresse DCC
  _questionB(); // attente d’appui sur MODE
  Mode_EnCours++; // question suivante
  lcd.clear();
  
  strcpy_P(buffer, (char*)pgm_read_word(&(string_table[Mode_EnCours])));
  lcd.print(buffer);                    // affichage 1ere ligne
  lcd.setCursor(2, 1); // vitesse minimale
  Config_Init.vitesse_min = _questionC(Config_Init.vitesse_min, 2);   
  Mode_EnCours++;
  lcd.clear();
  
  strcpy_P(buffer, (char*)pgm_read_word(&(string_table[Mode_EnCours])));
  lcd.print(buffer);                    // affichage 1ere ligne
  lcd.setCursor(2, 1); // incréments d’accélération
  Config_Init.increment_acceleration = _questionC(Config_Init.increment_acceleration, 3);   
  Mode_EnCours++;
  lcd.clear();
  
  strcpy_P(buffer, (char*)pgm_read_word(&(string_table[Mode_EnCours]))); 
  lcd.print(buffer);                    // affichage 1ere ligne
  lcd.setCursor(2, 1); // 1/2 durée arrêt en gare 1
  Config_Init.duree_arret_gare1 = _questionC(Config_Init.duree_arret_gare1, 4);   
  Mode_EnCours++;
  lcd.clear();
  
  strcpy_P(buffer, (char*)pgm_read_word(&(string_table[Mode_EnCours]))); 
  lcd.print(buffer);                    // affichage 1ere ligne
  lcd.setCursor(2, 1); // 1/2 durée arrêt en gare 2
  Config_Init.duree_arret_gare2 = _questionC(Config_Init.duree_arret_gare2, 5);   
  Mode_EnCours++;
  lcd.clear();
  
  strcpy_P(buffer, (char*)pgm_read_word(&(string_table[Mode_EnCours]))); 
  lcd.print(buffer);                    // affichage 1ere ligne
  lcd.setCursor(2, 1); // Distance zone Ligne en cm
  Config_Init.distance_ligne = _questionC(Config_Init.distance_ligne, 6);   
  Mode_EnCours++;
  lcd.clear();
  
  strcpy_P(buffer, (char*)pgm_read_word(&(string_table[Mode_EnCours]))); 
  lcd.print(buffer);                    // affichage 1ere ligne
  lcd.setCursor(2, 1); // Distance zone Gare 1 en cm
  Config_Init.distance_gare1 = _questionC(Config_Init.distance_gare1, 7);   
  Mode_EnCours++;
  lcd.clear();
  
  strcpy_P(buffer, (char*)pgm_read_word(&(string_table[Mode_EnCours]))); 
  lcd.print(buffer);                    // affichage 1ere ligne
  lcd.setCursor(2, 1); // Distance zone Gare 2 en cm
  Config_Init.distance_gare2 = _questionC(Config_Init.distance_gare2, 8);   
  Mode_EnCours++;
  lcd.clear();
  
  strcpy_P(buffer, (char*)pgm_read_word(&(string_table[Mode_EnCours]))); 
  lcd.print(buffer);                    // affichage 1ere ligne
  lcd.setCursor(2, 1); // Nombre de 1/2 secondes maximum sur zone Ligne
  Config_Init.pas_tempo_ligne = _questionC(Config_Init.pas_tempo_ligne, 9);   
  Mode_EnCours++;
  lcd.clear();
  
  strcpy_P(buffer, (char*)pgm_read_word(&(string_table[Mode_EnCours]))); 
  lcd.print(buffer);                    // affichage 1ere ligne
  lcd.setCursor(2, 1); // Nombre de 1/2 secondes à vitesse Vmin
  Config_Init.Nb_Vmin = _questionC(Config_Init.Nb_Vmin, 10);   
  Mode_EnCours = 0;
  Mode_Config = false;
  lcd.clear();
  
  lcd.print("Fin Config ");
  lcd.print(_RamFree());
  lcd.setCursor(2, 1); 
  lcd.print(max_loopduration);
  max_loopduration = 0;
  delay(2000);
}

_questionB() sert à renseigner uniquement la valeur de l’adresse DCC de la loco en service et de l’enregistrer en EEPROM. Elle n’a pas de paramètre en entrée.
La clé LUMIERE doit être positionnée en bas (lumière éteinte).
Après affichage de la valeur initiale une boucle « while » tourne tant que le booléen RXIT est faux.
Le booléen ROK passe à vrai si on lève la clé LUMIERE.
RXIT passe à vrai si on appuie sur le bouton MODE : on sort de la boucle sans modification si ROK est faux ou en modifiant le paramètre si ROK est vrai.

void _questionB()                             // adresse DCC, Mode_EnCours = 3
{
  boolean ROK = false;
  boolean RXIT = false; 
  byte Valeur = 0;
  
  lcd.print(Config_Init.dcc_adresse);       // ancienne valeur sur 2e ligne, max 3 cars
  lcd.print(" ->");                         // choix à afficher en ligne 2, colonne 8
  while (!RXIT) 
  {
                                 // on se sert de la somme des potentiometres
    Valeur = (analogRead(Pot_AV) + analogRead(Pot_AR)) >> 4; 
//division par 16 pour ramener le champ 0-2047 à 0-127
    lcd.setCursor(2, 6);
    lcd.print(Valeur);
    lcd.print("  ");             // pour effacer les caracteres suivants eventuels
    if (B_Mode.update())         // Poussoir Mode change-t-il ?
    {
      if (B_Mode.risingEdge()) 
      {
        RXIT = true;             // sortie de la boucle while
     }
    }
    if (B_SW_FL.update())        // COMMUTATEUR DE LUMIERE
    {
      if (B_SW_FL.read() == HIGH)
      {        
        Config_Init.dcc_adresse = Valeur; // validation 
        ROK = true;
      } 
    }
  }        // while !ROK  
  if (ROK) 
  {
// enregistrement en EEPROM
    EEPROM.write(0, highByte(Config_Init.dcc_adresse)); 
    delay(10);
    EEPROM.write(1, lowByte(Config_Init.dcc_adresse));
    lcd.print(" Ok!");
    delay(1000);
  }
}

_questionC() sert à renseigner les autres paramètres et les enregistrer en EEPROM. Elle a 2 paramètres en entrée : l’index du paramètre et sa valeur initiale.
La clé LUMIERE doit être positionnée en bas (lumière éteinte).
Après affichage de la valeur initiale une boucle « while » tourne tant que le booléen RXIT est faux.
Le booléen ROK passe à vrai si on lève la clé LUMIERE.
RXIT passe à vrai si on appuie sur le bouton MODE : on sort de la boucle sans modification si ROK est faux ou en modifiant le paramètre si ROK est vrai.


int _questionC(int _VAL, int _index)        // Mode_EnCours > 3
{
  boolean ROK = false;
  boolean RXIT = false;
  byte Valeur = 0;
  
  lcd.print(_VAL);                // ancienne valeur sur 2e ligne, max 3 cars
  lcd.print(" ->");               // choix à afficher en ligne 2, colonne 8
  while (!RXIT) 
  {
                                  // on se sert de la somme des potentiometres
    Valeur = (analogRead(Pot_AV) + analogRead(Pot_AR)) >> 4;
//division par 16 pour ramener le champ 0-2047 à 0-127
    lcd.setCursor(2, 6);
    lcd.print(Valeur);
    if (B_Mode.update())          // Poussoir Mode change-t-il ?
    {
      if (B_Mode.risingEdge()) 
      {
        RXIT = true;              // sortie de la boucle while
     }
    }
    if (B_SW_FL.update())         // COMMUTATEUR DE LUMIERE
    {
      if (B_SW_FL.read() == HIGH)
      {
        _VAL = Valeur; // validation
        ROK = true;
      } 
    }
  }        // while !ROK
  if (ROK) 
  {
// enregistrement en EEPROM
    EEPROM.write(_index, _VAL);
    lcd.print(" Ok!");
    delay(1000);
  }
  return(_VAL); // retour avec le paramètre modifié ou non
}


Voici des exemples d’écrans obtenus :


En fin de configuration, le dernier écran affiche la quantité de mémoire SRAM restant et la plus grande durée de la boucle principale LOOP (en micro-secondes) depuis le dernier affichage.
avatar
Sixtysix
Petit nouveau
Petit nouveau

Localisation : Ollainville
Humeur : M'enfin ...
Messages : 81
Age : 70
Emploi/loisirs : Retraite, modelisme, rando

http://bultez.fr

Revenir en haut Aller en bas

Re: Animation d'un Va-et-Vient automatique (centrale DCC Arduino complète)

Message par Sixtysix le Mar 27 Mai 2014 - 23:57

Boucle principale (loop)

La fonction loop() est exécutée de façon répétitive à l’infini. C’est dans cette fonction que toutes les tâches devront être exécutées les unes à la suite des autres.

Mais certaines tâches n’ont pas besoin d’être exécutées à chaque tour de loop ! C’est le cas de l’automate qui commande l’avancement automatique du train. Pour cet automate, on a choisi un pas d’avancement d’1/2 seconde. Chaque 1/2 seconde, l’automate avance d’un cran. 
Pour ce faire, la variable time500 est comparée au temps système millis() : si cette dernière dépasse de 500 millisecondes la valeur de time500, une procédure SR_demiseconde() est lancée et time500 est mis à jour avec la valeur lue de millis().

En parallèle, des conditions extérieures peuvent influer sur le fonctionnement et les états de l’automate : appui sur le bouton, changement d’état des clés ou détection de passage devant un capteur infrarouge. Pire, un dépassement de température du booster ! Ces événements doivent être traités en priorité, le plus vite possible : ils sont donc traités dans le fonction loop() qui s’exécute environ 2 fois par seconde.

Pour garantir un temps de réponse le plus court possible, la fonction delay() n’est JAMAIS utilisée dans loop(). Il faut donc « accrocher » les taches qui doivent attendre à la fonction SR_demiseconde() et utiliser des compteurs qu’il faut initialiser avec le nombre de 1/2 secondes à attendre. La fonction SR_demiseconde() n’a alors qu’à décrémenter le compteur et exécuter la tache seulement lorsqu’il arrive à zéro.

C’est le cas des taches suivantes :

  • la detection de passage devant les capteurs qui doit être confirmée après une temporisation de 0,2 seconde pour la tête de train et 1 seconde pour la queue du train (afin d’éliminer les éventuels espace entre wagon qui pourrait donner de fausses détection). Ici on ne sert pas de la détection de queue de train, mais cela pourrait servir dans l’avenir. On fait appel ici à une variable IRdebtime initialisée à 100 pour avoir des pas de 0,1 seconde.
  • le clignotement des leds est accroché à la fonction SR_demiseconde().
  • l’avancement de l’automate est régit par des tableaux de variables PasAR[Canton] et PasAV[Canton] qui sont initialisées à chaque changement de condition et décréments à chaque 1/2 seconde. Lorsqu’elle atteint 0, un changement d’état s’opère (s’il n’a pas eu lieu avant par une condition externe).
  • le rafraichissement de l’affichage LCD.


La seule exception à la regle du NON delay() arrive lorsque qu’il y a appel de la fonction _Configuration() qui contient des instruction delay(). Mais pour éviter tout risque dans ce cas, le train est d’abord stoppé (sa vitesse est programmée à 0 et le signal DCC est arrêté.

En plus des taches exécutées dans la boucle loop(), il faut savoir que les librairies lancées au démarrage mettent en place des taches prioritaires déclenchées par des horloges internes : les interruptions.
C’est le cas de la librairie CmdeArduino qui initialise le Timer 1. Toutes les 50 ou 100 microsecondes  environ, une interruption prend la main du processeur et s’occupe de la gestion du signal DCC : une transition d’un 0 à 1 ou 1 à 0 des trames DCC préparées par les instructions de commande de vitesse et de lumière.

Le détail des opérations de loop() est indiqué dans le corps du programme ci-dessous :

void loop() {
  
  int i; // variable locale, propre à loop()

  /////////////////////////////////////////
  // Boutons et commutateurs
  /////////////////////////////////////////

Bouton Auto/Manuel : on détecte uniquement un changement d’état (par rapport à un état précédent prev_AutoManu_state. Le passage en mode AUTO démarre l’automate : AutoManu est vrai, cette variable étant une condition pour le déroulement de l’automate dans SR_demiseconde().
Le passage en mode MANUEL stoppe l’automate  : AutoManu est faux, condition pour appliquer les valeurs de vitesse des potentiomètres dans loop().

  if (B_AutoManu.update())              // COMMUTATEUR AUTO/MANUEL
  {
    byte AutoManu_state = B_AutoManu.read(); // variable locale
    if (AutoManu_state != prev_AutoManu_state)  
    {
      prev_AutoManu_state = AutoManu_state;
      AutoManu = prev_AutoManu_state;

      if (AutoManu) 
      {                    // passage en mode Auto
      // pour le moment on suppose le train au depart en gare 1 
      Canton = 0;          // 1/2 arret en Gare1
      DIR = 1;             // Marche Avant
      vitesse = 0;         // initialisation vitesse
      PasAV[Canton]=Config_Init.duree_arret_gare1;  // init 1/2 duree arret en gare 1
      } else 
      {                    // passage en mode Manuel
        old_speed_AV = 0;
        old_speed_AR = 0;
        Vert_Clignotant=0;
        Jaune_Clignotant=0;
      // peu importe la position du train
      // mais on continue a mettre a jour sa position, direction et vitesse
      }
    }  
  }

Bouton Lumière: on détecte uniquement un changement d’état (par rapport à un état précédent prev_FL_state. Le changement d’état entraine une commande de lumière : allumage ou extinction.
Si la fonction dps.setFunctions0to4 retourne une erreur, le symbole « : » est affiché là ou le curseur se trouve (c’est une fonction de débugging) .

  /////////////////////////////////////////
  //Commande d'eclairage FL
  /////////////////////////////////////////
  if (B_SW_FL.update())                     // COMMUTATEUR DE LUMIERE
  {
    byte FL_state = B_SW_FL.read();         //high == not pushed; low == pushed
    if(FL_state != prev_FL_state)
   {
      prev_FL_state = FL_state;
      FL = prev_FL_state;
      if (!dps.setFunctions0to4(Config_Init.dcc_adresse,DCC_SHORT_ADDRESS,FL))
      {
      lcd.print(":");
      }
    }
  }

Bouton Mode: on détecte uniquement un changement d’état (par rapport à un état précédent prev_BM_state) et seulement le relâchement du bouton. Le changement entraine une mise à jour de la variable d’état Mode_En_Cours qui régit l’affichage LCD en fonctionnement standard et en configuration.
En fonctionnement standard, seuls les écrans 0, 1 et 2 sont possibles. Après 2, on retourne à 0.
En mode configuration (si les boutons Lumière et Auto/Manu sont en bas - sans lumière et mode manuel), la configuration est démarrée.

  /////////////////////////////////////////
  // MODE
  /////////////////////////////////////////
  if (B_Mode.update())                     // Poussoir Mode
  {
    byte BM_state = B_Mode.read();         //high == not pushed; low == pushed
    if(BM_state != prev_BM_state)
    {
      prev_BM_state = BM_state;
      BM = prev_BM_state;
      if (BM)
      // prise en compte du relachement
      {
        Mode_EnCours++;
        if (Mode_EnCours > 2 && !AutoManu && !FL) 
        {       // passage en mode configuration
          Mode_Config = true; 
          _Configuration();      // 1 question, 1 reponse, 
// + programmation EEPROM en fonction de Mode_EnCours
        } else // mode normal
        {
          Mode_Config = false;
          if (Mode_EnCours > 2) Mode_EnCours = 0;       
// affichages 1ere et 2e ligne faits par SR_demiseconde
        }
      }
    }     
  }

Gestion des potentiomètres de vitesse Avant et Arrière.
Comme l’arrêt correspond à la valeur de vitesse = 1, moins 2 vaut arrêt.
La commande de vitesse DCC n’est envoyée que si la vitesse change car la librairie CmdrArduino se charge de la répétition de la commande conformément à la norme NMRA.
Ne sont pris en compte que les changements de moins de 50% (écretage en cas de crachement du potentiomètre, pour éviter de saturer la librairie CmdrArduino).
En mode manuel, la vitesse est envoyée immédiatement et les leds de direction sont mises à jour
En mode auto, la vitesse est gérée par l’automate.
Rappel : en marche avant la vitesse est négative, mais positive en marche arrière

  /////////////////////////////////////////
  //Commandes de vitesse AV et AR
  /////////////////////////////////////////
  AV_value = analogRead(Pot_AV);
  speed_AV = (AV_value >> 3); //divide by 8 to take a 0-1023 range number and make it 0-127 range.
  if (speed_AV < 2)           //forcement un stop
  {
    speed_AV = _stop;         // 0 = e_stop;   1 = _stop 
  }
  if (speed_AV != old_speed_AV)
  {
    if (abs(speed_AV - old_speed_AV) < 64)  // ecretage en cas de pot qui crache
    {
      old_speed_AV = speed_AV;
      change_V = true;
    }
  }
  AR_value = analogRead(Pot_AR);
  speed_AR = (AR_value >> 3); //divide by 8 to take a 0-1023 range number and make it 0-127 range.
  if (speed_AR < 2)           //forcement un stop
  {
    speed_AR = _stop;      // 0 = e_stop;  1 = _stop 
  }
  if (speed_AR != old_speed_AR)
  {
    if (abs(speed_AR - old_speed_AR) < 64)  // ecretage en cas de pot qui crache
    {
      old_speed_AR = speed_AR;
      change_V = true;
    }
  }
  if (change_V && !AutoManu) 
    {                                // mode manuel : vitesse envoyee immediatement
    DIR = (speed_AV > speed_AR);
    if (speed_AR == _stop) DIR = 1;
    if (speed_AV == _stop && speed_AR == _stop) 
    {
digitalWrite(Pin_Arret, HIGH); 
    } else 
    {
digitalWrite(Pin_Arret, LOW);
    }
    digitalWrite(Pin_MAV, DIR);      // Led verte
    digitalWrite(Pin_MAR, !DIR);     // led jaune
    if (DIR) {                       // avant
      vitesse = speed_AV;            // 
      _speed = -vitesse;             // en avant vitesse negative
    } else   {                       // arriere
      vitesse = speed_AR;            // 
      _speed = vitesse;              // vitesse positive
    }
    if (!dps.setSpeed128(Config_Init.dcc_adresse,DCC_SHORT_ADDRESS,_speed))
    {
      lcd.print(".");     // détection d’anomalie
    }
    change_V = false;
    }
      
La librairie CmdrArduino a besoin d’opérer en tâche de fond (sous interruptions) aussi souvent que possible : elle est appelée dans loop() à chaque tour. Les interruptions servent à changer les bits 0 et 1 émis par la broche DIR (9) au rythme de l’horloge TIMER1 (toutes les 50 ou 100 µs environ). La fonction dos.update() sert à organiser les données privées de cette librairie et notamment la file d’attente des trames à émettre.

  /////////////////////////////////////////
  // Execution CmdrArduino à chaque LOOP
  /////////////////////////////////////////
  dps.update();
  
La liberation du booster par la clé Alim Rails se fait par une transition bas -> haut de cette clé.
Si la clé est initialement en position basse (arrêt), lever la clé alimente les rails en DCC.
Si la clé est initialement en position haute (marche, alors que la Led rouge DCC Stop est allumée), il faut d’abord baisser la clé, puis la lever.

  /////////////////////////////////////////
  // START / STOP BOOSTER
  /////////////////////////////////////////  
  if (B_DCC.update())                      // BOUTON ON / OFF DCC
  {
    byte ON_DCC_state = B_DCC.read();
    if (ON_DCC_state != prev_ON_DCC_state)  
    {
      prev_ON_DCC_state = ON_DCC_state;
      if (!ON_DCC_state)
      {
        ON_DCC = 0;
      }
      if (ON_DCC_state)
      {
        ON_DCC = !ON_DCC;                    // inversion ON -> OFF -> ON ...
      }
      digitalWrite(Pin_Out_PWM, ON_DCC);      // 1 = en marche
      digitalWrite(Pin_Led_Booster, !ON_DCC); // 0 = led OFF allumee en continu
      vitesse = 0;                            // par sécurite
    }
  }
 
Une surveillance du booster est possible, grâce aux 2 signaux Courant et Temperature.
La valeur 600 correspond à une tension de 2,5 v, soit 1,5 A dans le booster. En réalité on n’a pas réussi à lire une valeur plausible : des essais sont à poursuivre.
L’alarme temperature se déclenche au dessus de 145 °C
En cas d’alarme, le signa DCC est arrêté, la led DCC stop allumée et la led STOP clignotante
 
  /////////////////////////////////////////
  // ALARMES BOOSTER (courant et temperature)
  /////////////////////////////////////////
  mesure_courant = analogRead(Current_Sense);
  alarme_temperature = !digitalRead(Thermal_Sense);  // LOW si T > 145°C)
// puis inversé  
  if ((mesure_courant > 600) || alarme_temperature )
  {
    ON_DCC = 0;
    digitalWrite(Pin_Out_PWM, ON_DCC);        // 0 = STOP
    digitalWrite(Pin_Led_Booster, !ON_DCC);   // 1 = led Booster OFF allumée
    surchargeBooster = 3;                     // et clignotante
    Rouge_Clignotant = 3;                     // led ARRET clignotante
  }
  
Gestion des capteurs de passage (détecteurs infrarouge) : c’est une partie plus complexe !
On sépare la détection de l’avant du train de celle de l’arrière du train, par rapport au sens de la marche.
La tête est à l’avant en marche avant, la queue est en avant en marche arrière !
On applique une temporisation de 0,2 s pour confirmer la détection de la tête de train.
On applique une temporisation de 1,0 s pour confirmer la détection de la queue du train.
On allume la Led Arrêt pendant le passage du train pour contrôler le bon fonctionnement du détecteur.
Au 1er détecteur, TC est initialisé par le temps système
Au 2e détecteur on calcule le temps de passage entre détecteurs et la vitesse du train.
Une mise à jour du « temps de traversée » est faite pour l’automate, afin de sécuriser l'arrêt final du train, si l’un des détecteurs venait à défaillir.
La mesure de vitesse est réalisée à la fois en mode manuel et en mode automatique.
En mode automatique, le 2e passage détecté déclenche la décélération.

D’autres détails seront expliqués dans l’automate SR_demiseconde(). 

  /////////////////////////////////////////
  // CAPTEURS ZONE D'ARRET
  /////////////////////////////////////////
 
  // traitement detecteur Zone AV (pres de gare 1)
  detecteur_ZAV = digitalRead(Pin_ZoneAV);
  if ((detecteur_ZAV != prev_detecteur_ZAV) && (detecteur_ZAV == 1) && (etat_detecteur_ZAV == 0))
  {  // detection debut de convoi (tete en AV, queue en AR)               
    etat_detecteur_ZAV = 1; // etat 1 = detection initiale début de convoi
    IRdebounceAVH = 2;      // arme tempo de confirmation après 0,2 sec
  } else {
    if ((detecteur_ZAV == 1) && (IRdebounceAVH == 0) && (etat_detecteur_ZAV == 1))
    { // validation debut de convoi
      etat_detecteur_ZAV = 2;  // etat 2 = en cours de passage devant le detecteur
      prev_detecteur_ZAV = 1;
      // TRAITEMENT TETE DE CONVOI
      digitalWrite(Pin_Arret, HIGH);

     if (DIR) {          // marche avant, raz TC
        TC = millis();
      } else {            // marche arriere, TC -> calcul vitesse
        TC = millis() - TC;
        if (MTC == 0) {MTC = TC;} else {MTC = (MTC + TC) / 2;}    // tend vers la moyenne
        TO = (byte)(MTC/500);                                     // nb de 1/2 secondes
        if (TO > Config_Init.pas_tempo_ligne) { TO = Config_Init.pas_tempo_ligne; }
        VCM = (1000*(unsigned long)Config_Init.distance_ligne)/TC;
        VKM = VCM*576/100;
      }
      // si auto : DIR = 1 entree dans ligne (vitesse constante) ou DIR = 0 ralentir avant arret gare 1
      if (AutoManu)
      {
        if (DIR)         // avant
        {
          // rien (entree dans canton ligne)
        } else {         // arriere
          Canton = 2;    // deceleration et arret
          PasAR[Canton]=Config_Init.distance_gare1;               
    // PasAR = distance capteur -> arret gare 1
          MMA = (unsigned int)Config_Init.distance_gare1*100;      
    // init distance restant a parcourir jusqu'a arret *100
          DDS = (unsigned int)VCM*50;                             
// init Distance parcourue par 1/2 seconde *100
        } 
      }
    } else {
      if ((detecteur_ZAV != prev_detecteur_ZAV) && (detecteur_ZAV == 0) && (etat_detecteur_ZAV == 2))
      { // transition vers 0 en cours de passage de convoi (inter-wagon ou queue)
        etat_detecteur_ZAV = 3; // etat 3 detection retour a 0
        IRdebounceAVL = 10;     // armement tempo 1 sec
      } else {
        if ((detecteur_ZAV == 1) && (IRdebounceAVL != 0) && (etat_detecteur_ZAV == 3))
        { // interwagon a ignorer
          etat_detecteur_ZAV = 2;
          IRdebounceAVL = 0;
        } else {
          if ((detecteur_ZAV == 0) && (IRdebounceAVL == 0) && (etat_detecteur_ZAV == 3))
          {
            // queue de convoi
            etat_detecteur_ZAV = 0;
            prev_detecteur_ZAV = 0;
            // TRAITEMENT QUEUE DE CONVOI
            digitalWrite(Pin_Arret, LOW);
          }
        }
      }
    }
  }

  // traitement detecteur Zone AR (pres de gare 2)
  detecteur_ZAR = digitalRead(Pin_ZoneAR);
  if ((detecteur_ZAR != prev_detecteur_ZAR) && (detecteur_ZAR == 1) && (etat_detecteur_ZAR == 0))
  {  // detection debut de convoi (tete en AV, queue en AR)               
    etat_detecteur_ZAR = 1; // etat 1 = detection initiale début de convoi
    IRdebounceARH = 2;      // arme tempo de confirmation après 0,2 sec
  } else {
    if ((detecteur_ZAR == 1) && (IRdebounceARH == 0) && (etat_detecteur_ZAR == 1))
    { // validation debut de convoi
      etat_detecteur_ZAR = 2;  // etat 2 = en cours de passage devant le detecteur
      prev_detecteur_ZAR = 1;
      // TRAITEMENT TETE DE CONVOI
      digitalWrite(Pin_Arret, HIGH);

     if (!DIR) {          // arriere, raz TC
        TC = millis();
      } else {             // avant, TC -> calcul vitesse
        TC = millis() - TC;
        if (MTC == 0) {MTC = TC;} else {MTC = (MTC + TC) / 2;}    
// tend vers la moyenne
        TO = (byte)(MTC/500);                                     
// nb de 1/2 secondes
        if (TO > Config_Init.pas_tempo_ligne) { TO = Config_Init.pas_tempo_ligne; }
        VCM = (1000*(unsigned long)Config_Init.distance_ligne)/TC;
        VKM = VCM*576/100;
      }
      // si auto : DIR = 1 ralentir avant arret gare 2 ou DIR = 0 entree dans ligne (vitesse constante)
      if (AutoManu)
      {
        if (DIR)          // avant
        {
          Canton = 3;     // deceleration et arret
          PasAV[Canton]=Config_Init.distance_gare2;               
// PasAV = distance capteur -> arret gare 2
          MMA = (unsigned int)Config_Init.distance_gare2*100;      
// init distance restant a parcourir jusqu'a arret *100
          DDS = (unsigned int)VCM*50;                             
// init Distance parcourue par 1/2 seconde *100
        } else {          // arriere
          // rien (entree dans canton ligne)
        }
      }
    } else {
      if ((detecteur_ZAR != prev_detecteur_ZAR) && (detecteur_ZAR == 0) && (etat_detecteur_ZAR == 2))
      { // transition vers 0 en cours de passage de convoi (inter-wagon ou queue)
        etat_detecteur_ZAR = 3; // etat 3 detection retour a 0
        IRdebounceARL = 10;     // armement tempo 1 sec
      } else {
        if ((detecteur_ZAR == 1) && (IRdebounceARL != 0) && (etat_detecteur_ZAR == 3))
        { // interwagon a ignorer
          etat_detecteur_ZAR = 2;
          IRdebounceARL = 0;
        } else {
          if ((detecteur_ZAR == 0) && (IRdebounceARL == 0) && (etat_detecteur_ZAR == 3))
          {
            // queue de convoi
            etat_detecteur_ZAR = 0;
            prev_detecteur_ZAR = 0;
            // TRAITEMENT QUEUE DE CONVOI
            digitalWrite(Pin_Arret, LOW);
          }
        }
      }
    }
  }

Ce capteur n’est pas implémenté pour le moment mais son emplacement est prévu pour une évolution future facile.

  /////////////////////////////////////////
  // CAPTEUR FIN DE VOIE
  /////////////////////////////////////////
  
  if (!digitalRead(Fin_De_Voie))            // detection si LOW 
  {
    // arret train immediat : eStop et led Rouge allumée
    // vitesse = 0, attente retour potentiometres à zero
    // passage en mode manuel   
  }

Loop() ne contient aucun traitement du mode automatique. Ceux-ci sont réalisés dans la fonction SR_demiseconde().


  /////////////////////////////////////////
  // MODE AUTOMATIQUE
  /////////////////////////////////////////
  
  // voir automate dans SR_demiseconde()

Cette portion de code sert à déclencher les tâches périodiques, en utilisant le temps système.

  /////////////////////////////////////////
  // TACHES PERIODIQUES
  /////////////////////////////////////////  
  if ((time500 + 500) < millis())  {
    time500 = time500 + 500;                 // pour rattraper les secondes si ça dérape
    SR_demiseconde();     // automate
  }  
  if ((IRdebounce_time + IRdebtime) < millis()) {  // deboucing detecteurs IR
   IRdebounce_time = millis();
   if (IRdebounceAVH > 0) IRdebounceAVH--;    // tend vers 0 en IRdebtime ms
   if (IRdebounceAVL > 0) IRdebounceAVL--;    // tend vers 0 en IRdebtime ms
   if (IRdebounceARH > 0) IRdebounceARH--;    // tend vers 0 en IRdebtime ms
   if (IRdebounceARL > 0) IRdebounceARL--;    // tend vers 0 en IRdebtime ms
  }  
  loopduration = micros() - looptime;
  looptime = micros();
  if (loopduration > max_loopduration)
  {
    max_loopduration = loopduration;
  }
} // fin de LOOP

La variable 32 bits time500 est comparée au temps système millis() et augmentée de 500 (millisecondes) à chaque concordance. Celle-ci apparait donc toutes les 1/2 secondes. Cela déclenche l’appel de la fonction SR_demiseconde().

J’ai testé divers intervals de temps (1 seconde; 1/4 seconde) et j’ai trouvé que la demi-seconde est un bon compromis.

La même technique est utilisée pour réaliser des « time-out » ou temporisations de confirmation des détecteurs de passage

Enfin, le temps système en microsecondes est aussi mesuré pour déterminer la durée d’exécution de la boucle loop().
Seule est retenue la durée la plus longue qui peut être consultée à la fin de la configuration (hormis le temps de cette configuration). Sur ce sujet, je dois chercher la cause qui fait passer cette durée du minimum d’ 1/2 miliseconde au maximum de plus de 30 milisecondes.


Dernière édition par Sixtysix le Mer 28 Mai 2014 - 0:11, édité 1 fois
avatar
Sixtysix
Petit nouveau
Petit nouveau

Localisation : Ollainville
Humeur : M'enfin ...
Messages : 81
Age : 70
Emploi/loisirs : Retraite, modelisme, rando

http://bultez.fr

Revenir en haut Aller en bas

Re: Animation d'un Va-et-Vient automatique (centrale DCC Arduino complète)

Message par Sixtysix le Mer 28 Mai 2014 - 0:08

Dernière partie : l'automate

Fonctions de l’automate SR_demiseconde()

Nous allons maintenant passer en revue le module principal de l’automate : la fonction SR_demiseconde() qui s’exécute toutes les demi secondes.

///////////////////////////////////
void SR_demiseconde()
{

Clignotement des Leds : On utilise 2 bits de poids faible d’une variable « byte ».
Si cet octet est nul (tous les bits à 0) on ne fait rien.
Sinon, le clignotement est dérivé de la valeur du bit 1 qui est inversé à chaque appel de la fonction.


  if (surchargeBooster > 0)  {
    digitalWrite(Pin_Led_Booster, bitRead(surchargeBooster, 1));
    bitWrite(surchargeBooster, 1, !bitRead(surchargeBooster, 1));
  }

  if (Rouge_Clignotant > 0)  {
    digitalWrite(Pin_Arret, bitRead(Rouge_Clignotant, 1));
    bitWrite(Rouge_Clignotant, 1, !bitRead(Rouge_Clignotant, 1));
  }
  
  if (Jaune_Clignotant > 0)  {
    digitalWrite(Pin_MAR, bitRead(Jaune_Clignotant, 1));
    bitWrite(Jaune_Clignotant, 1, !bitRead(Jaune_Clignotant, 1));
  }
  
  if (Vert_Clignotant > 0)  {
    digitalWrite(Pin_MAV, bitRead(Vert_Clignotant, 1));
    bitWrite(Vert_Clignotant, 1, !bitRead(Vert_Clignotant, 1));
  }

Automate du mode automatique

  //////////// MODE AUTOMATIQUE //////////////
  
Mise à jour de l’état des Leds, à partir des variables DIR (direction) et vitesse.

  if (AutoManu) { // automate mode automatique (s'execute toutes les 1/2 secondes)
    digitalWrite(Pin_MAV, (DIR && (vitesse != _stop)));  
//Led Verte si DIR = AVANT ET PAS ARRET
    digitalWrite(Pin_MAR, (!DIR && (vitesse != _stop))); 
//Led Jaune si DIR = ARRIERE ET PAS ARRET
    digitalWrite(Pin_Arret, (vitesse == _stop));         
//Led Rouge si ARRET
        
Automate : Pour chaque sens de circulation (selon DIR) le mouvement du train est décomposé en 6 états appelés « Canton » de façon impropre (au départ il n’y en avait que 3, correspondant aux 3 cantons réels, puis d’autres cas sont apparus nécessaire. Mais le nom de la variable a été conservé). Dans chaque canton, une variable « Pas » évolue (partant d’une valeur initiale définie à la sortie du canton précédent, elle diminue jusqu’à 0, condition de passage au canton suivant).
Il y a une variable Pas pour chaque Canton, donc sous forme de tableau, bien que ce ne soit pas nécessaire.

A chaque appel de la fonction, la combinaison de DIR et Canton définit un module de traitement. Chaque module est décrit à l’aide de l’instruction « switch » qui est la plus pratique pour ce cas.

Cas de la marche avant : 
- 0: Le train reste à l’arrêt pendant le demi-arrêt en gare 1
- 1: Le train démarre et accélère jusqu’à atteindre la vitesse définie par le potentiomètre Avant
- 2: Le train circule à vitesse constante
- 3: Le train ralenti jusqu’à sa vitesse minimale
- 4- le train roule à vitesse minimale (devant le quai de la gare 2)
- 5: Le train s’arrête pendant le demi-arrêt en gare 2

    if (DIR)
    {                // Marche avant
      switch (Canton) {

0: Le train reste à l’arrêt pendant le demi-arrêt en gare 1
On se contente de décrémenter le Pas (configuration duree_arret_gare1)
        
        case 0:      // AV : arret en gare 1 avant départ
        vitesse = _stop;
        Rouge_Clignotant=0;
        PasAV[Canton]--;           // rester dans canton tant que PasAV > 0
        if (PasAV[Canton] == 0)  { // passage au canton suivant
          Canton = 1;              // passage au canton suivant : acceleration AV
          Vert_Clignotant=3;       // vert clignotant = acceleration dans l'etat suivant
        }
        break;

1: Le train démarre et accélère jusqu’à atteindre la vitesse définie par le potentiomètre Avant
On incréments la vitesse de la quantité en configuration increment_acceleration jusqu’à atteindre la vitesse de consigne
On initialise la durée maximale du canton suivant (en cas de défaut du détecteur)
         
        case 1:     // AV : depart de la gare 1 : acceleration jusqu'a speed_AV
        vitesse = vitesse + Config_Init.increment_acceleration;   
// acceleration constante, puis vitesse constante
        if (vitesse > speed_AV)
          {
            vitesse = speed_AV;
            Canton = 2;
            if (TO < Config_Init.pas_tempo_ligne)
            {
              PasAV[Canton] = TO + 10;
// butee de securite en cas de defaillance de capteur IR
            } else 
            {
            PasAV[Canton] = Config_Init.pas_tempo_ligne;  
            }                                                         
          }
        Vert_Clignotant=0;    // vert fixe : fin acceleration
        break;

2: Le train circule à vitesse constante
On décrémente le Pas. La détection de passage doit en principe intervenir avant que Pas = 0.
         
        case 2:               // AV : ligne a vitesse constante jusqu'a detecteur gare 2
        // vitesse constante
        PasAV[Canton]--;      // rester dans canton tant que PasAV > 0
        if (PasAV[Canton] == 0)  {      // passage au canton suivant
          Canton = 3;                   // passage au canton suivant : deceleration
          PasAV[Canton]=Config_Init.distance_gare2; 
// PasAV = distance capteur -> arret gare 2
          Vert_Clignotant=3;            // vert clignotant : deceleration
        }
        break;

3: Le train ralenti jusqu’à sa vitesse minimale
On diminue la vitesse de façon géométrique (80% de la vitesse précédente)
On calcule aussi la distance restant à parcourir que l’on compare à la configuration distance_gare2 (le code n’est pas encore conforme à cette spécification : il ne sera dans une prochaine version): ceci doit garantir l’arrêt du train exactement au point prévu, en bout de quai de gare, à condition d’avoir mesuré cette distance.
         
        case 3:     // AV : ralentissement jusqu' a V min avant arrivee en gare 2
        if (vitesse > Config_Init.vitesse_min)
        {
          PasAV[Canton] = PasAV[Canton] - vitesse/4; 
// decremente distance parcourue durant 1/2 seconde
          vitesse = vitesse*4/5;     //vitesse = deceleration geometrique;    
          if ((vitesse <= Config_Init.vitesse_min) || (vitesse > 126)) 
          {
            vitesse = Config_Init.vitesse_min;       
// vitesse est une valeur absolue jamais negative 
            Canton = 4;
            PasAV[Canton]=Config_Init.Nb_Vmin;       
// PasAV = Nb de 1/2 secondes à vitesse Vmin
          }
        }   
        break;

4- le train roule à vitesse minimale (devant le quai de la gare 2)
Pendant quelques Pas, le train roule très lentement, juste avant l’arrêt complet pour simuler la réalité au mieux
  
        case 4:   
        PasAV[Canton]--;          // decompte les 1/2 secondes a vitesse Vmin
        if (PasAV[Canton] == 0)   // si < 0 passage au canton suivant
        {
          Canton = 5;             // vers canton suivant : arret gare
          PasAV[Canton]=Config_Init.duree_arret_gare2;
// init 1/2 duree d'arret en gare 2
          Vert_Clignotant=0;     // vert eteint
        }
        break;

5: Le train s’arrête pendant le demi-arrêt en gare 2
Traitement similaire au cas 0
         
        case 5:                   // AV : arret en gare 2
        vitesse = _stop;
        PasAV[Canton]--;          // rester dans canton tant que PasAV > 0
        if (PasAV[Canton] == 0)  {      // passage au canton suivant
          DIR = 0;                      // changement de sens : marche AR
          Canton = 5;                   // vers canton suivant (marche arrière)
          PasAR[Canton]=Config_Init.duree_arret_gare2;  
// init 1/2 duree d'arret en gare 2
        }
        break;
      } 
    } // if DIR avant
    else

Cas de la marche arrière : 
- 5: Le train reste à l’arrêt pendant le demi-arrêt en gare 2
- 4: Le train démarre et accélère jusqu’à atteindre la vitesse définie par le potentiomètre Arrière
- 3: Le train circule à vitesse constante
- 2: Le train ralenti jusqu’à sa vitesse minimale
- 1- le train roule à vitesse minimale (devant le quai de la gare 1)
- 0: Le train s’arrête pendant le demi-arrêt en gare 1

    {  // DIR = 0 arriere
      switch (Canton) {

5: Le train reste à l’arrêt pendant le demi-arrêt en gare 2
        
        case 5:                     // AR : arret en gare 2
        vitesse = _stop;
        PasAR[Canton]--;            // rester dans canton tant que PasAV > 0
        if (PasAR[Canton] == 0)  {  // passage au canton suivant : acceleration en MAR
          Canton = 4;               // vers canton suivant
          Jaune_Clignotant=3;
        }
        break;

4: Le train démarre et accélère jusqu’à atteindre la vitesse définie par le potentiomètre Arrière

        case 4:                     // AR : depart de gare 2 : acceleration
        vitesse = vitesse + Config_Init.increment_acceleration;    
        if (vitesse > speed_AR) 
        {
          vitesse = speed_AR;
          Canton = 3;               // vers canton suivant : ligne
          if (TO < Config_Init.pas_tempo_ligne)
          {
            PasAR[Canton] = TO + 10;
// butee de securite en cas de defaillance de capteur IR
          } else 
          {
          PasAR[Canton] = Config_Init.pas_tempo_ligne;  
          }                                                         
        }
        Jaune_Clignotant=0;
        break;

3: Le train circule à vitesse constante

        case 3:     // AR : ligne a vitesse constante jusqu'a detecteur gare 1
        //vitesse constante
        PasAR[Canton]—;      // rester dans canton tant que PasAV > 0
        if (PasAR[Canton] == 0)  {    // passage au canton suivant
          Canton = 2;                 // vers canton suivant : deceleration
          PasAR[Canton]=Config_Init.distance_gare1;    
// PasAR = distance capteur -> arret gare 1
          Jaune_Clignotant=3;
        }
        break;

2: Le train ralenti jusqu’à sa vitesse minimale

        case 2:     // AR : ralentissement jusqu' a V min avant arrivee en gare 1   
        if (vitesse > Config_Init.vitesse_min)
        {
          PasAR[Canton] = PasAR[Canton] - vitesse/4;    
// decremente distance parcourue durant 1/2 seconde
          vitesse = vitesse*4/5;         //vitesse = deceleration geometrique;    
          if (vitesse <= Config_Init.vitesse_min || vitesse > 126) 
          {
            vitesse = Config_Init.vitesse_min; 
// vitesse est une valeur absolue jamais negative 
            Canton = 1;
            PasAR[Canton]=Config_Init.Nb_Vmin;          
// PasAV = Nb de 1/2 secondes à vitesse Vmin
          }
        }    
        break;

1- le train roule à vitesse minimale (devant le quai de la gare 1)
   
        case 1:     
        PasAR[Canton]--;          // decompte les 1/2 secondes a vitesse Vmin
        if (PasAR[Canton] == 0)  {      // si =  0 passage au canton suivant
          Canton = 0;                                  // vers canton suivant
          PasAR[Canton]=Config_Init.duree_arret_gare1; // init 1/2 duree arret en gare 1
          Jaune_Clignotant=0;
        }
        break;

0: Le train s’arrête pendant le demi-arrêt en gare 1
         
        case 0:                               // AR : 1/2 duree arret en gare 1  
        vitesse = _stop;
        PasAR[Canton]--;                      // rester dans canton tant que PasAV > 0
        if (PasAR[Canton] == 0)  {            // passage au canton suivant
          Canton = 0;                         // vers canton suivant
          DIR = 1;                            // changement de sens : marche AV
          PasAV[Canton]=Config_Init.duree_arret_gare1; // init 1/2 duree arret en gare 1
        }
        break;
      } // switch canton        
    } // if DIR arriere

Envoi des commandes DCC (vitesse et lumière)

    // commande DCC de vitesse et lumiere en auto
    _speed = vitesse;
    // préserver la variable vitesse qui est toujours comprise entre 0 et 127
    if (DIR || (vitesse == _stop))
    {
      _speed = -vitesse;   // en avant le bit de poids fort est à 1 en 128 pas
    }                      // et à l'arret, la direction est = AVANT   
    if (!dps.setSpeed128(Config_Init.dcc_adresse,DCC_SHORT_ADDRESS,_speed))
    {
     _erreurDPSS = true;
    }
    if (!dps.setFunctions0to4(Config_Init.dcc_adresse,DCC_SHORT_ADDRESS,FL))
    {
      _erreurDPSL = true;
    } // commandes DCC
  }   // if Automanu = Auto

Fin de l’automate en mode automatique !

On profite de cette fonction périodique pour assurer les affichages toutes les 1/2 secondes

  • un indicateur de fonctionnement suspect de la librairie CmdrArduino
  • les 3 écrans possibles en fonction de la variable Mode_EnCours

   
    // affichage des parametres en mode normal 
    lcd.clear();
    if (_erreurDPSS)
    {
      lcd.print(".");
      _erreurDPSS = false;
    }
    if (_erreurDPSL)
    {
      lcd.print(":");
      _erreurDPSL = false;
    }    

Affichage de la ligne 1

    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[Mode_EnCours])));
    lcd.print(buffer);                          // affichage 1ere ligne

Affichage de la ligne 2

   switch (Mode_EnCours)
    {
      case 0:                // Mode_EnCours 0 : normal, affichage "DCC V DIR AV AR "
      lcd.setCursor(2,1);
      lcd.print(Config_Init.dcc_adresse);
      lcd.setCursor(2,5);
      lcd.print(vitesse);
      lcd.setCursor(2,8);  // colonne 8 car un smiley malicieux s'est glissé  Very Happy
      if (DIR) {lcd.print(">>");} else {lcd.print("<<");} 
      lcd.setCursor(2,11);
      lcd.print(speed_AV, DEC);
      lcd.setCursor(2,14);
      lcd.print(speed_AR, DEC);
      break;
      
      case 1:              // Mode_EnCours 1 : normal, affichage "V DIR Canton Pas"
      lcd.setCursor(2,1);
      lcd.print(vitesse);
      lcd.setCursor(2,4);
      if (DIR) {lcd.print(">>");} else {lcd.print("<<");} 
      lcd.setCursor(2,8);  // colonne 8 car un smiley malicieux s'est glissé  Very Happy 
      lcd.print(Canton);
      lcd.setCursor(2,14);
      if (DIR) {lcd.print(PasAV[Canton]);} else {lcd.print(PasAR[Canton]);}
      break;
      
      case 2:            // Mode_EnCours 2 : normal, affichage "Vit  Km/h  Cm/s "
      lcd.setCursor(2,1);
      lcd.print(vitesse);
      lcd.setCursor(2,7);
      lcd.print(VKM);
      lcd.setCursor(2,13);
      lcd.print(VCM);
      break;
    }    
}
avatar
Sixtysix
Petit nouveau
Petit nouveau

Localisation : Ollainville
Humeur : M'enfin ...
Messages : 81
Age : 70
Emploi/loisirs : Retraite, modelisme, rando

http://bultez.fr

Revenir en haut Aller en bas

Re: Animation d'un Va-et-Vient automatique (centrale DCC Arduino complète)

Message par Sixtysix le Mer 28 Mai 2014 - 0:23

Ca y est, tout y est  Arrow 

Maintenant vous pouvez trouver un bout de réalisation qui peut vous servir, je l'espère   
 
Je vais me coucher, bonne nuit !
avatar
Sixtysix
Petit nouveau
Petit nouveau

Localisation : Ollainville
Humeur : M'enfin ...
Messages : 81
Age : 70
Emploi/loisirs : Retraite, modelisme, rando

http://bultez.fr

Revenir en haut Aller en bas

Re: Animation d'un Va-et-Vient automatique (centrale DCC Arduino complète)

Message par Invité le Lun 9 Juin 2014 - 15:13

Bonjour Dominique,

J'ai lu attentivement ta prose sur le "Va et Vient automatique".
J'ai en projet une ligne Va et Vient pour 3 autorails et je vais m'inspirer de ta réalisation.
J'ai vu que tu as utilisé un Booster LMD 18200. J'ai trouvé juste le CI chez CONRAD pour 15€,
mais le même circuit complet chez LEMEONBLEUE à Honk Kong à seulement 10$ 
ou as tu acheté le tien STP,
Hong Kong, c'est fiable ?

Merci d'avance,

Patrick.

PS. Je brûle d'envie de revenir vous voir toi,  Bernard M et le président dans votre grenier, (même si je fais du HO), j'attendais d'avoir réalisé enfin quelque chose.
avatar
Invité
Invité


Revenir en haut Aller en bas

Re: Animation d'un Va-et-Vient automatique (centrale DCC Arduino complète)

Message par Sixtysix le Lun 9 Juin 2014 - 15:25

patsushi a écrit:J'ai vu que tu as utilisé un Booster LMD 18200. J'ai trouvé juste le CI chez CONRAD pour 15€,
mais le même circuit complet chez LEMEONBLEUE à Honk Kong à seulement 10$ 
ou as tu acheté le tien STP, Hong Kong, c'est fiable ?
Bonjour Patrick,

Oui les miens viennent de HK dont le fameux lemonbleu (ou qqn d'approchant comme ça) : aucun problème de fiabilité !
J'en ai 3 en service !

Dominique
avatar
Sixtysix
Petit nouveau
Petit nouveau

Localisation : Ollainville
Humeur : M'enfin ...
Messages : 81
Age : 70
Emploi/loisirs : Retraite, modelisme, rando

http://bultez.fr

Revenir en haut Aller en bas

Re: Animation d'un Va-et-Vient automatique (centrale DCC Arduino complète)

Message par Sixtysix le Lun 9 Juin 2014 - 15:34






  • Size: 51*46*28mm
  • Core chip: LMD18200
  • Working voltage: 4.5~5.5V
  • DC motor max voltage: 55V
  • Recommended DC motor voltage: 12~48V (Note: no less than 12V)
  • With power status LED
  • Max Output: 3A (can reach peak current of 6A)
  • Max output: 75W
  • Motor speed can be smoothly adjusted by PWM
  • Advanced anti-interference
  • Can be used to independently control a DC motor /electromagnet /solenoid
  • Can control motor run clock-wise or anti clock-wise.

effectivement il est à 10,78$


tu peux en commander 3 ou 4 directement si le port est gratuit en plus.


Dominique
avatar
Sixtysix
Petit nouveau
Petit nouveau

Localisation : Ollainville
Humeur : M'enfin ...
Messages : 81
Age : 70
Emploi/loisirs : Retraite, modelisme, rando

http://bultez.fr

Revenir en haut Aller en bas

Re: Animation d'un Va-et-Vient automatique (centrale DCC Arduino complète)

Message par Invité le Lun 9 Juin 2014 - 15:46

Merci Dominique,

L'avantage des orages, c'est qu'on est devant l'ordi.
Il ne pleut même plus à St Yon.

Amicalement,

Patrick
avatar
Invité
Invité


Revenir en haut Aller en bas

Re: Animation d'un Va-et-Vient automatique (centrale DCC Arduino complète)

Message par Invité le Lun 9 Juin 2014 - 16:39

Merci Dominique,

Je viens d'en commander 3 pour 24,45 €.
Vraiment pas cher.
Merci beaucoup.

Patrick.
avatar
Invité
Invité


Revenir en haut Aller en bas

Re: Animation d'un Va-et-Vient automatique (centrale DCC Arduino complète)

Message par Sixtysix le Lun 9 Juin 2014 - 17:35

Super 
Reste plus qu'à attendre 2 à 3 semaines !
avatar
Sixtysix
Petit nouveau
Petit nouveau

Localisation : Ollainville
Humeur : M'enfin ...
Messages : 81
Age : 70
Emploi/loisirs : Retraite, modelisme, rando

http://bultez.fr

Revenir en haut Aller en bas

Re: Animation d'un Va-et-Vient automatique (centrale DCC Arduino complète)

Message par Sixtysix le Sam 15 Nov 2014 - 22:23

patsushi a écrit:Merci Dominique,

Je viens d'en commander 3 pour 24,45 €.
Vraiment pas cher.
Merci beaucoup.

Patrick.

Alors Patrick,

ça marche ?

Viens me voir à l'expo du Plessis Pate les 29 et 30 Novembre !

Amicalement
Dominique
avatar
Sixtysix
Petit nouveau
Petit nouveau

Localisation : Ollainville
Humeur : M'enfin ...
Messages : 81
Age : 70
Emploi/loisirs : Retraite, modelisme, rando

http://bultez.fr

Revenir en haut Aller en bas

Re: Animation d'un Va-et-Vient automatique (centrale DCC Arduino complète)

Message par Contenu sponsorisé


Contenu sponsorisé


Revenir en haut Aller en bas

Voir le sujet précédent Voir le sujet suivant Revenir en haut

- Sujets similaires

 
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum