Pages: [1] 2 3   Go Down
Author Topic: Variateur de lumière 8 canaux 230V  (Read 8810 times)
0 Members and 1 Guest are viewing this topic.
Pays de la betise
Offline Offline
Sr. Member
****
Karma: 3
Posts: 417
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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 consigne[c2] (soit un retard de xxx µs)
            => 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
Logged

"pour résoudre un gros problème, il est souvent plus facile de le diviser en petits problèmes élémentaires..."

projet domotique xPLDuino
IRC: freenode #xplduino

Pays de la betise
Offline Offline
Sr. Member
****
Karma: 3
Posts: 417
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

le code:

[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 = 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
Logged

"pour résoudre un gros problème, il est souvent plus facile de le diviser en petits problèmes élémentaires..."

projet domotique xPLDuino
IRC: freenode #xplduino

Pays de la betise
Offline Offline
Sr. Member
****
Karma: 3
Posts: 417
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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
« Last Edit: September 09, 2009, 02:54:56 pm by Gromain59 » Logged

"pour résoudre un gros problème, il est souvent plus facile de le diviser en petits problèmes élémentaires..."

projet domotique xPLDuino
IRC: freenode #xplduino

France
Online Online
Faraday Member
**
Karma: 23
Posts: 3032
There is an Arduino for that
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Pays de la betise
Offline Offline
Sr. Member
****
Karma: 3
Posts: 417
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

"pour résoudre un gros problème, il est souvent plus facile de le diviser en petits problèmes élémentaires..."

projet domotique xPLDuino
IRC: freenode #xplduino

Pays de la betise
Offline Offline
Sr. Member
****
Karma: 3
Posts: 417
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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



j'ai toujours ce phénomème quand l'arduino se reset.  smiley-sad
Logged

"pour résoudre un gros problème, il est souvent plus facile de le diviser en petits problèmes élémentaires..."

projet domotique xPLDuino
IRC: freenode #xplduino

France
Online Online
Faraday Member
**
Karma: 23
Posts: 3032
There is an Arduino for that
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
// 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.
Code:
// 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
      }            
Logged

Pays de la betise
Offline Offline
Sr. Member
****
Karma: 3
Posts: 417
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

"pour résoudre un gros problème, il est souvent plus facile de le diviser en petits problèmes élémentaires..."

projet domotique xPLDuino
IRC: freenode #xplduino

Pays de la betise
Offline Offline
Sr. Member
****
Karma: 3
Posts: 417
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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

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
 
 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


Logged

"pour résoudre un gros problème, il est souvent plus facile de le diviser en petits problèmes élémentaires..."

projet domotique xPLDuino
IRC: freenode #xplduino

Pays de la betise
Offline Offline
Sr. Member
****
Karma: 3
Posts: 417
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Code:

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.
Logged

"pour résoudre un gros problème, il est souvent plus facile de le diviser en petits problèmes élémentaires..."

projet domotique xPLDuino
IRC: freenode #xplduino

Pays de la betise
Offline Offline
Sr. Member
****
Karma: 3
Posts: 417
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

"pour résoudre un gros problème, il est souvent plus facile de le diviser en petits problèmes élémentaires..."

projet domotique xPLDuino
IRC: freenode #xplduino

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 89
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 ; ) )
Logged

Pays de la betise
Offline Offline
Sr. Member
****
Karma: 3
Posts: 417
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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
« Last Edit: February 10, 2010, 10:14:50 am by Gromain59 » Logged

"pour résoudre un gros problème, il est souvent plus facile de le diviser en petits problèmes élémentaires..."

projet domotique xPLDuino
IRC: freenode #xplduino

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 89
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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!
Logged

Pays de la betise
Offline Offline
Sr. Member
****
Karma: 3
Posts: 417
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

"pour résoudre un gros problème, il est souvent plus facile de le diviser en petits problèmes élémentaires..."

projet domotique xPLDuino
IRC: freenode #xplduino

Pages: [1] 2 3   Go Up
Jump to: