[code]



/*

DIMMERS 120V 60Hz (8-channel Possibly more)



by Gromain59

Translated By Mike Deuschle

mike.dausch@gmail.com



Material part:

- Triac driven by a digital output via an optocoupler

- AC opto-coupler for detecting the zero crossing of phase



Software part:

- A hardware interrupt input 2 at the zero crossing of phase

- A software interrupt that occurs between 100us and 1400us.

=> Interrupt interval is variable to obtain a light curve by linear orders, because of the shape of the sinusoidal signal.

we have:

1. Detection of the transition to zero on input 2

2. execution of detection_zero (): processing channel with a setpoint of 0% and 100%

3. deactivating hardware interrupt, enabling the software interrupt on the basis of delay [0]

4. interrupt after delay [c2] ?s (c2 = 0)

5. execution of controle_canaux ()

=> Index increment c2

and if c2 is greater than 49, then this is the last cycle

=> Turn OFF of all channels

=> Activate the hardware interrupt

otherwise:

=> Activation of output channels with 98% to record (either a 469?s delay) or if

=> Interrupt reconfiguration of time with another delay, delay [c2]



To change the setpoint of a channel, you must send via the serial monitor a frame of the form:

" D/0/45/F"

=> Space

=> "D" to indicate the start of the frame

=> "/" As separator

=> The affected channel (0 to 7 here)

=> "/" As separator

=> The desired level (from 0% to 100%)

=> "/" As separator

=> "F" to indicate the end of the frame



Once the frame received, the function sscanf is responsible for retrieving data.

It converts the received record levels (0 to 50 levels)



Resources:

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1230333861/30 for first test

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

http://www.abcelectronique.com/bigonoff/domocan.php?par=3efd4 for electronics and soft (PIC)

arduino forum



*/



#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[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); // 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;



}