I have worked up the attached test code. I haven't tested it in the flesh yet because mains voltage with breadboards needs approaching with circumspection I think.
I was wondering about the interrupt functions intakeFan() and circFan() which are fired from separate inputs, unless there's a way of saving one of those pins on a Nano. That's the question - is it at all possible to combine the two into a single function fired by a zero-crossing signal?
int offPeriods;
int fanOffPeriods;
int ventOffPeriods;
int fanOffTime;
int ventOffTime;
byte ventTriggerPin = 10;
byte fanTriggerPin = 11;
float currentTemp;
void setup() {
Serial.begin(9600);
attachInterrupt(0, intakeFan, RISING);
attachInterrupt(1, circFan, RISING);
}
void loop() {
for (currentTemp = 12; currentTemp < 36; currentTemp++) {
//currentTemp=(currentTemp+0.5);
fanOffPeriods = map(currentTemp, 15, 30, 15, 0);
ventOffPeriods = map(currentTemp, 20, 35, 15, 0);
fanOffPeriods = constrain(fanOffPeriods, 0, 16);
ventOffPeriods = constrain(ventOffPeriods, 0, 16);
// this returns 0 for max value and 21 for min value
// which means maximum 'off periods' at lowest temperatures.
fanOffTime = (640 * fanOffPeriods);
ventOffTime = (640 * ventOffPeriods);
Serial.print (currentTemp);
Serial.print(" ");
Serial.print("Fan off ");
Serial.print(fanOffTime);
Serial.print("mS ");
Serial.print("Vent off ");
Serial.print(ventOffTime);
Serial.println("mS");
delay(1000);
}
}
//-----------------------------------------------------------
void intakeFan() { //Function fired by zero crossing interrupt
delayMicroseconds(ventOffTime);
digitalWrite(ventTriggerPin, HIGH);
delayMicroseconds(10);
digitalWrite(ventTriggerPin, LOW);
}
//-------------------------------------------------------------
void circFan() { //Function fired by zero crossing interrupt
delayMicroseconds(fanOffTime);
digitalWrite(fanTriggerPin, HIGH);
delayMicroseconds(10);
digitalWrite(fanTriggerPin, LOW);
}
//------------------------------------------------------------
That's the question - is it at all possible to combine the two into a single function fired by a zero-crossing signal?
There is only one ac line with a single zero crossing time, and you need to time (delay) the two triac triggers from that common time.
Indeed, because the interrupt service routines can only work sequentially, you will have to do that. If you have two interrupts from the same signal, one isr would execute completely before the other, and the timing of the second one would not be correct.
You will need to have sequential triggers for the different firing times within a single isr. Something like this might work if the two delay periods are different by more than 10 microseconds and the several microseconds it takes to execute the digitalWrite().
void triacTriggers() { //Function fired by zero crossing interrupt
delayMicroseconds(shorter off time);
digitalWrite(shorterTimeTriggerPin, HIGH);
delayMicroseconds(10);
digitalWrite(shorterTimeTriggerPin, LOW);
delayMicroseconds(longer off time - (shorter offtime+10));
digitalWrite(longerTimeTriggerPin, HIGH);
delayMicroseconds(10);
digitalWrite(longerTimeTriggerPin, LOW);
}
I was imagining that ISRs on seperate pins would complete at the same time so I have learned something new. I'll try that out, thanks.
This is as far as I have progressed, I am being stymied by the odd results from the calculation of 'ventOffDelay' towards the end of the loop. The calculation of 'fanOffDelay' is perfectly predictable but the other variable is crazy.
I can't see where my error lies. The product of a single vent period and the number of periods should be around 9600 at the start, but the result doesn't give that.
byte fanControl;
byte fanOffPeriods;
int fanOffDelay;
byte ventControl;
byte ventOffPeriods;
byte ventOffDelay;
int oneFanPeriod = 600; //uS
int oneVentPeriod = 873; //uS
byte ventPin = 10;
byte fanPin = 11;
float currentTemp;
byte difference;
void setup() {
Serial.begin(9600);
attachInterrupt(0, triacTriggers, RISING);
}
void loop() {
for (currentTemp = 10; currentTemp < 40; currentTemp++) { // testing only
fanControl = constrain(currentTemp, 14, 30);
fanOffPeriods = map(fanControl, 15, 30, 15, 0);
ventControl = constrain(currentTemp, 24, 35);
ventOffPeriods = map(ventControl, 25, 35, 10, 0);
fanOffDelay = (oneFanPeriod * fanOffPeriods);
ventOffDelay = (oneVentPeriod * ventOffPeriods); //intend to subtract fanOffDelay+10uS here
Serial.print(currentTemp);
Serial.print(" Fan ");
Serial.print(fanOffDelay);
Serial.print(" One Period ");
Serial.print(oneFanPeriod);
Serial.print(" Number of Periods ");
Serial.println(fanOffPeriods);
Serial.print(" Vent ");
Serial.print(ventOffDelay);
Serial.print(" One Period ");
Serial.print(oneVentPeriod);
Serial.print(" Number of Periods ");
Serial.println(ventOffPeriods);
delay(1000);
}
}
//------------------------------------------------------------
void triacTriggers() { //Function fired by zero crossing interrupt
delayMicroseconds(fanOffDelay);
digitalWrite(fanPin, HIGH);
delayMicroseconds(10);
digitalWrite(fanPin, LOW);
delayMicroseconds(ventOffDelay);
digitalWrite(ventPin, HIGH);
delayMicroseconds(10);
digitalWrite(ventPin, LOW);
}
/*There is only one ac line with a single zero crossing time, and
you need to time (delay) the two triac triggers from that common
time.
Indeed, because the interrupt service routines can only work
sequentially, you will have to do that. If you have two interrupts
from the same signal, one isr would execute completely before the
other, and the timing of the second one would not be correct.
You will need to have sequential triggers for the different firing
times within a single isr. Something like this might work if the
two delay periods are different by more than 10 microseconds and
the several microseconds it takes to execute the digitalWrite().
A snubber is not necessary for the motor operation, but it reduces
the RF which can affect devices in the neighbourhood. I cannot suggest
values, look for commonly available mains RF/noise filters that
support (at least) the motor current.
*/
ventOffDelay is overflowing when typed as byte.
//byte ventOffDelay;
int ventOffDelay;