I am trying to control two dimmers independently with an arduino duemilanove. The dimmer is produced by inmojo (http://www.inmojo.com/store/inmojo-market/item/digital-ac-dimmer-module-lite-v.2/). I tried to use two functions to detect the pass by zero, but one of the functions interrupted the other one. I tried to set a variable to indicate when one of them is done, with no luck. Here is the code
/*
AC Light Dimmer - Inmojo
AC Voltage dimmer with Zero cross detection
Author: Charith Fernanado http://www.inmojo.com charith@inmojo.com
License: Released under the Creative Commons Attribution Share-Alike 3.0 License.
http://creativecommons.org/licenses/by-sa/3.0
Target: Arduino
Attach the Zero cross pin of the module to Arduino External Interrupt pin
Select the correct Interrupt # from the below table
Pin | Interrrupt # | Arduino Platform
---------------------------------------
2 | 0 | All
3 | 1 | All
18 | 5 | Arduino Mega Only
19 | 4 | Arduino Mega Only
20 | 3 | Arduino Mega Only
21 | 2 | Arduino Mega Only
*/
int AC_LOAD_0 = 4; // Output to Opto Triac pin
int AC_LOAD_1 = 5; // Output to Opto Triac pin
int dir_0 = 0; //defines the dimming direction
int dimtime_0;
int dimtime_1;
int minV = 104; //min dimmer value
int maxV = 24; //max dimmer value
int dimming_0 = (minV+maxV)/2; // Dimming level (0-128) 0 = ON, 128 = OFF
int dimming_1 = (minV+maxV)/2; // Dimming level (0-128) 0 = ON, 128 = OFF
int zeroW = 0;
void setup()
{
Serial.begin(9600);
delay(1000);
pinMode(AC_LOAD_0, OUTPUT); // Set the AC Load as output
pinMode(AC_LOAD_1, OUTPUT); // Set the AC Load as output
attachInterrupt(0, zero_crosss_int_0, RISING); // Choose the zero cross interrupt # from the table above
attachInterrupt(1, zero_crosss_int_1, RISING); // Choose the zero cross interrupt # from the table above
}
void loop()
{
Serial.println(dimming_0);
//dimmer 0
if(dimming_0>minV) dir_0=1;
if(dimming_0<maxV) dir_0=0;
if(dir_0==1) dimming_0--;
if(dir_0==0) dimming_0++;
//dimmer 1
dimming_1=(dimming_0*(-1))+minV+maxV;
Serial.println(dimming_1);
delay(100);
}
void zero_crosss_int_0() // function to be fired at the zero crossing to dim the light
{
// if(zeroW == 0){
// Firing angle calculation :: 60Hz-> 8.33ms (1/2 Cycle)
// (8333us - 8.33us) / 128 = 65 (Approx)
int dimtime_0 = (65*dimming_0);
delayMicroseconds(dimtime_0); // Off cycle
digitalWrite(AC_LOAD_0, HIGH); // triac firing
delayMicroseconds(8.33); // triac On propogation delay
digitalWrite(AC_LOAD_0, LOW); // triac Off
// zeroW = 1;
// }
}
void zero_crosss_int_1() // function to be fired at the zero crossing to dim the light
{
// Firing angle calculation :: 60Hz-> 8.33ms (1/2 Cycle)
// (8333us - 8.33us) / 128 = 65 (Approx)
// if(zeroW == 1){
int dimtime_1 = (65*dimming_1);
delayMicroseconds(dimtime_1); // Off cycle
digitalWrite(AC_LOAD_1, HIGH); // triac firing
delayMicroseconds(8.33); // triac On propogation delay
digitalWrite(AC_LOAD_1, LOW); // triac Off
// zeroW = 0;
// }
}
You should have only one interrupt to detect zero cross, as is the same timing for both loads.
Besides that, you should not use delay() or delaymicroseconds() inside an interrupt call.
Ok, I'm back after some research. I'm actually working on the same thing; that is controlling two dimmers from one arduino.
Putting the hardware together, I've tried the circuit shown here: http://wiki.dxarts.washington.edu/groups/general/wiki/4dd69/
and it works like a charm.
I've modified the code to work with two dimmers instead. I didn't try it yet but it should work.
I'll put this together this weekend and try the code so I'll post the circuit and the code if it needs tweaking.
As you see, there's no delay() or delayMicroseconds() ... I've read somewhere that those don't work inside an interrupt function.
Here's the code:
/*
AC dual dimmer Control
adapted from sketch by Robert Twomey <rtwomey@u.washington.edu>
http://wiki.dxarts.washington.edu/groups/general/wiki/4dd69/
*/
#include <TimerOne.h> // Avaiable from http://www.arduino.cc/playground/Code/Timer1
volatile int i=0; // Variable to use as a counter
volatile boolean zero_cross=0; // Boolean to store a "switch" to tell us if we have crossed zero
int AC_pin1 = 11; // Output to Opto Triac load#1
int AC_pin2 = 12; // Output to Triac load #2
int dim1 = 0;
int dim2 = 0; // Dimming level (0-128) 0 = on, 128 = 0ff
int freqStep = 65; // This is the delay-per-brightness step in microseconds.
// It is calculated based on the frequency of your voltage supply (50Hz or 60Hz)
// and the number of brightness steps you want.
//
// 1000000 us / 120 Hz = 8333 uS, length of one half-wave.
// 8333 uS / 128 steps = 65 uS / step
//
void setup() { // Begin setup
pinMode(AC_pin, OUTPUT); // Set the Triac pin as output
attachInterrupt(0, zero_cross_detect, RISING); // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
Timer1.initialize(freqStep); // Initialize TimerOne library for the freq we need
Timer1.attachInterrupt(dim_check, freqStep);
// Use the TimerOne Library to attach an interrupt
// to the function we use to check to see if it is
// the right time to fire the triac. This function
// will now run every freqStep (65 uS for a 60Hz sinewave).
}
void zero_cross_detect() {
i=0;
// since the control pin stays high, the TRIAC won't 'unlatch'
// when zero-crossing, so I need to put the pins to LOW
digitalWrite(AC_pin1, LOW);
digitalWrite(AC_pin2, LOW);
// writing pins is like 10 times faster if
// we write the register directly
// instead of using 'digitalWrite'
}
// Turn on the TRIAC at the appropriate time
void dim_check() {
if(i>=dim1) {
digitalWrite(AC_pin1, HIGH); // turn on triac #1
}
if (i>=dim2) {
digitalWrite(AC_pin2, HIGH); // turn on triac #2
}
i++; // increment time step counter
}
void loop() {
// here goes the code that sets the global variables dim1 and dim2 to the values you want
}
If you manage to do it just with one, I would like to know how you solved. I spend some time trying, but my coding skills are not good. I had problems synchronising the triacs.
I don't know why your code works, because (again) delaymicroseconds() doesn't work inside an interrupt call, that's arduino, and we can't do anything about it.
I finally managed to make a double dimmer and it is working beautifully. Check this schematics, I used exactly the same circuit:
but I repeated the dimmer part twice. The code I used is based on the sketch I found in that page, but I heavily modified to make it cleaner and simpler... and of course, to work with two signals from the arduino.
the sketch I wrote, dims one light while raising the other, and vice-versa. You can change the loop in the sketch to do wathever you want with the dimmers, all you have to do is to set the dim1 and dim2 variables. Here it is, I hope you will find it useful.
/*
AC dual dimmer Control
adapted from sketch by Robert Twomey <rtwomey@u.washington.edu>
http://wiki.dxarts.washington.edu/groups/general/wiki/4dd69/
*/
#include <TimerOne.h> // Avaiable from http://www.arduino.cc/playground/Code/Timer1
volatile int i=0; // Variable to use as a counter
int AC_pin1 = 4; // Output to Opto Triac load#1
int AC_pin2 = 5; // Output to Triac load #2
int dim1 = 0;
int dim2 = 0; // Dimming level (0-128) 0 = on, 128 = 0ff
int inc=1;
int freqStep = 65; // This is the delay-per-brightness step in microseconds.
// It is calculated based on the frequency of your voltage supply (50Hz or 60Hz)
// and the number of brightness steps you want.
//
// 1000000 us / 120 Hz = 8333 uS, length of one half-wave.
// 8333 uS / 128 steps = 65 uS / step
//
void setup() {
// Begin setup
//Serial.begin(9600);
pinMode(AC_pin1, OUTPUT); // Set the Triac pin as output
pinMode(AC_pin2, OUTPUT);
attachInterrupt(0, zero_cross_detect, RISING); // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
Timer1.initialize(freqStep); // Initialize TimerOne library for the freq we need
Timer1.attachInterrupt(dim_check, freqStep);
// Use the TimerOne Library to attach an interrupt
// to the function we use to check to see if it is
// the right time to fire the triac. This function
// will now run every freqStep (65 uS for a 60Hz sinewave).
}
void zero_cross_detect() {
i=0;
// since the control pin stays high, the TRIAC won't 'unlatch'
// when zero-crossing, so I need to put the pins to LOW
digitalWrite(AC_pin1, LOW);
digitalWrite(AC_pin2, LOW);
// writing pins is like 10 times faster if
// we write the register directly
// instead of using 'digitalWrite'
}
// Turn on the TRIAC at the appropriate time
void dim_check() {
if(i>=dim1) {
digitalWrite(AC_pin1, HIGH); // turn on triac #1
}
if (i>=dim2) {
digitalWrite(AC_pin2, HIGH); // turn on triac #2
}
i++; // increment time step counter
}
void loop() {
dim1+=inc;
if (dim1>=127 | dim1<=0){
inc*=-1;
}
dim2=127-dim1;
digitalWrite(13,HIGH);
delay(30);
digitalWrite(13,LOW);
delay(30);
}
I have been using 'delayMicroseconds' in an interrupt and it works like a charm. In fact I never see any warning (other than here) that it couldnt be used.
Sure if your delay is still busy when a new interrupt comes, it will screw up timing, but with the dimmer you have 10 (or 8,3) miliseconds before a new interrupt comes so say a delay of 10uS shouldnt be a problem
Yes, in the past there was a problem, but as of Arduino 0018, delayMicroseconds() no longer disables interrupts.
I don't know why your code works, because (again) delaymicroseconds() doesn't work inside an interrupt call, that's arduino, and we can't do anything about it.
Complete rubbish.
You shouldn't use it, but that's not the same as saying you can't