Décodeur pour signaux SNCF à base d'Arduino

Toutes les discussions sur l'Arduino !

Modérateur : MOD

macsddau
Papotier
Messages : 114
Enregistré le : jeu. 17 oct. 2013, 21:46
Echelle pratiquée : N

Décodeur pour signaux SNCF à base d'Arduino

Message par macsddau » dim. 06 juil. 2014, 21:19

Bonjour à tous.

J'écrit actuellement un programme pour un décodeur DCC pour signaux SNCF. Pour ce faire j'utilise trois librairies Arduino à ma sauce : Signal, Lamp, Pattern. La définition de ces librairies ce présentent à peu près sous cette forme :
dans Signal.h

Code : Tout sélectionner

class Signal {
  Signal();
  Lamp lamps[8];
  Pattern patterns[9];
}

dans Lamp.h

Code : Tout sélectionner

class Lamp {
  Lamp();
}

dans Pattern.h

Code : Tout sélectionner

class Pattern {
  Patern();
  Lamp lamps[8];
}

J'aimerai savoir si, sachant que la fonction Signal() est vide, lorsque je crée un objets de type Signal, les 8 "lamps" et les 9 "patterns" sont créés automatiquement ?
En fonctions de vos réponses, d'autres question viendrons mais je vous donne une indication sur le but de ces échanges : avoir dans "Pattern.lamps" quelques unes des "Signal.lamps" (mêmes objets : adresse identique en mémoire).

Merci d'avance à tous ceux qui me viendrons en aide.
Modifié en dernier par macsddau le lun. 07 juil. 2014, 23:44, modifié 1 fois.
MS2 CC2 S-DEC-4-DC Rocrail

Avatar du membre
jlb
Fécond
Messages : 686
Enregistré le : jeu. 04 oct. 2012, 15:38
Echelle pratiquée : N
Prénom : Jean-Luc
Site Internet : http://modelleisenbahn.triskell.org

Re: C++ (Arduino) et librairies "custom"

Message par jlb » dim. 06 juil. 2014, 21:37

Bonsoir

macsddau a écrit :J'aimerai savoir si, sachant que la fonction Signal() est vide, lorsque je crée un objets de type Signal, les 8 "lamps" et les 9 "patterns" sont créés automatiquement ?


elles le sont

En fonctions de vos réponses, d'autres question viendrons mais je vous donne une indication sur le but de ces échanges : avoir dans "Pattern.lamps" quelques unes des "Signal.lamps" (mêmes objets : adresse identique en mémoire).


Là par contre je n'ai pas compris :)

Avatar du membre
jlb
Fécond
Messages : 686
Enregistré le : jeu. 04 oct. 2012, 15:38
Echelle pratiquée : N
Prénom : Jean-Luc
Site Internet : http://modelleisenbahn.triskell.org

Re: C++ (Arduino) et librairies "custom"

Message par jlb » dim. 06 juil. 2014, 21:38

[quote="macsddau"]

Code : Tout sélectionner

class Pattern {
  Patern();
  Lamp lamps[8];
}


le nom du constructeur est Pattern, non ?

macsddau
Papotier
Messages : 114
Enregistré le : jeu. 17 oct. 2013, 21:46
Echelle pratiquée : N

Décodeur pour signaux SNCF à base d'Arduino

Message par macsddau » dim. 06 juil. 2014, 21:53

Merci jlb pour ta réponse rapide.
jlb a écrit :le nom du constructeur est Pattern, non ?
Oui il manque un "t". Je veux aller trop vite et ma relecture laisse des fautes.
jlb a écrit :Là par contre je n'ai pas compris
Tu vas comprendre tout de suite :
Si j'en croie ton explication lorsque que les "Signal.patterns" vont être créés automatiquement eux aussi, je vais me retrouver avec 9x8=72 nouvelles "lamps" qui n'ont rien à voir avec celles de "Signal.lamps". Aie ! C'est là que ça fait mal à la mémoire de l'Arduino Uno (que je compte remplacé au final par une carte maison avec un ATTiny84 à 512 octets de RAM).
Y a-t-il un moyen que ces objets ne soient pas créés automatiquement ?
Modifié en dernier par macsddau le lun. 07 juil. 2014, 23:45, modifié 1 fois.
MS2 CC2 S-DEC-4-DC Rocrail

Avatar du membre
jlb
Fécond
Messages : 686
Enregistré le : jeu. 04 oct. 2012, 15:38
Echelle pratiquée : N
Prénom : Jean-Luc
Site Internet : http://modelleisenbahn.triskell.org

Re: C++ (Arduino) et librairies "custom"

Message par jlb » lun. 07 juil. 2014, 06:56

Bonjour,

Oui il y a moyen en faisant de l'allocation dynamique mais j'ai aussi l'impression qu'il y a un pb de structuration de tes objets.

SI je comprends :

- Un signal contient un certain nombre de lampes
- Un signal contient un certain nombre de patterns qui sont une combinaison d'allumage des lampes.

Donc un pattern devrait référencer des lampes du signal mais ne pas instancier ses propres lampes.

Donc Pattern deviendrait :

Code : Tout sélectionner

class Pattern {
  Pattern();
  Lamp *lamps[8];
}


Et son constructeur prendrait des pointeurs de Lamp passés par la classe Signal et initialiserait le tableau de pointeurs de Lamp.

macsddau
Papotier
Messages : 114
Enregistré le : jeu. 17 oct. 2013, 21:46
Echelle pratiquée : N

Re: C++ (Arduino) et librairies "custom"

Message par macsddau » lun. 07 juil. 2014, 07:12

jlb a écrit :SI je comprends :

- Un signal contient un certain nombre de lampes
- Un signal contient un certain nombre de patterns qui sont une combinaison d'allumage des lampes.

Donc un pattern devrait référencer des lampes du signal mais ne pas instancier ses propres lampes.

Donc Pattern deviendrait :

Code : Tout sélectionner

class Pattern {
  Pattern();
  Lamp *lamps[8];
}

C'est tout à fait ça. En parcourant la littérature pour Nuls, c'est en effet ce que j'en avais déduit. Il va donc falloir que j'étudie plus en détail les " * " dans ou à l'extérieur des " ( ) "...
MS2 CC2 S-DEC-4-DC Rocrail

macsddau
Papotier
Messages : 114
Enregistré le : jeu. 17 oct. 2013, 21:46
Echelle pratiquée : N

Re: C++ (Arduino) et librairies "custom"

Message par macsddau » lun. 07 juil. 2014, 23:32

Je viens de modifier le programme en suivant les instructions de jlb. C'est en effet la bonne solution. voici quelques morceaux du code :
dans le fichier .ino

Code : Tout sélectionner

void setup() {
[…]
    Lamp* pLamp;
   
    pLamp = new Lamp(DDR_LAMP_A,  DDRB_LAMP_A,  DDRBL_LAMP_A,  PR_LAMP_A,  PRB_LAMP_A,  PM_LAMP_A);
    signal.setLamp(lampA,pLamp);
    pLamp = new Lamp(DDR_LAMP_S,  DDRB_LAMP_S,  DDRBL_LAMP_S,  PR_LAMP_S,  PRB_LAMP_S,  PM_LAMP_S);
    signal.setLamp(lampS,pLamp);
    pLamp = new Lamp(DDR_LAMP_VL, DDRB_LAMP_VL, DDRBL_LAMP_VL, PR_LAMP_VL, PRB_LAMP_VL, PM_LAMP_VL);
    signal.setLamp(lampVL,pLamp);
    pLamp = new Lamp(DDR_LAMP_M,  DDRB_LAMP_M,  DDRBL_LAMP_M,  PR_LAMP_M,  PRB_LAMP_M,  PM_LAMP_M);
    signal.setLamp(lampM,pLamp);
    pLamp = new Lamp(DDR_LAMP_C,  DDRB_LAMP_C,  DDRBL_LAMP_C,  PR_LAMP_C,  PRB_LAMP_C,  PM_LAMP_C);
    signal.setLamp(lampC,pLamp);
    pLamp = new Lamp(DDR_LAMP_R,  DDRB_LAMP_R,  DDRBL_LAMP_R,  PR_LAMP_R,  PRB_LAMP_R,  PM_LAMP_R);
    signal.setLamp(lampR,pLamp);
    pLamp = new Lamp(DDR_LAMP_RR, DDRB_LAMP_RR, DDRBL_LAMP_RR, PR_LAMP_RR, PRB_LAMP_RR, PM_LAMP_RR);
    signal.setLamp(lampRR,pLamp);
    pLamp = new Lamp(DDR_LAMP_OE, DDRB_LAMP_OE, DDRBL_LAMP_OE, PR_LAMP_OE, PRB_LAMP_OE, PM_LAMP_OE);
    signal.setLamp(lampOE,pLamp);
   
    Pattern* pPattern;
    for (uint8_t p = 0; p < PATTERN_COUNT; p++) {
        pPattern = new Pattern(_patterns[p]);
        signal.setPattern(p, pPattern);
        for (uint8_t l = 0; l < LAMP_COUNT; l++) {
            pPattern->setLamp(l, signal.getLamp(l));
        }
    }
[…]
    signal.displayPattern(patternOff);
[…]
}

dans Signal.h

Code : Tout sélectionner

class Signal {
public:
    Signal();

    void        setLamp(uint8_t aLamp, Lamp* pLamp);
    Lamp*       getLamp(uint8_t aLamp);
   
    void        setPattern(uint8_t aPattern, Pattern* pPattern);
    void        displayPattern(uint8_t aPattern);
   
    void        update();
private:
    Pattern*    pPatterns[PATTERN_COUNT];
    Lamp*       pLamps[LAMP_COUNT];
};

dans Pattern.h

Code : Tout sélectionner

class Pattern {  
public:
    Pattern(uint8_t aPattern);
    void    setLamp(uint8_t aLamp, Lamp* pLamp);
    void    display();
private:
    Lamp*   pLamps[LAMP_COUNT];
    uint8_t pattern;
};

et pour finir dans Lamp.h

Code : Tout sélectionner

class Lamp {
public:
    Lamp(volatile uint8_t&  ddr,    //data direction register
         uint8_t            ddrb,   //data direction register bit
         bitLevel_t         ddrbl,  //data direction register bit level (set / clear)
         volatile uint8_t&  pr,     //port register
         uint8_t            prb,    //port register bit
         pullMode           pm);    //pull up
   
    void        switchOn();
    void        switchOff();
[…]   
    void        update();   
private:
    volatile uint8_t*   port;       //port register
    uint8_t             bit;        //port register bit
    pullMode            mode;       //pullup or pulldown
[…]
};


J'ai galèré pour trouver comment passer à la classe Lamp les registres du microcontrôleur, mais la solution mise en oeuvre commence à me faire plaisir.

Cdt.
MS2 CC2 S-DEC-4-DC Rocrail

Avatar du membre
jlb
Fécond
Messages : 686
Enregistré le : jeu. 04 oct. 2012, 15:38
Echelle pratiquée : N
Prénom : Jean-Luc
Site Internet : http://modelleisenbahn.triskell.org

Re: C++ (Arduino) et librairies "custom"

Message par jlb » mar. 08 juil. 2014, 06:54

Bonjour,

macsddau a écrit :et pour finir dans Lamp.h

Code : Tout sélectionner

class Lamp {
public:
    Lamp(volatile uint8_t&  ddr,    //data direction register
         uint8_t            ddrb,   //data direction register bit
         bitLevel_t         ddrbl,  //data direction register bit level (set / clear)
         volatile uint8_t&  pr,     //port register
         uint8_t            prb,    //port register bit
         pullMode           pm);    //pull up
   
    void        switchOn();
    void        switchOff();
[…]   
    void        update();   
private:
    volatile uint8_t*   port;       //port register
    uint8_t             bit;        //port register bit
    pullMode            mode;       //pullup or pulldown
[…]
};



Je comprends tout à fait la volonté d'optimiser en ne passant pas par pinMode et digitalWrite pour programmer le port et allumer ou éteindre une lampe.

Mais pour cette appli, ça ne se justifie pas je pense. Il n'est pas nécessaire d'être performant en temps d'exécution et un objet Lamp stocke au moins 3 octets (le pointer vers le registre et le numéro de bit). En ne stockant que le numéro de pin virtuelle, il n'occuperait qu'un octet. Le constructeur serait considérablement allégé, les appels aussi. Le programme gagnerait en clarté. Question : pourquoi stocker l'info de pullUp ?

Bonne journée

macsddau
Papotier
Messages : 114
Enregistré le : jeu. 17 oct. 2013, 21:46
Echelle pratiquée : N

Re: Décodeur pour signaux SNCF à base d'Arduino

Message par macsddau » mar. 08 juil. 2014, 08:17

jlb a écrit :Je comprends tout à fait la volonté d'optimiser en ne passant pas par pinMode et digitalWrite pour programmer le port et allumer ou éteindre une lampe.

Mais pour cette appli, ça ne se justifie pas je pense.

Actuellement je développe sur une carte Arduino UNO mais je trouve l'ATmega328P un peu trop riche en E/S. J'essaye donc de rendre mon code le plus universelle pour qu'il puisse fonctionner sur un ATtiny84 (signaux sur cible H et le shield de programmation pour le premier est déjà prêt : http://forum.e-train.fr/viewtopic.php?f=63&t=75315&start=105#p1595668)voir sur un ATtiny85 (signaux de manoeuvre CV/M). Pour cela je ne peut pas utiliser les commandes usuelles d'Arduino mais je dois passer par l'accès directe aux registres.
Ci dessous le fichier de définition correspondant à la carte. On voit que le code est delà prévu pour 2 modèles de MCU.

Code : Tout sélectionner

#include <avr/io.h>

#if defined(__AVR_ATmega328P__) //Arduino UNO board with ATmega328P MCU

#define     DDR_LAMP_A      DDRD    //data direction register
#define     DDR_LAMP_S      DDRD
#define     DDR_LAMP_VL     DDRD
#define     DDR_LAMP_M      DDRD
#define     DDR_LAMP_C      DDRB
#define     DDR_LAMP_R      DDRB
#define     DDR_LAMP_RR     DDRB
#define     DDR_LAMP_OE     DDRB
#define     DDRB_LAMP_A     DDD4    //data direction register bit
#define     DDRB_LAMP_S     DDD5
#define     DDRB_LAMP_VL    DDD6
#define     DDRB_LAMP_M     DDD7
#define     DDRB_LAMP_C     DDB0
#define     DDRB_LAMP_R     DDB1
#define     DDRB_LAMP_RR    DDB2
#define     DDRB_LAMP_OE    DDB3
#define     DDRBL_LAMP_A    set     //data direction register bit level (set / clear)
#define     DDRBL_LAMP_S    set
#define     DDRBL_LAMP_VL   set
#define     DDRBL_LAMP_M    set
#define     DDRBL_LAMP_C    set
#define     DDRBL_LAMP_R    set
#define     DDRBL_LAMP_RR   set
#define     DDRBL_LAMP_OE   set
#define     PR_LAMP_A       PORTD   //port register
#define     PR_LAMP_S       PORTD
#define     PR_LAMP_VL      PORTD
#define     PR_LAMP_M       PORTD
#define     PR_LAMP_C       PORTB
#define     PR_LAMP_R       PORTB
#define     PR_LAMP_RR      PORTB
#define     PR_LAMP_OE      PORTB
#define     PRB_LAMP_A      PORTD4  //port register bit
#define     PRB_LAMP_S      PORTD5
#define     PRB_LAMP_VL     PORTD6
#define     PRB_LAMP_M      PORTD7
#define     PRB_LAMP_C      PORTB0
#define     PRB_LAMP_R      PORTB1
#define     PRB_LAMP_RR     PORTB2
#define     PRB_LAMP_OE     PORTB3
#define     PM_LAMP_A       pullup  //pull mode (pullup / pulldown)
#define     PM_LAMP_S       pullup
#define     PM_LAMP_VL      pullup
#define     PM_LAMP_M       pullup
#define     PM_LAMP_C       pullup
#define     PM_LAMP_R       pullup
#define     PM_LAMP_RR      pullup
#define     PM_LAMP_OE      pullup

#elif defined(__AVR_ATtiny84__) //Shield for Arduino UNO with ATtiny84 MCU

#define     DDR_LAMP_A      DDRA    //data direction register
#define     DDR_LAMP_S      DDRA
#define     DDR_LAMP_VL     DDRA
#define     DDR_LAMP_M      DDRA
#define     DDR_LAMP_C      DDRA
#define     DDR_LAMP_R      DDRA
#define     DDR_LAMP_RR     DDRA
#define     DDR_LAMP_OE     DDRA
#define     DDRB_LAMP_A     DDA7    //data direction register bit
#define     DDRB_LAMP_S     DDA6
#define     DDRB_LAMP_VL    DDA5
#define     DDRB_LAMP_M     DDA4
#define     DDRB_LAMP_C     DDA3
#define     DDRB_LAMP_R     DDA2
#define     DDRB_LAMP_RR    DDA1
#define     DDRB_LAMP_OE    DDA0
#define     DDRBL_LAMP_A    set     //data direction register bit level
#define     DDRBL_LAMP_S    set
#define     DDRBL_LAMP_VL   set
#define     DDRBL_LAMP_M    set
#define     DDRBL_LAMP_C    set
#define     DDRBL_LAMP_R    set
#define     DDRBL_LAMP_RR   set
#define     DDRBL_LAMP_OE   set
#define     PR_LAMP_A       PORTA   //port register
#define     PR_LAMP_S       PORTA
#define     PR_LAMP_VL      PORTA
#define     PR_LAMP_M       PORTA
#define     PR_LAMP_C       PORTA
#define     PR_LAMP_R       PORTA
#define     PR_LAMP_RR      PORTA
#define     PR_LAMP_OE      PORTA
#define     PRB_LAMP_A      PORTA7  //port register bit
#define     PRB_LAMP_S      PORTA6
#define     PRB_LAMP_VL     PORTA5
#define     PRB_LAMP_M      PORTA4
#define     PRB_LAMP_C      PORTA3
#define     PRB_LAMP_R      PORTA2
#define     PRB_LAMP_RR     PORTA1
#define     PRB_LAMP_OE     PORTA0
#define     PM_LAMP_A       pullup  //pull mode
#define     PM_LAMP_S       pullup
#define     PM_LAMP_VL      pullup
#define     PM_LAMP_M       pullup
#define     PM_LAMP_C       pullup
#define     PM_LAMP_R       pullup
#define     PM_LAMP_RR      pullup
#define     PM_LAMP_OE      pullup

#else
#error Unknown MCU
#endif

enum {
    lampA,
    lampS,
    lampVL,
    lampM,
    lampC,
    lampR,
    lampRR,
    lampOE
};
#define LAMP_COUNT  8

enum {
    patternOff,
    patternA,
    patternS,
    patternVL,
    patternM,
    patternCR,
    patternCV,
    patternR,
    patternRR
};
#define PATTERN_COUNT   9

const uint8_t _patterns[PATTERN_COUNT] = {
    0x00,                           //patternOff
    (1 << lampA)  | (1 << lampOE),  //patternA
    (1 << lampS)  | (1 << lampOE),  //patternS
    (1 << lampVL) | (1 << lampOE),  //patternVL
    (1 << lampM),                   //patternM
    (1 << lampS)  | (1 << lampC),   //patternCR
    (1 << lampC),                   //patternCV
    (1 << lampR),                   //patternR
    (1 << lampRR)                   //patternRR
};


jlb a écrit :Question : pourquoi stocker l'info de pullUp ?

Je n'ai pas encore décidé de la méthode de câblage des sorties. Sur la plaque d'essai j'utilise le pullup mais je ne sais pas si je conserverai ce mode sur les circuits définitifs (à base d'ATtiny). Je pourrais toujours supprimer cette information plus tard.

Cdt.

ps. J'ai renommé ce sujet pour être plus général et vous pourrez suivre l'évolution de mes travaux sur ce décodeur
MS2 CC2 S-DEC-4-DC Rocrail

macsddau
Papotier
Messages : 114
Enregistré le : jeu. 17 oct. 2013, 21:46
Echelle pratiquée : N

Re: Décodeur pour signaux SNCF à base d'Arduino

Message par macsddau » dim. 13 juil. 2014, 09:40

Bonjour à tous,

Actuellement je bloque lors de la compilation. Les messages sont les suivants :

Code : Tout sélectionner

Builds/main.o:(.data._dataDirectionRegisters+0x0): multiple definition of 
 `_dataDirectionRegisters'
Builds/Lamp.o:(.data._dataDirectionRegisters+0x0): first defined here
Builds/main.o:(.data._portRegisters+0x0): multiple definition of `_portRegisters'
Builds/Lamp.o:(.data._portRegisters+0x0): first defined here


Une info importante, je développe sous EmbedXCode !

Voici le fichier SignalModule.h de définition :

Code : Tout sélectionner

#ifndef SignalModule_h
#define SignalModule_h

#include <avr/io.h>
#include <avr/pgmspace.h>

//LAMP_COUNT
//  number of lamps (or groups)
#define LAMP_COUNT  8

//DATA_DIRECTION_REGISTER_BIT_LEVEL
//  0: clear
//  1: set
#define DATA_DIRECTION_REGISTER_BIT_LEVEL   1

//_dataDirectionRegisters
const prog_uint8_t* _dataDirectionRegisters[LAMP_COUNT] = {
#if defined(__AVR_ATmega328P__)
    (uint8_t*) &DDRD,
    (uint8_t*) &DDRD,
    (uint8_t*) &DDRD,
    (uint8_t*) &DDRD,
    (uint8_t*) &DDRB,
    (uint8_t*) &DDRB,
    (uint8_t*) &DDRB,
    (uint8_t*) &DDRB
#elif defined(__AVR_ATtiny84__)
    (uint8_t*) &DDRA,
    (uint8_t*) &DDRA,
    (uint8_t*) &DDRA,
    (uint8_t*) &DDRA,
    (uint8_t*) &DDRA,
    (uint8_t*) &DDRA,
    (uint8_t*) &DDRA,
    (uint8_t*) &DDRA
#else
#error  Unknown MCU
#endif
};

//_dataDirectionRegisterBits
const prog_uint8_t _dataDirectionRegisterBits[LAMP_COUNT] = {
#if defined(__AVR_ATmega328P__)
    DDD4,
    DDD5,
    DDD6,
    DDD7,
    DDB0,
    DDB1,
    DDB2,
    DDB3
#elif defined(__AVR_ATtiny84__)
    DDA0,
    DDA1,
    DDA2,
    DDA3,
    DDA4,
    DDA5,
    DDA6,
    DDA7
#else
#error  Unknown MCU
#endif
};

//_portRegisters
const prog_uint8_t* _portRegisters[LAMP_COUNT] = {
#if defined(__AVR_ATmega328P__)
    (uint8_t*) &PORTD,
    (uint8_t*) &PORTD,
    (uint8_t*) &PORTD,
    (uint8_t*) &PORTD,
    (uint8_t*) &PORTB,
    (uint8_t*) &PORTB,
    (uint8_t*) &PORTB,
    (uint8_t*) &PORTB
#elif defined(__AVR_ATtiny84__)
    (uint8_t*) &PORTA,
    (uint8_t*) &PORTA,
    (uint8_t*) &PORTA,
    (uint8_t*) &PORTA,
    (uint8_t*) &PORTA,
    (uint8_t*) &PORTA,
    (uint8_t*) &PORTA,
    (uint8_t*) &PORTA
#else
#error  Unknown MCU
#endif
};

//_portRegisterBits
const prog_uint8_t _portRegisterBits[LAMP_COUNT] = {
#if defined(__AVR_ATmega328P__)
    PORTD4,
    PORTD5,
    PORTD6,
    PORTD7,
    PORTB0,
    PORTB1,
    PORTB2,
    PORTB3
#elif defined(__AVR_ATtiny84__)
    PORTA0,
    PORTA1,
    PORTA2,
    PORTA3,
    PORTA4,
    PORTA5,
    PORTA6,
    PORTA7
#else
#error  Unknown MCU
#endif
};

//PORT_MODE
//  0: pulldown
//  1: pullup
#define PORT_MODE 1

//lamps names
enum {lampA, lampS, lampVL, lampM, lampC, lampR, lampRR, lampOE };

//PATTERN_COUNT
//  number of parterns
#define PATTERN_COUNT 8

//patterns names
enum {patternA, patternS, patternVL, patternCR, patternM, patternCV, patternR, patternRR };

//patterns definitions
const prog_uint8_t _patterns[PATTERN_COUNT] = {
    (1 << lampA)  | (1 << lampOE),
    (1 << lampS)  | (1 << lampOE),
    (1 << lampVL) | (1 << lampOE),
    (1 << lampS)  | (1 << lampC),
    (1 << lampM),
    (1 << lampC),
    (1 << lampR),
    (1 << lampRR)
};

#endif


ce fichier est inclus dans :
Lamp.h

Code : Tout sélectionner

#ifndef Lamp_h
#define Lamp_h

#include "SignalModule.h"
[…]
#endif

lui même inclus dans Lamp.cpp et dans SignalModule.ino

Est-ce que quelqu'un aurait une idée pour résoudre ce problème ?
MS2 CC2 S-DEC-4-DC Rocrail

Avatar du membre
jlb
Fécond
Messages : 686
Enregistré le : jeu. 04 oct. 2012, 15:38
Echelle pratiquée : N
Prénom : Jean-Luc
Site Internet : http://modelleisenbahn.triskell.org

Re: Décodeur pour signaux SNCF à base d'Arduino

Message par jlb » dim. 13 juil. 2014, 13:55

Bonjour,

Comme ta constante es définie dans le .h, elle se retrouve définie autant de fois que le .h est inclus. À l'édition de lien ça coince.

Ce qu'il faut faire :

1. Déclarer la contante dans le .h comme ceci :

Code : Tout sélectionner

extern const blabla ...


Sans l'initialiser

Puis dans le .c ce que tu avais auparavant dans le .h

macsddau
Papotier
Messages : 114
Enregistré le : jeu. 17 oct. 2013, 21:46
Echelle pratiquée : N

Re: Décodeur pour signaux SNCF à base d'Arduino

Message par macsddau » dim. 13 juil. 2014, 16:18

Merci pour ta réponse.
jlb a écrit :1. Déclarer la contante dans le .h comme ceci :

Code : Tout sélectionner

extern const blabla ...

Sans l'initialiser
Puis dans le .c ce que tu avais auparavant dans le .h

Pourquoi ne pas l'initialiser ?
Si je met en application ce que tu me décris, je me retrouve avec mes définitions en dehors du fichier ".h". Malheureusement c'est le contraire de ce que je veux faire : avoir toutes mes définitions dans un seul fichier ".h". Comment faire ?
MS2 CC2 S-DEC-4-DC Rocrail

Avatar du membre
jlb
Fécond
Messages : 686
Enregistré le : jeu. 04 oct. 2012, 15:38
Echelle pratiquée : N
Prénom : Jean-Luc
Site Internet : http://modelleisenbahn.triskell.org

Re: Décodeur pour signaux SNCF à base d'Arduino

Message par jlb » mar. 15 juil. 2014, 08:12

Si tu veux partager des constantes entre plusieurs fichiers .c, il n'y a qu'une seule solution.

Les définitions vont dans un fichier .c

Les déclarations vont dans le fichier .h correspondant

Le .c inclue le .h pour que le compilateur puisse vérifier la conformité de la déclaration et de la définition.

Les sources qui ont besoin de la constante incluent le .h

macsddau
Papotier
Messages : 114
Enregistré le : jeu. 17 oct. 2013, 21:46
Echelle pratiquée : N

Re: Décodeur pour signaux SNCF à base d'Arduino

Message par macsddau » mer. 16 juil. 2014, 16:03

Bonjour à tous,

Ca y est, les fonctions de base du signal sont en place. voici le lignes de programme :
Lamp.h

Code : Tout sélectionner

#ifndef Lamp_h
#define Lamp_h

//LAMP_COUNT
//  number of lamps (or groups)
#define LAMP_COUNT  8

//lamps names
enum {lampA, lampS, lampVL, lampM, lampC, lampR, lampRR, lampOE };

class Lamp {
   
public:
    Lamp(uint8_t aLamp);
   
    void switchOn();
    void switchOff();
   
    void update();
   
private:
    uint8_t lamp;
    uint8_t state;
   
    void on();
    void off();
    void toggle();
};

#endif

Lamp.cpp

Code : Tout sélectionner

// Library header
#include "Lamp.h"
#include <avr/io.h>
#include <avr/pgmspace.h>

//DATA_DIRECTION_REGISTER_BIT_LEVEL
//  0: clear
//  1: set
#define DATA_DIRECTION_REGISTER_BIT_LEVEL   1

//_dataDirectionRegisters
const prog_uint8_t* _dataDirectionRegisters[LAMP_COUNT] = {
#if defined(__AVR_ATmega328P__)
    (uint8_t*) &DDRD,
    (uint8_t*) &DDRD,
    (uint8_t*) &DDRD,
    (uint8_t*) &DDRB,
    (uint8_t*) &DDRB,
    (uint8_t*) &DDRB,
    (uint8_t*) &DDRB,
    (uint8_t*) &DDRD
#elif defined(__AVR_ATtiny84__)
    (uint8_t*) &DDRA,
    (uint8_t*) &DDRA,
    (uint8_t*) &DDRA,
    (uint8_t*) &DDRA,
    (uint8_t*) &DDRA,
    (uint8_t*) &DDRA,
    (uint8_t*) &DDRA,
    (uint8_t*) &DDRA
#else
#error  Unknown MCU
#endif
};

//_dataDirectionRegisterBits
const prog_uint8_t _dataDirectionRegisterBits[LAMP_COUNT] = {
#if defined(__AVR_ATmega328P__)
    DDD5,
    DDD6,
    DDD7,
    DDB0,
    DDB1,
    DDB2,
    DDB3,
    DDD4
#elif defined(__AVR_ATtiny84__)
    DDA0,
    DDA1,
    DDA2,
    DDA3,
    DDA4,
    DDA5,
    DDA6,
    DDA7
#else
#error  Unknown MCU
#endif
};

//_portRegisters
const prog_uint8_t* _portRegisters[LAMP_COUNT] = {
#if defined(__AVR_ATmega328P__)
    (uint8_t*) &PORTD,
    (uint8_t*) &PORTD,
    (uint8_t*) &PORTD,
    (uint8_t*) &PORTB,
    (uint8_t*) &PORTB,
    (uint8_t*) &PORTB,
    (uint8_t*) &PORTB,
    (uint8_t*) &PORTD
#elif defined(__AVR_ATtiny84__)
    (uint8_t*) &PORTA,
    (uint8_t*) &PORTA,
    (uint8_t*) &PORTA,
    (uint8_t*) &PORTA,
    (uint8_t*) &PORTA,
    (uint8_t*) &PORTA,
    (uint8_t*) &PORTA,
    (uint8_t*) &PORTA
#else
#error  Unknown MCU
#endif
};

//_portRegisterBits
const prog_uint8_t _portRegisterBits[LAMP_COUNT] = {
#if defined(__AVR_ATmega328P__)
    PORTD5,
    PORTD6,
    PORTD7,
    PORTB0,
    PORTB1,
    PORTB2,
    PORTB3,
    PORTD4
#elif defined(__AVR_ATtiny84__)
    PORTA0,
    PORTA1,
    PORTA2,
    PORTA3,
    PORTA4,
    PORTA5,
    PORTA6,
    PORTA7
#else
#error  Unknown MCU
#endif
};

//PORT_MODE
//  0: pulldown
//  1: pullup
#define PORT_MODE 1

//lamps states
enum {
    lampStateOff,
    lampStateOn
};

// Code
Lamp::Lamp(uint8_t aLamp) {
    lamp = aLamp;
    state = lampStateOff;
   
    if (DATA_DIRECTION_REGISTER_BIT_LEVEL) {
        *(volatile uint8_t *)_dataDirectionRegisters[lamp] |=  (1 << _dataDirectionRegisterBits[lamp]);
    } else {
        *(volatile uint8_t *)_dataDirectionRegisters[lamp] &= ~(1 << _dataDirectionRegisterBits[lamp]);
    }
}

void Lamp::switchOn() {
    state = lampStateOn;
}

void Lamp::switchOff() {
    state = lampStateOff;
}

void Lamp::update() {
    switch (state) {
        case lampStateOff:
            off();
            break;
           
        case lampStateOn:
            on();
            break;
           
        default:
            break;
    }
}

void Lamp::on() {
    if (PORT_MODE) {
        *(volatile uint8_t *)_portRegisters[lamp] &= ~(1 << _portRegisterBits[lamp]);
    } else {
        *(volatile uint8_t *)_portRegisters[lamp] |=  (1 << _portRegisterBits[lamp]);
    }
}

void Lamp::off() {
    if (PORT_MODE) {
        *(volatile uint8_t *)_portRegisters[lamp] |=  (1 << _portRegisterBits[lamp]);
    } else {
        *(volatile uint8_t *)_portRegisters[lamp] &= ~(1 << _portRegisterBits[lamp]);
    }
}

void Lamp::toggle() {
    *(volatile uint8_t *)_portRegisters[lamp] ^=  (1 << _portRegisterBits[lamp]);
}

Pattern.h

Code : Tout sélectionner

#ifndef Pattern_h
#define Pattern_h

//PATTERN_COUNT
//  number of parterns
#define PATTERN_COUNT 8

//patterns names
enum {patternA, patternS, patternVL, patternCR, patternM, patternCV, patternR, patternRR };

//patterns level
//  if new pattern have same level replace level pattern
//  if pattern have other level then add or remove the new pattern
//  one level0 pattern have to be shown at any time
//  level1 and above can be not shown
enum {level0, level1};

class Pattern {
 
public:
    Pattern(uint8_t aPattern);
   
    uint8_t getPattern();
    uint8_t getLevel();
 
private:
    uint8_t pattern;
};

#endif

Pattern.cpp

Code : Tout sélectionner

#include "Pattern.h"
#include "Lamp.h"
#include <avr/pgmspace.h>

//patterns definitions
const prog_uint8_t _patterns[PATTERN_COUNT] = {
    (1 << lampA)  | (1 << lampOE),
    (1 << lampS)  | (1 << lampOE),
    (1 << lampVL) | (1 << lampOE),
    (1 << lampS)  | (1 << lampC),
    (1 << lampM),
    (1 << lampC),
    (1 << lampR),
    (1 << lampRR)
};

const prog_uint8_t _patternLevels[PATTERN_COUNT] = {
    level0,
    level0,
    level0,
    level0,
    level0,
    level0,
    level1,
    level1
};

// Code
Pattern::Pattern(uint8_t aPattern) {
    pattern = aPattern;
}

uint8_t Pattern::getPattern() {
    return _patterns[pattern];
}

uint8_t Pattern::getLevel() {
    return _patternLevels[pattern];
}

SignalModule.ino

Code : Tout sélectionner

#include "Lamp.h"
#include "Pattern.h"
#include "Signal.h"
#include "DCC.h"

// Define variables and constants
//
// Brief
// Details
//
Signal signal;
DCC dcc;

uint8_t curPattern = 0;

void whait(uint32_t ms) {
    uint32_t j;
    volatile uint32_t i;
    for (j = 0; j < ms; j++) {
        for (i = 0; i < 1024; i++) {
        }
    }
}

//
// Brief   Setup
// Details
//
// Add setup code
void setup() {
    Lamp*   lamp;
    for (uint8_t l = 0; l < LAMP_COUNT; l++) {
        lamp = new Lamp(l);
        signal.setLamp(l, lamp);
    }
   
    Pattern* pattern;
    for (uint8_t p = 0; p < PATTERN_COUNT; p++) {
        pattern = new Pattern(p);
        signal.setPattern(p, pattern);
    }
   
    sei();
}

//
// Brief   Loop
// Details   Blink the LED
//
// Add loop code
void loop() {
    signal.display(curPattern);
   
    signal.update();
   
    //prepare next one
    if (curPattern++ >= (PATTERN_COUNT - 1)) {
        curPattern = 0;
        for (uint8_t p = 0; p < PATTERN_COUNT; p++) {
            signal.erase(p);
        }
    }
   
    whait(500);
}

Actuellement, le programme ne fait que afficher un chenillard des motifs.

Dans le dernier programme vous avez vu les lignes :

Code : Tout sélectionner

#include "DCC.h"
DCC dcc;

J'ai commencé a intégrer la partie interface numérique. Voici le programme :
DCC.h

Code : Tout sélectionner

#ifndef DCC_h
#define DCC_h

#define PACKET_MAX_LENGTH   6

class DCC {
 
public:
    DCC();

    //timing
    void startPeriodA(uint8_t aTime);
    void startPeriodB(uint8_t aTime);
    void stretchedZero();
   
    uint8_t address();
    uint8_t instruction(uint8_t aByte);
       
private:
    //timing
    uint8_t periodA;
    uint8_t timerOverflow;
   
    //reading
    uint8_t state;
    uint8_t readCount;
    uint8_t byteIndex;
    uint8_t newPacket[PACKET_MAX_LENGTH];
   
    //active packet
    uint8_t packetLength;
    uint8_t packet[PACKET_MAX_LENGTH - 1];
   
    void storeBit(uint8_t aBit);
    void reset();
};

extern DCC dcc;

#endif

DCC.cpp

Code : Tout sélectionner

#include "DCC.h"

// timing
#define PRESCALAR               8
#define ONE_MIN_TIME            (52L * F_CPU / 1000000L / PRESCALAR)
#define ONE_MAX_TIME            (64L * F_CPU / 1000000L / PRESCALAR)
#define ZERO_MIN_TIME           (90L * F_CPU / 1000000L / PRESCALAR)
#define MAX_PERIOD_DIFFERENCE   ( 6L * F_CPU / 1000000L / PRESCALAR)

// optocoupler delays
#define RISING_DELAY            ( 1L * F_CPU / 1000000L / PRESCALAR)
#define FALLING_DELAY           (14L * F_CPU / 1000000L / PRESCALAR)

//packet
#define MIN_PREAMBLE_BIT_COUNT  10
#define ZERO                    0x00
#define ONE                     0x01
#define PACKET_MIN_LENGTH       3

//dcc machine states
enum {preambleState, dataByteState, startBitState};

// input interrupt processing
ISR(INT0_vect) {
    //save tine
    volatile uint8_t t = TCNT0;
   
    //save port state
#if defined(__AVR_ATmega328P__)
    volatile uint8_t p = PORTD & (1 << PORTD2);
#elif defined(__AVR_ATtiny84__)
    volatile uint8_t p = PORTB & (1 << PORTB2);
#else
#error Unknown MCU
#endif
   
    //restart counter
    TCNT0 = 0;
   
    //process time
    if (p) {
        dcc.startPeriodA(t - RISING_DELAY);
    } else {
        dcc.startPeriodB(t - FALLING_DELAY);
    }
}

// timer overflow interrupt : for very long period (stretched zero)
#if defined(__AVR_ATmega328P__)
ISR(TIMER0_OVF_vect)
#elif defined(__AVR_ATtiny84__)
ISR(TIM0_OVF_vect)
#else
#error Unknown MCU
#endif
{
    dcc.stretchedZero();
}

// Code
DCC::DCC() {
    //input & interrupt pin
#if defined(__AVR_ATmega328P__)
    DDRD  &= ~(1 << DDD2);   // input pin PD2(INT0)
    EIMSK |=  (1 << INT0);   // external interrupt 0
    EICRA &= ~((1 << ISC00) | (1 << ISC01));
    EICRA |=  (1 << ISC00); //pin change interrupt mode
#elif defined(__AVR_ATtiny84__)
    DDRB  &= ~(1 << DDB2);   // input pin PB2(INT0)
    GIMSK |=  (1 << INT0);   // external interrupt 0
    MCUCR &= ~((1 << ISC00) | (1 << ISC01));
    MCUCR |=  (1 << ISC00); //pin change interrupt mode
#else
#error Unknown MCU
#endif

    //timer
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATtiny84__)
    //Arduino use timer0 for it purpose. We must reset.
    TCCR0A &= ~((1 << COM0A1) | (1 << COM0A0) | (1 << COM0B1) | (1 << COM0B0) | (1 << WGM01) | (1 << WGM00));
    TCCR0B &= ~((1 << WGM02) | (1 << CS02) | (1 << CS01) | (1 << CS00));
    TCCR0B |=  (1 << CS00); // clk/8
    TIMSK0 &= ~((1 << OCIE0B) | (1 << OCIE0A) | (1 << TOIE0));
    TIMSK0 |=  (1 << TOIE0);// overflow
#else
#error Unknown MCU
#endif
   
    reset();
    packetLength = 0;
    for (uint8_t b = 0; b < PACKET_MAX_LENGTH - 1; b++) {
        packet[b] = 0;
    }
}

void DCC::startPeriodA(uint8_t aTime) {
    //check period 1 duartion
    if ((periodA >= ONE_MIN_TIME) &&
        (periodA <= ONE_MAX_TIME) &&
        (abs(periodA - aTime) <= MAX_PERIOD_DIFFERENCE)) {
        storeBit(ONE);
    } else if ((periodA >= ZERO_MIN_TIME) || timerOverflow) {
        storeBit(ZERO);
        timerOverflow = 0;
    } else {
        //error not a valid bit
        reset();
        return;
    }
}

void DCC::startPeriodB(uint8_t aTime) {
    periodA = aTime;
}

void DCC::stretchedZero() {
    timerOverflow++;
}

uint8_t DCC::address() {
    return packet[0];
}

uint8_t DCC::instruction(uint8_t aByte) {
    if ((aByte > 0) && (aByte < PACKET_MAX_LENGTH)) {
        return packet[aByte];
    } else {
        return 0;
    }
}

void DCC::storeBit(uint8_t aBit) {
    switch (state) {
        case preambleState:
            if (aBit) {
                //stil in preamble
                readCount++;
            } else {
                if (readCount < MIN_PREAMBLE_BIT_COUNT) {
                    //error preamble to short
                    reset();
                    return;
                }
               
                //it is the packet start bit
                readCount = 0;
                state = dataByteState;
            }
            break;
           
        case dataByteState:
            if (readCount++ < 8) {
                newPacket[byteIndex] << 1;
                newPacket[byteIndex] |= aBit;
            } else {
                state = startBitState;
            }
            break;
           
        case startBitState:
            if (aBit) {
                // packet end
               
                //packet length checking
                if ((byteIndex < PACKET_MIN_LENGTH ) || (byteIndex >  PACKET_MIN_LENGTH)) {
                    reset();
                    return;
                }
               
                //checksum
                uint8_t checksum = newPacket[0];
                for (uint8_t b = 1; b < byteIndex - 1; b++) {
                    checksum ^= newPacket[b];
                }
                if (checksum != newPacket[byteIndex]) {
                    reset();
                    return;
                }
               
                //copy the packet;
                packetLength = byteIndex - 1;
                for (uint8_t b = 0; b < packetLength; b++) {
                    packet[b] = newPacket[b];
                }
               
                byteIndex = 0;
                readCount = 1;//packet end bit considered as the first preamble bit
                state = preambleState;
            } else {
                byteIndex++;
                readCount = 0;
                state = dataByteState;
            }
            break;
    }
}

void DCC::reset() {
    //bit processort reset
    timerOverflow = 0;

    //packet reader processor reset
    state = preambleState;
    readCount = 0;
    byteIndex = 0;
    for (uint8_t b = 0; b < PACKET_MAX_LENGTH; b++) {
        newPacket[b] = 0;
    }
}

J'utilise le timer0 pour gérer le minutage de (voir le standard NMRA S-91) or il est utilisé par Arduino pour gérer les fonctions micros() et millis(). J'ai vu dans Wiring.c que l'interruption overflow est déjà utilisée. Y-a-t-il un moyen de désactiver ce mode de fonctionnement ?
J'attends vos réponses
Cdt.
MS2 CC2 S-DEC-4-DC Rocrail

macsddau
Papotier
Messages : 114
Enregistré le : jeu. 17 oct. 2013, 21:46
Echelle pratiquée : N

Re: Décodeur pour signaux SNCF à base d'Arduino

Message par macsddau » jeu. 17 juil. 2014, 06:21

Bonjour à tous,

J'ai résolu mon problème d'hier en remplaçant le timer0 (8bits) par le timer1 (16bits). Il m'offre deux avantages : il n'est pas utilisé par Arduino (pas d'ISR) et je n'ai plus à gérer les bits "0" étirés (stretched zéro).
J'ai pu enfin commencer à déverminner cette partie du programme. En voici le code :
DCC.h

Code : Tout sélectionner

#ifndef DCC_h
#define DCC_h

#define PACKET_MAX_LENGTH   6

class DCC {
 
public:
    DCC();

    //reading
    void store(uint8_t aBit);
    void reset();
   
    //active packet
    uint8_t address();
    uint8_t length();
    uint8_t instruction(uint8_t aByte);

private:
    //reading
    uint8_t state;
    uint8_t readCount;
    uint8_t packetIndex;
    uint8_t newPacket[PACKET_MAX_LENGTH];
   
    //active packet
    uint8_t packetLength;
    uint8_t packet[PACKET_MAX_LENGTH - 1];
   
};

extern DCC dcc;

volatile extern uint8_t _debug;

#endif

DCC.cpp

Code : Tout sélectionner

#include "DCC.h"

// timing
#define PRESCALAR               8
// NMRA S-91-2004-07 values
#define ONE_MIN_TIME            (52L * F_CPU / 1000000L / PRESCALAR)
#define ONE_MAX_TIME            (64L * F_CPU / 1000000L / PRESCALAR)
#define ZERO_MIN_TIME           (90L * F_CPU / 1000000L / PRESCALAR)
#define MAX_PERIOD_DIFFERENCE   ( 6L * F_CPU / 1000000L / PRESCALAR)

// optocoupler delays
#define RISING_DELAY            ( 2L * F_CPU / 1000000L / PRESCALAR)
#define FALLING_DELAY           ( 1L * F_CPU / 1000000L / PRESCALAR)

//packet
#define MIN_PREAMBLE_BIT_COUNT  10
#define ZERO                    0x00
#define ONE                     0x01
#define PACKET_MIN_LENGTH       3

//dcc machine states
enum {preambleState, dataByteState, startBitState };

// Code
DCC::DCC() {
    //input & interrupt pin
#if defined(__AVR_ATmega328P__)
    DDRD  &= ~(1 << DDD2);   // input pin PD2(INT0)
    EIMSK |=  (1 << INT0);   // external interrupt 0
    EICRA &= ~((1 << ISC00) | (1 << ISC01));
    EICRA |=  (1 << ISC00); //pin change interrupt mode
#elif defined(__AVR_ATtiny84__)
    DDRB  &= ~(1 << DDB2);   // input pin PB2(INT0)
    GIMSK |=  (1 << INT0);   // external interrupt 0
    MCUCR &= ~((1 << ISC00) | (1 << ISC01));
    MCUCR |=  (1 << ISC00); //pin change interrupt mode
#else
#error Unknown MCU
#endif

    //timer
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATtiny84__)
    TCCR1A &= ~((1 << COM1A1) | (1 << COM1A0) | (1 << COM1B1) | (1 << COM1B0) | (1 << WGM11) | (1 << WGM10));
    TCCR1B &= ~((1 << ICNC1) | (1 << ICES1) | (1 << WGM13) | (1 << WGM12) | (1 << CS12) | (1 << CS11) | (1 << CS10));
    TCCR1B |=  (1 << CS10); // clk/8
    TCCR1C &= ~((1 << FOC1A) | (1 << FOC1B));
    TIMSK1 &= ~((1 << ICIE1) | (1 << OCIE1B) | (1 << OCIE1A) | (1 << TOIE1));
#else
#error Unknown MCU
#endif
   
    reset();
    packetLength = 0;
    for (uint8_t b = 0; b < PACKET_MAX_LENGTH - 1; b++) {
        packet[b] = 0;
    }
}

volatile uint8_t _debug;
volatile uint16_t _periodA;

// input interrupt processing
ISR(INT0_vect) {
    //save tine
    volatile uint16_t t = TCNT1;
   
    //restart counter
    TCNT1 = 0x0000;
   
    //process periods
    if (
        // input pin is in pullup mode
        // period A is the negative period on DCC bus. It is read as set.
        // period B is the positive period on DCC bus. It is read as clear.
#if defined(__AVR_ATmega328P__)
        PIND & (1 << PIND2)
#elif defined(__AVR_ATtiny84__)
        PINB & (1 << PINB2)
#else
#error Unknown MCU
#endif
        ) {
        // period A
        //check the durations of the periods
        t -= RISING_DELAY;
        if ((_periodA >= ONE_MIN_TIME) &&
            (_periodA <= ONE_MAX_TIME) &&
            (abs(_periodA - t) <= MAX_PERIOD_DIFFERENCE)) {
            _debug = 1;
            dcc.store(ONE);
        } else if (_periodA >= ZERO_MIN_TIME) {
            _debug = 2;
            dcc.store(ZERO);
        } else {
            //error not a valid bit
            _debug = 3;
            dcc.reset();
            return;
        }
    } else {
        // period B
        _debug = 4;
        _periodA = t - FALLING_DELAY;
    }
}

void DCC::store(uint8_t aBit) {
    switch (state) {
        case preambleState:
            if (aBit) {
                //stil in preamble
                readCount++;
            } else {
                if (readCount < MIN_PREAMBLE_BIT_COUNT) {
                    //error preamble to short
                    reset();
                    return;
                }
               
                //it is the packet start bit
                readCount = 0;
                state = dataByteState;
            }
            break;
           
        case dataByteState:
            if (readCount++ < 8) {
                newPacket[packetIndex] << 1;
                newPacket[packetIndex] |= aBit;
            } else {
                state = startBitState;
            }
            break;
           
        case startBitState:
            if (aBit) {
                // packet end bit
               
                //packet length checking
                if (packetIndex < PACKET_MIN_LENGTH ) {
                    reset();
                    return;
                }
               
                //checksum
                uint8_t checksum = newPacket[0];
                for (uint8_t b = 1; b < packetIndex - 1; b++) {
                    checksum ^= newPacket[b];
                }
                if (checksum != newPacket[packetIndex]) {
                    reset();
                    return;
                }
               
                //copy the packet;
                packetLength = packetIndex - 1;
                for (uint8_t b = 0; b < packetLength; b++) {
                    packet[b] = newPacket[b];
                }
               
                reset();
                readCount++;//packet end bit considered as the first preamble bit
            } else {
                // data start bit
                if (packetIndex++ > PACKET_MAX_LENGTH) {
                    reset();
                    return;
                }
                readCount = 0;
                state = dataByteState;
            }
            break;
    }
}

void DCC::reset() {
    //packet reader processor reset
    state = preambleState;
    readCount = 0;
    packetIndex = 0;
    for (uint8_t b = 0; b < PACKET_MAX_LENGTH; b++) {
        newPacket[b] = 0;
    }
}

uint8_t DCC::address() {
    return packet[0];
}

uint8_t DCC::length() {
    return packetLength;
}

uint8_t DCC::instruction(uint8_t aByte) {
    if ((aByte > 0) && (aByte < packetLength)) {
        return packet[aByte];
    } else {
        return 0;
    }
}


Actuellement je but dans la fonction ISR(INT0_vect). Aucun bit n'est reconnu comme étant de la bonne durée; tout passe par "_debug = 3". La commande DCC est générée par la centrale MINITRIX MS2. Est-ce que quelques-uns d'entre vous aurai déjà visualisé le signal de cette centrale sur un oscilloscope ?

A+
MS2 CC2 S-DEC-4-DC Rocrail

Répondre