Since the cooker's heater is controlled by a relay, we can't use a standard PWM output to control it. PWM is a very easy and precise way to control heating but requires a more expensive SSR. There are some PID feedback systems that benefit greatly from PWM control. Fortunately, our system is a big tub of water and water heats up and cools down very slowly. Due to this 'thermal mass' of the system, the response time is relatively slow so we can use a very slow form of PWM known as "Time Proportional Output". In this case, the frequency of the pulses is 0.1 Hz or once very 10 seconds. Its basically like really really slow-scale PWM
We need to control the pulse timing accurately, so we don't want to be affected by any delays that there might be in the main loop. So we use a timer to generate a periodic interrupt. The timer is initialized in setup():
// Run timer2 interrupt every 15 ms TCCR2A = 0; TCCR2B = 1<<CS22 | 1<<CS21 | 1<<CS20; //Timer2 Overflow Interrupt Enable TIMSK2 |= 1<<TOIE2;
And the interrupt service routine is called once every 15 milliseconds to update the relay output.
// ************************************************ // Timer Interrupt Handler // ************************************************ SIGNAL(TIMER2_OVF_vect) { if (opState == OFF) { digitalWrite(RelayPin, LOW); // make sure relay is off } else { DriveOutput(); } }
The DriveOutput() function implements the time proportional output.
// ************************************************ // Called by ISR every 15ms to drive the output // ************************************************ void DriveOutput() { long now = millis(); // Set the output // "on time" is proportional to the PID output if(now - windowStartTime>WindowSize) { //time to shift the Relay Window windowStartTime += WindowSize; } if((onTime > 100) && (onTime > (now - windowStartTime))) { digitalWrite(RelayPin,HIGH); } else { digitalWrite(RelayPin,LOW); } }
Text editor powered by tinymce.