Variateur de lumière 8 canaux 230V

Bonjour,

je voulais vous faire partager une première application qui rentre dans le cadre de mon projet domotique: un gradateur de lumière 230V contrôlé par une carte arduino duemilanove pour éclairage halogène ou incandescent.

Le principe est celui du retard de phase: plus on retarde le declenchement du triac après le passage à zéro de la courbe sinusoïdale, moins la tension moyenne en sortie de triac sera élevée, moins l'éclairage sera puissant.

Partie materielle: - triac piloté par une sortie digitale via un optocoupleur - opto-coupleur AC pour la détection du passage à zéro de la phase

Partie logicielle: - une interruption materielle sur l'entrée 2 lors du passage à zéro de la phase - une interruption logicielle qui intervient entre 100µs et 1400µs. => l'intervalle d'interruption est variable afin d'obtenir une courbe de luminosité linéaire selon la consigne, du fait de la forme sinusoïdale du signal.

on a donc:

  1. detection du passage à zero sur l'entree 2 => execution de detection_zero() => RAZ de c2 => traitement des canaux avec une consigne de 0% et de 100% => desactivation de l'interruption materielle => activation de l'interruption logicielle sur la base de retard[0]

  2. interruption au bout de retard[c2] µs => execution de controle_canaux() => incrementation de l'index c2 et si c2 est supérieur à 49, alors c'est le dernier cycle => extinction de tous les canaux => activation de l'interruption materielle sinon: => activation sorties des canaux ayant pour consigne consignec2 => reconfiguration de l'interruption temporelle avec un nouveau retard, retard[c2]

on execute donc 49 fois controle_canaux() par demi-oscillation (50Hz= 100 demi-oscillation par seconde, un passage à zero tous les 10 ms)

Pour modifier la consigne d'un canal, il faut envoyer via le serial monitor une trame de la forme: " D/0/45/F" => un espace => "D" pour indiquer le début de la trame => "/" comme séparateur => le canal concerné (de 0 à 7 ici) => "/" comme séparateur => le niveau souhaité (de 0% à 100%) => "/" comme séparateur => "F" pour indiquer la fin de la trame

Une fois la trame recu, la fonction sscanf se charge de recuperer les donnees. On convertit la consigne recu en niveau (de 0 à 50 niveaux)

ressources: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1230333861/30 pour les premiers essais http://www.hoelscher-hi.de/hendrik/english/dimmer.htm pour la partie electronique http://www.abcelectronique.com/bigonoff/domocan.php?par=3efd4 pour la partie electronique et soft (PIC) et le forum arduino, notamment pour la partie traitement de la trame...

Des améliorations sont prévues, comme gérer des temps de transitions lors de changement de consignes (soft start).

Voilà !

Gromain

le code:

/*
GRADATEURS 230V (8 canaux, potentionnellement plus)
 
par Gromain59
 
 Partie materielle:
 - triac piloté par une sortie digitale via un optocoupleur
 - opto-coupleur AC pour la détection du passage à zéro de la phase
 
 Partie logicielle:
 -       une interruption materielle sur l'entrée 2 lors du passage à zéro de la phase
 -       une interruption logicielle qui intervient entre 100µs et 1400µs.
      => l'intervalle d'interruption est variable afin d'obtenir une courbe de luminosité linéaire selon la consigne, du fait de la forme sinusoïdale du signal.
 on a donc:
 1. detection du passage à zero sur l'entree 2
 2. execution de detection_zero(): traitement des canaux avec une consigne de 0% et de 100%
 3. desactivation d'interruption materielle, activation de l'interruption logicielle sur la base de retard[0]
 4. interruption au bout de retard[c2] µs (c2=0)
 5. execution de controle_canaux()
      => incrementation de l'index c2
      et si c2 est supérieur à 49, alors c'est le dernier cycle
            => extinction de tous les canaux
            => activation de l'interruption materielle
      sinon:
            => activation sorties des canaux ayant pour consigne 98% (soit un retard de 469µs) ou si 
            => reconfiguration de l'interruption temporelle avec un nouveau retard, retard[c2]
            
Pour modifier la consigne d'un canal, il faut envoyer via le serial monitor une trame de la forme:
            " D/0/45/F"
      => un espace
      => "D" pour indiquer le début de la trame
      => "/" comme séparateur
      => le canal concerné (de 0 à 7 ici)
      => "/" comme séparateur
      => le niveau souhaité (de 0% à 100%)
      => "/" comme séparateur      
      => "F" pour indiquer la fin de la trame
      
      Une fois la trame recu, la fonction sscanf se charge de recuperer les donnees.
      On convertit la consigne recu en niveau (de 0 à 50 niveaux)
      
ressources: 
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1230333861/30 pour les premiers essais
http://www.hoelscher-hi.de/hendrik/english/dimmer.htm pour la partie electronique
http://www.abcelectronique.com/bigonoff/domocan.php?par=3efd4 pour la partie electronique et soft (PIC)
le forum arduino
 
*/

#include <TimerOne.h>       // pour l'interruption temps http://www.arduino.cc/playground/Code/Timer1
#include <stdio.h>                   // pour le traitement de la trame contenant le changement de consigne

//valeur de timeout pour la reception de la trame
int tps_max_lecture = 200;      //lecture d'un code, compteur max entre tous les caractères d'un code
int tps_max_carte = 1000;      //compteur max entre reception d'un caractère


long retard[]= {
1469 , // 98 % 1 225,3V retard / zéro = 1469 ms
287 , // 96 % 2 222,7V retard / zéro = 1867 ms
234 , // 94 % 3 220,6V retard / zéro = 2154 ms
201 , // 92 % 4 218,2V retard / zéro = 2388 ms
180 , // 90 % 5 215,4V retard / zéro = 2589 ms
164 , // 88 % 6 213,3V retard / zéro = 2769 ms
152 , // 86 % 7 210,8V retard / zéro = 2933 ms
143 , // 84 % 8 208V retard / zéro = 3085 ms
135 , // 82 % 9 205,7V retard / zéro = 3228 ms
129 , // 80 % 10 202,8V retard / zéro = 3363 ms
124 , // 78 % 11 200,5V retard / zéro = 3492 ms
120 , // 76 % 12 197,6V retard / zéro = 3616 ms
116 , // 74 % 13 195,2V retard / zéro = 3736 ms
112 , // 72 % 14 192,4V retard / zéro = 3852 ms
110 , // 70 % 15 189,6V retard / zéro = 3964 ms
108 , // 68 % 16 186,8V retard / zéro = 4074 ms
106 , // 66 % 17 184V retard / zéro = 4182 ms
105 , // 64 % 18 180,9V retard / zéro = 4288 ms
103 , // 62 % 19 178,1V retard / zéro = 4393 ms
102 , // 60 % 20 175,1V retard / zéro = 4496 ms
101 , // 58 % 21 172,1V retard / zéro = 4598 ms
101 , // 56 % 22 168,9V retard / zéro = 4699 ms
100 , // 54 % 23 166,2V retard / zéro = 4800 ms
100 , // 52 % 24 162,6V retard / zéro = 4900 ms
100 , // 50 % 25 159,3V retard / zéro = 5000 ms
101 , // 48 % 26 155,8V retard / zéro = 5100 ms
100 , // 46 % 27 152,6V retard / zéro = 5201 ms
101 , // 44 % 28 149,1V retard / zéro = 5301 ms
102 , // 42 % 29 145,3V retard / zéro = 5402 ms
103 , // 40 % 30 141,8V retard / zéro = 5504 ms
105 , // 38 % 31 138V retard / zéro = 5607 ms
106 , // 36 % 32 133,8V retard / zéro = 5712 ms
108 , // 34 % 33 130V retard / zéro = 5818 ms
110 , // 32 % 34 126V retard / zéro = 5926 ms
112 , // 30 % 35 121,7V retard / zéro = 6036 ms
116 , // 28 % 36 117,1V retard / zéro = 6148 ms
120 , // 26 % 37 112,6V retard / zéro = 6264 ms
124 , // 24 % 38 107,7V retard / zéro = 6384 ms
129 , // 22 % 39 102,4V retard / zéro = 6508 ms
135 , // 20 % 40 97,2V retard / zéro = 6637 ms
143 , // 18 % 41 92V retard / zéro = 6772 ms
152 , // 16 % 42 85,7V retard / zéro = 6915 ms
164 , // 14 % 43 79,4V retard / zéro = 7067 ms
180 , // 12 % 44 72,8V retard / zéro = 7231 ms
201 , // 10 % 45 64,8V retard / zéro = 7411 ms
234 , // 8 % 46 56,4V retard / zéro = 7612 ms
286 , // 6 % 47 46V retard / zéro = 7846 ms
399 , // 4 % 48 32,4V retard / zéro = 8132 ms
500//1469 , // 2 % 49 0V retard / zéro = 8531 ms
};

int consigne[]= {      // consigne niveau de canal (0=100%, 50=0%)
0, // sortie 0
0, // sortie 1
0, // sortie 2
0, // sortie 3
0, // sortie 4
0, // sortie 5
0, // sortie 6
0, // sortie 7
};

int sortie[]= {            //affecte une pin pour chaque canal.
8,       // sortie 0
13, // sortie 1
0,       // sortie 2
0,       // sortie 3
0,       // sortie 4
0,       // sortie 5
0,       // sortie 6
0,       // sortie 7
};

volatile int c1=0;      // index c1 pour lecture des données de chaque canal (n° pin, consigne)
volatile int c2=0;      // index c2 nombre de passage dans la boucle de controle retard de phase (49 passages)

// definition des macros pour piloter les sorties
#define  allume(index)  (digitalWrite(sortie[index], HIGH))
#define  eteint(index)  (digitalWrite(sortie[index], LOW))


void setup() {    // Debut du setup
 
// initialise la liaison série
Serial.begin(9600);
 
// initialise les sorties des canaux (triacs)
      for (c1=0; c1 <= 7; c1++){                         // on parcourt les 8 canaux pour les configurer
                  pinMode(sortie[c1], OUTPUT);       // on associe chaque canal a une pin, qu'on configure en sortie digitale
                  eteint(sortie[c1]);                        // et on éteint la sortie
            }            

      Serial.println("GRADATEUR 8 CANAUX v0.1");
      Serial.println("TRAME ATTENDUE: <espace>'D'/'numero de sortie'/'consigne'/'F'");


// initialise l'interruption de temps Timer1
      Timer1.initialize();                      // Initialize TimerOne library for the freq we need


// Attache l'interruption 0 à la pin 2 pour la detection du passage a zero (Zero Cross Detection)
      attachInterrupt(0, detection_zero, FALLING);   // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
 
}                                                   // Fin du setup

void detection_zero() {              // Fonction associee à l'interruption 0                          

      detachInterrupt(0);                   // on desactive l'interruption zero crossing

      c2=0;                                    
      
      for (c1=0; c1 <= 7; c1++){       // on parcourt les 8 sorties pour verifier leur consigne
               if  (consigne[c1]>=49){ // si consigne 0% 
                  eteint(c1);                  // alors on éteint
            }
            
            if  (consigne[c1]<=0){       // si consigne 100% 
                  allume(c1);                  // alors on allume
            }            
            
   } 

      Timer1.attachInterrupt(controle_canaux, retard[c2]);      // on attache l'interruption temporelle
      
 }                                 // Fin de detection_zero

void controle_canaux() {  // ici on verifie si le triac doit etre amorce

     c2=c2++;
      
      attachInterrupt(0, detection_zero, FALLING);        // on attache une interruption sur la pin 2 (interruption 0)
      Timer1.detachInterrupt();                                    // on detache l'interruption temporelle

      if (c2>=49){ // si dernier cycle alors

      for (c1=0; c1 <= 7; c1++){       // on parcourt les 8 sorties
            eteint(c1);                        // et on eteint le canal en vue du prochain cycle
      }

      
      }
else { // sinon

      Timer1.attachInterrupt(controle_canaux, retard[c2]);      // on attache une interruption temporelle

      for (c1=0; c1 <= 7; c1++){       // on parcourt les 8 sorties pour verifier leur consigne
               if  (consigne[c1]==c2)      // si consigne est egale a la valeur traitee (n° de passage dans la boucle) 
            { allume(c1);}                  // alors on allume le canal
      }            
                  
}                                    // End controle_canaux function

}
void loop() {                        // Main Loop
  
      int n = 0;
      
      if(Serial.available()>0){
            n = lecture();
      }
 
}

int lecture(){            // lecture d'une trame type: " D/aaa/bbb/F"
                              // ou "D" caractere de debut de trame
                              // ou "aaaa" n° de sortie dont la consigne est a modifier
                              // ou "bbbb" nouvelle consigne de la sortie (entre 0 et 100%)



      char buf[15]="              ";
      int timeout=0;
      int i=0;
      int n1=0;
      int n2=0;
      char c1,c2;
      
      while(Serial.available()>0){
            if(i!=14){
            buf[i] = Serial.read();
            i++;
            }

      timeout++;
      
      if(timeout>tps_max_lecture)
            {Serial.println("T1");
            return -1;
            }
      if(timeout> tps_max_lecture)
            {Serial.println("T2");
            return -2;
            }      
      }
      sscanf(buf, "%c/%d/%d/%c", &c1, &n1, &n2, &c2); //decodage trame
       
      if (c1=='D' && c2 == 'F'){       // on verifie si la trame commence bien par D et termine bien par F
            
            int nouv_cons=n2;             // on stocke la nouvelle valeur pour la travailler ensuite
            
            nouv_cons=constrain(nouv_cons, 0, 100); // on borne la nouvelle valeur entre 0 et 100%
                  
            Serial.print("sortie ");
            Serial.print(n1);
            Serial.print(" , nouvelle consigne de: ");
            Serial.print(nouv_cons);
            Serial.print(" % soit index retard: ");
                  
            consigne[n1]= (50-(nouv_cons/2));       // on convertit la valeur 0-100% en n° de retard de phase
                  
            Serial.println(consigne[n1]);      
      }
      else                                                       // si caractere de debut ou de fin de trame non reconnu
      {Serial.println("code inconnu");}
      
      return i;
      
}


[/code

Bonsoir,

j'ai ajouté le réglage du temps de transition entre deux changements de consigne, ainsi l'allumage et l'extinction sont plus doux.

Cependant, j'ai un petit problème que je n'arrive pas à résoudre. En effet, lors de la configuration d'une pin en sortie [pinMode(sortie[c1], OUTPUT)], la sortie est à l'état haut immédiatement jusqu'à ce que je commande la sortie à l'état bas [digitalWrite(sortie[c1], LOW] à la ligne suivante. Il en résulte un allumage intempestif à pleine puissance de la lampe.

Y-a-t-il une astuce pour empêcher les lampes de s'allumer un bref instant ? car ça fait un peu désordre à la maison...

Gromain

En principe le registre de donnée est à 0 après un reset donc les sorties devraient être éteintes par défaut. Ne serait-ce pas plutôt le fait qu'après un reset les I/O sont configurées en entrée et donc les broches flottantes? un pull down pourrait corriger ton problème. Ou alors c'est dans le code d'initialisation de l'Arduino il faudrait jeter un oeil dans les sources.

merci fdufnews. En effet je n'ai pas de résistance de pulldown. Je vais faire des essais en en mettant une. Je te tiens au courant.

bon, j'ai ajouté la résistance de pulldown, sans succès...

j'ai toujours ce phénomème quand l'arduino se reset. :(

// initialise les sorties des canaux (triacs)
for (c1=0; c1 <= 7; c1++){ // on parcourt les 8 canaux pour les configurer
pinMode(sortie[c1], OUTPUT); // on associe chaque canal a une pin, qu’on configure en sortie digitale
eteint(sortie[c1]); // et on éteint la sortie
}

As-tu essayé d’échanger les 2 lignes. Ainsi lorsque la sortie deviendrait active, son état serait déjà fixé à 0.

// initialise les sorties des canaux (triacs)
     for (c1=0; c1 <= 7; c1++){          // on parcourt les 8 canaux pour les configurer
           eteint(sortie[c1]);           // et on éteint la sortie
           pinMode(sortie[c1], OUTPUT);   // on associe chaque canal a une pin, qu'on configure en sortie digitale
      }

La permutation n'a rien changé, mais j'ai corrigé un paramètre du coup je n'ai plus cette allumage 100% puis extinction progressive. Quand à la résistance de pull-down, elle empêche les allumages parasites à l'initialisation de la carte. Merci fdufnews.

Ci-dessous la dernière version du code.
En 2 parties car je dépasse le nombre de caractères autorisés…

Partie 1/2: INITIALISATION

/*
GRADATEURS 230V (8 canaux, potentionnellement plus)
 
par Gromain59
 
 Partie materielle:
 - triac piloté par une sortie digitale via un optocoupleur
 - opto-coupleur AC pour la détection du passage à zéro de la phase
 
 Partie logicielle:
 -       une interruption materielle sur l'entrée 2 lors du passage à zéro de la phase
 -       une interruption logicielle qui intervient entre 100µs et 1400µs.
      => l'intervalle d'interruption est variable afin d'obtenir une courbe de luminosité linéaire selon la consigne, du fait de la forme sinusoïdale du signal.
 on a donc:
 1. detection du passage à zero sur l'entree 2
 2. execution de detection_zero(): traitement des canaux avec une consigne de 0% et de 100%
 3. desactivation d'interruption materielle, activation de l'interruption logicielle sur la base de retard[0]
 4. interruption au bout de retard[c2] µs (c2=0)
 5. execution de controle_canaux()
      => incrementation de l'index c2
      et si c2 est supérieur à 49, alors c'est le dernier cycle
            => extinction de tous les canaux
            => activation de l'interruption materielle
      sinon:
            => activation sorties des canaux ayant pour consigne 98% (soit un retard de 469µs) ou si 
            => reconfiguration de l'interruption temporelle avec un nouveau retard, retard[c2]
            
Pour modifier la consigne d'un canal, il faut envoyer via le serial monitor une trame de la forme:
            " D/0/45/F"
      => un espace
      => "D" pour indiquer le début de la trame
      => "/" comme séparateur
      => le canal concerné (de 0 à 7 ici)
      => "/" comme séparateur
      => le niveau souhaité (de 0% à 100%)
      => "/" comme séparateur      
      => "F" pour indiquer la fin de la trame
      
      Une fois la trame recu, la fonction sscanf se charge de recuperer les donnees.
      On convertit la consigne recu en niveau (de 0 à 50 niveaux)
      
ressources: 
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1230333861/30 pour les premiers essais
http://www.hoelscher-hi.de/hendrik/english/dimmer.htm pour la partie electronique
http://www.abcelectronique.com/bigonoff/domocan.php?par=3efd4 pour la partie electronique et soft (PIC)
le forum arduino
 
 V0 = 1ere version fonctionnelle
 V4 = Ajout de la possibilité d'un délai de transition lors d'un changement de consigne
 V5 = test avec memoire structure + configuration par MAXCANAL
 V6 = ajout champ nom dans structure Canal
*/

#include <TimerOne.h>       // pour l'interruption temps http://www.arduino.cc/playground/Code/Timer1
#include <stdio.h>                   // pour le traitement de la trame contenant le changement de consigne

// definition des macros pour piloter les sorties
#define  allume(index)  (digitalWrite(canal[index].sortie, HIGH))
#define  eteint(index)  (digitalWrite(canal[index].sortie, LOW))

#define MAX_CANAL 8                   // definir ici le nombre de canaux à gérer (8 par défaut)

int ForMaxCanal = MAX_CANAL-1;       // variable permettant de definir le nombre de passage dans les différentes boucles FOR

//valeur de timeout pour la reception de la trame
int tps_max_lecture = 200;      //lecture d'un code, compteur max entre tous les caractères d'un code
int tps_max_carte = 1000;      //compteur max entre reception d'un caractère


long retard[]= {
1469 , // 98 % 1 225,3V retard / zéro = 1469 ms
287 , // 96 % 2 222,7V retard / zéro = 1867 ms
234 , // 94 % 3 220,6V retard / zéro = 2154 ms
201 , // 92 % 4 218,2V retard / zéro = 2388 ms
180 , // 90 % 5 215,4V retard / zéro = 2589 ms
164 , // 88 % 6 213,3V retard / zéro = 2769 ms
152 , // 86 % 7 210,8V retard / zéro = 2933 ms
143 , // 84 % 8 208V retard / zéro = 3085 ms
135 , // 82 % 9 205,7V retard / zéro = 3228 ms
129 , // 80 % 10 202,8V retard / zéro = 3363 ms
124 , // 78 % 11 200,5V retard / zéro = 3492 ms
120 , // 76 % 12 197,6V retard / zéro = 3616 ms
116 , // 74 % 13 195,2V retard / zéro = 3736 ms
112 , // 72 % 14 192,4V retard / zéro = 3852 ms
110 , // 70 % 15 189,6V retard / zéro = 3964 ms
108 , // 68 % 16 186,8V retard / zéro = 4074 ms
106 , // 66 % 17 184V retard / zéro = 4182 ms
105 , // 64 % 18 180,9V retard / zéro = 4288 ms
103 , // 62 % 19 178,1V retard / zéro = 4393 ms
102 , // 60 % 20 175,1V retard / zéro = 4496 ms
101 , // 58 % 21 172,1V retard / zéro = 4598 ms
101 , // 56 % 22 168,9V retard / zéro = 4699 ms
100 , // 54 % 23 166,2V retard / zéro = 4800 ms
100 , // 52 % 24 162,6V retard / zéro = 4900 ms
100 , // 50 % 25 159,3V retard / zéro = 5000 ms
101 , // 48 % 26 155,8V retard / zéro = 5100 ms
100 , // 46 % 27 152,6V retard / zéro = 5201 ms
101 , // 44 % 28 149,1V retard / zéro = 5301 ms
102 , // 42 % 29 145,3V retard / zéro = 5402 ms
103 , // 40 % 30 141,8V retard / zéro = 5504 ms
105 , // 38 % 31 138V retard / zéro = 5607 ms
106 , // 36 % 32 133,8V retard / zéro = 5712 ms
108 , // 34 % 33 130V retard / zéro = 5818 ms
110 , // 32 % 34 126V retard / zéro = 5926 ms
112 , // 30 % 35 121,7V retard / zéro = 6036 ms
116 , // 28 % 36 117,1V retard / zéro = 6148 ms
120 , // 26 % 37 112,6V retard / zéro = 6264 ms
124 , // 24 % 38 107,7V retard / zéro = 6384 ms
129 , // 22 % 39 102,4V retard / zéro = 6508 ms
135 , // 20 % 40 97,2V retard / zéro = 6637 ms
143 , // 18 % 41 92V retard / zéro = 6772 ms
152 , // 16 % 42 85,7V retard / zéro = 6915 ms
164 , // 14 % 43 79,4V retard / zéro = 7067 ms
180 , // 12 % 44 72,8V retard / zéro = 7231 ms
201 , // 10 % 45 64,8V retard / zéro = 7411 ms
234 , // 8 % 46 56,4V retard / zéro = 7612 ms
286 , // 6 % 47 46V retard / zéro = 7846 ms
399 , // 4 % 48 32,4V retard / zéro = 8132 ms
500//1469 , // 2 % 49 0V retard / zéro = 8531 ms
};

typedef struct Canal Canal;
struct Canal
{
    int consigne;                                     // consigne actuelle
    int consigne_cible;                              // consigne niveau de canal (0=100%, 50=0%)
      int compteur_transition;                  // temps de transition lors d'un changement niveau de canal (par pas de 10 ms) ex: 2 x 50 cycles de 10ms= 1s de transition
      int compteur_transition_courant;      // compte le nombre de transition
      int sortie;                                          // affecte une pin pour chaque canal.
      char mnemo[16];                                    // mnemonique de la variable
};

//creation des instances
 Canal canal[MAX_CANAL]; // L'ordinateur comprend qu'il s'agit de "struct Coordonnees" grâce au typedef

volatile int c1=0;      // index c1 pour lecture des données de chaque canal (n° pin, consigne)
volatile int c2=0;      // index c2 nombre de passage dans la boucle de controle retard de phase (49 passages)


void initialiserCanal() //on initialise les paramètres de chaque canal.
{
            // configuration du canal 0
      canal[0].consigne=50;
    canal[0].consigne_cible=50;
      canal[0].compteur_transition=2;
    canal[0].compteur_transition_courant=0;
    canal[0].sortie=8;
      canal[0].mnemo[16]='salon';
      
      // configuration du canal 1
      //canal[1].consigne=50;
    //canal[1].consigne_cible=50;
      //canal[1].compteur_transition=2;
    //canal[1].compteur_transition_courant=0;
    //canal[1].sortie=9;
      canal[1].mnemo[16]='N/A';
      
            // configuration du canal 2
      //canal[2].consigne=50;
    //canal[2].consigne_cible=50;
      //canal[2].compteur_transition=2;
    //canal[2].compteur_transition_courant=0;
    //canal[2].sortie=9;
      canal[2].mnemo[16]='N/A';
      
            // configuration du canal 3
      //canal[3].consigne=50;
    //canal[3].consigne_cible=50;
      //canal[3].compteur_transition=2;
    //canal[3].compteur_transition_courant=0;
    //canal[3].sortie=9;
      canal[3].mnemo[16]='N/A';
      
            // configuration du canal 4
      //canal[4].consigne=50;
    //canal[4].consigne_cible=50;
      //canal[4].compteur_transition=2;
    //canal[4].compteur_transition_courant=0;
    //canal[4].sortie=9;
      canal[4].mnemo[16]='N/A';
      
            // configuration du canal 5
      //canal[5].consigne=50;
    //canal[5].consigne_cible=50;
      //canal[5].compteur_transition=2;
    //canal[5].compteur_transition_courant=0;
    //canal[5].sortie=9;
      canal[5].mnemo[16]='N/A';
      
            // configuration du canal 6
      //canal[6].consigne=50;
    //canal[6].consigne_cible=50;
      //canal[6].compteur_transition=2;
    //canal[6].compteur_transition_courant=0;
    //canal[6].sortie=9;
      canal[6].mnemo[16]='N/A';
      
            // configuration du canal 7
      //canal[7].consigne=50;
    //canal[7].consigne_cible=50;
      //canal[7].compteur_transition=2;
    //canal[7].compteur_transition_courant=0;
    //canal[7].sortie=9;
      canal[7].mnemo[16]='N/A';
      
}




void setup() {    // Debut du setup
 
// initialise la liaison série
Serial.begin(9600);

Serial.println("GRADATEUR 8 CANAUX v0.1");
Serial.println("TRAME ATTENDUE: <espace>'D'/'numero de sortie'/'consigne'/'F'");
      
initialiserCanal();
 
// initialise les sorties des canaux (triacs)
      for (c1=0; c1 <= ForMaxCanal; c1++){                         // on parcourt les 8 canaux pour les configurer
                  pinMode(canal[c1].sortie, OUTPUT);       // on associe chaque canal a une pin, qu'on configure en sortie digitale
                  eteint(canal[c1].sortie);                        // et on éteint la sortie
                  canal[c1].compteur_transition_courant=canal[c1].compteur_transition;
                  Serial.print(canal[0].mnemo[16]);
                  Serial.print(", Canal");
                  Serial.print(c1);
                  Serial.print(" sur la PIN ");
                  Serial.println(canal[c1].sortie);
      }            




// initialise l'interruption de temps Timer1
      Timer1.initialize();                      // Initialize TimerOne library for the freq we need


// Attache l'interruption 0 à la pin 2 pour la detection du passage a zero (Zero Cross Detection)
      attachInterrupt(0, detection_zero, FALLING);   // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
 
}                                                   // Fin du setup

Partie 2/2: Routines d’interruption, loop et réception des consignes.

void detection_zero() {              // Fonction associee à l'interruption 0                          

      detachInterrupt(0);                   // on desactive l'interruption zero crossing

      c2=0;                                    
      
      for (c1=0; c1 <= ForMaxCanal; c1++){       // on parcourt les 8 sorties pour verifier leur consigne
               if  (canal[c1].consigne>=49){ // si consigne 0% 
                  eteint(c1);                  // alors on éteint
            }
            
            if  (canal[c1].consigne<=0){       // si consigne 100% 
                  allume(c1);                  // alors on allume
            }            
                  // gestion transition automatique
            if (canal[c1].consigne<canal[c1].consigne_cible){                                                       // si la consigne actuelle est inferieur a la consigne demandee
                  canal[c1].compteur_transition_courant=canal[c1].compteur_transition_courant-1;       //on decremente le compteur de transition
                  if (canal[c1].compteur_transition_courant<=0){                                                       // et si celui ci est nul
                        canal[c1].consigne=canal[c1].consigne+1;                                                       // on incremente la consigne actuelle pour tendre a se rapprocher de la consigne demandee
                        canal[c1].compteur_transition_courant=canal[c1].compteur_transition;             // et on re-initialise le compteur de transition
                  }
            }
            
            if (canal[c1].consigne>canal[c1].consigne_cible){                                                      // si la consigne actuelle est superieur a la consigne demandee
                  canal[c1].compteur_transition_courant=canal[c1].compteur_transition_courant-1;      // on decremente le compteur de transition
                  if (canal[c1].compteur_transition_courant<=0){                                                      // et si celui ci est nul
                        canal[c1].consigne=canal[c1].consigne-1;                                                      // on decremente la consigne actuelle pour tendre a se rapprocher de la consigne demandee
                        canal[c1].compteur_transition_courant=canal[c1].compteur_transition;            // et on re-initialise le compteur de transition
                  }
            }      
      
   } 

      Timer1.attachInterrupt(controle_canaux, retard[c2]);      // on attache l'interruption temporelle
      
 }                                 // Fin de detection_zero

void controle_canaux() {  // ici on verifie si le triac doit etre amorce

     c2=c2++;
      
      attachInterrupt(0, detection_zero, FALLING);        // on attache une interruption sur la pin 2 (interruption 0)
      Timer1.detachInterrupt();                                    // on detache l'interruption temporelle

      if (c2>=49){ // si dernier cycle alors

      for (c1=0; c1 <= ForMaxCanal; c1++){       // on parcourt les 8 sorties
            eteint(c1);                        // et on eteint le canal en vue du prochain cycle
      }

      
      }
else { // sinon

      Timer1.attachInterrupt(controle_canaux, retard[c2]);      // on attache une interruption temporelle

      for (c1=0; c1 <= ForMaxCanal; c1++){       // on parcourt les 8 sorties pour verifier leur consigne
               if  (canal[c1].consigne==c2)      // si consigne est egale a la valeur traitee (n° de passage dans la boucle) 
            { allume(c1);}                  // alors on allume le canal
      }            
                  
}                                    // End controle_canaux function

}
void loop() {                        // Main Loop
  
      int n = 0;
      
      if(Serial.available()>0){
            n = lecture();
      }
 
}

int lecture(){            // lecture d'une trame type: " D/aaa/bbb/F"
                              // ou "D" caractere de debut de trame
                              // ou "aaaa" n° de sortie dont la consigne est a modifier
                              // ou "bbbb" nouvelle consigne de la sortie (entre 0 et 100%)



      char buf[15]="              ";
      int timeout=0;
      int i=0;
      int n1=0;
      int n2=0;
      char c1,c2;
      
      while(Serial.available()>0){
            if(i!=14){
            buf[i] = Serial.read();
            i++;
            }

      timeout++;
      
      if(timeout>tps_max_lecture)
            {Serial.println("T1");
            return -1;
            }
      if(timeout> tps_max_lecture)
            {Serial.println("T2");
            return -2;
            }      
      }
      sscanf(buf, "%c/%d/%d/%c", &c1, &n1, &n2, &c2); //decodage trame
       
      if (c1=='D' && c2 == 'F'){       // on verifie si la trame commence bien par D et termine bien par F
            
            int nouv_cons=n2;             // on stocke la nouvelle valeur pour la travailler ensuite
            
            nouv_cons=constrain(nouv_cons, 0, 100); // on borne la nouvelle valeur entre 0 et 100%
                  
            Serial.print("sortie ");
            Serial.print(n1);
            Serial.print(" , nouvelle consigne de: ");
            Serial.print(nouv_cons);
            Serial.print(" % soit index retard: ");
                  
            canal[n1].consigne_cible= (50-(nouv_cons/2));       // on convertit la valeur 0-100% en n° de retard de phase
            canal[n1].compteur_transition_courant=canal[n1].compteur_transition;
            
            Serial.println(canal[n1].consigne_cible);
            Serial.print("courant: ");
            Serial.println(canal[n1].consigne);      
      
      }
      else                                                       // si caractere de debut ou de fin de trame non reconnu
      {Serial.println("code inconnu");}
      
      return i;
      
}

à copier/coller à la suite du post précédent.

la partie zero cross detection:

OK1 4N33 ou CNY17-1 D1 1N4007 R1A et R1B 27k / 1W R3 10k

source: http://www.hoelscher-hi.de/hendrik/english/dimmer.htm

la partie puissance:

dans un premier temps, pour des tests, la self et le condensateur (ici un MKS4 400V) de filtrage ne sont pas indispensables. Prévoir un radiateur sur le triac BT138 si la charge est importante. Pour une ampoule de 60w, ca ne semble pas nécessaire.

Bonjour Gromain, felicitation pour ton travail!

Je cherche à faire un gradateur 230V/50Hz pour une lampe en france. Ce qui m'échappe c'est que tout tes schémas semble être en 120V! Aurai-tu par chance un schéma de gradateur adapté à la norme française... ainsi qu'une liste des composants à acheter (si ils ne sont pas sur le schéma) ? Je suis étonné de voir la disparité et la rapide complexité des schémas que l'on trouve sur internet!

Je remarque que tu dois être dans un projet domotique assez similaire au mien puisque je te croise sur bcp de sujets (je viens de poser une question concernant l'envoi de trame sur arduino ; ) )

salut,

les schémas que j'ai joint au post précédent sont faits pour du 230V. Je les ai même testé car j'ai réalisé une carte de puissance fonctionnelle (http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1231928902/56#56) Donc tu peux y aller les yeux fermés (sans mettre les doigts dans sur les parties sous tension bien sur !) pour les composants, les references sont dans le même post. Sauf la self de déparasitage (ref 2100HT-470V-RC, chez mouser.com) Je peux éventuellement fournir la liste du matériel que j'avais commandé chez mouser.

Il n'y a qu'un circuit de zero cross detection / arduino, et autant de circuit de puissance que de lumière à commander.

si tu as des questions...

Gromain59

Merci pour ta rapidité de réponse!

tout d'abord je veux bien ta liste liste de composants, la liste que tu fourni en début de ce topic ne me permet pas avec mes connaissances actuelles de choisir entre la multitude de composants(triac, optocoupleur...).

Sur l'autre Topic, tu fais un appel pour de l'aide sur l'avancement de ton projet, je répondrai bien présent... mais je pense pas pouvoir t'être utile à grand chose pour le moment! Mais je vais y travailler!

Je suis actuellement en train de travailler sur un code pour faire communiquer mon module arduino avec un Atmega8 (autant ne pas racheter la plaque entière à chaque fois!) le tout sans fil et en crypté. Pour cela j'utilise des modules aurel (j'en avais deja parlé rapidement pendant les vacances sur ton topic "domotique") si cela t'intéresse je t'enverrai code et schéma dès que cela fonctionnera (un jour j'éspere). Je me sert d'ailleurs de ton code sur les trames (tu viens de répondre je vois!)

voici a tous hasard un lien vers les modules aurel : electrossama.ifrance.com/electro/31.pdf

J'aimerai que l'atmega8 controle un gradateur, c'est pour cela que je m'intéresse aussi à ton montage!

Voici la liste des composants:

MOC3020M http://fr.mouser.com/Search/ProductDetail.aspx?R=MOC3020Mvirtualkey51210000virtualkey512-MOC3020M
Opto CNY17-1 http://fr.mouser.com/Search/ProductDetail.aspx?R=CNY17-1.virtualkey61370000virtualkey782-CNY17-1.
dissipateur http://fr.mouser.com/ProductDetail/Wakefield/274-1AB/?qs=sGAEpiMZZMttgyDkZ5Wiuita4PD18Ap7e0ZyfdsUPiE%3D
self de deparasitage verticale 47µH 20 mm 5A http://fr.mouser.com/ProductDetail/JW-Miller-Bourns/2100HT-470V-RC/?qs=Iovtn17QcgWgQQhL6irfDg%3D%3D
BT139 http://fr.mouser.com/ProductDetail/NXP-Semiconductors/BT139-800G127/?qs=sGAEpiMZZMvKM5ialpXrmuCPTYg4eXZm
Condensateur C1 MKS4 http://fr.mouser.com/ProductDetail/WIMA/MKS4-047-400-10P10/?qs=sGAEpiMZZMvOcEq4GH1AAqrHESw68rBXqJabP7MTYZU%3D

Resistance 4.7KR, 470R,
LED

Bonjour,

Je suis en train de réfléchir (moi aussi...) à la meilleure manière de domotiser ma maison, sachant que : - je ne souhaite pas passer de cables (ben voui, j'ai une femme...) - je souhaite que ce soit simple - je souhaite que ce soit évolutif

Sur le principe, j'ai commencé par acheter des modules "home easy" qui sont (entre autres) des interrupteurs utilisant les ondes hertziennes pour fonctionner (433Mhz). A ce propos, Jeanot1314, j'ai réalisé grâce à une arduino, et un module aurel un interrupteur qui pilote mes lumieres home easy, je t'invites à jeter un coup d'oeil dans cette direction si tu souhaites coder ton signal (codage Manchester), je suis à ta disposition pour en reparler.

Bref, j'en étais là de mes réflexions quand un besoin irrépressible se fit sentir : ma VMC. En effet, ma VMC n'a qu'une seule vitesse, il parait que ce sont les bouches de ventillation qui agissent et qui changent le volume aspiré... Mouais En tous les cas, elle fonctionne toute la journée et toute la nuit à la meme vitesse, j'apprécierais donc de pouvoir la commander de manière à ce qu'elle ralentisse pendant la nuit (et donc qu'elle aspire moins de bon air chaud). En farfouillant sur les sites, j'ai cru trouver mon bonheur ici... tout cela me semble parfait, Et la un doute m'habite !!! Il y a quelques années, il me semble avoir appris que l'on ne pouvait pas piloter de la même manière une charge résistive (lampe incandescente) et une charge inductive (moteur). Je ne me souviens plus pourquoi d'ailleurs... :-/

Gromain59, saurais tu me dire si le montage que tu as réalisé peut piloter ma VMC ?

Merci d'avance

Manuel

"

Il y a quelques années, il me semble avoir appris que l'on ne pouvait pas piloter de la même manière une charge résistive (lampe incandescente) et une charge inductive (moteur). Je ne me souviens plus pourquoi

c'est exact et tu va trouver plein de montage pour des variateur de vitesse pour VMC, ventilo etc. Tu peux même récupérer celui d'un veil aspirateur. J'ai fini par opter pour un modèle de VMC avec 2 vitesses et je la change en fonction des paramètres, ca semble beaucoup plus simple et je suis pas sur qu'une variation plus fine soit nécessaire.

Effectivement, pas besoin de + de 2 vitesses, et un variateur d'aspirateur suffit... en général... Car là, il y a un hic : je suis marié... lol Et je ne me vois pas passer un cable de mon grenier à ma cuisine, en traversant la chambre qui est au dessus... Donc la solution du gradateur piloté par un pic (ou une arduino), recevant ses ordre via un module AUREL, ça, ça plait à ma femme !!!

Et qu'est ce que je ne ferait pas pour elle (et la paix dans mon ménage !!!!) ;D

Manuel

Bonjour Manu,

tes quelques lignes me redonne de l'espoir car j'éssaye depuis un bon moment de faire fonctionner ces modules aurel... en fait je n'arrive pas à trouver d'élements sur internet pour m'aiguiller. J'ai éssayé de reprendre des codes de transmissions IR et de les adapter, mais rien à faire. J'avais pensé à une trame à 4 champs (ID, num de trame à incrémenter, état du récepteur, cheksum) à envoyer afin d'éviter les parasitages du récepteur, mais je suis completement bloqué. Si tu as nimporte quel élement ce serai super! :) merci d'avance

jette un oeil sur ce code et ces pages : http://www.arduino.cc/playground/Code/HomeEasy http://www.thegiblins.com/projects/arduino_homeeasy_receiver_manual1.php?Bigulate=0 http://www.zen28611.zen.co.uk/Arduino/HE_RF_to_BBSB_RF_0.1.pde

je suis pas sur que ce soit le bon forum pour développer cela, mais si tu creuses du coté de Homeeasy tu vas trouver ton bonheur... Pourquoi ne pas ouvrir un nouveau topic, si il n'en existe pas deja un...

Manuel