How to dim multiple AC channels?

hey, can someone help me with this one.
I have been searching some way to dim ac light, and i have been managing to control, but just one channel.

i found this thread and it was looking nice, but could some one say how to control those channel values through serial?
im not a code wizard. thanks for the trouble

http://forum.arduino.cc/index.php?topic=6970.75

/*
  AC Light Control
  
  Ryan McLaughlin <ryanjmclaughlin@gmail.com>
  
  The hardware consists of an Triac to act as an A/C switch and
  an opto-isolator to give us a zero-crossing reference.
  The software uses two interrupts to control dimming of the light.
  The first is a hardware interrupt to detect the zero-cross of
  the AC sine wave, the second is software based and always running
  at 1/128 of the AC wave speed. After the zero-cross is detected
  the function check to make sure the proper dimming level has been
  reached and the light is turned on mid-wave, only providing
  partial current and therefore dimming our AC load.
  
  Thanks to http://www.andrewkilpatrick.org/blog/?page_id=445
    and http://www.hoelscher-hi.de/hendrik/english/dimmer.htm
  
 */
 
/*
  Modified by Mark Chester <mark@chesterfamily.org>
  
  to use the AC line frequency (half-period) as a reference point 
  and fire the triacs based on that plus a dimmer delay value.
  I removed the second timer-based interrupt and replaced it with a
  means to reference the zero-crossing point as per interrupt 0.
  It also tracks the rollover of the internal microseconds counter
  to avoid the glitch that would arise about every 70 minutes otherwise.
*/

// General
volatile unsigned long int ZeroXTime1 = 0;             // Timestamp in micros() of the latest zero crossing interrupt
volatile unsigned long int ZeroXTime2 = 0;             // Timestamp in micros() of the previous zero crossing interrupt
volatile unsigned long int XTimePeriod;                // The calculated micros() between the last two zero crossings
byte TriacFireWidth = 2;                               // How many microseconds to leave the triac trigger high
unsigned int DimChangeDelay = 500;                     // How many millis() between changes of dimmer level
unsigned long int DimChangeTime = 0;                   // Timestamp in millis() when the dimmer was changed

// Channel specific
# define Channels 4                                    // How many dimmer channels (triacs) are there?
unsigned long int DimLevel[Channels];                  // Dimming level (high value = more dim, low value = more light)
unsigned long int DimDelay[Channels];         // How many micros() to wait after zero cross to fire the triacs
unsigned long int NextTriacFire[Channels];    // Timestamp in micros() when it's OK to fire the triacs again.
volatile boolean zero_cross[Channels];                 // Boolean to store a "switch" to tell us if we have crossed zero

// Associate pins to each channel (triac)
byte TriacPin[Channels] = {4,5,6,7};

void setup() {                                         // Begin setup
  for ( byte c=0; c<Channels; c++ ) {                  // Loop through and set pin modes
    pinMode(TriacPin[c], OUTPUT);                      // Set the Triac pin as output
  }
  attachInterrupt(0, zero_cross_detect, FALLING);      // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
  delay(50);                                           // Give the interrupt time to capture a few AC cycles
}                                                      // End setup
  
void zero_cross_detect() {                             // function to be fired at the zero crossing
  ZeroXTime2 = ZeroXTime1;                             // shift the current zero cross value to the previous
  ZeroXTime1 = micros();                               // set the new current zero cross time in micros()
  XTimePeriod = ZeroXTime1 - ZeroXTime2;               // Calculate the time since the last zero crossing
  for ( byte c=0; c<Channels; c++ ) {
    DimDelay[c] = XTimePeriod / DimLevel[c];          // Calc how long to wait after zero cross to fire the triacs
    NextTriacFire[c] = ZeroXTime1 + DimDelay[c];      // Calc the next triac fire time
    zero_cross[c] = 1;                                 // set the boolean to true to tell our dimming function that a zero cross has occured
  }
}                                                      // End zero_cross_detect

void loop() {                                          // Main Loop
  
// Set DimLevel in some fashion.
  DimLevel[0] = analogRead(0);                      // For testing, we're just reading an analog input
  DimLevel[1] = analogRead(0);                      // For testing, we're just reading an analog input
  DimLevel[2] = analogRead(0);                      // For testing, we're just reading an analog input
  DimLevel[3] = analogRead(0);                      // For testing, we're just reading an analog input

// DimLevel is used to set NextTriacFire in zero_cross_detect()
  for ( byte d=0; d<Channels; d++ ) {                                 // Loop through each channel
    if ( zero_cross[d] ) {
      if ( micros() >= NextTriacFire[d] ) {                         // Check to see if it's time to fire the triac
        digitalWrite(TriacPin[d], HIGH);                            // Fire the Triac mid-phase
        delayMicroseconds(TriacFireWidth);                          // Pause briefly to ensure the triac turned on
        digitalWrite(TriacPin[d], LOW);                             // Turn off the Triac gate (Triac will not turn off until next zero cross)
        NextTriacFire[d] = NextTriacFire[d] + XTimePeriod;
        zero_cross[d] = 0;                                          // Reset the zero cross detection  
      }
    }
  }
}

You need to replace this part of your code, with a routine to read ints from the Serial port:

// Set DimLevel in some fashion.
  DimLevel[0] = analogRead(0);                      // For testing, we're just reading an analog input
  DimLevel[1] = analogRead(0);                      // For testing, we're just reading an analog input
  DimLevel[2] = analogRead(0);                      // For testing, we're just reading an analog input
  DimLevel[3] = analogRead(0);                      // For testing, we're just reading an analog input

The best way to proceed from here is to read about Serial data and how to receive it. Write a small sketch that simple receives serial data and sends it back out, with or without intermediate processing. Have a look at Nick Gammon's tutorial at Gammon Forum : Electronics : Microprocessors : How to process incoming serial data without blocking

Design a protocol to tell the Arduino which chanel to set.

Then, once you have that, replace the above code with the new stuff.

How to dim multiple AC channels?

hey, can someone help me with this one.
I have been searching some way to dim ac light, and i have been managing to control, but just one channel.

Conceptually it's simple. You just need different dwell times for each channel.

And, you cannot use delay() or delayMicroseconds(). You have to use the concepts in the [u]Blink Without Delay Example[/u], so that the different delays for the different channels don't interfere with each other.

Since all of the lamps are presumably on the same phase (or the opposite phase) you only need to find one zero-crossing. (The exception would be in a theater where you might have 3-phase power with different lamps on different phases, or different phases from the controller.)

Then you need one Arduino output-pin, one opto-isolator and one TRIAC for each lamp-output.

I've built a 4-channnel sound activated lighting controller, but it's only on-off. I've built a one-channel dimmer a long time ago with a different microcontroller.

but could some one say how to control those channel values through serial?

You should probably experiment with some simple serial communication first.

There is actually an existing theatrical lighting control protocol called [u]DMX 512[/u]. If you search, you can find some Arduino based DMX projects. You can build DMX controllers or DMX dimmers, or both. One advantage of using DMX is that you can buy a DMX dimmer or light and use that to test & debug your controller, so you are not trying to debug your controller & dimmer at the same time while tying to figure-out which end has the problem.

Or maybe you can use some existing DMX equipment so you can build something simpler, or build nothing at all!

super duper thank you already for answering

i used this instructions to make a triac dimmer, and my purpose was to use of course only one dimmer zero phase and build other dimmers to use that. and for now i use the same phase for all the dimmers, so no extra problem from there.

I have been thinking to find out dmx but in this case i was thinking that it shouldn't be impossible to dim more than one light using same serial and arduino, just i don't know how to do it.

i would be really thankful if someone would have some solutions for this

Umm... see reply #1.

Use Serial.available() and Serial.read() to read in the levels for the number of channels you want to control, then do the dimming with that data instead of the iput used in the code now. Did you read try, and understand the tutorial I mentioned?

sorry i forgot to answer that i tried to figure out that link earlier, but I'm bit dumb and didn't understand or at least didn't get it to work. Also one thing what i haven't understand yet is how to feed data from several channels. do you separate values with comma in example serial monitor 255,230,.... etc?

svai:
Also one thing what i haven't understand yet is how to feed data from several channels. do you separate values with comma in example serial monitor 255,230,.... etc?

You can do it in a number of ways. Separating input with a delimiter is just one way. another is to indicate which channel you want to change by using an indicator character.

So you can use something like:

120,45,240,100 (and terminate it with a newline)
read bytes, check for them being digits, and build an integer
if a byte is a comma, throw it away, then start working on the second channel
repeat this until you get a newline, then do the same as for a comma, but now you can go send your values to the channels

or, you can use something like

a100, c50 (newline)
Same as above, but when you get an 'a', gather digits, make an integer, and put it into the firsat channel ('a' tells you it's the first channel)

This way allows you to only send anything that you want changed.

yeah i can say that i dont understand how to get it work

can you tell how i could get it to work that i can send from puredata command example "a125" or "b50" and so on, or in form "255,255,0,0" that i could easily just to dim each channel.

thanks for all the trouble

/*
  AC Light Control
 
 Ryan McLaughlin <ryanjmclaughlin@gmail.com>
 
 The hardware consists of an Triac to act as an A/C switch and
 an opto-isolator to give us a zero-crossing reference.
 The software uses two interrupts to control dimming of the light.
 The first is a hardware interrupt to detect the zero-cross of
 the AC sine wave, the second is software based and always running
 at 1/128 of the AC wave speed. After the zero-cross is detected
 the function check to make sure the proper dimming level has been
 reached and the light is turned on mid-wave, only providing
 partial current and therefore dimming our AC load.
 
 Thanks to http://www.andrewkilpatrick.org/blog/?page_id=445
 and http://www.hoelscher-hi.de/hendrik/english/dimmer.htm
 
 */

/*
  Modified by Mark Chester <mark@chesterfamily.org>
 
 to use the AC line frequency (half-period) as a reference point 
 and fire the triacs based on that plus a dimmer delay value.
 I removed the second timer-based interrupt and replaced it with a
 means to reference the zero-crossing point as per interrupt 0.
 It also tracks the rollover of the internal microseconds counter
 to avoid the glitch that would arise about every 70 minutes otherwise.
 */

// General
volatile unsigned long int ZeroXTime1 = 0;             // Timestamp in micros() of the latest zero crossing interrupt
volatile unsigned long int ZeroXTime2 = 0;             // Timestamp in micros() of the previous zero crossing interrupt
volatile unsigned long int XTimePeriod;                // The calculated micros() between the last two zero crossings
byte TriacFireWidth = 2;                               // How many microseconds to leave the triac trigger high
unsigned int DimChangeDelay = 500;                     // How many millis() between changes of dimmer level
unsigned long int DimChangeTime = 0;                   // Timestamp in millis() when the dimmer was changed

// Channel specific
# define Channels 4                                    // How many dimmer channels (triacs) are there?
unsigned long int DimLevel[Channels];                  // Dimming level (high value = more dim, low value = more light)
unsigned long int DimDelay[Channels];         // How many micros() to wait after zero cross to fire the triacs
unsigned long int NextTriacFire[Channels];    // Timestamp in micros() when it's OK to fire the triacs again.
volatile boolean zero_cross[Channels];                 // Boolean to store a "switch" to tell us if we have crossed zero

// Associate pins to each channel (triac)
byte TriacPin[Channels] = {
  4,5,6,7};

void setup() {                                         // Begin setup
  for ( byte c=0; c<Channels; c++ ) {                  // Loop through and set pin modes
    pinMode(TriacPin[c], OUTPUT);                      // Set the Triac pin as output
  }
  attachInterrupt(0, zero_cross_detect, FALLING);      // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
  delay(50);                                           // Give the interrupt time to capture a few AC cycles
}                                                      // End setup

void zero_cross_detect() {                             // function to be fired at the zero crossing
  ZeroXTime2 = ZeroXTime1;                             // shift the current zero cross value to the previous
  ZeroXTime1 = micros();                               // set the new current zero cross time in micros()
  XTimePeriod = ZeroXTime1 - ZeroXTime2;               // Calculate the time since the last zero crossing
  for ( byte c=0; c<Channels; c++ ) {
    DimDelay[c] = XTimePeriod / DimLevel[c];          // Calc how long to wait after zero cross to fire the triacs
    NextTriacFire[c] = ZeroXTime1 + DimDelay[c];      // Calc the next triac fire time
    zero_cross[c] = 1;                                 // set the boolean to true to tell our dimming function that a zero cross has occured
  }
}                                                      // End zero_cross_detect

void loop() {                                          // Main Loop


    byte a, b, c, d;
  if (Serial.available () > 0)
  {
    a = Serial.read ();  
    b = Serial.read ();  
    c = Serial.read ();  
    d = Serial.read ();

  }  // end of if serial data available


  // Set DimLevel in some fashion.
  /* DimLevel[0] = analogRead(0);                      // For testing, we're just reading an analog input
   DimLevel[1] = analogRead(0);                      // For testing, we're just reading an analog input
   DimLevel[2] = analogRead(0);                      // For testing, we're just reading an analog input
   DimLevel[3] = analogRead(0);                      // For testing, we're just reading an analog input
   */
  // DimLevel is used to set NextTriacFire in zero_cross_detect()
  for ( byte d=0; d<Channels; d++ ) {                                 // Loop through each channel
    if ( zero_cross[d] ) {
      if ( micros() >= NextTriacFire[d] ) {                         // Check to see if it's time to fire the triac
        digitalWrite(TriacPin[d], HIGH);                            // Fire the Triac mid-phase
        delayMicroseconds(TriacFireWidth);                          // Pause briefly to ensure the triac turned on
        digitalWrite(TriacPin[d], LOW);                             // Turn off the Triac gate (Triac will not turn off until next zero cross)
        NextTriacFire[d] = NextTriacFire[d] + XTimePeriod;
        zero_cross[d] = 0;                                          // Reset the zero cross detection  
      }
    }
  }
}

hmm, still no luck to get it work, but I wonder if someone could help with even this one.
I found pretty good looking code to my purpose but of course it won't compile, so what is here the problem?

so this is the code:

#include <TimerOne.h>  // for the interruption time http://www.arduino.cc/playground/Code/Timer1
#include <stdio.h>  // for the treatment of the frame containing the change orders

// timeout value for the reception of the frame
int tps_max_lecture = 200; // reading code, counter max between all the characters of a code
int tps_max_carte = 1000; // max meter between reception of a character


long curve[] = {
  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 set[] = {    // set channel level (0 = 100%, 50 = 0%)
  0, // Output 0
  0, // output 1
  0, // output 2
  0, // output 3
  0, // output 4
  0, // output 5
  0, // output 6
  0, // output 7
};

int output [] = { // assign a pin for each channel.
  4, // Output 0
  3, // output 1
  5, // output 2
  0, // output 3
  0, // output 4
  0, // output 5
  0, // output 6
  0, // output 7
};

volatile int c1 = 0; // index c1 for reading data from each channel (No pin, luggage)
volatile int c2 = 0; // c2 index number passing through the loop control phase delay (49 passages)

// Definition of macros to drive the output
#define lightON(index) (digitalWrite(output[index], HIGH))
#define lightOFF(index) (digitalWrite(output[index], LOW))


void setup () {// Start of setup

    // Initialize the serial
  Serial.begin (9600);

  // Initialize the channel outputs (triacs)
  for (c1 = 0; c1 <= 7; c1++) {// we traverse the 8 channels to configure
    pinMode(output[c1], OUTPUT); // we associate each channel has a pin, which sets the output digital
    lightOFF(output[c1]); // and we switch off the output
  }

  Serial.println( "Gromain 8-CHANNEL DIMMER v0.2");
  Serial.println( "FRAME EXPECTED: <space> 'D' / 'Output Port' / 'Value of DIM' / 'F'");


  // Initialize the interruption time Timer1
  Timer1.initialize(); // Initialize TimerOne library for the freq we need


  // Attach the interrupt 0 to pin 2 for the detection of zero crossing (Zero Cross Detection)
  attachInterrupt(0, detection_zero, FALLING); // Attach an Interrupt to Pin 2 (Interrupt 0) for Zero Cross Detection

} // End of setup

void detection_zero() {// function associated with the interrupt 0

  detachInterrupt(0); // disables the interrupt on zero crossing

  c2 = 0;

  for (c1 = 0; c1 <= 7; c1++) {// we scan the 8 outputs to check their orders
    if (set[c1] >= 49 ) {// if set 0%
      lightOFF(c1); // then we switch off
    }

    if (set[c1]<= 0){// if set 100%
      lightON(c1); // then we light
    }

  }

  Timer1.attachInterrupt(controle_canaux, curve[c2]); // we attach the interruption time

} // End of detection_zero

void controle_canaux() {// here we verified whether the triac must be initiated

  c2=c2++;

  attachInterrupt(0, detection_zero, FALLING); // we attach an interrupt on pin 2 (interrupt 0)
  Timer1.detachInterrupt(); // we detach the interruption time

  if (c2 >= 41) {// If last cycle then (best at 41 for 60Hz)

    for (c1 = 0; c1 <= 7; c1++) {// we scan the 8 outputs
      lightOFF(c1);  // and we put out the channel for the next cycle
    }


  }
  else { // else

      Timer1.attachInterrupt(controle_canaux, curve[c2]); // we attach a break time

    for (c1 = 0; c1 <= 7; c1++) { // we scan the 8 outputs to check their orders
      if (set[c1] == c2) // if is set equal to the processed (no change in the loop)
      {
        lightON(c1);
      } // then we light the channel
    }

  } // End function controle_canaux

}
void loop() {// Main Loop

    int n = 0;

  if (Serial.available ()> 0) {
    n = lecture();
  }

}

int lecture() {// read a frame type: "D / aaa / bbb / F
  // Or "D" starting character frame
  // Or "yyyy" No output which is set to modify
  // Or "bbbb" new set of output (between 0 and 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); // decoding frame

  if (c1 == 'D' && c2 == 'F') {// Check if the plot starts out by D and ending in F

    int nouv_cons = n2;  // we store the new value for the work then

    nouv_cons = constrain(nouv_cons, 0, 100); // on the new terminal value between 0 and 100%
    Serial.print("Output ");
    Serial.print(n1);
    Serial.print(" , new value of: ");
    Serial.print(nouv_cons);
    Serial.print(" % index, delay: ");

    set[n1] = (50 - (nouv_cons / 2)); // it converts the value 0-100% in no phase delay

    Serial.println (set[n1]);
  }
  else // if character from the beginning or end of frame not recognized
  {
    Serial.println("Code Unknown");
  }

  return i;

}

and this is the message after trying to compile

dimmer.ino: In function 'int lecture()':
dimmer:243: error: incompatible types in assignment of 'int' to 'char [15]'

would appreciate for help.

Looks like an index got lost - the forum software does that to code that wasn't put in code tags:

      buf[i] = Serial.read ();

Probably worth null terminating buf too.

so do you mean that this

 while (Serial.available() > 0) {
            if(i!=14){
            buf = Serial.read ();
            i++;
            }

should be changed to this?

 while (Serial.available() > 0) {
            if(i!=14){
            buf [i]= Serial.read ();
            i++;
            }

if I do that after compile it says

dimmer.cpp.o: In function `lecture()':
/Applications/dimmer.ino:205: undefined reference to `sscanf(char*, char*, ...)'

and how to fix that index lost?

Hi, this is the problematic part of the code working :stuck_out_tongue:

int n = 0;
int set[] = {    // set channel level (0 = 100%, 50 = 0%)
  50, // Output 0
  50, // output 1
  50, // output 2
  50, // output 3
  50, // output 4
  50, // output 5
  50, // output 6
  50, // output 7
};

int i = 0;
String buf = "";
void setup() {
  Serial.begin(9600);
  pinMode(13, OUTPUT);
}

void loop() {
  if (Serial.available () > 0) {
    buf = Serial.readStringUntil(13); //reads until carriage return
    digitalWrite(13, HIGH); //debug
    //Serial.println(buf); //debug
    lecture();
    buf = "";
  }
}

//D/4/76/F


void lecture() {// read a frame type: "D / aaa / bbb / F
  // Or "D" starting character frame
  // Or "yyyy" No output which is set to modify
  // Or "bbbb" new set of output (between 0 and 100%)

  int timeout = 0;
  char data[15];
  int n1 = 0;
  int n2 = 0;
  char c1, c2;

  digitalWrite(13, LOW);  //debug
  buf.toCharArray(data, 15);
  sscanf(data, "%c/%d/%d/%c", &c1, &n1, &n2, &c2); // decoding frame

  if (c1 == 'D' && c2 == 'F') {// Check if the plot starts out by D and ending in F

    int nouv_cons = n2;  // we store the new value for the work then

    nouv_cons = constrain(nouv_cons, 0, 100); // on the new terminal value between 0 and 100%
    Serial.print("Output ");
    Serial.print(n1);
    Serial.print(" , new value of: ");
    Serial.print(nouv_cons);
    Serial.print(" % index, delay: ");

    set[n1] = (50 - (nouv_cons / 2)); // it converts the value 0-100% in no phase delay

    Serial.println (set[n1]);
  }
  else // if character from the beginning or end of frame not recognized
  {
    Serial.println("Code Unknown");
  }

}