Chenillard à délai variable + "chevauchement" des sorties

Bonsoir à tous,

Comme je disais dans un autre topic, je suis entrain de fabriquer un petit rafaleur pyrotechnique.
Le principe n'est pas très compliqué, il s'agit de faire un chenillard avec un temps réglable entre chaque allumage d'une LED. (cette tempo peut être fixe ou variable entre chaque allumage d'une led).
Donc pour faciliter les choses, j'adapterai mes propos en parlant de chenillard et donc de led, en réalité le µC pilotera des MOSFET etc.

La où ça se complique (pour moi en tout cas) c'est que je veux une impulsion de mise à feux (= temps d'allumage d'une led pour un chenillard) de 50ms (voir un peu plus, mais basons nous sur 50) mais je veux pouvoir allumer la led suivante avec une tempo de mini 10ms ce qui implique donc un "chevauchement" de deux sorties à l'état haut.

Je sèche donc un peu sur mon programme .... je ne veux pas une réponse toute cuite, mais je souhaiterai que vous me donniez quelques pistes pour avancer svp.

Voila sur quelle base je comptais partir:

  • Un tableau qui stocke toutes les sorties (s1 à s10)
  • Un autre qui stock le temps entre deux allumages, soit un tableau avec 9 valeurs.

et après utilisation d'une boucle pour parcourir les deux tableaux.

Voici un code fonctionnel, mais qui ne gère pas le chevauchement, autrement dit, je ne peux pas avoir une tempo de moins de 50ms entre deux départs...

int bp = 2;     // Bouton poussoir pin 2

int s1 = 3;     // Sortie 1, pin 3
int s2 = 4;     // etc.
int s3 = 5;
int s4 = 6;
int s5 = 7;
int s6 = 8;
int s7 = 9;
int s8 = 10;
int s9 = 11;
int s10 = 12;   // sortie 10, pin 12


int delay_seq;       // temps d'allumage d'une led
boolean fin_seq;     // fin de la séquence ? oui/non
int nbr_lign;        // nombre de ligne = nombre de LED
int tab_s[10];       // tableau contenant les sorties
int tab_delay[10];   // tableau contenant les délais entre chaque allumage d'une led
int i;          


void setup() {                


  pinMode(s1, OUTPUT); 
  pinMode(s2, OUTPUT); 
  pinMode(s3, OUTPUT); 
  pinMode(s4, OUTPUT); 
  pinMode(s5, OUTPUT); 
  pinMode(s6, OUTPUT); 
  pinMode(s7, OUTPUT); 
  pinMode(s8, OUTPUT); 
  pinMode(s9, OUTPUT); 
  pinMode(s10, OUTPUT); 

  pinMode(bp, INPUT);  

  fin_seq = 0;       //Fin séquence ? -> non
  delay_seq = 50;    // Allumage d'une led pendant 50ms
  nbr_lign = 7;      // 3 led

  tab_s[0] = s1;      // 1ere sortie
  tab_s[1] = s2;      // 2eme sortie
  tab_s[2] = s3;      // etc ...
  tab_s[3] = s4;
  tab_s[4] = s5;
  tab_s[5] = s6;
  tab_s[6] = s7;
  tab_s[7] = s8;
  tab_s[8] = s9;
  tab_s[9] = s10;

  tab_delay[0] = 200;  // Tempo entre led 1 et led 2 = 200ms
  tab_delay[1] = 100;  // Tempo entre led 2 et led 3 = 100ms
  tab_delay[2] = 50;  // ...
  tab_delay[3] = 350;
  tab_delay[4] = 500;
  tab_delay[5] = 500;
  tab_delay[6] = 600;
  tab_delay[7] = 650;
  tab_delay[8] = 50;

}


void loop() {


  if ( (digitalRead(bp) == HIGH) and (fin_seq == 0)) // Si le bouton poussoir est actionné et que la sequence n'a pas encore été lancée.

  {   

    for(i=0; i <= (nbr_lign - 1) ; i++)
    {
      digitalWrite(tab_s[i], HIGH);  // -> tableau contenant les sorties
      delay(delay_seq);              // delay de 50ms
      digitalWrite(tab_s[i], LOW);   // extinction de la led

      delay(tab_delay[i] - delay_seq); // prochain allumage -> lecture de la tempo désiré dans le tableau et soustraction des 50ms.
    }

    // fin_seq = 1; // Fin de la sequence, désactivation lancement d'une nouvelle sequence.

  }
}

Voilà, donc auriez-vous svp quelques petits tuyaux à me donner pour m'aider dans l'avancement de mon codage ?

Merci par avance,
Bonne journée à tous.

Salut,

En gros, tu voudrais avoir un monostable de 50ms sur chacune de tes sorties. Avec l'arduino, c'est pas possible. Mais il est possible de partir sur une unité de temps (j'ai pris 10ms ici). Tu déclares tes événements dans le tableau tab_delay comme je l'ai fait ci-dessous. En gros, le tableau contient le moment auquel doit se produire un événement, et non plus la tempo entre deux évènements.

Tu continues à utiliser delay_seq comme valeur de tempo des monostables.

int bp = 2;     // Bouton poussoir pin 2

int s1 = 3;     // Sortie 1, pin 3
int s2 = 4;     // etc.
int s3 = 5;
int s4 = 6;
int s5 = 7;
int s6 = 8;
int s7 = 9;
int s8 = 10;
int s9 = 11;
int s10 = 12;   // sortie 10, pin 12

int delay_seq;       // temps d'allumage d'une led
boolean fin_seq;     // fin de la séquence ? oui/non
int nbr_lign;        // nombre de ligne = nombre de LED
int tab_s[10];       // tableau contenant les sorties
int tab_delay[10];   // tableau contenant les délais entre chaque allumage d'une led
int i;          

void setup() {                
  pinMode(s1, OUTPUT); 
  pinMode(s2, OUTPUT); 
  pinMode(s3, OUTPUT); 
  pinMode(s4, OUTPUT); 
  pinMode(s5, OUTPUT); 
  pinMode(s6, OUTPUT); 
  pinMode(s7, OUTPUT); 
  pinMode(s8, OUTPUT); 
  pinMode(s9, OUTPUT); 
  pinMode(s10, OUTPUT); 

  pinMode(bp, INPUT);  

  fin_seq = 0;       //Fin séquence ? -> non
  delay_seq = 5;    // Allumage d'une led pendant 50ms
  nbr_lign = 7;      // 3 led (??)

  tab_s[0] = s1;      // 1ere sortie
  tab_s[1] = s2;      // 2eme sortie
  tab_s[2] = s3;      // etc ...
  tab_s[3] = s4;
  tab_s[4] = s5;
  tab_s[5] = s6;
  tab_s[6] = s7;
  tab_s[7] = s8;
  tab_s[8] = s9;
  tab_s[9] = s10;

  tab_delay[0] = 20;  // Tempo déclenchement led 1 = 200ms
  tab_delay[1] = 30;  // Tempo déclenchement led 2 = 100ms (se déclenche à t=300ms)
  tab_delay[2] = 35;  // ...
  tab_delay[3] = 70;
  tab_delay[4] = 120;
  tab_delay[5] = 170;
  tab_delay[6] = 230;
  tab_delay[7] = 295;
  tab_delay[8] = 300;

}

word t = 0;  // variable indicateur de temps

ISR(TIMER1_COMPA){  // est appelée toutes les 10ms par le timer 1
  byte i;
    for(i=0; i <= 8 ; i++)
    {
      if (t = tab_delay[i]) digitalWrite(tab_s[i], HIGH);  // -> allumage
      if (t = tab_delay[i] + delay_seq) digitalWrite(tab_s[i], LOW);  // -> extinction
    }

    t++;     // incrémenter le compteur temps de 10ms

    if (t > tab_delay[8] + delay_seq)           // on est arrivé à la fin de la séquence
    {
      // ici, on désactive le timer1, on n'en a plus besoin, car il ne faudrait pas qu'il reparte pour un tour!
    }
}

void loop() {

  if ( (digitalRead(bp) == HIGH) and (fin_seq == 0)) // Si le bouton poussoir est actionné et que la sequence n'a pas encore été lancée.
  {   
    fin_seq = 1;  // La séquence ne pourra plus être lancée
    // ici on active le timer 1
  }
}

Principe : il faut configurer le timer 1 pour qu'il génère une interruption "COMP1A" en mode CTC toutes les 10ms. Tu peux par exemple changer cette base de temps en 1 ms, mais arrange toi pour qu'elle soit la plus grande possible, car plus tu voudras être précis, moins la séquence pourra durer. (attention à la capacité de t, la variable indicateur de temps : ici, elle peut aller de 0 à 65535, soit 655,35 secondes (pas loin de 11 minutes) pour une base de 10ms, 65.535 pour une base de 1ms...

Attention aussi à la durée de traitement de la routine d'ISR : elle ne doit pas dépasser la base de temps, sinon, ton arduino va se bouffer les pinceaux et ça ne marchera pas du tout comme prévu. (si tu augmentes le nombre de sorties, la boucle de comparaison va s'allonger)

Il manque les codes de configuration, activation et désactivation du timer1, je n'ai pas trop le temps de retourner dans les docs pour te les mettre là, peut-être plus tard.

Je n'ai pas trop compris nb_lign, donc je n'en ai pas tenu compte (tu corrigeras)

Avec ce code, c'est la simplicité et la précision garanties, et tu vois qu'il n'y a plus rien dans loop(), c'est normal! c'est justement le principe des timers : déclencher une action tous les x secondes!

Amuse-toi bien!

Bon ,comme j'en ai eu besoin, j'ai réfléchis à la config du timer 1 :

dans ton setup, rajoute les lignes :

TCCR1A = 0x00;  // pas de sortie PWM
TCCR1B = 0x08;  // Mode CTC, timer arrêté
TIMSK1 = 0x02;   // Autoriser l'interruption pour OCR1A
OCR1A = 2500;  // durée du timer = 10ms

Pour la durée du timer, il suffit de calculer la valeur OCR1A = T x 250, T étant la période du timer en ms (ici, 10ms donnent 10 x 250 = 2500, pour 1 ms, il faut mettre OCR1A = 250;).
Puis pour activer le timer :

 TCCR1B |= 0x03;  // Démarre le timer avec Clock = 250KHz

Désactiver le timer :

 TCCR1B &= 0xFC;  // arrête le timer avec Clock = 0Hz

voilà!

Super_Cinci:
...
Je n'ai pas trop compris nb_lign, donc je n'en ai pas tenu compte (tu corrigeras)
...
Avec ce code, c'est la simplicité et la précision garanties, et tu vois qu'il n'y a plus rien dans loop(), c'est normal! c'est justement le principe des timers : déclencher une action tous les x secondes!

Amuse-toi bien!

Bonjour Supercinci

Le nb de lignes c'est le nb de "voies" du chenillard
le domaine dans lequel evolue Hexor impose et c'est ce qu'il a fait dans sa réflexion des timings de ON/OFF des sorties conditionnés par les caractéristiques de mise en œuvre.

Il lui faut à la fois concilier la fluidité de l'enchainement ET toujours mettre en securité l'ensemble.

ta proposition sur timer est la plus adaptable et souple pour son projet.

Pour resumer , il s'agit là de gestion en securité positive
En "production" une voie ne doit etre activée que le temps nécessaire, le Delta T ignition entre voies étant contraint par l’élément final.
Element final dont la "reaction temporelle" est finalement electroniquement parlant prise dans une fenêtre assez "large" :grin:

Bonjour à tous,

Merci pour ta réponse Super_cinci, effectivement c'est bien un monostable que je veux créer sur les sorties de l'arduino (ça fait quelques années que je n'ai pas fait d'électronique et j'avais oublié l’existence des monostable...)

Dans mon code à un moment j'ai mis " nbr_lign = 7; // 3 led (??)", je me suis trompé dans mon commentaire, il devrait y avoir marqué " // 7 led" (j'ai du modifier le code entre temps et je n'avais pas vu)
Comme le dit Artouste, ça correspond aux nombres de sorties utilisé de l'arduino, ou au nombre de led du chenillard comme tu veux. (Au final ça sera le nombre de ligne (= 1 infla) que représentera ce nombre)

Je vais étudier ton code et le tester dès que j'ai un peu de temps, après je n'y avais pas pensé, mais je peux aussi utiliser des monostable en sorti de l'arduino ... mais par contre la durée de l'impulsion sera fixée par une Résistance et un Condensateur, donc plus modifiable "informatiquement" si jamais je voulais augmenter/réduire l'impulsion de 50ms...

Je te remercie, je vais aller réfléchir à tout ça.

Je sais que je t'ai fourni un code "tout fait", c'est pour gagner du temps : la manipulation des registres n'est pas évidente, et vu le temps que ça m'a pris pour décortiquer le fonctionnement des timers (je ne compte plus les heures), j'estime qu'on peut s'offrir ce genre de raccourci. [mavie]J'ai d'ailleurs encore appris hier : j'ai découvert la fonction ICP des timers...[/mavie]

Je ne t'ai pas orienté vers la lib "timer2", car j'ai déjà essayé, et la précision m'a tellement fait peur (+/-10% selon la pluie ou le beau temps) que c'est comme ça que j'ai commencé à jouer en interne avec les timers. Ceux qui disent qu'on ne peut pas se fier au quartz de l'arduino car il n'est pas assez précis se plantent grave finalement, car en fait, ce sont les libs toutes faites qui ne sont pas précises. Depuis que j'utilise en direct les timers, j'ai des fonctions ultra précises.

La solution du monostable externe serait assez simple, mais risquée, car plus il y aura d'électronique, plus il y aura de risque d'un état inconnu à la mise en route du système, tu aurais l'air un peu bête si tout tes inflas partaient en même temps... Puis peu précise au final, comme tu le dis. Attention à ne pas utiliser les pins 0 et 1, car elles servent au bootloader et ne sont pas forcément à 0 au démarrage de l'arduino, tout comme la pin 13 (led) qui clignote.

Il reste encore la solution de ne brancher la batterie de puissance qu'une fois que ton système est réellement en route (un relais sur tempo, ou mieux et plus sûr, une intervention humaine à clé en fonction d'un voyant "prêt"). On rejoint un peu le sujet de ton choix de résistances, tu verras tout cela une fois ton séquenceur fini, quand tu en seras à la partie sécurité... Tant que ce ne sont que des leds...

Cinci

PS : pour tes essais, n'hésite pas à mettre des temps assez larges (500ms min), car ton delay_seq de 50ms, tu risques de ne pas le voir sur une led (0.05 sec, c'est très rapide...)

Super_Cinci:
...

Il reste encore la solution de ne brancher la batterie de puissance qu'une fois que ton système est réellement en route (un relais sur tempo, ou mieux et plus sûr, une intervention humaine à clé en fonction d'un voyant "prêt"). On rejoint un peu le sujet de ton choix de résistances, tu verras tout cela une fois ton séquenceur fini, quand tu en seras à la partie sécurité... Tant que ce ne sont que des leds...

Bonjour supercinci
Dans ce genre de domaine "on commence impérativement par la secu avant de descendre vers la commande" :grin:
En fait le souhait d'Hexor est simple mais :
il est conditionné électriquement et temporellement par les caractéristiques de ses inflas, et comme en électronique il y a là aussi des datasheets avec des "Max absolute rating" et des "conditions nominales" :grin:

la fluidité recherchée là dans les enchainements est essentiellement contrainte par les caractéristiques temporelle de la chimie.

On est loin de la planche à clous qui a enchantée les 14/07 de mon enfance. :grin:

Electroniquement parlant la vraie et seule réelle contrainte ici est :

J'initie ON une voie pendant MAX X ms (X imperatif et fonction des sheets inflas) , je coupe ensuite (OFF) ET la secu positive du prog doit prendre en compte que JAMAIS cette voie ne sera/pourra être à nouveau ON avant RAZ du tableau/programme.