Auteur Sujet: SIGNAUX: CIBLES ET DECODEURS  (Lu 5224 fois)

laurentr

  • Hero Member
  • *****
  • Messages: 565
    • Voir le profil
Re : SIGNAUX: CIBLES ET DECODEURS
« Réponse #15 le: janvier 21, 2023, 11:47:14 pm »
Bonsoir

Journée constructive propice aux échanges et aux pistes de réflexion(s)!

"Bon bah à koa ki pe  resssss bler le décodeur pou les signaux alors?" (en chti et dans le texte!)

Voici une première ébauche assez complète dans la lignée des montages précédents. (redressement de la tension, décodage du signal DCC, ack, convertisseur de tension DC-DC ( ca ne chauffe pas!), CPU et convertisseur de signaux logiques du bus I2C, petite réserve d'énergie.

Le montage est "compact et ne mesure que 46mm x 60mm ce qui permet de le placer sous la plateforme. Son épaisseur le rend aussi assez passe partout (15mm en gros)

On peut y raccorder "facilement " 4 puces SX150X pouvant alors traiter jusqu'à 16x4 =  64 canaux d'affichage ( Rouge, Jaune , Vert, Blanc, Violet ...) ( Croix, triangle, Carré et rond => les initiés comprendront!)

A noter qu'une version à base d Arduino Nano Every avec les "composants usuels va voir le jour également pour les adeptes du "DIY". (Optocoupleurs , pont de diodes, Nano Every, résistance traversantes, LM7805 ou LM317 (ca chauffe!) etc

Puis viendra "THE CODE" ... :)

PS: Un petit bout est déjà en cours de test chez Dominique ::) :-X

A suivre...

Laurent


« Modifié: janvier 21, 2023, 11:52:28 pm par laurentr »

laurentr

  • Hero Member
  • *****
  • Messages: 565
    • Voir le profil
Re : SIGNAUX: CIBLES ET DECODEURS
« Réponse #16 le: janvier 22, 2023, 06:18:34 pm »
Bonjour

"THE CODE":

Posons quelques bases qui nous permettrons de bâtir la trame globale ensuite.

Un signal est une combinaison d' états allumé(s)/éteint(s) de différentes lampes de couleurs régies par un code.

Ces combinaisons sont multiples. Ce n'est pas un sapin de noël enguirlandé non plus!

Selon les réseaux SNCF, SNCB, DB, CFF FS, NL... ces codes varient.

Nous allons faire volontairement un focus sur la partie SNCF mais l'approche reste similaire pour les autres réseaux.

Je vous recommande la lecture de la page suivante qui illustre bien ce sur quoi nous allons nous appuyer ensuite:
https://geillon.pagesperso-orange.fr/trains/signaux/

La cible contenant le plus de feux est la "cible H": elle présente 9 feux + l'œilleton.

Celle ci peut afficher en fixe au maximum 3 lampes (+œilleton) simultanément.
Les couleurs sont selon les combinaisons

  • Voie libre = 1 feu vert (peut clignoter) Vl
  • Sémaphore = 1 feu rouge (peut clignoter) S
  • Avertissement = 1 feu jaune (peut clignoter) Av
  • Carré = 2 feux rouges (fixes) C
  • Carré violet = 1 feu violet (fixe) Cv
  • Blanc = 1 feu blanc ( peut clignoter) Blc
  • Ralentissement = 2 feux jaunes horizontaux (peut clignoter) Ral
  • Rappel de ralentissement = 2 feux jaunes verticaux (peut clignoter) RRal
  • L œilleton est toujours fixe: soit éteint ( C, Cv , Blc) soit allumé pour les autres aspects.


Les combinaisons avec clignotement sont en fait soit un état ou tout est éteint , soit un état ou l œilleton est présent en combinaison avec un ou plusieurs feux éteint(s) et ou allumé(s).

On en ressort avec le tableau de synthèse suivant qui permet d identifier 22 éléments

[/list]

laurentr

  • Hero Member
  • *****
  • Messages: 565
    • Voir le profil
Re : SIGNAUX: CIBLES ET DECODEURS
« Réponse #17 le: janvier 22, 2023, 06:53:28 pm »
Poursuivons:

Nous allons poser quelques règles de conception.

L'usage des puces SX1508 et S1509 ouvre la possibilité de travailler sur les IO en 3V3 ou  5V.
Par simplification nous allons travailler en 3V3. (ce qui nous évite 1 fils supplémentaire)
Ceci va donc IMPOSER de monter en parallèle les leds car lorsque 2 seront requises dans des combinaisons de RAL et RRAL car  la tension y serait insuffisante.

Autre règle: nous pourrions utiliser la possibilité HARDWARE de la gestion du "breathe" pour l allumage te l extinction progressive des led sur des broches dédiées.

Au maximum 8 le sont sr le SX1509 et uniquement 4 sur le SX1508.

Si cela couvre les besoins de nos signaux de base, l ajout d ID ou de TID n'offrira alors pas cette possibilité. Idem pour le cas de potences ou les multiples combinaisons seraient restreintes.

Nous aurons donc un peu plus de lignes de code à traiter pour des mouvement de luminosité par variation du PWM lui dispo sur chaque IO.

A ce stade je m'interroge sur le mode de mise en œuvre/mise en service: gestion FULL CV ou via "IHM"?

La solution type "ACROMORA" est séduisante, simple, efficace. C'est une piste. L'autre est une gestion d accessoires classiques via une (interminable) liste de CV.

Vos avis sont les bienvenus pour statuer sur l'une ou l'autre des orientations à donner.

laurentr

  • Hero Member
  • *****
  • Messages: 565
    • Voir le profil
Re : SIGNAUX: CIBLES ET DECODEURS
« Réponse #18 le: janvier 22, 2023, 08:44:33 pm »
Les blocs de traitement vont donc être:

  • MAPPER les adresses DCC et les états à afficher
  • GERER l'intensité lumineuse : de MINIMUM (0) à MAXIMUM (255) ou a un LEVEL déterminé
  • PASSER d'une intensité lumineuse à une autre
  • BASCULER d'un état à un autre
  • PILOTER les sorties correspondantes de puces I2C



« Modifié: janvier 22, 2023, 08:50:01 pm par laurentr »

laurentr

  • Hero Member
  • *****
  • Messages: 565
    • Voir le profil
Re : SIGNAUX: CIBLES ET DECODEURS
« Réponse #19 le: janvier 22, 2023, 08:57:17 pm »
Gestion des feux clignotants:

Il y a une bascule entre 2 états:

Celui ou tout est allume VERSUS, celui on un certain nombre de feux est éteint et réciproquement

Le passage d'un état vers l'autre se fait via un fondu visuel appelé "FADING".

Cela se traite par un variation du PWM. ( simplement via la commande ANALOGUEWRITE en incrémentant la valeur du PWM entre deux seuils à une vitesse plus ou moins rapide).

Nous pouvons variabiliser ces éléments et les rendre modifiables via CV ou une IHM.

laurentr

  • Hero Member
  • *****
  • Messages: 565
    • Voir le profil
Re : SIGNAUX: CIBLES ET DECODEURS
« Réponse #20 le: janvier 24, 2023, 03:53:49 pm »
Bonjour

Poursuite des préparatifs

La gestion des commandes décodeurs d accessoires répond selon des déclinaisons du protocole DCC ( 9bits mode basic , 11bits mode "Extended") et selon les fabricants de centrale ( ROCO, LENZ...)

Une centrale comme la DR5000 pilote chaque sortie individuellement en mode "Extended" selon 2 états ( ROUGE/ VERT) et offre 2048 items x2 choix : rouge ou vert = 4096).

Une centrale come la LENZ LH100 passe elle par un mode d adressage basic ( adresses de 0 à 511) avec 4 états possibles d'ou 512 x4 x 2 états possibles par sortie  = 4096.

C est la gestion interne du décodeur qui devra "aiguiller" ensuite vers les sorties à piloter. (ON OFF, fading...) selon la combinaison que l'on désire afficher.


Se pose alors une double problématique.
Veut on économiser sur les sorties (PIN OUT et leur affectation à l'attribution de la gestion d'une couleur de feu? ( chaque puce SX1509 offre 16 sorties. contre 8 pour les SX1508)
Veut on économiser le nombre d adresses de base et/ou de sorties pilotées pour exploiter par exemple toutes les PIN OUT des puces SX sans en laisser sans affectation.

Ces questionnements simples sont pourtant des axes important d' implémentation.

Une analyse simple et directe peut être de repartir de la cible H avec toutes les combinaisons qu'elle peut présenter et y ajouter celle du disque.

On à alors:

Pilotage physique de 8 canaux pour les leds ( blanc, rouge, jaune vert  ou violet) selon toutes les combinaisons possibles.
5 adresses de bases consommées
10 OUTPUTS de 2 états

Si les besoins sont inferieurs on saute jusqu' au slot dispo suivant et les ressources sont "perdues" par auto consommation ou à affecter avec soins par ailleurs. (pour un aiguillage par exemple)

Exemple on affecte la première adresse à 120 ( adresse de base), on consomme alors 5 adresses en mode basic soient les adresses supplémentaires 121 122 123 et 124 qui avec la 120 donnent bien 5 adresses contiguës.
Dans le cas d'affectation directe des sorties nous auront alors à activer les OUTPUTS portant les numéros allant de 477 à 496. ( selon la formule ( Sortie = (Addresse-1)*4 + n  avec n=[1;4] )

Si on n'utilise pas  certaines combinaisons alors on peut re affecter leur usage pour d autres accessoires mais cela IMPOSE un RIGUEUR dans la gestion des ressources ou votre ami "EXCEL" sera de mise.

Le tableau suivant illustre cette implémentation.


« Modifié: janvier 25, 2023, 02:13:23 pm par laurentr »

laurentr

  • Hero Member
  • *****
  • Messages: 565
    • Voir le profil
Re : SIGNAUX: CIBLES ET DECODEURS
« Réponse #21 le: janvier 24, 2023, 04:52:07 pm »
Mais ou veut il en venir?...

J arrive, j arrive!

En utilisant la librairie d'AIKO PRA :
https://github.com/aikopras/AP_DCC_library

et en regardant ce qui est fait dans le "decoder-core":
https://github.com/aikopras/AP_DCC_Decoder_Core

On voit que la gestion des adresses et des sorties est déjà en place. Il restera à configurer les décodeurs selon le type de trame qu il va recevoir ( ROCO , LENZ, ...)

La plage d adresse du décodeur va donc selon les besoin propre à chaque signal être soit un groupe de 5 adresses contiguës ( cas pour une cible H (8 feux) ) soit une variation de ceci selon le remplissage "matriçage" cible d'optimisation en sorties ou en adresses ( ou des deux!)

Tout le monde suit toujours?


laurentr

  • Hero Member
  • *****
  • Messages: 565
    • Voir le profil
Re : SIGNAUX: CIBLES ET DECODEURS
« Réponse #22 le: février 01, 2023, 03:01:11 pm »
Bonjour

J ai un peu avancé dans la trame du code de pilotage des différents aspects du signal.

Pour le moment j ai un effet ON/OFF très acceptable visuellement de chaque led selon la combinaison de leds que je désire voir s'afficher ( en fixe ou clignotant avec pour chaque couleur un niveau d intensité lumineuse pré réglable)

Pour pousser plus loin l'effet visuel  simulant la montée/descente  progressive de l'intensité lumineuse d'une AMPOULE INCANDESCENTE sur une LED il faut donc jouer de la "PWM".

Jusque la tout va bien le "analogWrite" qui va bien va nous aider.

Chaque led va donc via l incrémentation de la valeur PWM confiée à "analogWrite" faire varier progressivement l'intensité lumineuse jusqu'au seuil haut désiré dans la plage [0;255] que supporte notre SX150X.

Si cette incrémentation est IDENTIQUE pour chaque cycle et chaque canal nous allons avoir un "loupé" .Les leds vont avoir des niveaux d'intensité lumineuse différents selon leur couleur d affichage.

Le seuil haut ( niveau désiré d éclairage de la led) d une led verte aura par exemple une valeur de 120 et une rouge sera à 80 ( valeurs arbitraires pour illustrer)

On va donc avoir la led ROUGE qui aura atteint son intensité désirée avant celle de la verte qui doit continuer de s'incrémenter.
Hors les combinaisons lumineuses quelque soient les couleurs affichées doivent être synchrones entre le niveau 0 et leur seuil haut d'intensité lumineuse désirée.

Même si les temps sont extrêmement brefs j ai peur que ce "décalage" soit "visuellement disgracieux" si perçu.

Une solution est de mixer la valeur des résistances de chaque canal avec la couleur de la led à allumer. On perd la flexibilité de mapping mais on simplifie le code. ( et le hard n'est plus  identique en terme de valeur de résistance avec chaque led associée sur le canal)
C est une première option.

Une autre option est que pour un intervalle de temps donné (disons 500 ms pour illustrer) on incrémente selon la couleur une valeur différente chaque changement de  niveau d'intensité. On grimpe par exemple de 3 en 3 pour une verte la ou on grimpe de 1 en 1 pour une rouge.
Cette option séduisante sur le papier se heurte au pragmatise du code. En effet on doit passer en valeur des bytes ( uint8_t) ( donc des nombre entiers) compris entre 0 et 255. Pas le droit d utiliser des float ou alors il faut les remapper ( via fonction map par exemple) en entier et on va se retrouver in fine avec un décalage ( très réduit) de l'atteinte des seuils.

L'effet visuel disgracieux est réduit mais encore présent ( reste t il toutefois réellement bien perceptible?)

Finalement une petite combinaison de multiples pour les différents seuils lumineux par couleur de manière pré établie dans cette logique aurait peut être vocation à nous sortir de l'embarras en apportant la souplesse attendue.

Traduction on incrémente la valeur qui pilote la couleur ayant le rendu lumineux le plus intense pour un même niveau de PWM le moins vite possible et inversement, la couleur ayant le rendu le moins intense pour un même niveau de PWM s'incrémente moins souvent mais avec une valeur d'incrémentation plus forte et proportionnelle.

Ainsi pour chaque cycle d'incrémentation de la valeur de PWM par ajout/soustraction d un pas selon la couleur permet de grimper de 0 à 255 avec un fondu visuel similaire quelque soit la couleur de chaque sortie.

Est ce assez astucieux? Sur le papier je dirai que oui. Revenons cote encodage de cela.
Nous avons "7 combinaisons de couleurs par usage": ( 8 si on considère l'intensité du deuxième feu du carré différente de celle du feu rouge du sémaphore)
BLANC pour l'œilleton
BLANC pour la manœuvre
VIOLET carré violet
ROUGE ( intensité pour feux Sémaphore et carre et confondus sinon ROUGE S et ROUGE C)
VERT
JAUNE 1 feux
JAUNE pour 2 feux en PARALLELE

convertit en multiples nous aurions les valeurs 1 7 14 21 28 35 42.

Se méfier des fausses bonnes idées puisque on va vite se rendre compte que 255/42 va en gros nous laisser 5 paliers au plus entre le 100/100 allume et le 100/100 éteint. ( max/min de l'intensité possible) Hors nous seront en chemin vers celle ci et il faut aussi ne pas la dépasser. Coté progressivité c est "saccadé" et donc contraire au but recherche.

Alors que reste t il comme solution(s)?
« Modifié: février 01, 2023, 04:50:09 pm par laurentr »

laurentr

  • Hero Member
  • *****
  • Messages: 565
    • Voir le profil
Re : SIGNAUX: CIBLES ET DECODEURS
« Réponse #23 le: février 01, 2023, 03:26:50 pm »
Et bien en fait nous avons déjà une partie de ce que je pense être "une bonne réponse":

Nous savons que les incrémentations  d'affichage PWM doivent se faire en parallèle OU si on recompose l'équation cela se traduit par: pour chaque couleur de canal on fait varier à une vitesse différente la même incrémentation dans un rapport de vitesse disons de 1 à 8. ( nos 8 fameuses couleurs !!)

On en vient donc à l'idée d'utiliser un "timer" dont le rôle va être d incrémenter à intervalle fixe une valeur tous les x temps. Pour chaque couleur on rythme l'incrémentation en fonction du décompte de ce timer et on a alors la variation de la valeur PWM de chaque canal de temps

Il nous restera juste à nous assurer alors que notre temps d intervalle soit lui le multiple le plus proche de 8 qui nous intéresse.

Et si deux couleurs différentes doivent varier à la même vitesse finalement? Simple, elle auront alors les mêmes compteurs de bascule d'incrément.
En revanche si le rapport 1 à 8 est insuffisant? Et bien comme le dit une célèbre pub "patron on est mal! ?? Pas tout à fait car nous avons fixé ce rapport librement et arbitrairement il nous faudrait alors le revoir et l'ajuster

L'approche j en conviens n'est pas des plus simple! Si  parmi vous d autres on des idées pour "solutionner" je suis preneur.

@Trimarco232, qu'en penses tu? Tu es le plus avancé d entre nous sur le sujet "pilotage de signaux", ceci te parait il être une "bonne méthode" ou faut il finalement aller au plus simple...? ( via les PIN capable de faire du "BREATH" uniquement? ( alternative "simplissime" :) )

Pour les plus curieux voici un bel article (en anglais) qui illustre l utilisation du SX1509:

https://learn.sparkfun.com/tutorials/sx1509-io-expander-breakout-hookup-guide#-example-digital-inout-and-pwm

A vos avis!?

Laurent
« Modifié: février 01, 2023, 04:05:55 pm par laurentr »

laurentr

  • Hero Member
  • *****
  • Messages: 565
    • Voir le profil
Re : SIGNAUX: CIBLES ET DECODEURS
« Réponse #24 le: février 02, 2023, 06:33:16 pm »
Bonjour

Pour les plus impatients qui voudraient tester un module SX1509 voici un petit programme de demo qui fait changer les états de 2 groupes de 8 leds (2 cibles H) répartis sur les IO0 à 7 puis 8 à 15 de la puce.

///
// TEST SX1509 BREAKOUT BOARD V1.0 31012023 @LTR
///

#include <Wire.h>           // Include the I2C library (required)
#include <SparkFunSX1509.h> //Click here for the library: http://librarymanager/All#SparkFun_SX1509


// SX1509 I2C address (set by ADDR1 and ADDR0 (00 by default):
const byte SX1509_ADDRESS = 0x3E; // SX1509 I2C address
SX1509 io;                        // Create an SX1509 object to be used throughout

// SX1509 Pin definition:
const byte SX1509_LED_16 = 15; // LED to SX1509's pin 15
const byte SX1509_LED_15 = 14; // LED to SX1509's pin 14
const byte SX1509_LED_14 = 13; // LED to SX1509's pin 13
const byte SX1509_LED_13 = 12; // LED to SX1509's pin 12
const byte SX1509_LED_12 = 11; // LED to SX1509's pin 11
const byte SX1509_LED_11 = 10; // LED to SX1509's pin 10
const byte SX1509_LED_10 = 9; // LED to SX1509's pin 9
const byte SX1509_LED_9 = 8; // LED to SX1509's pin 8
const byte SX1509_LED_8 = 7; // LED to SX1509's pin 7
const byte SX1509_LED_7 = 6; // LED to SX1509's pin 6
const byte SX1509_LED_6 = 5; // LED to SX1509's pin 5
const byte SX1509_LED_5 = 4; // LED to SX1509's pin 4
const byte SX1509_LED_4 = 3; // LED to SX1509's pin 3
const byte SX1509_LED_3 = 2; // LED to SX1509's pin 2
const byte SX1509_LED_2 = 1; // LED to SX1509's pin 1
const byte SX1509_LED_1 = 0; // LED to SX1509's pin 0

uint8_t SIGNAL_1_PINS[8] = {SX1509_LED_1, SX1509_LED_2, SX1509_LED_3, SX1509_LED_4, SX1509_LED_5 , SX1509_LED_6, SX1509_LED_7, SX1509_LED_8};

const uint8_t OE_LEVEL = 32;
const uint8_t GREEN_LEVEL = 128;
const uint8_t YELLOW_LEVEL = 100;
const uint8_t YELLOW2_LEVEL = 120;
const uint8_t WHITE_LEVEL = 80;
const uint8_t PURPULE_LEVEL = 120;
const uint8_t RED_LEVEL = 150;

uint8_t SIGNAL_LIGHT_PHASE = 0b11111111;
uint8_t SIGNAL_LIGHT_PHASE2 = 0b11111111;

uint8_t SIGNAL_1_COLOR_LEVELS[8] = {OE_LEVEL, YELLOW_LEVEL, RED_LEVEL, GREEN_LEVEL, RED_LEVEL, WHITE_LEVEL, YELLOW2_LEVEL, YELLOW2_LEVEL};

uint8_t SIGNAL_LIGHT_COMBO_CARRE =  0b00010100;
uint8_t SIGNAL_LIGHT_MODE_CARRE =   0b11111111;

uint8_t SIGNAL_LIGHT_COMBO_CV =     0b00010000;
uint8_t SIGNAL_LIGHT_MODE_CV =      0b11111111;

uint8_t SIGNAL_LIGHT_COMBO_VL =     0b00001001;
uint8_t SIGNAL_LIGHT_MODE_VL =      0b11111111;

uint8_t SIGNAL_LIGHT_COMBO_S =      0b00000101;
uint8_t SIGNAL_LIGHT_MODE_S =       0b11111111;

uint8_t SIGNAL_LIGHT_COMBO_RC =     0b00000101;
uint8_t SIGNAL_LIGHT_MODE_RC =      0b11111011;

uint8_t SIGNAL_LIGHT_COMBO_V160 =   0b00001001;
uint8_t SIGNAL_LIGHT_MODE_V160 =    0b11110111;

uint8_t SIGNAL_LIGHT_COMBO_AV =     0b00000011;
uint8_t SIGNAL_LIGHT_MODE_AV =      0b11111111;

uint8_t SIGNAL_LIGHT_COMBO_JC =     0b00000011;
uint8_t SIGNAL_LIGHT_MODE_JC =      0b11111101;

uint8_t SIGNAL_LIGHT_COMBO_RAL =    0b01000001;
uint8_t SIGNAL_LIGHT_MODE_RAL =     0b11111111;

uint8_t SIGNAL_LIGHT_COMBO_RAL60 =  0b01000001;
uint8_t SIGNAL_LIGHT_MODE_RAL60 =   0b10111111;

uint8_t SIGNAL_LIGHT_COMBO_RRAL =   0b10000001;
uint8_t SIGNAL_LIGHT_MODE_RRAL =    0b11111111;

uint8_t SIGNAL_LIGHT_COMBO_RRAL60 = 0b10000001;
uint8_t SIGNAL_LIGHT_MODE_RRAL60 =  0b01111111;

uint8_t SIGNAL_LIGHT_COMBO_MAN =    0b00100000;
uint8_t SIGNAL_LIGHT_MODE_MAN =     0b11111111;

uint8_t SIGNAL_LIGHT_COMBO_BC =     0b00100000;
uint8_t SIGNAL_LIGHT_MODE_BC =      0b11011111;

uint8_t SIGNAL_LIGHT_COMBO_DISQUE =    0b00000110;
uint8_t SIGNAL_LIGHT_MODE_DISQUE =     0b11111111;

uint8_t SIGNAL_LIGHT_COMBO_AV_RRAL =   0b10000011;
uint8_t SIGNAL_LIGHT_MODE_AV_RRAL =    0b11111111;

uint8_t SIGNAL_LIGHT_COMBO_AV_RRAL60 = 0b10000011;
uint8_t SIGNAL_LIGHT_MODE_AV_RRAL60 =  0b01111111;

uint8_t SIGNAL_LIGHT_COMBO_JC_RRAL60 = 0b10000011;
uint8_t SIGNAL_LIGHT_MODE_JC_RRAL60 =  0b01111101;

uint8_t SIGNAL_LIGHT_COMBO_AV_RAL60 =  0b01000011;
uint8_t SIGNAL_LIGHT_MODE_AV_RAL60 =   0b10111111;

uint8_t SIGNAL_LIGHT_COMBO_JC_RAL60 =  0b01000011;
uint8_t SIGNAL_LIGHT_MODE_JC_RAL60 =   0b10111101;

const uint8_t SIGNAL_LIGHT_COMBO_DUAL_CROSSING = 0b00010100;
const uint8_t SIGNAL_LIGHT_MODE_DUAL_CROSSING =  0b11101011;

uint8_t SIGNAL_LIGHT_COMBO = 0;
uint8_t SIGNAL_LIGHT_MODE = 0;

uint8_t index;

uint8_t SIGNAL_LIGHT_COMBO_LIST[] = {
  SIGNAL_LIGHT_COMBO_VL,
  SIGNAL_LIGHT_COMBO_V160,
  SIGNAL_LIGHT_COMBO_AV,
  SIGNAL_LIGHT_COMBO_JC,
  SIGNAL_LIGHT_COMBO_S,
  SIGNAL_LIGHT_COMBO_RC,
  SIGNAL_LIGHT_COMBO_CARRE,
  SIGNAL_LIGHT_COMBO_CV,
  SIGNAL_LIGHT_COMBO_MAN,
  SIGNAL_LIGHT_COMBO_BC,
  SIGNAL_LIGHT_COMBO_RAL,
  SIGNAL_LIGHT_COMBO_RAL60,
  SIGNAL_LIGHT_COMBO_RRAL,
  SIGNAL_LIGHT_COMBO_RRAL60,
  SIGNAL_LIGHT_COMBO_AV_RRAL,
  SIGNAL_LIGHT_COMBO_AV_RRAL60,
  SIGNAL_LIGHT_COMBO_JC_RRAL60,
  SIGNAL_LIGHT_COMBO_AV_RAL60,
  SIGNAL_LIGHT_COMBO_JC_RAL60,
  SIGNAL_LIGHT_COMBO_DISQUE,
  SIGNAL_LIGHT_COMBO_DUAL_CROSSING
};

uint8_t SIGNAL_LIGHT_MODE_LIST[] = {
  SIGNAL_LIGHT_MODE_VL,
  SIGNAL_LIGHT_MODE_V160,
  SIGNAL_LIGHT_MODE_AV,
  SIGNAL_LIGHT_MODE_JC,
  SIGNAL_LIGHT_MODE_S,
  SIGNAL_LIGHT_MODE_RC,
  SIGNAL_LIGHT_MODE_CARRE,
  SIGNAL_LIGHT_MODE_CV,
  SIGNAL_LIGHT_MODE_MAN,
  SIGNAL_LIGHT_MODE_BC,
  SIGNAL_LIGHT_MODE_RAL,
  SIGNAL_LIGHT_MODE_RAL60,
  SIGNAL_LIGHT_MODE_RRAL,
  SIGNAL_LIGHT_MODE_RRAL60,
  SIGNAL_LIGHT_MODE_AV_RRAL,
  SIGNAL_LIGHT_MODE_AV_RRAL60,
  SIGNAL_LIGHT_MODE_JC_RRAL60,
  SIGNAL_LIGHT_MODE_AV_RAL60,
  SIGNAL_LIGHT_MODE_JC_RAL60,
  SIGNAL_LIGHT_MODE_DISQUE,
  SIGNAL_LIGHT_MODE_DUAL_CROSSING
};



bool bascule = true;

uint32_t currenttime;
uint32_t starttime;
uint32_t starttime2;

//uint8_t SX1509_LED[8] = {SX1509_LED_1, SX1509_LED_2, SX1509_LED_3, SX1509_LED_4, SX1509_LED_5, SX1509_LED_6, SX1509_LED_7, SX1509_LED_8};

//uint8_t SX1509_LED2[8] = {SX1509_LED_9, SX1509_LED_10, SX1509_LED_11, SX1509_LED_12, SX1509_LED_13, SX1509_LED_14, SX1509_LED_15, SX1509_LED_16};

uint8_t SX1509_LED[16] = {SX1509_LED_1, SX1509_LED_2, SX1509_LED_3, SX1509_LED_4, SX1509_LED_5, SX1509_LED_6, SX1509_LED_7, SX1509_LED_8, SX1509_LED_9, SX1509_LED_10, SX1509_LED_11, SX1509_LED_12, SX1509_LED_13, SX1509_LED_14, SX1509_LED_15, SX1509_LED_16};

uint8_t last_index;
bool lock;

//////////////////
//////////////////
//////////////////

void setup()
{
  // initialize serial communication at 115200 bits per second:
  Serial.begin(115200);
  while (!Serial);
  //delay(1000);
  Serial.println("SX1509 Example");

  Wire.begin();

  pinMode (LED_BUILTIN, OUTPUT);
  digitalWrite (LED_BUILTIN, LOW);

  // Call io.begin(<address>) to initialize the SX1509. If it
  // successfully communicates, it'll return 1.
  if (io.begin(SX1509_ADDRESS) == false)
  {
    Serial.println("Failed to communicate. Check wiring and address of SX1509.");
    while (1)
      ; // If we fail to communicate, loop forever.
  }

  // Use the pinMode(<pin>, <mode>) function to set our led
  // pin as an ANALOG_OUTPUT, which is required for PWM output
  io.pinMode(SX1509_LED_16, ANALOG_OUTPUT);
  io.pinMode(SX1509_LED_15, ANALOG_OUTPUT);
  io.pinMode(SX1509_LED_14, ANALOG_OUTPUT);
  io.pinMode(SX1509_LED_13, ANALOG_OUTPUT);
  io.pinMode(SX1509_LED_12, ANALOG_OUTPUT);
  io.pinMode(SX1509_LED_11, ANALOG_OUTPUT);
  io.pinMode(SX1509_LED_10, ANALOG_OUTPUT);
  io.pinMode(SX1509_LED_9, ANALOG_OUTPUT);
  io.pinMode(SX1509_LED_8, ANALOG_OUTPUT);
  io.pinMode(SX1509_LED_7, ANALOG_OUTPUT);
  io.pinMode(SX1509_LED_6, ANALOG_OUTPUT);
  io.pinMode(SX1509_LED_5, ANALOG_OUTPUT);
  io.pinMode(SX1509_LED_4, ANALOG_OUTPUT);
  io.pinMode(SX1509_LED_3, ANALOG_OUTPUT);
  io.pinMode(SX1509_LED_2, ANALOG_OUTPUT);
  io.pinMode(SX1509_LED_1, ANALOG_OUTPUT);

  //INIT AT LOW LEVEL EACH CHANNEL:

  io.analogWrite(SX1509_LED_16, 0);
  io.analogWrite(SX1509_LED_15, 0);
  io.analogWrite(SX1509_LED_14, 0);
  io.analogWrite(SX1509_LED_13, 0);
  io.analogWrite(SX1509_LED_12, 0);
  io.analogWrite(SX1509_LED_11, 0);
  io.analogWrite(SX1509_LED_10, 0);
  io.analogWrite(SX1509_LED_9, 0);
  io.analogWrite(SX1509_LED_8, 0);
  io.analogWrite(SX1509_LED_7, 0);
  io.analogWrite(SX1509_LED_6, 0);
  io.analogWrite(SX1509_LED_5, 0);
  io.analogWrite(SX1509_LED_4, 0);
  io.analogWrite(SX1509_LED_3, 0);
  io.analogWrite(SX1509_LED_2, 0);
  io.analogWrite(SX1509_LED_1, 0);

  index = 0;
  last_index = index;
  lock = false;

  //INIT FIRST STATE:
  SIGNAL_LIGHT_COMBO = SIGNAL_LIGHT_COMBO_LIST[index];
  SIGNAL_LIGHT_MODE = SIGNAL_LIGHT_MODE_LIST[index];

  starttime = millis();
  starttime2 = millis();

  Serial.println("Init Done");

}

////////////////////
////////////////////
////////////////////
void loop()
{
  currenttime = millis();

  digitalWrite(LED_BUILTIN, bascule);

  ///////////////
  //SIGNAL 1:
  ///////////////
  for (uint8_t i = 0; i < 8; i++)
  {
    switch (bitRead(SIGNAL_LIGHT_MODE, i)) //SORTIE FIXE ou CLI
    {
      case 1: //SORTIE FIXE
        if (bitRead(SIGNAL_LIGHT_COMBO, i) == 1) //quelle sortie active?
        {
          io.analogWrite(SX1509_LED[i],  SIGNAL_1_COLOR_LEVELS[i]); //allumer selon level
        }
        else
        {
          io.analogWrite(SX1509_LED[i], 0); //eteindre les autres
        }
        break;

      case 0: //SORTIE CLIGNOTANTE

        if (bascule == 1)
        {
          if (bitRead(SIGNAL_LIGHT_COMBO, i) == 1) //quelle sortie active?
          {
            if (bitRead(SIGNAL_LIGHT_PHASE, i) == 1 )
            {
              io.analogWrite(SX1509_LED[i],  SIGNAL_1_COLOR_LEVELS[i]); //allumer selon level
            }
            else
            {
              io.analogWrite(SX1509_LED[i], 0);
            }
          }
        }
        else //(bascule == 0)
        {
          if (bitRead(SIGNAL_LIGHT_COMBO, i) == 1)
          {
            if (bitRead(SIGNAL_LIGHT_PHASE, i) == 1)
            {
              io.analogWrite(SX1509_LED[i], 0);
            }
            else
            {
              io.analogWrite(SX1509_LED[i],  SIGNAL_1_COLOR_LEVELS[i]);
            }
          }
        }
        break;
    }
  }

  /////////////////
  //SIGNAL 2
  ////////////////
  for (uint8_t i = 0; i < 8; i++)
  {
    if (index == 20)
    {
      SIGNAL_LIGHT_PHASE2 = 0b11111011;
    }
    else
    {
      SIGNAL_LIGHT_PHASE2 = 0b11111111;
    }


    switch (bitRead(SIGNAL_LIGHT_MODE, i)) //SORTIE FIXE ou CLI
    {
      case 1: //SORTIE FIXE
        if (bitRead(SIGNAL_LIGHT_COMBO, i) == 1) //quelle sortie active?
        {
          io.analogWrite(SX1509_LED[15 - i],  SIGNAL_1_COLOR_LEVELS[i]); //allumer selon level
        }
        else
        {
          io.analogWrite(SX1509_LED[15 - i], 0); //eteindre les autres
        }
        break;

      case 0: //SORTIE CLIGNOTANTE

        if (bascule == 1)
        {
          if (bitRead(SIGNAL_LIGHT_COMBO, i) == 1) //quelle sortie active?
          {
            if (bitRead(SIGNAL_LIGHT_PHASE2, i) == 1 )
            {
              io.analogWrite(SX1509_LED[15 - i],  SIGNAL_1_COLOR_LEVELS[i]); //allumer selon level
            }
            else
            {
              io.analogWrite(SX1509_LED[15 - i], 0);
            }
          }
        }
        else //(bascule == 0)
        {
          if (bitRead(SIGNAL_LIGHT_COMBO, i) == 1)
          {
            if (bitRead(SIGNAL_LIGHT_PHASE2, i) == 1)
            {
              io.analogWrite(SX1509_LED[15 - i], 0);
            }
            else
            {
              io.analogWrite(SX1509_LED[15 - i],  SIGNAL_1_COLOR_LEVELS[i]);
            }
          }
        }
        break;
    }
  }


  ///////////////////
  //TIMINGS SWAPS:
  //////////////////
  if (currenttime - starttime > 500)
  {
    bascule = !bascule;
    starttime = millis();
  }

  if (currenttime - starttime2 > 8000)
  {
    if (index < 20)
    {
      index++;
    }
    else
    {
      index = 0;
    }

    SIGNAL_LIGHT_COMBO = SIGNAL_LIGHT_COMBO_LIST[index];
    SIGNAL_LIGHT_MODE = SIGNAL_LIGHT_MODE_LIST[index];

    starttime2 = millis();
  }

  ////
  if (lock == false)
  {
    Serial.print("index: ");
    Serial.println(index);

    lock = true;

    Serial.print("SIGNAL : ");
    switch (index)
    {
      case 0:
        Serial.println("VOIE LIBRE");
        break;

      case 1:
        Serial.println("VERT CLI/RAL 160");
        break;

      case 2:
        Serial.println("AVERTISSEMENT");
        break;

      case 3:
        Serial.println("JAUNE CLI");
        break;

      case 4:
        Serial.println("SEMAPHORE");
        break;

      case 5:
        Serial.println("ROUGE CLI");
        break;

      case 6:
        Serial.println("CARRE");
        break;

      case 7:
        Serial.println("CARRE VIOLET");
        break;

      case 8:
        Serial.println("MANOEUVRE");
        break;

      case 9:
        Serial.println("BLANC CLI");
        break;

      case 10:
        Serial.println("RAL30");
        break;

      case 11:
        Serial.println("RAL60");
        break;

      case 12:
        Serial.println("RAPPEL RAL30");
        break;

      case 13:
        Serial.println("RAPPEL RAL60");
        break;

      case 14:
        Serial.println("AVERTISSEMENT + RAPPEL RAL30");
        break;

      case 15:
        Serial.println("AVERTISSEMENT + RAPPEL RAL60");
        break;

      case 16:
        Serial.println("JAUNE CLI + RAPPEL RAL60");
        break;

      case 17:
        Serial.println("AVERTISSEMENT + RAL60");
        break;

      case 18:
        Serial.println("JAUNE CLI + RAL60");
        break;

      case 19:
        Serial.println("DISQUE");
        break;

      case 20:
        Serial.println("PN");
        break;
   
    }
   
  }


  if (last_index != index)
  {
    lock = false;
    last_index = index;
  }

  ////


}

La rotation s'effectue toutes les 8 secondes et la fréquence de 1Hz effectue donc un changement d état pour les signaux clignotant toutes les 500ms ( estimatif car non base sur une interruption hardware d'un TIMER)

Une piste d'amélioration :)

edit: ajout fonction de suivi des états sur le moniteur série


Laurent
« Modifié: février 02, 2023, 08:47:24 pm par laurentr »

laurentr

  • Hero Member
  • *****
  • Messages: 565
    • Voir le profil
Re : SIGNAUX: CIBLES ET DECODEURS
« Réponse #25 le: février 02, 2023, 09:05:15 pm »
Complément d'info:

La gestion de l'affichage/effacement de l'œilleton est accordé avec la combinaison de chaque feu.

Illustration du montage demo en photo.

On repère bien les 4 fils "uniques" qui vont du Nano Every vers le module SX1509.

La magie opère ensuite pour peu que l'on se projette avec les bonnes couleurs de leds (ici toutes bleues)


Laurent